Merge branch 'scrollbar-month-label' into dev

This commit is contained in:
Ming Ming 2022-07-06 00:06:22 +08:00
commit cf2e0e4c48
5 changed files with 110 additions and 10 deletions

View file

@ -33,6 +33,7 @@ import 'package:nc_photos/platform/features.dart' as features;
import 'package:nc_photos/platform/k.dart' as platform_k;
import 'package:nc_photos/pref.dart';
import 'package:nc_photos/pref_util.dart' as pref_util;
import 'package:visibility_detector/visibility_detector.dart';
Future<void> initAppLaunch() async {
if (_hasInitedInThisIsolate) {
@ -51,6 +52,7 @@ Future<void> initAppLaunch() async {
_initSelfSignedCertManager();
}
_initDiContainer();
_initVisibilityDetector();
_hasInitedInThisIsolate = true;
}
@ -172,6 +174,10 @@ void _initDiContainer() {
));
}
void _initVisibilityDetector() {
VisibilityDetectorController.instance.updateInterval = Duration.zero;
}
final _log = Logger("app_init");
var _hasInitedInThisIsolate = false;

View file

@ -1,9 +1,12 @@
import 'dart:collection';
import 'dart:math' as math;
import 'dart:ui';
import 'package:collection/collection.dart';
import 'package:draggable_scrollbar/draggable_scrollbar.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:intl/intl.dart';
import 'package:kiwi/kiwi.dart';
import 'package:logging/logging.dart';
import 'package:nc_photos/account.dart';
@ -31,6 +34,7 @@ import 'package:nc_photos/service.dart' as service;
import 'package:nc_photos/share_handler.dart';
import 'package:nc_photos/snack_bar_manager.dart';
import 'package:nc_photos/theme.dart';
import 'package:nc_photos/throttler.dart';
import 'package:nc_photos/use_case/sync_favorite.dart';
import 'package:nc_photos/widget/album_browser_util.dart' as album_browser_util;
import 'package:nc_photos/widget/builder/photo_list_item_builder.dart';
@ -46,6 +50,7 @@ import 'package:nc_photos/widget/selection_app_bar.dart';
import 'package:nc_photos/widget/settings.dart';
import 'package:nc_photos/widget/viewer.dart';
import 'package:nc_photos/widget/zoom_menu_button.dart';
import 'package:visibility_detector/visibility_detector.dart';
class HomePhotos extends StatefulWidget {
const HomePhotos({
@ -105,6 +110,17 @@ class _HomePhotosState extends State<HomePhotos>
});
}
@override
onVisibilityChanged(VisibilityInfo info, int index, SelectableItem item) {
if (info.visibleFraction >= 0.2) {
_visibleItems.add(_VisibleItem(index, item));
} else {
_visibleItems.remove(_VisibleItem(index, item));
}
_visibilityThrottler.trigger(
maxResponceTime: const Duration(milliseconds: 500));
}
void _initBloc() {
if (_bloc.state is ScanAccountDirBlocInit) {
_log.info("[_initBloc] Initialize bloc");
@ -138,6 +154,8 @@ class _HomePhotosState extends State<HomePhotos>
// status bar + app bar
topOffset: _calcAppBarExtent(context),
bottomOffset: _calcBottomAppBarExtent(context),
labelTextBuilder: (_) => _buildScrollLabel(context),
labelPadding: const EdgeInsets.symmetric(horizontal: 24),
child: ScrollConfiguration(
behavior: ScrollConfiguration.of(context)
.copyWith(scrollbars: false),
@ -163,6 +181,7 @@ class _HomePhotosState extends State<HomePhotos>
_itemListMaxExtent = value;
});
},
isEnableVisibilityCallback: true,
),
SliverToBoxAdapter(
child: SizedBox(
@ -318,6 +337,32 @@ class _HomePhotosState extends State<HomePhotos>
);
}
Widget _buildScrollLabel(BuildContext context) {
final date = _visibleItems
.sorted()
.firstWhereOrNull((e) => e.item is PhotoListFileItem)
?.item
.as<PhotoListFileItem>()
?.file
.bestDateTime;
if (date != null) {
final text = DateFormat(DateFormat.YEAR_ABBR_MONTH,
Localizations.localeOf(context).languageCode)
.format(date.toLocal());
return Padding(
padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 8),
child: Text(
text,
style: const TextStyle(
color: AppTheme.primaryTextColorLight,
),
),
);
} else {
return const SizedBox();
}
}
void _onStateChange(BuildContext context, ScanAccountDirBlocState state) {
if (state is ScanAccountDirBlocInit) {
itemStreamListItems = [];
@ -640,6 +685,16 @@ class _HomePhotosState extends State<HomePhotos>
double? _itemListMaxExtent;
final _visibleItems = HashSet<_VisibleItem>();
late final _visibilityThrottler = Throttler(onTriggered: (_) {
// label text is always 1 frame behind, so we need to update the text for
// the last frame
if (mounted) {
_log.fine("[_visibilityThrottler] Update screen");
setState(() {});
}
});
late final _prefUpdatedListener =
AppEventListener<PrefUpdatedEvent>(_onPrefUpdated);
@ -946,3 +1001,19 @@ enum _SelectionMenuOption {
delete,
download,
}
class _VisibleItem implements Comparable<_VisibleItem> {
const _VisibleItem(this.index, this.item);
@override
operator ==(Object other) => other is _VisibleItem && other.index == index;
@override
compareTo(_VisibleItem other) => index.compareTo(other.index);
@override
get hashCode => index.hashCode;
final int index;
final SelectableItem item;
}

View file

@ -12,6 +12,7 @@ import 'package:nc_photos/session_storage.dart';
import 'package:nc_photos/snack_bar_manager.dart';
import 'package:nc_photos/widget/measurable_item_list.dart';
import 'package:nc_photos/widget/selectable.dart';
import 'package:visibility_detector/visibility_detector.dart';
abstract class SelectableItem {
const SelectableItem();
@ -33,6 +34,10 @@ mixin SelectableItemStreamListMixin<T extends StatefulWidget> on State<T> {
@protected
void onItemTap(SelectableItem item, int index);
@protected
void onVisibilityChanged(
VisibilityInfo info, int index, SelectableItem item) {}
@protected
Widget buildItemStreamListOuter(
BuildContext context, {
@ -57,6 +62,7 @@ mixin SelectableItemStreamListMixin<T extends StatefulWidget> on State<T> {
required double maxCrossAxisExtent,
double mainAxisSpacing = 0,
ValueChanged<double?>? onMaxExtentChanged,
bool isEnableVisibilityCallback = false,
}) {
final Widget content;
if (onMaxExtentChanged != null) {
@ -64,7 +70,8 @@ mixin SelectableItemStreamListMixin<T extends StatefulWidget> on State<T> {
key: _listKey,
maxCrossAxisExtent: maxCrossAxisExtent,
itemCount: _items.length,
itemBuilder: _buildItem,
itemBuilder: (context, i) =>
_buildItem(context, i, isEnableVisibilityCallback),
staggeredTileBuilder: (index) => _items[index].staggeredTile,
mainAxisSpacing: mainAxisSpacing,
onMaxExtentChanged: onMaxExtentChanged,
@ -74,7 +81,8 @@ mixin SelectableItemStreamListMixin<T extends StatefulWidget> on State<T> {
key: ObjectKey(maxCrossAxisExtent),
maxCrossAxisExtent: maxCrossAxisExtent,
itemCount: _items.length,
itemBuilder: _buildItem,
itemBuilder: (context, i) =>
_buildItem(context, i, isEnableVisibilityCallback),
staggeredTileBuilder: (index) => _items[index].staggeredTile,
mainAxisSpacing: mainAxisSpacing,
);
@ -127,11 +135,12 @@ mixin SelectableItemStreamListMixin<T extends StatefulWidget> on State<T> {
?.updateListHeight());
}
Widget _buildItem(BuildContext context, int index) {
Widget _buildItem(
BuildContext context, int index, bool isEnableVisibilityCallback) {
final item = _items[index];
final content = item.buildWidget(context);
Widget content = item.buildWidget(context);
if (item.isSelectable) {
return Selectable(
content = Selectable(
isSelected: _selectedItems.contains(item),
iconSize: 32,
onTap: () => _onItemTap(item, index),
@ -140,9 +149,15 @@ mixin SelectableItemStreamListMixin<T extends StatefulWidget> on State<T> {
: () => _onItemLongPress(item, index),
child: content,
);
} else {
return content;
}
if (isEnableVisibilityCallback) {
content = VisibilityDetector(
key: Key("$index"),
child: content,
onVisibilityChanged: (info) => onVisibilityChanged(info, index, item),
);
}
return content;
}
void _onItemTap(SelectableItem item, int index) {

View file

@ -294,8 +294,8 @@ packages:
dependency: "direct main"
description:
path: "."
ref: "v0.1.0-nc-photos-3"
resolved-ref: "805fb925a6129f693abaa8f30ebb11900543ffc8"
ref: "v0.1.0-nc-photos-5"
resolved-ref: a1a34c57a069dc1cffa9759f86ffab2e0c7420ca
url: "https://gitlab.com/nc-photos/flutter-draggable-scrollbar"
source: git
version: "0.1.0"
@ -1199,6 +1199,13 @@ packages:
url: "https://gitlab.com/nc-photos/flutter-plugins"
source: git
version: "2.0.4"
visibility_detector:
dependency: "direct main"
description:
name: visibility_detector
url: "https://pub.dartlang.org"
source: hosted
version: "0.2.2"
vm_service:
dependency: transitive
description:

View file

@ -43,7 +43,7 @@ dependencies:
draggable_scrollbar:
git:
url: https://gitlab.com/nc-photos/flutter-draggable-scrollbar
ref: v0.1.0-nc-photos-3
ref: v0.1.0-nc-photos-5
equatable: ^2.0.0
event_bus: ^2.0.0
exifdart:
@ -97,6 +97,7 @@ dependencies:
url: https://gitlab.com/nc-photos/flutter-plugins
ref: video_player-v2.2.6-nc-photos-2
path: packages/video_player/video_player
visibility_detector: ^0.2.2
wakelock: ^0.5.2
woozy_search: ^2.0.3
xml: ^5.0.2