chore: bump line length to 120 (#20191)

This commit is contained in:
shenlong
2025-07-25 08:07:22 +05:30
committed by GitHub
parent 977c9b96ba
commit ad65e9011a
517 changed files with 4520 additions and 9514 deletions
@@ -65,8 +65,7 @@ class _AssetDragRegionState extends State<AssetDragRegion> {
Widget build(BuildContext context) {
return RawGestureDetector(
gestures: {
_CustomLongPressGestureRecognizer: GestureRecognizerFactoryWithHandlers<
_CustomLongPressGestureRecognizer>(
_CustomLongPressGestureRecognizer: GestureRecognizerFactoryWithHandlers<_CustomLongPressGestureRecognizer>(
() => _CustomLongPressGestureRecognizer(),
_registerCallbacks,
),
@@ -89,9 +88,7 @@ class _AssetDragRegionState extends State<AssetDragRegion> {
final local = box.globalToLocal(position);
if (!box.hitTest(hitTestResult, position: local)) return null;
return (hitTestResult.path
.firstWhereOrNull((hit) => hit.target is _AssetIndexProxy)
?.target as _AssetIndexProxy?)
return (hitTestResult.path.firstWhereOrNull((hit) => hit.target is _AssetIndexProxy)?.target as _AssetIndexProxy?)
?.index;
}
@@ -99,8 +96,7 @@ class _AssetDragRegionState extends State<AssetDragRegion> {
/// Calculate widget height and scroll offset when long press starting instead of in [initState]
/// or [didChangeDependencies] as the grid might still be rendering into view to get the actual size
final height = context.size?.height;
if (height != null &&
(topScrollOffset == null || bottomScrollOffset == null)) {
if (height != null && (topScrollOffset == null || bottomScrollOffset == null)) {
topScrollOffset = height * scrollOffset;
bottomScrollOffset = height - topScrollOffset!;
}
@@ -188,8 +184,7 @@ class AssetIndexWrapper extends SingleChildRenderObjectWidget {
// ignore: library_private_types_in_public_api
_AssetIndexProxy renderObject,
) {
renderObject.index =
AssetIndex(rowIndex: rowIndex, sectionIndex: sectionIndex);
renderObject.index = AssetIndex(rowIndex: rowIndex, sectionIndex: sectionIndex);
}
}
@@ -53,8 +53,7 @@ class RenderList {
/// global offset of assets in [_buf]
int _bufOffset = 0;
RenderList(this.elements, this.query, this.allAssets)
: totalAssets = allAssets?.length ?? query!.countSync();
RenderList(this.elements, this.query, this.allAssets) : totalAssets = allAssets?.length ?? query!.countSync();
bool get isEmpty => totalAssets == 0;
@@ -90,9 +89,7 @@ class RenderList {
// a tiny bit resulting in a another required load from the DB
final start = max(
0,
forward
? offset - oppositeSize
: (len > batchSize ? offset : offset + count - len),
forward ? offset - oppositeSize : (len > batchSize ? offset : offset + count - len),
);
// load the calculated batch (start:start+len) from the DB and put it into the buffer
_buf = query!.offset(start).limit(len).findAllSync();
@@ -156,9 +153,7 @@ class RenderList {
: null;
for (int i = 0; i < total; i += sectionSize) {
final date = assets != null
? assets[i].fileCreatedAt
: await dateLoader?.getDate(i);
final date = assets != null ? assets[i].fileCreatedAt : await dateLoader?.getDate(i);
final int count = i + sectionSize > total ? total - i : sectionSize;
if (date == null) break;
@@ -175,11 +170,8 @@ class RenderList {
return RenderList(elements, query, assets);
}
final formatSameYear =
groupBy == GroupAssetsBy.month ? DateFormat.MMMM() : DateFormat.MMMEd();
final formatOtherYear = groupBy == GroupAssetsBy.month
? DateFormat.yMMMM()
: DateFormat.yMMMEd();
final formatSameYear = groupBy == GroupAssetsBy.month ? DateFormat.MMMM() : DateFormat.MMMEd();
final formatOtherYear = groupBy == GroupAssetsBy.month ? DateFormat.yMMMM() : DateFormat.yMMMEd();
final currentYear = DateTime.now().year;
final formatMergedSameYear = DateFormat.MMMd();
final formatMergedOtherYear = DateFormat.yMMMd();
@@ -193,16 +185,9 @@ class RenderList {
int lastMonthIndex = 0;
String formatDateRange(DateTime from, DateTime to) {
final startDate = (from.year == currentYear
? formatMergedSameYear
: formatMergedOtherYear)
.format(from);
final endDate = (to.year == currentYear
? formatMergedSameYear
: formatMergedOtherYear)
.format(to);
if (DateTime(from.year, from.month, from.day) ==
DateTime(to.year, to.month, to.day)) {
final startDate = (from.year == currentYear ? formatMergedSameYear : formatMergedOtherYear).format(from);
final endDate = (to.year == currentYear ? formatMergedSameYear : formatMergedOtherYear).format(to);
if (DateTime(from.year, from.month, from.day) == DateTime(to.year, to.month, to.day)) {
// format range with time when both dates are on the same day
final startTime = DateFormat.Hm().format(from);
final endTime = DateFormat.Hm().format(to);
@@ -212,10 +197,7 @@ class RenderList {
}
void mergeMonth() {
if (last != null &&
groupBy == GroupAssetsBy.auto &&
monthCount <= 30 &&
elements.length > lastMonthIndex + 1) {
if (last != null && groupBy == GroupAssetsBy.auto && monthCount <= 30 && elements.length > lastMonthIndex + 1) {
// merge all days into a single section
assert(elements[lastMonthIndex].date.month == last.month);
final e = elements[lastMonthIndex];
@@ -233,8 +215,7 @@ class RenderList {
}
void addElems(DateTime d, DateTime? prevDate) {
final bool newMonth =
last == null || last.year != d.year || last.month != d.month;
final bool newMonth = last == null || last.year != d.year || last.month != d.month;
if (newMonth) {
mergeMonth();
lastMonthIndex = elements.length;
@@ -258,12 +239,8 @@ class RenderList {
totalCount: groupBy == GroupAssetsBy.auto ? sectionCount : count,
offset: lastOffset + j,
title: j == 0
? (d.year == currentYear
? formatSameYear.format(d)
: formatOtherYear.format(d))
: (groupBy == GroupAssetsBy.auto
? formatDateRange(d, prevDate ?? d)
: null),
? (d.year == currentYear ? formatSameYear.format(d) : formatOtherYear.format(d))
: (groupBy == GroupAssetsBy.auto ? formatDateRange(d, prevDate ?? d) : null),
),
);
}
@@ -277,11 +254,7 @@ class RenderList {
// TODO replace with groupBy once Isar supports such queries
final dates = assets != null
? assets.map((a) => a.fileCreatedAt)
: await query!
.offset(offset)
.limit(pageSize)
.fileCreatedAtProperty()
.findAll();
: await query!.offset(offset).limit(pageSize).fileCreatedAtProperty().findAll();
int i = 0;
for (final date in dates) {
final d = DateTime(
@@ -357,11 +330,7 @@ class DateBatchLoader {
Future<void> _loadBatch(int targetIndex) async {
final batchStart = (targetIndex ~/ batchSize) * batchSize;
_buffer = await query
.offset(batchStart)
.limit(batchSize)
.fileCreatedAtProperty()
.findAll();
_buffer = await query.offset(batchStart).limit(batchSize).fileCreatedAtProperty().findAll();
_bufferStart = batchStart;
}
@@ -71,15 +71,11 @@ class ControlBottomAppBar extends HookConsumerWidget {
@override
Widget build(BuildContext context, WidgetRef ref) {
final hasRemote =
selectionAssetState.hasRemote || selectionAssetState.hasMerged;
final hasLocal =
selectionAssetState.hasLocal || selectionAssetState.hasMerged;
final trashEnabled =
ref.watch(serverInfoProvider.select((v) => v.serverFeatures.trash));
final hasRemote = selectionAssetState.hasRemote || selectionAssetState.hasMerged;
final hasLocal = selectionAssetState.hasLocal || selectionAssetState.hasMerged;
final trashEnabled = ref.watch(serverInfoProvider.select((v) => v.serverFeatures.trash));
final albums = ref.watch(albumProvider).where((a) => a.isRemote).toList();
final sharedAlbums =
ref.watch(albumProvider).where((a) => a.shared).toList();
final sharedAlbums = ref.watch(albumProvider).where((a) => a.shared).toList();
const bottomPadding = 0.24;
final scrollController = useDraggableScrollController();
final isInLockedView = ref.watch(inLockedViewProvider);
@@ -132,9 +128,7 @@ class ControlBottomAppBar extends HookConsumerWidget {
List<Widget> renderActionButtons() {
return [
ControlBoxButton(
iconData: Platform.isAndroid
? Icons.share_rounded
: Icons.ios_share_rounded,
iconData: Platform.isAndroid ? Icons.share_rounded : Icons.ios_share_rounded,
label: "share".tr(),
onPressed: enabled ? () => onShare(true) : null,
),
@@ -146,16 +140,13 @@ class ControlBottomAppBar extends HookConsumerWidget {
),
if (hasRemote && onArchive != null)
ControlBoxButton(
iconData:
unarchive ? Icons.unarchive_outlined : Icons.archive_outlined,
iconData: unarchive ? Icons.unarchive_outlined : Icons.archive_outlined,
label: (unarchive ? "unarchive" : "archive").tr(),
onPressed: enabled ? onArchive : null,
),
if (hasRemote && onFavorite != null)
ControlBoxButton(
iconData: unfavorite
? Icons.favorite_border_rounded
: Icons.favorite_rounded,
iconData: unfavorite ? Icons.favorite_border_rounded : Icons.favorite_rounded,
label: (unfavorite ? "unfavorite" : "favorite").tr(),
onPressed: enabled ? onFavorite : null,
),
@@ -174,11 +165,8 @@ class ControlBottomAppBar extends HookConsumerWidget {
child: ControlBoxButton(
iconData: Icons.delete_sweep_outlined,
label: "delete".tr(),
onPressed: enabled
? () => handleRemoteDelete(!trashEnabled, onDelete!)
: null,
onLongPressed:
enabled ? () => showForceDeleteDialog(onDelete!) : null,
onPressed: enabled ? () => handleRemoteDelete(!trashEnabled, onDelete!) : null,
onLongPressed: enabled ? () => showForceDeleteDialog(onDelete!) : null,
),
),
if (hasRemote && onDeleteServer != null && !isInLockedView)
@@ -264,18 +252,12 @@ class ControlBottomAppBar extends HookConsumerWidget {
ConstrainedBox(
constraints: const BoxConstraints(maxWidth: 100),
child: ControlBoxButton(
iconData: isInLockedView
? Icons.lock_open_rounded
: Icons.lock_outline_rounded,
label: isInLockedView
? "remove_from_locked_folder".tr()
: "move_to_locked_folder".tr(),
iconData: isInLockedView ? Icons.lock_open_rounded : Icons.lock_outline_rounded,
label: isInLockedView ? "remove_from_locked_folder".tr() : "move_to_locked_folder".tr(),
onPressed: enabled ? onToggleLocked : null,
),
),
if (!selectionAssetState.hasLocal &&
selectionAssetState.selectedCount > 1 &&
onStack != null)
if (!selectionAssetState.hasLocal && selectionAssetState.selectedCount > 1 && onStack != null)
ConstrainedBox(
constraints: const BoxConstraints(maxWidth: 90),
child: ControlBoxButton(
@@ -276,8 +276,7 @@ class ScrollLabel extends StatelessWidget {
final Text child;
final BoxConstraints? constraints;
static const BoxConstraints _defaultConstraints =
BoxConstraints.tightFor(width: 72.0, height: 28.0);
static const BoxConstraints _defaultConstraints = BoxConstraints.tightFor(width: 72.0, height: 28.0);
const ScrollLabel({
super.key,
@@ -308,8 +307,7 @@ class ScrollLabel extends StatelessWidget {
}
}
class DraggableScrollbarState extends State<DraggableScrollbar>
with TickerProviderStateMixin {
class DraggableScrollbarState extends State<DraggableScrollbar> with TickerProviderStateMixin {
late double _barOffset;
late double _viewOffset;
late bool _isDragInProcess;
@@ -356,8 +354,7 @@ class DraggableScrollbarState extends State<DraggableScrollbar>
super.dispose();
}
double get barMaxScrollExtent =>
context.size!.height - widget.heightScrollThumb;
double get barMaxScrollExtent => context.size!.height - widget.heightScrollThumb;
double get barMinScrollExtent => 0;
@@ -447,8 +444,7 @@ class DraggableScrollbarState extends State<DraggableScrollbar>
}
}
if (notification is ScrollUpdateNotification ||
notification is OverscrollNotification) {
if (notification is ScrollUpdateNotification || notification is OverscrollNotification) {
if (_thumbAnimationController.status != AnimationStatus.forward) {
_thumbAnimationController.forward();
}
@@ -627,8 +623,7 @@ class SlideFadeTransition extends StatelessWidget {
Widget build(BuildContext context) {
return AnimatedBuilder(
animation: animation,
builder: (context, child) =>
animation.value == 0.0 ? const SizedBox() : child!,
builder: (context, child) => animation.value == 0.0 ? const SizedBox() : child!,
child: SlideTransition(
position: Tween(
begin: const Offset(0.3, 0.0),
@@ -169,8 +169,7 @@ class ScrollLabel extends StatelessWidget {
final Text child;
final BoxConstraints? constraints;
static const BoxConstraints _defaultConstraints =
BoxConstraints.tightFor(width: 72.0, height: 28.0);
static const BoxConstraints _defaultConstraints = BoxConstraints.tightFor(width: 72.0, height: 28.0);
const ScrollLabel({
super.key,
@@ -202,8 +201,7 @@ class ScrollLabel extends StatelessWidget {
}
}
class DraggableScrollbarState extends State<DraggableScrollbar>
with TickerProviderStateMixin {
class DraggableScrollbarState extends State<DraggableScrollbar> with TickerProviderStateMixin {
late double _barOffset;
late bool _isDragInProcess;
late int _currentItem;
@@ -250,10 +248,7 @@ class DraggableScrollbarState extends State<DraggableScrollbar>
super.dispose();
}
double get barMaxScrollExtent =>
(context.size?.height ?? 0) -
widget.heightScrollThumb -
(widget.heightOffset ?? 0);
double get barMaxScrollExtent => (context.size?.height ?? 0) - widget.heightScrollThumb - (widget.heightOffset ?? 0);
double get barMinScrollExtent => 0;
@@ -317,8 +312,7 @@ class DraggableScrollbarState extends State<DraggableScrollbar>
setState(() {
try {
int firstItemIndex =
widget.itemPositionsListener.itemPositions.value.first.index;
int firstItemIndex = widget.itemPositionsListener.itemPositions.value.first.index;
if (notification is ScrollUpdateNotification) {
_barOffset = (firstItemIndex / maxItemCount) * barMaxScrollExtent;
@@ -331,8 +325,7 @@ class DraggableScrollbarState extends State<DraggableScrollbar>
}
}
if (notification is ScrollUpdateNotification ||
notification is OverscrollNotification) {
if (notification is ScrollUpdateNotification || notification is OverscrollNotification) {
if (_thumbAnimationController.status != AnimationStatus.forward) {
_thumbAnimationController.forward();
}
@@ -536,8 +529,7 @@ class SlideFadeTransition extends StatelessWidget {
Widget build(BuildContext context) {
return AnimatedBuilder(
animation: animation,
builder: (context, child) =>
animation.value == 0.0 ? const SizedBox() : child!,
builder: (context, child) => animation.value == 0.0 ? const SizedBox() : child!,
child: SlideTransition(
position: Tween(
begin: const Offset(0.3, 0.0),
@@ -32,8 +32,7 @@ class GroupDividerTitle extends HookConsumerWidget {
useEffect(
() {
groupBy.value = GroupAssetsBy.values[
appSettingService.getSetting<int>(AppSettingsEnum.groupAssetsBy)];
groupBy.value = GroupAssetsBy.values[appSettingService.getSetting<int>(AppSettingsEnum.groupAssetsBy)];
return null;
},
[],
@@ -75,14 +74,12 @@ class GroupDividerTitle extends HookConsumerWidget {
? Icon(
Icons.check_circle_rounded,
color: context.primaryColor,
semanticLabel:
"unselect_all_in".tr(namedArgs: {"group": text}),
semanticLabel: "unselect_all_in".tr(namedArgs: {"group": text}),
)
: Icon(
Icons.check_circle_outline_rounded,
color: context.colorScheme.onSurfaceSecondary,
semanticLabel:
"select_all_in".tr(namedArgs: {"group": text}),
semanticLabel: "select_all_in".tr(namedArgs: {"group": text}),
),
),
],
@@ -27,8 +27,7 @@ class ImmichAssetGrid extends HookConsumerWidget {
final bool canDeselect;
final bool? dynamicLayout;
final bool showMultiSelectIndicator;
final void Function(Iterable<ItemPosition> itemPositions)?
visibleItemsListener;
final void Function(Iterable<ItemPosition> itemPositions)? visibleItemsListener;
final Widget? topWidget;
final bool shrinkWrap;
final bool showDragScroll;
@@ -82,10 +81,8 @@ class ImmichAssetGrid extends HookConsumerWidget {
Widget buildAssetGridView(RenderList renderList) {
return RawGestureDetector(
gestures: {
CustomScaleGestureRecognizer: GestureRecognizerFactoryWithHandlers<
CustomScaleGestureRecognizer>(
() => CustomScaleGestureRecognizer(),
(CustomScaleGestureRecognizer scale) {
CustomScaleGestureRecognizer: GestureRecognizerFactoryWithHandlers<CustomScaleGestureRecognizer>(
() => CustomScaleGestureRecognizer(), (CustomScaleGestureRecognizer scale) {
scale.onStart = (details) {
baseScaleFactor.value = scaleFactor.value;
};
@@ -106,15 +103,13 @@ class ImmichAssetGrid extends HookConsumerWidget {
onRefresh: onRefresh,
assetsPerRow: perRow.value,
listener: listener,
showStorageIndicator: showStorageIndicator ??
settings.getSetting(AppSettingsEnum.storageIndicator),
showStorageIndicator: showStorageIndicator ?? settings.getSetting(AppSettingsEnum.storageIndicator),
renderList: renderList,
margin: margin,
selectionActive: selectionActive,
preselectedAssets: preselectedAssets,
canDeselect: canDeselect,
dynamicLayout: dynamicLayout ??
settings.getSetting(AppSettingsEnum.dynamicLayout),
dynamicLayout: dynamicLayout ?? settings.getSetting(AppSettingsEnum.dynamicLayout),
showMultiSelectIndicator: showMultiSelectIndicator,
visibleItemsListener: visibleItemsListener,
topWidget: topWidget,
@@ -51,8 +51,7 @@ class ImmichAssetGridView extends ConsumerStatefulWidget {
final bool canDeselect;
final bool dynamicLayout;
final bool showMultiSelectIndicator;
final void Function(Iterable<ItemPosition> itemPositions)?
visibleItemsListener;
final void Function(Iterable<ItemPosition> itemPositions)? visibleItemsListener;
final Widget? topWidget;
final int heroOffset;
final bool shrinkWrap;
@@ -90,24 +89,20 @@ class ImmichAssetGridView extends ConsumerStatefulWidget {
class ImmichAssetGridViewState extends ConsumerState<ImmichAssetGridView> {
final ItemScrollController _itemScrollController = ItemScrollController();
final ScrollOffsetController _scrollOffsetController =
ScrollOffsetController();
final ItemPositionsListener _itemPositionsListener =
ItemPositionsListener.create();
final ScrollOffsetController _scrollOffsetController = ScrollOffsetController();
final ItemPositionsListener _itemPositionsListener = ItemPositionsListener.create();
late final KeepAliveLink currentAssetLink;
/// The timestamp when the haptic feedback was last invoked
int _hapticFeedbackTS = 0;
DateTime? _prevItemTime;
bool _scrolling = false;
final Set<Asset> _selectedAssets =
LinkedHashSet(equals: (a, b) => a.id == b.id, hashCode: (a) => a.id);
final Set<Asset> _selectedAssets = LinkedHashSet(equals: (a, b) => a.id == b.id, hashCode: (a) => a.id);
bool _dragging = false;
int? _dragAnchorAssetIndex;
int? _dragAnchorSectionIndex;
final Set<Asset> _draggedAssets =
HashSet(equals: (a, b) => a.id == b.id, hashCode: (a) => a.id);
final Set<Asset> _draggedAssets = HashSet(equals: (a, b) => a.id == b.id, hashCode: (a) => a.id);
ScrollPhysics? _scrollPhysics;
@@ -131,9 +126,7 @@ class ImmichAssetGridViewState extends ConsumerState<ImmichAssetGridView> {
void _deselectAssets(List<Asset> assets) {
final assetsToDeselect = assets.where(
(a) =>
widget.canDeselect ||
!(widget.preselectedAssets?.contains(a) ?? false),
(a) => widget.canDeselect || !(widget.preselectedAssets?.contains(a) ?? false),
);
setState(() {
@@ -152,9 +145,7 @@ class ImmichAssetGridViewState extends ConsumerState<ImmichAssetGridView> {
_dragAnchorSectionIndex = null;
_draggedAssets.clear();
_dragging = false;
if (!widget.canDeselect &&
widget.preselectedAssets != null &&
widget.preselectedAssets!.isNotEmpty) {
if (!widget.canDeselect && widget.preselectedAssets != null && widget.preselectedAssets!.isNotEmpty) {
_selectedAssets.addAll(widget.preselectedAssets!);
}
_callSelectionListener(false);
@@ -162,8 +153,7 @@ class ImmichAssetGridViewState extends ConsumerState<ImmichAssetGridView> {
}
bool _allAssetsSelected(List<Asset> assets) {
return widget.selectionActive &&
assets.firstWhereOrNull((e) => !_selectedAssets.contains(e)) == null;
return widget.selectionActive && assets.firstWhereOrNull((e) => !_selectedAssets.contains(e)) == null;
}
Future<void> _scrollToIndex(int index) async {
@@ -244,8 +234,7 @@ class ImmichAssetGridViewState extends ConsumerState<ImmichAssetGridView> {
}
Widget _buildAssetGrid() {
final useDragScrolling =
widget.showDragScroll && widget.renderList.totalAssets >= 20;
final useDragScrolling = widget.showDragScroll && widget.renderList.totalAssets >= 20;
void dragScrolling(bool active) {
if (active != _scrolling) {
@@ -256,9 +245,7 @@ class ImmichAssetGridViewState extends ConsumerState<ImmichAssetGridView> {
}
bool appBarOffset() {
return (ref.watch(tabProvider).index == 0 &&
ModalRoute.of(context)?.settings.name ==
TabControllerRoute.name) ||
return (ref.watch(tabProvider).index == 0 && ModalRoute.of(context)?.settings.name == TabControllerRoute.name) ||
(ModalRoute.of(context)?.settings.name == AlbumViewerRoute.name);
}
@@ -272,8 +259,7 @@ class ImmichAssetGridViewState extends ConsumerState<ImmichAssetGridView> {
physics: _scrollPhysics,
itemScrollController: _itemScrollController,
scrollOffsetController: _scrollOffsetController,
itemCount: widget.renderList.elements.length +
(widget.topWidget != null ? 1 : 0),
itemCount: widget.renderList.elements.length + (widget.topWidget != null ? 1 : 0),
addRepaintBoundaries: true,
shrinkWrap: widget.shrinkWrap,
);
@@ -283,13 +269,10 @@ class ImmichAssetGridViewState extends ConsumerState<ImmichAssetGridView> {
scrollStateListener: dragScrolling,
itemPositionsListener: _itemPositionsListener,
controller: _itemScrollController,
backgroundColor: context.isDarkTheme
? context.colorScheme.primary.darken(amount: .5)
: context.colorScheme.primary,
backgroundColor:
context.isDarkTheme ? context.colorScheme.primary.darken(amount: .5) : context.colorScheme.primary,
labelTextBuilder: widget.showLabel ? _labelBuilder : null,
padding: appBarOffset()
? const EdgeInsets.only(top: 60)
: const EdgeInsets.only(),
padding: appBarOffset() ? const EdgeInsets.only(top: 60) : const EdgeInsets.only(),
heightOffset: appBarOffset() ? 60 : 0,
labelConstraints: const BoxConstraints(maxHeight: 28),
scrollbarAnimationDuration: const Duration(milliseconds: 300),
@@ -323,10 +306,7 @@ class ImmichAssetGridViewState extends ConsumerState<ImmichAssetGridView> {
// Search for the index of the exact date in the list
var index = widget.renderList.elements.indexWhere(
(e) =>
e.date.year == date.year &&
e.date.month == date.month &&
e.date.day == date.day,
(e) => e.date.year == date.year && e.date.month == date.month && e.date.day == date.day,
);
// If the exact date is not found, the timeline is grouped by month,
@@ -343,8 +323,7 @@ class ImmichAssetGridViewState extends ConsumerState<ImmichAssetGridView> {
} else {
ImmichToast.show(
context: context,
msg:
"The date (${DateFormat.yMd().format(date)}) could not be found in the timeline.",
msg: "The date (${DateFormat.yMd().format(date)}) could not be found in the timeline.",
gravity: ToastGravity.BOTTOM,
toastType: ToastType.error,
);
@@ -417,8 +396,7 @@ class ImmichAssetGridViewState extends ConsumerState<ImmichAssetGridView> {
// on startup.
if (_prevItemTime == null) {
_prevItemTime = date;
} else if (_prevItemTime?.year != date.year ||
_prevItemTime?.month != date.month) {
} else if (_prevItemTime?.year != date.year || _prevItemTime?.month != date.month) {
_prevItemTime = date;
final now = Timeline.now;
@@ -511,12 +489,10 @@ class ImmichAssetGridViewState extends ConsumerState<ImmichAssetGridView> {
final selectedAssets = <Asset>{};
var currentSectionIndex = startSectionIndex;
while (currentSectionIndex < endSectionIndex) {
final section =
widget.renderList.elements.elementAtOrNull(currentSectionIndex);
final section = widget.renderList.elements.elementAtOrNull(currentSectionIndex);
if (section == null) continue;
final sectionAssets =
widget.renderList.loadAssets(section.offset, section.count);
final sectionAssets = widget.renderList.loadAssets(section.offset, section.count);
if (currentSectionIndex == startSectionIndex) {
selectedAssets.addAll(
@@ -531,8 +507,7 @@ class ImmichAssetGridViewState extends ConsumerState<ImmichAssetGridView> {
final section = widget.renderList.elements.elementAtOrNull(endSectionIndex);
if (section != null) {
final sectionAssets =
widget.renderList.loadAssets(section.offset, section.count);
final sectionAssets = widget.renderList.loadAssets(section.offset, section.count);
if (startSectionIndex == endSectionIndex) {
selectedAssets.addAll(
sectionAssets.slice(startSectionAssetIndex, endSectionAssetIndex + 1),
@@ -562,8 +537,7 @@ class ImmichAssetGridViewState extends ConsumerState<ImmichAssetGridView> {
/// "add to album" button.
///
/// `_selectedAssets` includes `preselectedAssets` on initialization.
if (_selectedAssets.length >
(widget.preselectedAssets?.length ?? 0)) {
if (_selectedAssets.length > (widget.preselectedAssets?.length ?? 0)) {
/// `_deselectAll` only deselects the selected assets,
/// doesn't affect the preselected ones.
_deselectAll();
@@ -585,8 +559,7 @@ class ImmichAssetGridViewState extends ConsumerState<ImmichAssetGridView> {
),
child: _buildAssetGrid(),
),
if (widget.showMultiSelectIndicator && widget.selectionActive)
_buildMultiSelectIndicator(),
if (widget.showMultiSelectIndicator && widget.selectionActive) _buildMultiSelectIndicator(),
],
),
);
@@ -671,26 +644,20 @@ class _Section extends StatelessWidget {
) {
return LayoutBuilder(
builder: (context, constraints) {
final width = constraints.maxWidth / assetsPerRow -
margin * (assetsPerRow - 1) / assetsPerRow;
final width = constraints.maxWidth / assetsPerRow - margin * (assetsPerRow - 1) / assetsPerRow;
final rows = (section.count + assetsPerRow - 1) ~/ assetsPerRow;
final List<Asset> assetsToRender = scrolling
? []
: renderList.loadAssets(section.offset, section.count);
final List<Asset> assetsToRender = scrolling ? [] : renderList.loadAssets(section.offset, section.count);
return Column(
key: ValueKey(section.offset),
crossAxisAlignment: CrossAxisAlignment.start,
children: [
if (section.type == RenderAssetGridElementType.monthTitle)
_MonthTitle(date: section.date),
if (section.type == RenderAssetGridElementType.monthTitle) _MonthTitle(date: section.date),
if (section.type == RenderAssetGridElementType.groupDividerTitle ||
section.type == RenderAssetGridElementType.monthTitle)
_Title(
selectionActive: selectionActive,
title: section.title!,
assets: scrolling
? []
: renderList.loadAssets(section.offset, section.totalCount),
assets: scrolling ? [] : renderList.loadAssets(section.offset, section.totalCount),
allAssetsSelected: allAssetsSelected,
selectAssets: selectAssets,
deselectAssets: deselectAssets,
@@ -699,9 +666,7 @@ class _Section extends StatelessWidget {
scrolling
? _PlaceholderRow(
key: ValueKey(i),
number: i + 1 == rows
? section.count - i * assetsPerRow
: assetsPerRow,
number: i + 1 == rows ? section.count - i * assetsPerRow : assetsPerRow,
width: width,
height: width,
margin: margin,
@@ -747,9 +712,7 @@ class _MonthTitle extends StatelessWidget {
@override
Widget build(BuildContext context) {
final monthFormat = DateTime.now().year == date.year
? DateFormat.MMMM()
: DateFormat.yMMMM();
final monthFormat = DateTime.now().year == date.year ? DateFormat.MMMM() : DateFormat.yMMMM();
final String title = monthFormat.format(date);
return Padding(
key: Key("month-$title"),
@@ -844,8 +807,7 @@ class _AssetRow extends StatelessWidget {
final widthDistribution = List.filled(assets.length, 1.0);
if (dynamicLayout) {
final aspectRatios =
assets.map((e) => (e.width ?? 1) / (e.height ?? 1)).toList();
final aspectRatios = assets.map((e) => (e.width ?? 1) / (e.height ?? 1)).toList();
final meanAspectRatio = aspectRatios.sum / assets.length;
// 1: mean width
@@ -65,11 +65,9 @@ class MultiselectGrid extends HookConsumerWidget {
final bool unfavorite;
final bool editEnabled;
final Widget? emptyIndicator;
Widget buildDefaultLoadingIndicator() =>
const Center(child: CircularProgressIndicator());
Widget buildDefaultLoadingIndicator() => const Center(child: CircularProgressIndicator());
Widget buildEmptyIndicator() =>
emptyIndicator ?? Center(child: const Text("no_assets_to_show").tr());
Widget buildEmptyIndicator() => emptyIndicator ?? Center(child: const Text("no_assets_to_show").tr());
@override
Widget build(BuildContext context, WidgetRef ref) {
@@ -103,8 +101,7 @@ class MultiselectGrid extends HookConsumerWidget {
) {
selectionEnabledHook.value = multiselect;
selection.value = selectedAssets;
selectionAssetState.value =
AssetSelectionState.fromSelection(selectedAssets);
selectionAssetState.value = AssetSelectionState.fromSelection(selectedAssets);
}
errorBuilder(String? msg) => msg != null && msg.isNotEmpty
@@ -120,16 +117,13 @@ class MultiselectGrid extends HookConsumerWidget {
String? ownerErrorMessage,
}) {
final assets = selection.value;
return assets
.remoteOnly(errorCallback: errorBuilder(localErrorMessage))
.ownedOnly(
return assets.remoteOnly(errorCallback: errorBuilder(localErrorMessage)).ownedOnly(
currentUser,
errorCallback: errorBuilder(ownerErrorMessage),
);
}
Iterable<Asset> remoteSelection({String? errorMessage}) =>
selection.value.remoteOnly(
Iterable<Asset> remoteSelection({String? errorMessage}) => selection.value.remoteOnly(
errorCallback: errorBuilder(errorMessage),
);
@@ -139,9 +133,7 @@ class MultiselectGrid extends HookConsumerWidget {
// Share = Download + Send to OS specific share sheet
handleShareAssets(ref, context, selection.value);
} else {
final ids =
remoteSelection(errorMessage: "home_page_share_err_local".tr())
.map((e) => e.remoteId!);
final ids = remoteSelection(errorMessage: "home_page_share_err_local".tr()).map((e) => e.remoteId!);
context.pushRoute(SharedLinkEditRoute(assetsList: ids.toList()));
}
processing.value = false;
@@ -187,18 +179,14 @@ class MultiselectGrid extends HookConsumerWidget {
errorCallback: errorBuilder('home_page_delete_err_partner'.tr()),
)
.toList();
final isDeleted = await ref
.read(assetProvider.notifier)
.deleteAssets(toDelete, force: force);
final isDeleted = await ref.read(assetProvider.notifier).deleteAssets(toDelete, force: force);
if (isDeleted) {
ImmichToast.show(
context: context,
msg: force
? 'assets_deleted_permanently'
.tr(namedArgs: {'count': "${selection.value.length}"})
: 'assets_trashed'
.tr(namedArgs: {'count': "${selection.value.length}"}),
? 'assets_deleted_permanently'.tr(namedArgs: {'count': "${selection.value.length}"})
: 'assets_trashed'.tr(namedArgs: {'count': "${selection.value.length}"}),
gravity: ToastGravity.BOTTOM,
);
selectionEnabledHook.value = false;
@@ -213,26 +201,20 @@ class MultiselectGrid extends HookConsumerWidget {
try {
final localAssets = selection.value.where((a) => a.isLocal).toList();
final toDelete = isMergedAsset
? localAssets.where((e) => e.storage == AssetState.merged)
: localAssets;
final toDelete = isMergedAsset ? localAssets.where((e) => e.storage == AssetState.merged) : localAssets;
if (toDelete.isEmpty) {
return;
}
final isDeleted = await ref
.read(assetProvider.notifier)
.deleteLocalAssets(toDelete.toList());
final isDeleted = await ref.read(assetProvider.notifier).deleteLocalAssets(toDelete.toList());
if (isDeleted) {
final deletedCount =
localAssets.where((e) => !isMergedAsset || e.isRemote).length;
final deletedCount = localAssets.where((e) => !isMergedAsset || e.isRemote).length;
ImmichToast.show(
context: context,
msg: 'assets_removed_permanently_from_device'
.tr(namedArgs: {'count': "$deletedCount"}),
msg: 'assets_removed_permanently_from_device'.tr(namedArgs: {'count': "$deletedCount"}),
gravity: ToastGravity.BOTTOM,
);
@@ -248,9 +230,7 @@ class MultiselectGrid extends HookConsumerWidget {
try {
final toDownload = selection.value.toList();
final results = await ref
.read(downloadStateProvider.notifier)
.downloadAllAsset(toDownload);
final results = await ref.read(downloadStateProvider.notifier).downloadAllAsset(toDownload);
final totalCount = toDownload.length;
final successCount = results.where((e) => e).length;
@@ -290,19 +270,16 @@ class MultiselectGrid extends HookConsumerWidget {
ownerErrorMessage: 'home_page_delete_err_partner'.tr(),
).toList();
final isDeleted =
await ref.read(assetProvider.notifier).deleteRemoteAssets(
toDelete,
shouldDeletePermanently: shouldDeletePermanently,
);
final isDeleted = await ref.read(assetProvider.notifier).deleteRemoteAssets(
toDelete,
shouldDeletePermanently: shouldDeletePermanently,
);
if (isDeleted) {
ImmichToast.show(
context: context,
msg: shouldDeletePermanently
? 'assets_deleted_permanently_from_server'
.tr(namedArgs: {'count': "${toDelete.length}"})
: 'assets_trashed_from_server'
.tr(namedArgs: {'count': "${toDelete.length}"}),
? 'assets_deleted_permanently_from_server'.tr(namedArgs: {'count': "${toDelete.length}"})
: 'assets_trashed_from_server'.tr(namedArgs: {'count': "${toDelete.length}"}),
gravity: ToastGravity.BOTTOM,
);
}
@@ -379,9 +356,7 @@ class MultiselectGrid extends HookConsumerWidget {
if (assets.isEmpty) {
return;
}
final result = await ref
.read(albumServiceProvider)
.createAlbumWithGeneratedName(assets);
final result = await ref.read(albumServiceProvider).createAlbumWithGeneratedName(assets);
if (result != null) {
ref.watch(albumProvider.notifier).refreshRemoteAlbums();
@@ -449,9 +424,7 @@ class MultiselectGrid extends HookConsumerWidget {
);
if (remoteAssets.isNotEmpty) {
final isInLockedView = ref.read(inLockedViewProvider);
final visibility = isInLockedView
? AssetVisibilityEnum.timeline
: AssetVisibilityEnum.locked;
final visibility = isInLockedView ? AssetVisibilityEnum.timeline : AssetVisibilityEnum.locked;
await handleSetAssetsVisibility(
ref,
@@ -489,8 +462,7 @@ class MultiselectGrid extends HookConsumerWidget {
child: Stack(
children: [
ref.watch(renderListProvider).when(
data: (data) => data.isEmpty &&
(buildLoadingIndicator != null || topWidget == null)
data: (data) => data.isEmpty && (buildLoadingIndicator != null || topWidget == null)
? (buildLoadingIndicator ?? buildEmptyIndicator)()
: ImmichAssetGrid(
renderList: data,
@@ -25,10 +25,8 @@ class MultiselectGridStatusIndicator extends HookConsumerWidget {
),
)
: buildLoadingIndicator!(),
RenderListStatusEnum.empty =>
emptyIndicator ?? Center(child: const Text("no_assets_to_show").tr()),
RenderListStatusEnum.error =>
Center(child: const Text("error_loading_assets").tr()),
RenderListStatusEnum.empty => emptyIndicator ?? Center(child: const Text("no_assets_to_show").tr()),
RenderListStatusEnum.error => Center(child: const Text("error_loading_assets").tr()),
RenderListStatusEnum.complete => const SizedBox()
};
}
@@ -41,9 +41,8 @@ class ThumbnailImage extends StatelessWidget {
@override
Widget build(BuildContext context) {
final assetContainerColor = context.isDarkTheme
? context.primaryColor.darken(amount: 0.6)
: context.primaryColor.lighten(amount: 0.8);
final assetContainerColor =
context.isDarkTheme ? context.primaryColor.darken(amount: 0.6) : context.primaryColor.lighten(amount: 0.8);
return Stack(
children: [
@@ -118,9 +117,8 @@ class _SelectedIcon extends StatelessWidget {
@override
Widget build(BuildContext context) {
final assetContainerColor = context.isDarkTheme
? context.primaryColor.darken(amount: 0.6)
: context.primaryColor.lighten(amount: 0.8);
final assetContainerColor =
context.isDarkTheme ? context.primaryColor.darken(amount: 0.6) : context.primaryColor.lighten(amount: 0.8);
return DecoratedBox(
decoration: BoxDecoration(
@@ -322,9 +320,7 @@ class _ImageIcon extends StatelessWidget {
}
return DecoratedBox(
decoration: canDeselect
? BoxDecoration(color: assetContainerColor)
: const BoxDecoration(color: Colors.grey),
decoration: canDeselect ? BoxDecoration(color: assetContainerColor) : const BoxDecoration(color: Colors.grey),
child: ClipRRect(
borderRadius: const BorderRadius.all(Radius.circular(15.0)),
child: image,