chore: bump dart sdk to 3.8 (#20355)

* chore: bump dart sdk to 3.8

* chore: make build

* make pigeon

* chore: format files

---------

Co-authored-by: shenlong-tanwen <139912620+shalong-tanwen@users.noreply.github.com>
This commit is contained in:
shenlong
2025-07-29 00:34:03 +05:30
committed by GitHub
parent 9b3718120b
commit e52b9d15b5
643 changed files with 32561 additions and 35292 deletions

View File

@@ -34,23 +34,15 @@ final _features = [
final assets = await ref.read(remoteAssetRepositoryProvider).getSome(user.id);
final selectedAssets = await ctx.pushRoute<Set<BaseAsset>>(
DriftAssetSelectionTimelineRoute(
lockedSelectionAssets: assets.toSet(),
),
DriftAssetSelectionTimelineRoute(lockedSelectionAssets: assets.toSet()),
);
DLog.log(
"Selected ${selectedAssets?.length ?? 0} assets",
);
DLog.log("Selected ${selectedAssets?.length ?? 0} assets");
return Future.value();
},
),
_Feature(
name: '',
icon: Icons.vertical_align_center_sharp,
onTap: (_, __) => Future.value(),
),
_Feature(name: '', icon: Icons.vertical_align_center_sharp, onTap: (_, __) => Future.value()),
_Feature(
name: 'Sync Local',
icon: Icons.photo_album_rounded,
@@ -76,11 +68,7 @@ final _features = [
icon: Icons.save_rounded,
onTap: (_, ref) => ref.read(driftProvider).customStatement("pragma wal_checkpoint(truncate)"),
),
_Feature(
name: '',
icon: Icons.vertical_align_center_sharp,
onTap: (_, __) => Future.value(),
),
_Feature(name: '', icon: Icons.vertical_align_center_sharp, onTap: (_, __) => Future.value()),
_Feature(
name: 'Clear Delta Checkpoint',
icon: Icons.delete_rounded,
@@ -88,10 +76,7 @@ final _features = [
),
_Feature(
name: 'Clear Local Data',
style: const TextStyle(
color: Colors.orange,
fontWeight: FontWeight.bold,
),
style: const TextStyle(color: Colors.orange, fontWeight: FontWeight.bold),
icon: Icons.delete_forever_rounded,
onTap: (_, ref) async {
final db = ref.read(driftProvider);
@@ -102,10 +87,7 @@ final _features = [
),
_Feature(
name: 'Clear Remote Data',
style: const TextStyle(
color: Colors.orange,
fontWeight: FontWeight.bold,
),
style: const TextStyle(color: Colors.orange, fontWeight: FontWeight.bold),
icon: Icons.delete_sweep_rounded,
onTap: (_, ref) async {
final db = ref.read(driftProvider);
@@ -123,29 +105,20 @@ final _features = [
),
_Feature(
name: 'Local Media Summary',
style: const TextStyle(
color: Colors.indigo,
fontWeight: FontWeight.bold,
),
style: const TextStyle(color: Colors.indigo, fontWeight: FontWeight.bold),
icon: Icons.table_chart_rounded,
onTap: (ctx, _) => ctx.pushRoute(const LocalMediaSummaryRoute()),
),
_Feature(
name: 'Remote Media Summary',
style: const TextStyle(
color: Colors.indigo,
fontWeight: FontWeight.bold,
),
style: const TextStyle(color: Colors.indigo, fontWeight: FontWeight.bold),
icon: Icons.summarize_rounded,
onTap: (ctx, _) => ctx.pushRoute(const RemoteMediaSummaryRoute()),
),
_Feature(
name: 'Reset Sqlite',
icon: Icons.table_view_rounded,
style: const TextStyle(
color: Colors.red,
fontWeight: FontWeight.bold,
),
style: const TextStyle(color: Colors.red, fontWeight: FontWeight.bold),
onTap: (_, ref) async {
final drift = ref.read(driftProvider);
// ignore: invalid_use_of_protected_member, invalid_use_of_visible_for_testing_member
@@ -165,10 +138,7 @@ class FeatInDevPage extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('Features in Development'),
centerTitle: true,
),
appBar: AppBar(title: const Text('Features in Development'), centerTitle: true),
body: Column(
children: [
Flexible(
@@ -178,10 +148,7 @@ class FeatInDevPage extends StatelessWidget {
final feat = _features[index];
return Consumer(
builder: (ctx, ref, _) => ListTile(
title: Text(
feat.name,
style: feat.style,
),
title: Text(feat.name, style: feat.style),
trailing: Icon(feat.icon),
visualDensity: VisualDensity.compact,
onTap: () => unawaited(feat.onTap(ctx, ref)),
@@ -200,12 +167,7 @@ class FeatInDevPage extends StatelessWidget {
}
class _Feature {
const _Feature({
required this.name,
required this.icon,
required this.onTap,
this.style,
});
const _Feature({required this.name, required this.icon, required this.onTap, this.style});
final String name;
final IconData icon;
@@ -244,18 +206,11 @@ class _DevLogs extends StatelessWidget {
return ListTile(
title: Text(
logMessage.message,
style: TextStyle(
color: ctx.colorScheme.onSurface,
fontSize: 14.0,
overflow: TextOverflow.ellipsis,
),
style: TextStyle(color: ctx.colorScheme.onSurface, fontSize: 14.0, overflow: TextOverflow.ellipsis),
),
subtitle: Text(
"at ${DateFormat("HH:mm:ss.SSS").format(logMessage.createdAt)}",
style: TextStyle(
color: ctx.colorScheme.onSurfaceSecondary,
fontSize: 12.0,
),
style: TextStyle(color: ctx.colorScheme.onSurfaceSecondary, fontSize: 12.0),
),
dense: true,
visualDensity: VisualDensity.compact,

View File

@@ -21,12 +21,7 @@ class _Summary extends StatelessWidget {
final Future<int> countFuture;
final void Function()? onTap;
const _Summary({
required this.name,
required this.countFuture,
this.leading,
this.onTap,
});
const _Summary({required this.name, required this.countFuture, this.leading, this.onTap});
@override
Widget build(BuildContext context) {
@@ -40,31 +35,17 @@ class _Summary extends StatelessWidget {
} else if (snapshot.hasError) {
subtitle = const Icon(Icons.error_rounded);
} else {
subtitle = Text(
'${snapshot.data ?? 0}',
style: ctx.textTheme.bodyLarge,
);
subtitle = Text('${snapshot.data ?? 0}', style: ctx.textTheme.bodyLarge);
}
return ListTile(
leading: leading,
title: Text(name),
trailing: subtitle,
onTap: onTap,
);
return ListTile(leading: leading, title: Text(name), trailing: subtitle, onTap: onTap);
},
);
}
}
final _localStats = [
_Stat(
name: 'Local Assets',
load: (db) => db.managers.localAssetEntity.count(),
),
_Stat(
name: 'Local Albums',
load: (db) => db.managers.localAlbumEntity.count(),
),
_Stat(name: 'Local Assets', load: (db) => db.managers.localAssetEntity.count()),
_Stat(name: 'Local Albums', load: (db) => db.managers.localAlbumEntity.count()),
];
@RoutePage()
@@ -97,10 +78,7 @@ class LocalMediaSummaryPage extends StatelessWidget {
const Divider(),
Padding(
padding: const EdgeInsets.only(left: 15),
child: Text(
"Album summary",
style: ctx.textTheme.titleMedium,
),
child: Text("Album summary", style: ctx.textTheme.titleMedium),
),
],
),
@@ -117,15 +95,14 @@ class LocalMediaSummaryPage extends StatelessWidget {
return SliverList.builder(
itemBuilder: (_, index) {
final album = albums[index];
final countFuture =
db.managers.localAlbumAssetEntity.filter((f) => f.albumId.id.equals(album.id)).count();
final countFuture = db.managers.localAlbumAssetEntity
.filter((f) => f.albumId.id.equals(album.id))
.count();
return _Summary(
leading: const Icon(Icons.photo_album_rounded),
name: album.name,
countFuture: countFuture,
onTap: () => context.router.push(
LocalTimelineRoute(album: album),
),
onTap: () => context.router.push(LocalTimelineRoute(album: album)),
);
},
itemCount: albums.length,
@@ -141,38 +118,14 @@ class LocalMediaSummaryPage extends StatelessWidget {
}
final _remoteStats = [
_Stat(
name: 'Remote Assets',
load: (db) => db.managers.remoteAssetEntity.count(),
),
_Stat(
name: 'Exif Entities',
load: (db) => db.managers.remoteExifEntity.count(),
),
_Stat(
name: 'Remote Albums',
load: (db) => db.managers.remoteAlbumEntity.count(),
),
_Stat(
name: 'Memories',
load: (db) => db.managers.memoryEntity.count(),
),
_Stat(
name: 'Memories Assets',
load: (db) => db.managers.memoryAssetEntity.count(),
),
_Stat(
name: 'Stacks',
load: (db) => db.managers.stackEntity.count(),
),
_Stat(
name: 'People',
load: (db) => db.managers.personEntity.count(),
),
_Stat(
name: 'AssetFaces',
load: (db) => db.managers.assetFaceEntity.count(),
),
_Stat(name: 'Remote Assets', load: (db) => db.managers.remoteAssetEntity.count()),
_Stat(name: 'Exif Entities', load: (db) => db.managers.remoteExifEntity.count()),
_Stat(name: 'Remote Albums', load: (db) => db.managers.remoteAlbumEntity.count()),
_Stat(name: 'Memories', load: (db) => db.managers.memoryEntity.count()),
_Stat(name: 'Memories Assets', load: (db) => db.managers.memoryAssetEntity.count()),
_Stat(name: 'Stacks', load: (db) => db.managers.stackEntity.count()),
_Stat(name: 'People', load: (db) => db.managers.personEntity.count()),
_Stat(name: 'AssetFaces', load: (db) => db.managers.assetFaceEntity.count()),
];
@RoutePage()
@@ -205,10 +158,7 @@ class RemoteMediaSummaryPage extends StatelessWidget {
const Divider(),
Padding(
padding: const EdgeInsets.only(left: 15),
child: Text(
"Album summary",
style: ctx.textTheme.titleMedium,
),
child: Text("Album summary", style: ctx.textTheme.titleMedium),
),
],
),
@@ -225,15 +175,14 @@ class RemoteMediaSummaryPage extends StatelessWidget {
return SliverList.builder(
itemBuilder: (_, index) {
final album = albums[index];
final countFuture =
db.managers.remoteAlbumAssetEntity.filter((f) => f.albumId.id.equals(album.id)).count();
final countFuture = db.managers.remoteAlbumAssetEntity
.filter((f) => f.albumId.id.equals(album.id))
.count();
return _Summary(
leading: const Icon(Icons.photo_album_rounded),
name: album.name,
countFuture: countFuture,
onTap: () => context.router.push(
RemoteAlbumRoute(album: album),
),
onTap: () => context.router.push(RemoteAlbumRoute(album: album)),
);
},
itemCount: albums.length,

View File

@@ -35,13 +35,8 @@ class _DriftAlbumsPageState extends ConsumerState<DriftAlbumsPage> {
pinned: true,
actions: [
IconButton(
icon: const Icon(
Icons.add_rounded,
size: 28,
),
onPressed: () => context.pushRoute(
const DriftCreateAlbumRoute(),
),
icon: const Icon(Icons.add_rounded, size: 28),
onPressed: () => context.pushRoute(const DriftCreateAlbumRoute()),
),
],
showUploadButton: false,
@@ -49,9 +44,7 @@ class _DriftAlbumsPageState extends ConsumerState<DriftAlbumsPage> {
AlbumSelector(
onAlbumSelected: (album) {
ref.read(currentRemoteAlbumProvider.notifier).setAlbum(album);
context.router.push(
RemoteAlbumRoute(album: album),
);
context.router.push(RemoteAlbumRoute(album: album));
},
),
],

View File

@@ -16,18 +16,16 @@ class DriftArchivePage extends StatelessWidget {
Widget build(BuildContext context) {
return ProviderScope(
overrides: [
timelineServiceProvider.overrideWith(
(ref) {
final user = ref.watch(currentUserProvider);
if (user == null) {
throw Exception('User must be logged in to access archive');
}
timelineServiceProvider.overrideWith((ref) {
final user = ref.watch(currentUserProvider);
if (user == null) {
throw Exception('User must be logged in to access archive');
}
final timelineService = ref.watch(timelineFactoryProvider).archive(user.id);
ref.onDispose(timelineService.dispose);
return timelineService;
},
),
final timelineService = ref.watch(timelineFactoryProvider).archive(user.id);
ref.onDispose(timelineService.dispose);
return timelineService;
}),
],
child: Timeline(
appBar: MesmerizingSliverAppBar(

View File

@@ -10,10 +10,7 @@ import 'package:immich_mobile/providers/user.provider.dart';
@RoutePage()
class DriftAssetSelectionTimelinePage extends ConsumerWidget {
final Set<BaseAsset> lockedSelectionAssets;
const DriftAssetSelectionTimelinePage({
super.key,
this.lockedSelectionAssets = const {},
});
const DriftAssetSelectionTimelinePage({super.key, this.lockedSelectionAssets = const {}});
@override
Widget build(BuildContext context, WidgetRef ref) {
@@ -21,27 +18,19 @@ class DriftAssetSelectionTimelinePage extends ConsumerWidget {
overrides: [
multiSelectProvider.overrideWith(
() => MultiSelectNotifier(
MultiSelectState(
selectedAssets: {},
lockedSelectionAssets: lockedSelectionAssets,
forceEnable: true,
),
MultiSelectState(selectedAssets: {}, lockedSelectionAssets: lockedSelectionAssets, forceEnable: true),
),
),
timelineServiceProvider.overrideWith(
(ref) {
final user = ref.watch(currentUserProvider);
if (user == null) {
throw Exception(
'User must be logged in to access asset selection timeline',
);
}
timelineServiceProvider.overrideWith((ref) {
final user = ref.watch(currentUserProvider);
if (user == null) {
throw Exception('User must be logged in to access asset selection timeline');
}
final timelineService = ref.watch(timelineFactoryProvider).remoteAssets(user.id);
ref.onDispose(timelineService.dispose);
return timelineService;
},
),
final timelineService = ref.watch(timelineFactoryProvider).remoteAssets(user.id);
ref.onDispose(timelineService.dispose);
return timelineService;
}),
],
child: const Timeline(),
);

View File

@@ -70,12 +70,7 @@ class _DriftCreateAlbumPageState extends ConsumerState<DriftCreateAlbumPage> {
Widget _buildContent() {
if (selectedAssets.isEmpty) {
return SliverList(
delegate: SliverChildListDelegate([
_buildEmptyState(),
_buildSelectPhotosButton(),
]),
);
return SliverList(delegate: SliverChildListDelegate([_buildEmptyState(), _buildSelectPhotosButton()]));
} else {
return _buildSelectedImageGrid();
}
@@ -84,10 +79,7 @@ class _DriftCreateAlbumPageState extends ConsumerState<DriftCreateAlbumPage> {
Widget _buildEmptyState() {
return Padding(
padding: const EdgeInsets.only(top: 0, left: 18),
child: Text(
'create_shared_album_page_share_add_assets',
style: context.textTheme.labelLarge,
).t(),
child: Text('create_shared_album_page_share_add_assets', style: context.textTheme.labelLarge).t(),
);
}
@@ -97,27 +89,17 @@ class _DriftCreateAlbumPageState extends ConsumerState<DriftCreateAlbumPage> {
child: FilledButton.icon(
style: FilledButton.styleFrom(
alignment: Alignment.centerLeft,
padding: const EdgeInsets.symmetric(
vertical: 24.0,
horizontal: 16.0,
),
shape: const RoundedRectangleBorder(
borderRadius: BorderRadius.all(Radius.circular(10.0)),
),
padding: const EdgeInsets.symmetric(vertical: 24.0, horizontal: 16.0),
shape: const RoundedRectangleBorder(borderRadius: BorderRadius.all(Radius.circular(10.0))),
backgroundColor: context.colorScheme.surfaceContainerHigh,
),
onPressed: onSelectPhotos,
icon: Icon(Icons.add_rounded, color: context.primaryColor),
label: Padding(
padding: const EdgeInsets.only(
left: 8.0,
),
padding: const EdgeInsets.only(left: 8.0),
child: Text(
'create_shared_album_page_share_select_photos',
style: context.textTheme.titleMedium?.copyWith(
fontWeight: FontWeight.w600,
color: context.primaryColor,
),
style: context.textTheme.titleMedium?.copyWith(fontWeight: FontWeight.w600, color: context.primaryColor),
).t(),
),
),
@@ -133,16 +115,13 @@ class _DriftCreateAlbumPageState extends ConsumerState<DriftCreateAlbumPage> {
crossAxisSpacing: 1.0,
mainAxisSpacing: 1.0,
),
delegate: SliverChildBuilderDelegate(
(context, index) {
final asset = selectedAssets.elementAt(index);
return GestureDetector(
onTap: onBackgroundTapped,
child: Thumbnail(asset: asset),
);
},
childCount: selectedAssets.length,
),
delegate: SliverChildBuilderDelegate((context, index) {
final asset = selectedAssets.elementAt(index);
return GestureDetector(
onTap: onBackgroundTapped,
child: Thumbnail(asset: asset),
);
}, childCount: selectedAssets.length),
),
);
}
@@ -162,9 +141,7 @@ class _DriftCreateAlbumPageState extends ConsumerState<DriftCreateAlbumPage> {
Future<void> onSelectPhotos() async {
final assets = await context.pushRoute<Set<BaseAsset>>(
DriftAssetSelectionTimelineRoute(
lockedSelectionAssets: selectedAssets,
),
DriftAssetSelectionTimelineRoute(lockedSelectionAssets: selectedAssets),
);
if (assets == null || assets.isEmpty) {
@@ -183,16 +160,15 @@ class _DriftCreateAlbumPageState extends ConsumerState<DriftCreateAlbumPage> {
if (title.isEmpty) {
if (context.mounted) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text('create_album_title_required'.t()),
backgroundColor: context.colorScheme.error,
),
SnackBar(content: Text('create_album_title_required'.t()), backgroundColor: context.colorScheme.error),
);
}
return;
}
final album = await ref.watch(remoteAlbumProvider.notifier).createAlbum(
final album = await ref
.watch(remoteAlbumProvider.notifier)
.createAlbum(
title: title,
description: albumDescriptionController.text.trim(),
assetIds: selectedAssets.map((asset) {
@@ -203,18 +179,13 @@ class _DriftCreateAlbumPageState extends ConsumerState<DriftCreateAlbumPage> {
if (album != null) {
ref.read(currentRemoteAlbumProvider.notifier).setAlbum(album);
context.replaceRoute(
RemoteAlbumRoute(album: album),
);
context.replaceRoute(RemoteAlbumRoute(album: album));
}
}
Widget buildTitleInputField() {
return Padding(
padding: const EdgeInsets.only(
right: 10.0,
left: 10.0,
),
padding: const EdgeInsets.only(right: 10.0, left: 10.0),
child: _AlbumTitleTextField(
focusNode: albumTitleTextFieldFocusNode,
textController: albumTitleController,
@@ -230,11 +201,7 @@ class _DriftCreateAlbumPageState extends ConsumerState<DriftCreateAlbumPage> {
Widget buildDescriptionInputField() {
return Padding(
padding: const EdgeInsets.only(
right: 10.0,
left: 10.0,
top: 8,
),
padding: const EdgeInsets.only(right: 10.0, left: 10.0, top: 8),
child: _AlbumViewerEditableDescription(
textController: albumDescriptionController,
focusNode: albumDescriptionTextFieldFocusNode,
@@ -244,11 +211,7 @@ class _DriftCreateAlbumPageState extends ConsumerState<DriftCreateAlbumPage> {
Widget buildControlButton() {
return Padding(
padding: const EdgeInsets.only(
left: 12.0,
top: 8.0,
bottom: 8.0,
),
padding: const EdgeInsets.only(left: 12.0, top: 8.0, bottom: 8.0),
child: SizedBox(
height: 42.0,
child: ListView(
@@ -272,10 +235,7 @@ class _DriftCreateAlbumPageState extends ConsumerState<DriftCreateAlbumPage> {
elevation: 0,
centerTitle: false,
backgroundColor: context.scaffoldBackgroundColor,
leading: IconButton(
onPressed: () => context.maybePop(),
icon: const Icon(Icons.close_rounded),
),
leading: IconButton(onPressed: () => context.maybePop(), icon: const Icon(Icons.close_rounded)),
title: const Text('create_album').t(),
actions: [
TextButton(
@@ -292,12 +252,7 @@ class _DriftCreateAlbumPageState extends ConsumerState<DriftCreateAlbumPage> {
),
body: GestureDetector(
onTap: onBackgroundTapped,
child: CustomScrollView(
slivers: [
_buildSliverAppBar(),
_buildContent(),
],
),
child: CustomScrollView(slivers: [_buildSliverAppBar(), _buildContent()]),
),
);
}
@@ -341,11 +296,7 @@ class _AlbumTitleTextFieldState extends State<_AlbumTitleTextField> {
Widget build(BuildContext context) {
return TextField(
focusNode: widget.focusNode,
style: TextStyle(
fontSize: 28.0,
color: context.colorScheme.onSurface,
fontWeight: FontWeight.bold,
),
style: TextStyle(fontSize: 28.0, color: context.colorScheme.onSurface, fontWeight: FontWeight.bold),
controller: widget.textController,
onTap: () {
if (widget.textController.text == 'create_album_page_untitled'.t(context: context)) {
@@ -353,35 +304,23 @@ class _AlbumTitleTextFieldState extends State<_AlbumTitleTextField> {
}
},
decoration: InputDecoration(
contentPadding: const EdgeInsets.symmetric(
horizontal: 8.0,
vertical: 16.0,
),
contentPadding: const EdgeInsets.symmetric(horizontal: 8.0, vertical: 16.0),
suffixIcon: widget.textController.text.isNotEmpty && widget.isFocus
? IconButton(
onPressed: () {
widget.textController.clear();
},
icon: Icon(
Icons.cancel_rounded,
color: context.primaryColor,
),
icon: Icon(Icons.cancel_rounded, color: context.primaryColor),
splashRadius: 10.0,
)
: null,
enabledBorder: const OutlineInputBorder(
borderSide: BorderSide(color: Colors.transparent),
borderRadius: BorderRadius.all(
Radius.circular(16.0),
),
borderRadius: BorderRadius.all(Radius.circular(16.0)),
),
focusedBorder: OutlineInputBorder(
borderSide: BorderSide(
color: context.primaryColor.withValues(alpha: 0.3),
),
borderRadius: const BorderRadius.all(
Radius.circular(16.0),
),
borderSide: BorderSide(color: context.primaryColor.withValues(alpha: 0.3)),
borderRadius: const BorderRadius.all(Radius.circular(16.0)),
),
hintText: 'add_a_title'.t(),
hintStyle: context.themeData.inputDecorationTheme.hintStyle?.copyWith(
@@ -398,10 +337,7 @@ class _AlbumTitleTextFieldState extends State<_AlbumTitleTextField> {
}
class _AlbumViewerEditableDescription extends StatefulWidget {
const _AlbumViewerEditableDescription({
required this.textController,
required this.focusNode,
});
const _AlbumViewerEditableDescription({required this.textController, required this.focusNode});
final TextEditingController textController;
final FocusNode focusNode;
@@ -448,37 +384,23 @@ class _AlbumViewerEditableDescriptionState extends State<_AlbumViewerEditableDes
minLines: 1,
controller: widget.textController,
decoration: InputDecoration(
contentPadding: const EdgeInsets.symmetric(
horizontal: 12.0,
vertical: 16.0,
),
contentPadding: const EdgeInsets.symmetric(horizontal: 12.0, vertical: 16.0),
suffixIcon: widget.focusNode.hasFocus && widget.textController.text.isNotEmpty
? IconButton(
onPressed: () {
widget.textController.clear();
},
icon: Icon(
Icons.cancel_rounded,
color: context.primaryColor,
),
icon: Icon(Icons.cancel_rounded, color: context.primaryColor),
splashRadius: 10.0,
)
: null,
enabledBorder: OutlineInputBorder(
borderSide: BorderSide(
color: context.colorScheme.outline.withValues(alpha: 0.3),
),
borderRadius: const BorderRadius.all(
Radius.circular(16.0),
),
borderSide: BorderSide(color: context.colorScheme.outline.withValues(alpha: 0.3)),
borderRadius: const BorderRadius.all(Radius.circular(16.0)),
),
focusedBorder: OutlineInputBorder(
borderSide: BorderSide(
color: context.primaryColor.withValues(alpha: 0.3),
),
borderRadius: const BorderRadius.all(
Radius.circular(16.0),
),
borderSide: BorderSide(color: context.primaryColor.withValues(alpha: 0.3)),
borderRadius: const BorderRadius.all(Radius.circular(16.0)),
),
hintStyle: context.themeData.inputDecorationTheme.hintStyle?.copyWith(
fontSize: 16.0,

View File

@@ -16,18 +16,16 @@ class DriftFavoritePage extends StatelessWidget {
Widget build(BuildContext context) {
return ProviderScope(
overrides: [
timelineServiceProvider.overrideWith(
(ref) {
final user = ref.watch(currentUserProvider);
if (user == null) {
throw Exception('User must be logged in to access favorite');
}
timelineServiceProvider.overrideWith((ref) {
final user = ref.watch(currentUserProvider);
if (user == null) {
throw Exception('User must be logged in to access favorite');
}
final timelineService = ref.watch(timelineFactoryProvider).favorite(user.id);
ref.onDispose(timelineService.dispose);
return timelineService;
},
),
final timelineService = ref.watch(timelineFactoryProvider).favorite(user.id);
ref.onDispose(timelineService.dispose);
return timelineService;
}),
],
child: Timeline(
appBar: MesmerizingSliverAppBar(

View File

@@ -27,12 +27,7 @@ class DriftLibraryPage extends ConsumerWidget {
return const Scaffold(
body: CustomScrollView(
slivers: [
ImmichSliverAppBar(
snap: false,
floating: false,
pinned: true,
showUploadButton: false,
),
ImmichSliverAppBar(snap: false, floating: false, pinned: true, showUploadButton: false),
_ActionButtonGrid(),
_CollectionCards(),
_QuickAccessButtonList(),
@@ -47,9 +42,7 @@ class _ActionButtonGrid extends ConsumerWidget {
@override
Widget build(BuildContext context, WidgetRef ref) {
final isTrashEnable = ref.watch(
serverInfoProvider.select((state) => state.serverFeatures.trash),
);
final isTrashEnable = ref.watch(serverInfoProvider.select((state) => state.serverFeatures.trash));
return SliverPadding(
padding: const EdgeInsets.only(left: 16, top: 16, right: 16, bottom: 12),
@@ -97,11 +90,7 @@ class _ActionButtonGrid extends ConsumerWidget {
}
class _ActionButton extends StatelessWidget {
const _ActionButton({
required this.icon,
required this.onTap,
required this.label,
});
const _ActionButton({required this.icon, required this.onTap, required this.label});
final IconData icon;
final VoidCallback onTap;
@@ -114,13 +103,7 @@ class _ActionButton extends StatelessWidget {
onPressed: onTap,
label: Padding(
padding: const EdgeInsets.only(left: 4.0),
child: Text(
label,
style: TextStyle(
color: context.colorScheme.onSurface,
fontSize: 15,
),
),
child: Text(label, style: TextStyle(color: context.colorScheme.onSurface, fontSize: 15)),
),
style: FilledButton.styleFrom(
elevation: 0,
@@ -129,16 +112,10 @@ class _ActionButton extends StatelessWidget {
alignment: Alignment.centerLeft,
shape: RoundedRectangleBorder(
borderRadius: const BorderRadius.all(Radius.circular(25)),
side: BorderSide(
color: context.colorScheme.onSurface.withAlpha(10),
width: 1,
),
side: BorderSide(color: context.colorScheme.onSurface.withAlpha(10), width: 1),
),
),
icon: Icon(
icon,
color: context.primaryColor,
),
icon: Icon(icon, color: context.primaryColor),
),
);
}
@@ -155,11 +132,7 @@ class _CollectionCards extends StatelessWidget {
child: Wrap(
spacing: 8,
runSpacing: 8,
children: [
_PeopleCollectionCard(),
_PlacesCollectionCard(),
_LocalAlbumsCollectionCard(),
],
children: [_PeopleCollectionCard(), _PlacesCollectionCard(), _LocalAlbumsCollectionCard()],
),
),
);
@@ -188,22 +161,15 @@ class _PeopleCollectionCard extends ConsumerWidget {
height: size,
width: size,
decoration: BoxDecoration(
borderRadius: const BorderRadius.all(
Radius.circular(20),
),
borderRadius: const BorderRadius.all(Radius.circular(20)),
gradient: LinearGradient(
colors: [
context.colorScheme.primary.withAlpha(30),
context.colorScheme.primary.withAlpha(25),
],
colors: [context.colorScheme.primary.withAlpha(30), context.colorScheme.primary.withAlpha(25)],
begin: Alignment.topCenter,
end: Alignment.bottomCenter,
),
),
child: people.widgetWhen(
onLoading: () => const Center(
child: CircularProgressIndicator(),
),
onLoading: () => const Center(child: CircularProgressIndicator()),
onData: (people) {
return GridView.count(
crossAxisCount: 2,
@@ -253,9 +219,7 @@ class _PlacesCollectionCard extends StatelessWidget {
final size = context.width * widthFactor - 20.0;
return GestureDetector(
onTap: () => context.pushRoute(
DriftPlaceRoute(currentLocation: null),
),
onTap: () => context.pushRoute(DriftPlaceRoute(currentLocation: null)),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
@@ -270,10 +234,7 @@ class _PlacesCollectionCard extends StatelessWidget {
child: IgnorePointer(
child: MapThumbnail(
zoom: 8,
centre: const LatLng(
21.44950,
-157.91959,
),
centre: const LatLng(21.44950, -157.91959),
showAttribution: false,
themeMode: context.isDarkTheme ? ThemeMode.dark : ThemeMode.light,
),
@@ -323,10 +284,7 @@ class _LocalAlbumsCollectionCard extends ConsumerWidget {
decoration: BoxDecoration(
borderRadius: const BorderRadius.all(Radius.circular(20)),
gradient: LinearGradient(
colors: [
context.colorScheme.primary.withAlpha(30),
context.colorScheme.primary.withAlpha(25),
],
colors: [context.colorScheme.primary.withAlpha(30), context.colorScheme.primary.withAlpha(25)],
begin: Alignment.topCenter,
end: Alignment.bottomCenter,
),
@@ -340,24 +298,14 @@ class _LocalAlbumsCollectionCard extends ConsumerWidget {
children: albums.when(
data: (data) {
return data.take(4).map((album) {
return LocalAlbumThumbnail(
albumId: album.id,
);
return LocalAlbumThumbnail(albumId: album.id);
}).toList();
},
error: (error, _) {
return [
Center(
child: Text('Error: $error'),
),
];
return [Center(child: Text('Error: $error'))];
},
loading: () {
return [
const Center(
child: CircularProgressIndicator(),
),
];
return [const Center(child: CircularProgressIndicator())];
},
),
),
@@ -394,13 +342,8 @@ class _QuickAccessButtonList extends ConsumerWidget {
sliver: SliverToBoxAdapter(
child: Container(
decoration: BoxDecoration(
border: Border.all(
color: context.colorScheme.onSurface.withAlpha(10),
width: 1,
),
borderRadius: const BorderRadius.all(
Radius.circular(20),
),
border: Border.all(color: context.colorScheme.onSurface.withAlpha(10), width: 1),
borderRadius: const BorderRadius.all(Radius.circular(20)),
gradient: LinearGradient(
colors: [
context.colorScheme.primary.withAlpha(10),
@@ -425,41 +368,26 @@ class _QuickAccessButtonList extends ConsumerWidget {
bottomRight: Radius.circular(partners.isEmpty ? 20 : 0),
),
),
leading: const Icon(
Icons.folder_outlined,
size: 26,
),
leading: const Icon(Icons.folder_outlined, size: 26),
title: Text(
'folders'.t(context: context),
style: context.textTheme.titleSmall?.copyWith(
fontWeight: FontWeight.w500,
),
style: context.textTheme.titleSmall?.copyWith(fontWeight: FontWeight.w500),
),
onTap: () => context.pushRoute(FolderRoute()),
),
ListTile(
leading: const Icon(
Icons.lock_outline_rounded,
size: 26,
),
leading: const Icon(Icons.lock_outline_rounded, size: 26),
title: Text(
'locked_folder'.t(context: context),
style: context.textTheme.titleSmall?.copyWith(
fontWeight: FontWeight.w500,
),
style: context.textTheme.titleSmall?.copyWith(fontWeight: FontWeight.w500),
),
onTap: () => context.pushRoute(const DriftLockedFolderRoute()),
),
ListTile(
leading: const Icon(
Icons.group_outlined,
size: 26,
),
leading: const Icon(Icons.group_outlined, size: 26),
title: Text(
'partners'.t(context: context),
style: context.textTheme.titleSmall?.copyWith(
fontWeight: FontWeight.w500,
),
style: context.textTheme.titleSmall?.copyWith(fontWeight: FontWeight.w500),
),
onTap: () => context.pushRoute(const DriftPartnerRoute()),
),
@@ -494,22 +422,13 @@ class _PartnerList extends StatelessWidget {
bottomRight: Radius.circular(isLastItem ? 20 : 0),
),
),
contentPadding: const EdgeInsets.only(
left: 12.0,
right: 18.0,
),
leading: PartnerUserAvatar(
partner: partner,
),
contentPadding: const EdgeInsets.only(left: 12.0, right: 18.0),
leading: PartnerUserAvatar(partner: partner),
title: const Text(
"partner_list_user_photos",
style: TextStyle(
fontWeight: FontWeight.w500,
),
style: TextStyle(fontWeight: FontWeight.w500),
).t(context: context, args: {'user': partner.name}),
onTap: () => context.pushRoute(
DriftPartnerDetailRoute(partner: partner),
),
onTap: () => context.pushRoute(DriftPartnerDetailRoute(partner: partner)),
);
},
);

View File

@@ -16,14 +16,7 @@ class DriftLocalAlbumsPage extends StatelessWidget {
@override
Widget build(BuildContext context) {
return const Scaffold(
body: CustomScrollView(
slivers: [
LocalAlbumsSliverAppBar(),
_AlbumList(),
],
),
);
return const Scaffold(body: CustomScrollView(slivers: [LocalAlbumsSliverAppBar(), _AlbumList()]));
}
}
@@ -37,10 +30,7 @@ class _AlbumList extends ConsumerWidget {
return albums.when(
loading: () => const SliverToBoxAdapter(
child: Center(
child: Padding(
padding: EdgeInsets.all(20.0),
child: CircularProgressIndicator(),
),
child: Padding(padding: EdgeInsets.all(20.0), child: CircularProgressIndicator()),
),
),
error: (error, stack) => SliverToBoxAdapter(
@@ -49,9 +39,7 @@ class _AlbumList extends ConsumerWidget {
padding: const EdgeInsets.all(20.0),
child: Text(
'Error loading albums: $error, stack: $stack',
style: TextStyle(
color: context.colorScheme.error,
),
style: TextStyle(color: context.colorScheme.error),
),
),
),
@@ -60,10 +48,7 @@ class _AlbumList extends ConsumerWidget {
if (albums.isEmpty) {
return const SliverToBoxAdapter(
child: Center(
child: Padding(
padding: EdgeInsets.all(20.0),
child: Text('No albums found'),
),
child: Padding(padding: EdgeInsets.all(20.0), child: Text('No albums found')),
),
);
}
@@ -77,30 +62,12 @@ class _AlbumList extends ConsumerWidget {
return Padding(
padding: const EdgeInsets.only(bottom: 8.0),
child: LargeLeadingTile(
leadingPadding: const EdgeInsets.only(
right: 16,
),
leading: SizedBox(
width: 80,
height: 80,
child: LocalAlbumThumbnail(
albumId: album.id,
),
),
title: Text(
album.name,
style: context.textTheme.titleSmall?.copyWith(
fontWeight: FontWeight.w600,
),
),
leadingPadding: const EdgeInsets.only(right: 16),
leading: SizedBox(width: 80, height: 80, child: LocalAlbumThumbnail(albumId: album.id)),
title: Text(album.name, style: context.textTheme.titleSmall?.copyWith(fontWeight: FontWeight.w600)),
subtitle: Text(
'items_count'.t(
context: context,
args: {'count': album.assetCount},
),
style: context.textTheme.bodyMedium?.copyWith(
color: context.colorScheme.onSurfaceSecondary,
),
'items_count'.t(context: context, args: {'count': album.assetCount}),
style: context.textTheme.bodyMedium?.copyWith(color: context.colorScheme.onSurfaceSecondary),
),
onTap: () => context.pushRoute(LocalTimelineRoute(album: album)),
),

View File

@@ -45,27 +45,23 @@ class _DriftLockedFolderPageState extends ConsumerState<DriftLockedFolderPage> w
Widget build(BuildContext context) {
return ProviderScope(
overrides: [
timelineServiceProvider.overrideWith(
(ref) {
final user = ref.watch(currentUserProvider);
if (user == null) {
throw Exception('User must be logged in to access locked folder');
}
timelineServiceProvider.overrideWith((ref) {
final user = ref.watch(currentUserProvider);
if (user == null) {
throw Exception('User must be logged in to access locked folder');
}
final timelineService = ref.watch(timelineFactoryProvider).lockedFolder(user.id);
ref.onDispose(timelineService.dispose);
return timelineService;
},
),
final timelineService = ref.watch(timelineFactoryProvider).lockedFolder(user.id);
ref.onDispose(timelineService.dispose);
return timelineService;
}),
],
child: _showOverlay
? const SizedBox()
: PopScope(
onPopInvokedWithResult: (didPop, _) => didPop ? ref.read(authProvider.notifier).lockPinCode() : null,
child: Timeline(
appBar: MesmerizingSliverAppBar(
title: 'locked_folder'.t(context: context),
),
appBar: MesmerizingSliverAppBar(title: 'locked_folder'.t(context: context)),
bottomSheet: const LockedFolderBottomSheet(),
),
),

View File

@@ -22,20 +22,14 @@ class DriftMemoryPage extends HookConsumerWidget {
final List<DriftMemory> memories;
final int memoryIndex;
const DriftMemoryPage({
required this.memories,
required this.memoryIndex,
super.key,
});
const DriftMemoryPage({required this.memories, required this.memoryIndex, super.key});
@override
Widget build(BuildContext context, WidgetRef ref) {
final currentMemory = useState(memories[memoryIndex]);
final currentAssetPage = useState(0);
final currentMemoryIndex = useState(memoryIndex);
final assetProgress = useState(
"${currentAssetPage.value + 1}|${currentMemory.value.assets.length}",
);
final assetProgress = useState("${currentAssetPage.value + 1}|${currentMemory.value.assets.length}");
const bgColor = Colors.black;
final currentAsset = useState<RemoteAsset?>(null);
@@ -55,19 +49,13 @@ class DriftMemoryPage extends HookConsumerWidget {
});
toNextMemory() {
memoryPageController.nextPage(
duration: const Duration(milliseconds: 500),
curve: Curves.easeIn,
);
memoryPageController.nextPage(duration: const Duration(milliseconds: 500), curve: Curves.easeIn);
}
void toPreviousMemory() {
if (currentMemoryIndex.value > 0) {
// Move to the previous memory page
memoryPageController.previousPage(
duration: const Duration(milliseconds: 500),
curve: Curves.easeIn,
);
memoryPageController.previousPage(duration: const Duration(milliseconds: 500), curve: Curves.easeIn);
// Wait for the next frame to ensure the page is built
SchedulerBinding.instance.addPostFrameCallback((_) {
@@ -94,10 +82,7 @@ class DriftMemoryPage extends HookConsumerWidget {
// Go to the next asset
PageController controller = memoryAssetPageControllers[currentMemoryIndex.value];
controller.nextPage(
curve: Curves.easeInOut,
duration: const Duration(milliseconds: 500),
);
controller.nextPage(curve: Curves.easeInOut, duration: const Duration(milliseconds: 500));
} else {
// Go to the next memory since we are at the end of our assets
toNextMemory();
@@ -109,10 +94,7 @@ class DriftMemoryPage extends HookConsumerWidget {
// Go to the previous asset
PageController controller = memoryAssetPageControllers[currentMemoryIndex.value];
controller.previousPage(
curve: Curves.easeInOut,
duration: const Duration(milliseconds: 500),
);
controller.previousPage(curve: Curves.easeInOut, duration: const Duration(milliseconds: 500));
} else {
// Go to the previous memory since we are at the end of our assets
toPreviousMemory();
@@ -160,14 +142,7 @@ class DriftMemoryPage extends HookConsumerWidget {
// Precache the asset
final size = MediaQuery.sizeOf(context);
await precacheImage(
getFullImageProvider(
asset,
size: Size(size.width, size.height),
),
context,
size: size,
);
await precacheImage(getFullImageProvider(asset, size: Size(size.width, size.height)), context, size: size);
}
// Precache the next page right away if we are on the first page
@@ -219,9 +194,7 @@ class DriftMemoryPage extends HookConsumerWidget {
backgroundColor: bgColor,
body: SafeArea(
child: PageView.builder(
physics: const BouncingScrollPhysics(
parent: AlwaysScrollableScrollPhysics(),
),
physics: const BouncingScrollPhysics(parent: AlwaysScrollableScrollPhysics()),
scrollDirection: Axis.vertical,
controller: memoryPageController,
onPageChanged: (pageNumber) {
@@ -249,23 +222,13 @@ class DriftMemoryPage extends HookConsumerWidget {
}
final yearsAgo = DateTime.now().year - memories[mIndex].data.year;
final title = 'years_ago'.t(
context: context,
args: {
'years': yearsAgo.toString(),
},
);
final title = 'years_ago'.t(context: context, args: {'years': yearsAgo.toString()});
// Build horizontal page
final assetController = memoryAssetPageControllers[mIndex];
return Column(
children: [
Padding(
padding: const EdgeInsets.only(
left: 24.0,
right: 24.0,
top: 8.0,
bottom: 2.0,
),
padding: const EdgeInsets.only(left: 24.0, right: 24.0, top: 8.0, bottom: 2.0),
child: AnimatedBuilder(
animation: assetController,
builder: (context, child) {
@@ -285,9 +248,7 @@ class DriftMemoryPage extends HookConsumerWidget {
child: Stack(
children: [
PageView.builder(
physics: const BouncingScrollPhysics(
parent: AlwaysScrollableScrollPhysics(),
),
physics: const BouncingScrollPhysics(parent: AlwaysScrollableScrollPhysics()),
controller: assetController,
onPageChanged: onAssetChanged,
scrollDirection: Axis.horizontal,
@@ -298,11 +259,7 @@ class DriftMemoryPage extends HookConsumerWidget {
children: [
Container(
color: Colors.black,
child: DriftMemoryCard(
asset: asset,
title: title,
showTitle: index == 0,
),
child: DriftMemoryCard(asset: asset, title: title, showTitle: index == 0),
),
Positioned.fill(
child: Row(
@@ -343,35 +300,24 @@ class DriftMemoryPage extends HookConsumerWidget {
// turn off full screen mode here
// https://github.com/Milad-Akarie/auto_route_library/issues/1799
context.maybePop();
SystemChrome.setEnabledSystemUIMode(
SystemUiMode.edgeToEdge,
);
SystemChrome.setEnabledSystemUIMode(SystemUiMode.edgeToEdge);
},
shape: const CircleBorder(),
color: Colors.white.withValues(alpha: 0.2),
elevation: 0,
child: const Icon(
Icons.close_rounded,
color: Colors.white,
),
child: const Icon(Icons.close_rounded, color: Colors.white),
),
),
if (currentAsset.value != null && currentAsset.value!.isVideo)
Positioned(
bottom: 24,
right: 32,
child: Icon(
Icons.videocam_outlined,
color: Colors.grey[200],
),
child: Icon(Icons.videocam_outlined, color: Colors.grey[200]),
),
],
),
),
DriftMemoryBottomInfo(
memory: memories[mIndex],
title: title,
),
DriftMemoryBottomInfo(memory: memories[mIndex], title: title),
],
);
},

View File

@@ -15,28 +15,20 @@ import 'package:immich_mobile/widgets/common/mesmerizing_sliver_app_bar.dart';
class DriftPartnerDetailPage extends StatelessWidget {
final PartnerUserDto partner;
const DriftPartnerDetailPage({
super.key,
required this.partner,
});
const DriftPartnerDetailPage({super.key, required this.partner});
@override
Widget build(BuildContext context) {
return ProviderScope(
overrides: [
timelineServiceProvider.overrideWith(
(ref) {
final timelineService = ref.watch(timelineFactoryProvider).remoteAssets(partner.id);
ref.onDispose(timelineService.dispose);
return timelineService;
},
),
timelineServiceProvider.overrideWith((ref) {
final timelineService = ref.watch(timelineFactoryProvider).remoteAssets(partner.id);
ref.onDispose(timelineService.dispose);
return timelineService;
}),
],
child: Timeline(
appBar: MesmerizingSliverAppBar(
title: partner.name,
icon: Icons.person_outline,
),
appBar: MesmerizingSliverAppBar(title: partner.name, icon: Icons.person_outline),
topSliverWidget: _InfoBox(partner: partner),
topSliverWidgetHeight: 110,
bottomSheet: const PartnerDetailBottomSheet(),
@@ -48,9 +40,7 @@ class DriftPartnerDetailPage extends StatelessWidget {
class _InfoBox extends ConsumerStatefulWidget {
final PartnerUserDto partner;
const _InfoBox({
required this.partner,
});
const _InfoBox({required this.partner});
@override
ConsumerState<_InfoBox> createState() => _InfoBoxState();
@@ -72,10 +62,7 @@ class _InfoBoxState extends ConsumerState<_InfoBox> {
}
try {
await ref.read(partnerUsersProvider.notifier).toggleShowInTimeline(
widget.partner.id,
user.id,
);
await ref.read(partnerUsersProvider.notifier).toggleShowInTimeline(widget.partner.id, user.id);
setState(() {
_inTimeline = !_inTimeline;
@@ -101,18 +88,10 @@ class _InfoBoxState extends ConsumerState<_InfoBox> {
padding: const EdgeInsets.only(left: 8.0, right: 8.0, top: 16.0),
child: Container(
decoration: BoxDecoration(
border: Border.all(
color: context.colorScheme.onSurface.withAlpha(10),
width: 1,
),
borderRadius: const BorderRadius.all(
Radius.circular(20),
),
border: Border.all(color: context.colorScheme.onSurface.withAlpha(10), width: 1),
borderRadius: const BorderRadius.all(Radius.circular(20)),
gradient: LinearGradient(
colors: [
context.colorScheme.primary.withAlpha(10),
context.colorScheme.primary.withAlpha(15),
],
colors: [context.colorScheme.primary.withAlpha(10), context.colorScheme.primary.withAlpha(15)],
begin: Alignment.topCenter,
end: Alignment.bottomCenter,
),
@@ -122,18 +101,13 @@ class _InfoBoxState extends ConsumerState<_InfoBox> {
child: ListTile(
title: Text(
"Show in timeline",
style: context.textTheme.titleSmall?.copyWith(
color: context.colorScheme.primary,
),
style: context.textTheme.titleSmall?.copyWith(color: context.colorScheme.primary),
),
subtitle: Text(
"Show photos and videos from this user in your timeline",
style: context.textTheme.bodyMedium,
),
trailing: Switch(
value: _inTimeline,
onChanged: (_) => _toggleInTimeline(),
),
trailing: Switch(value: _inTimeline, onChanged: (_) => _toggleInTimeline()),
),
),
),

View File

@@ -52,9 +52,7 @@ class _PlaceSliverAppBar extends StatelessWidget {
pinned: true,
snap: false,
backgroundColor: context.colorScheme.surfaceContainer,
shape: const RoundedRectangleBorder(
borderRadius: BorderRadius.all(Radius.circular(5)),
),
shape: const RoundedRectangleBorder(borderRadius: BorderRadius.all(Radius.circular(5))),
automaticallyImplyLeading: search.value == null,
centerTitle: true,
title: search.value != null
@@ -98,20 +96,14 @@ class _Map extends StatelessWidget {
child: MapThumbnail(
onTap: (_, __) => context.pushRoute(MapRoute(initialLocation: currentLocation)),
zoom: 8,
centre: currentLocation ??
const LatLng(
21.44950,
-157.91959,
),
centre: currentLocation ?? const LatLng(21.44950, -157.91959),
showAttribution: false,
themeMode: context.isDarkTheme ? ThemeMode.dark : ThemeMode.light,
),
),
),
)
: const SliverToBoxAdapter(
child: SizedBox.shrink(),
);
: const SliverToBoxAdapter(child: SizedBox.shrink());
}
}
@@ -127,10 +119,7 @@ class _PlaceList extends ConsumerWidget {
return places.when(
loading: () => const SliverToBoxAdapter(
child: Center(
child: Padding(
padding: EdgeInsets.all(20.0),
child: CircularProgressIndicator(),
),
child: Padding(padding: EdgeInsets.all(20.0), child: CircularProgressIndicator()),
),
),
error: (error, stack) => SliverToBoxAdapter(
@@ -139,9 +128,7 @@ class _PlaceList extends ConsumerWidget {
padding: const EdgeInsets.all(20.0),
child: Text(
'Error loading places: $error, stack: $stack',
style: TextStyle(
color: context.colorScheme.error,
),
style: TextStyle(color: context.colorScheme.error),
),
),
),
@@ -174,21 +161,10 @@ class _PlaceTile extends StatelessWidget {
Widget build(BuildContext context) {
return LargeLeadingTile(
onTap: () => context.pushRoute(DriftPlaceDetailRoute(place: place.$1)),
title: Text(
place.$1,
style: context.textTheme.titleMedium?.copyWith(
fontWeight: FontWeight.w500,
),
),
title: Text(place.$1, style: context.textTheme.titleMedium?.copyWith(fontWeight: FontWeight.w500)),
leading: ClipRRect(
borderRadius: const BorderRadius.all(
Radius.circular(20),
),
child: Thumbnail(
size: const Size(80, 80),
fit: BoxFit.cover,
remoteId: place.$2,
),
borderRadius: const BorderRadius.all(Radius.circular(20)),
child: Thumbnail(size: const Size(80, 80), fit: BoxFit.cover, remoteId: place.$2),
),
);
}

View File

@@ -9,28 +9,20 @@ import 'package:immich_mobile/widgets/common/mesmerizing_sliver_app_bar.dart';
class DriftPlaceDetailPage extends StatelessWidget {
final String place;
const DriftPlaceDetailPage({
super.key,
required this.place,
});
const DriftPlaceDetailPage({super.key, required this.place});
@override
Widget build(BuildContext context) {
return ProviderScope(
overrides: [
timelineServiceProvider.overrideWith(
(ref) {
final timelineService = ref.watch(timelineFactoryProvider).place(place);
ref.onDispose(timelineService.dispose);
return timelineService;
},
),
timelineServiceProvider.overrideWith((ref) {
final timelineService = ref.watch(timelineFactoryProvider).place(place);
ref.onDispose(timelineService.dispose);
return timelineService;
}),
],
child: Timeline(
appBar: MesmerizingSliverAppBar(
title: place,
icon: Icons.location_on,
),
appBar: MesmerizingSliverAppBar(title: place, icon: Icons.location_on),
),
);
}

View File

@@ -15,24 +15,18 @@ class DriftRecentlyTakenPage extends StatelessWidget {
Widget build(BuildContext context) {
return ProviderScope(
overrides: [
timelineServiceProvider.overrideWith(
(ref) {
final user = ref.watch(currentUserProvider);
if (user == null) {
throw Exception(
'User must be logged in to access recently taken',
);
}
timelineServiceProvider.overrideWith((ref) {
final user = ref.watch(currentUserProvider);
if (user == null) {
throw Exception('User must be logged in to access recently taken');
}
final timelineService = ref.watch(timelineFactoryProvider).remoteAssets(user.id);
ref.onDispose(timelineService.dispose);
return timelineService;
},
),
final timelineService = ref.watch(timelineFactoryProvider).remoteAssets(user.id);
ref.onDispose(timelineService.dispose);
return timelineService;
}),
],
child: Timeline(
appBar: MesmerizingSliverAppBar(title: 'recently_taken'.t()),
),
child: Timeline(appBar: MesmerizingSliverAppBar(title: 'recently_taken'.t())),
);
}
}

View File

@@ -21,10 +21,7 @@ import 'package:immich_mobile/widgets/common/remote_album_sliver_app_bar.dart';
class RemoteAlbumPage extends ConsumerStatefulWidget {
final RemoteAlbum album;
const RemoteAlbumPage({
super.key,
required this.album,
});
const RemoteAlbumPage({super.key, required this.album});
@override
ConsumerState<RemoteAlbumPage> createState() => _RemoteAlbumPageState();
@@ -40,16 +37,16 @@ class _RemoteAlbumPageState extends ConsumerState<RemoteAlbumPage> {
final albumAssets = await ref.read(remoteAlbumProvider.notifier).getAssets(widget.album.id);
final newAssets = await context.pushRoute<Set<BaseAsset>>(
DriftAssetSelectionTimelineRoute(
lockedSelectionAssets: albumAssets.toSet(),
),
DriftAssetSelectionTimelineRoute(lockedSelectionAssets: albumAssets.toSet()),
);
if (newAssets == null || newAssets.isEmpty) {
return;
}
final added = await ref.read(remoteAlbumProvider.notifier).addAssets(
final added = await ref
.read(remoteAlbumProvider.notifier)
.addAssets(
widget.album.id,
newAssets.map((asset) {
final remoteAsset = asset as RemoteAsset;
@@ -60,21 +57,14 @@ class _RemoteAlbumPageState extends ConsumerState<RemoteAlbumPage> {
if (added > 0) {
ImmichToast.show(
context: context,
msg: "assets_added_to_album_count".t(
context: context,
args: {
'count': added.toString(),
},
),
msg: "assets_added_to_album_count".t(context: context, args: {'count': added.toString()}),
toastType: ToastType.success,
);
}
}
Future<void> addUsers(BuildContext context) async {
final newUsers = await context.pushRoute<List<String>>(
DriftUserSelectionRoute(album: widget.album),
);
final newUsers = await context.pushRoute<List<String>>(DriftUserSelectionRoute(album: widget.album));
if (newUsers == null || newUsers.isEmpty) {
return;
@@ -86,12 +76,7 @@ class _RemoteAlbumPageState extends ConsumerState<RemoteAlbumPage> {
if (newUsers.isNotEmpty) {
ImmichToast.show(
context: context,
msg: "users_added_to_album_count".t(
context: context,
args: {
'count': newUsers.length,
},
),
msg: "users_added_to_album_count".t(context: context, args: {'count': newUsers.length}),
toastType: ToastType.success,
);
}
@@ -107,9 +92,7 @@ class _RemoteAlbumPageState extends ConsumerState<RemoteAlbumPage> {
}
Future<void> toggleAlbumOrder() async {
await ref.read(remoteAlbumProvider.notifier).toggleAlbumOrder(
widget.album.id,
);
await ref.read(remoteAlbumProvider.notifier).toggleAlbumOrder(widget.album.id);
ref.invalidate(timelineServiceProvider);
}
@@ -123,16 +106,9 @@ class _RemoteAlbumPageState extends ConsumerState<RemoteAlbumPage> {
content: Column(
mainAxisSize: MainAxisSize.min,
children: [
Text(
'album_delete_confirmation'.t(
context: context,
args: {'album': widget.album.name},
),
),
Text('album_delete_confirmation'.t(context: context, args: {'album': widget.album.name})),
const SizedBox(height: 8),
Text(
'album_delete_confirmation_description'.t(context: context),
),
Text('album_delete_confirmation_description'.t(context: context)),
],
),
actions: [
@@ -142,9 +118,7 @@ class _RemoteAlbumPageState extends ConsumerState<RemoteAlbumPage> {
),
TextButton(
onPressed: () => Navigator.of(context).pop(true),
style: TextButton.styleFrom(
foregroundColor: Theme.of(context).colorScheme.error,
),
style: TextButton.styleFrom(foregroundColor: Theme.of(context).colorScheme.error),
child: Text('delete_album'.t(context: context)),
),
],
@@ -230,13 +204,11 @@ class _RemoteAlbumPageState extends ConsumerState<RemoteAlbumPage> {
Widget build(BuildContext context) {
return ProviderScope(
overrides: [
timelineServiceProvider.overrideWith(
(ref) {
final timelineService = ref.watch(timelineFactoryProvider).remoteAlbum(albumId: widget.album.id);
ref.onDispose(timelineService.dispose);
return timelineService;
},
),
timelineServiceProvider.overrideWith((ref) {
final timelineService = ref.watch(timelineFactoryProvider).remoteAlbum(albumId: widget.album.id);
ref.onDispose(timelineService.dispose);
return timelineService;
}),
],
child: Timeline(
appBar: RemoteAlbumSliverAppBar(
@@ -245,9 +217,7 @@ class _RemoteAlbumPageState extends ConsumerState<RemoteAlbumPage> {
onToggleAlbumOrder: () => toggleAlbumOrder(),
onEditTitle: () => showEditTitleAndDescription(context),
),
bottomSheet: RemoteAlbumBottomSheet(
album: widget.album,
),
bottomSheet: RemoteAlbumBottomSheet(album: widget.album),
),
);
}
@@ -257,18 +227,13 @@ class _EditAlbumData {
final String name;
final String? description;
const _EditAlbumData({
required this.name,
this.description,
});
const _EditAlbumData({required this.name, this.description});
}
class _EditAlbumDialog extends ConsumerStatefulWidget {
final RemoteAlbum album;
const _EditAlbumDialog({
required this.album,
});
const _EditAlbumDialog({required this.album});
@override
ConsumerState<_EditAlbumDialog> createState() => _EditAlbumDialogState();
@@ -302,19 +267,14 @@ class _EditAlbumDialogState extends ConsumerState<_EditAlbumDialog> {
final newTitle = titleController.text.trim();
final newDescription = descriptionController.text.trim();
await ref.read(remoteAlbumProvider.notifier).updateAlbum(
widget.album.id,
name: newTitle,
description: newDescription.isEmpty ? null : newDescription,
);
await ref
.read(remoteAlbumProvider.notifier)
.updateAlbum(widget.album.id, name: newTitle, description: newDescription.isEmpty ? null : newDescription);
if (mounted) {
Navigator.of(context).pop(
_EditAlbumData(
name: newTitle,
description: newDescription.isEmpty ? null : newDescription,
),
);
Navigator.of(
context,
).pop(_EditAlbumData(name: newTitle, description: newDescription.isEmpty ? null : newDescription));
}
} catch (e) {
if (mounted) {
@@ -331,11 +291,7 @@ class _EditAlbumDialogState extends ConsumerState<_EditAlbumDialog> {
Widget build(BuildContext context) {
return Dialog(
insetPadding: const EdgeInsets.all(24),
shape: const RoundedRectangleBorder(
borderRadius: BorderRadius.all(
Radius.circular(16),
),
),
shape: const RoundedRectangleBorder(borderRadius: BorderRadius.all(Radius.circular(16))),
child: SingleChildScrollView(
child: Container(
padding: const EdgeInsets.all(16),
@@ -348,16 +304,9 @@ class _EditAlbumDialogState extends ConsumerState<_EditAlbumDialog> {
children: [
Row(
children: [
Icon(
Icons.edit_outlined,
color: context.colorScheme.primary,
size: 24,
),
Icon(Icons.edit_outlined, color: context.colorScheme.primary, size: 24),
const SizedBox(width: 12),
Text(
'edit_album'.t(context: context),
style: context.textTheme.titleMedium,
),
Text('edit_album'.t(context: context), style: context.textTheme.titleMedium),
],
),
const SizedBox(height: 24),
@@ -365,9 +314,7 @@ class _EditAlbumDialogState extends ConsumerState<_EditAlbumDialog> {
// Album Name
Text(
'album_name'.t(context: context).toUpperCase(),
style: context.textTheme.labelSmall?.copyWith(
fontWeight: FontWeight.w600,
),
style: context.textTheme.labelSmall?.copyWith(fontWeight: FontWeight.w600),
),
const SizedBox(height: 4),
TextFormField(
@@ -375,9 +322,7 @@ class _EditAlbumDialogState extends ConsumerState<_EditAlbumDialog> {
maxLines: 1,
textCapitalization: TextCapitalization.sentences,
decoration: InputDecoration(
border: const OutlineInputBorder(
borderRadius: BorderRadius.all(Radius.circular(12)),
),
border: const OutlineInputBorder(borderRadius: BorderRadius.all(Radius.circular(12))),
filled: true,
fillColor: context.colorScheme.surface,
),
@@ -394,9 +339,7 @@ class _EditAlbumDialogState extends ConsumerState<_EditAlbumDialog> {
// Description
Text(
'description'.t(context: context).toUpperCase(),
style: context.textTheme.labelSmall?.copyWith(
fontWeight: FontWeight.w600,
),
style: context.textTheme.labelSmall?.copyWith(fontWeight: FontWeight.w600),
),
const SizedBox(height: 4),
TextFormField(
@@ -404,11 +347,7 @@ class _EditAlbumDialogState extends ConsumerState<_EditAlbumDialog> {
maxLines: 4,
textCapitalization: TextCapitalization.sentences,
decoration: InputDecoration(
border: const OutlineInputBorder(
borderRadius: BorderRadius.all(
Radius.circular(12),
),
),
border: const OutlineInputBorder(borderRadius: BorderRadius.all(Radius.circular(12))),
filled: true,
fillColor: context.colorScheme.surface,
),

View File

@@ -16,18 +16,16 @@ class DriftTrashPage extends StatelessWidget {
Widget build(BuildContext context) {
return ProviderScope(
overrides: [
timelineServiceProvider.overrideWith(
(ref) {
final user = ref.watch(currentUserProvider);
if (user == null) {
throw Exception('User must be logged in to access trash');
}
timelineServiceProvider.overrideWith((ref) {
final user = ref.watch(currentUserProvider);
if (user == null) {
throw Exception('User must be logged in to access trash');
}
final timelineService = ref.watch(timelineFactoryProvider).trash(user.id);
ref.onDispose(timelineService.dispose);
return timelineService;
},
),
final timelineService = ref.watch(timelineFactoryProvider).trash(user.id);
ref.onDispose(timelineService.dispose);
return timelineService;
}),
],
child: Timeline(
showStorageIndicator: true,
@@ -42,18 +40,14 @@ class DriftTrashPage extends StatelessWidget {
topSliverWidgetHeight: 24,
topSliverWidget: Consumer(
builder: (context, ref, child) {
final trashDays = ref.watch(
serverInfoProvider.select((v) => v.serverConfig.trashDays),
);
final trashDays = ref.watch(serverInfoProvider.select((v) => v.serverConfig.trashDays));
return SliverPadding(
padding: const EdgeInsets.all(16.0),
sliver: SliverToBoxAdapter(
child: SizedBox(
height: 24.0,
child: const Text(
"trash_page_info",
).t(context: context, args: {"days": "$trashDays"}),
child: const Text("trash_page_info").t(context: context, args: {"days": "$trashDays"}),
),
),
);

View File

@@ -49,10 +49,7 @@ final driftUsersProvider = FutureProvider.autoDispose<List<UserDto>>((ref) async
class DriftUserSelectionPage extends HookConsumerWidget {
final RemoteAlbum album;
const DriftUserSelectionPage({
super.key,
required this.album,
});
const DriftUserSelectionPage({super.key, required this.album});
@override
Widget build(BuildContext context, WidgetRef ref) {
@@ -65,17 +62,9 @@ class DriftUserSelectionPage extends HookConsumerWidget {
buildTileIcon(UserDto user) {
if (sharedUsersList.value.contains(user)) {
return CircleAvatar(
backgroundColor: context.primaryColor,
child: const Icon(
Icons.check_rounded,
size: 25,
),
);
return CircleAvatar(backgroundColor: context.primaryColor, child: const Icon(Icons.check_rounded, size: 25));
} else {
return UserCircleAvatar(
user: user,
);
return UserCircleAvatar(user: user);
}
}
@@ -88,31 +77,19 @@ class DriftUserSelectionPage extends HookConsumerWidget {
padding: const EdgeInsets.symmetric(horizontal: 8.0),
child: Chip(
backgroundColor: context.primaryColor.withValues(alpha: 0.15),
label: Text(
user.name,
style: const TextStyle(
fontSize: 12,
fontWeight: FontWeight.bold,
),
),
label: Text(user.name, style: const TextStyle(fontSize: 12, fontWeight: FontWeight.bold)),
),
),
);
}
return ListView(
children: [
Wrap(
children: [...usersChip],
),
Wrap(children: [...usersChip]),
Padding(
padding: const EdgeInsets.all(16.0),
child: Text(
'suggestions'.tr(),
style: const TextStyle(
fontSize: 14,
color: Colors.grey,
fontWeight: FontWeight.bold,
),
style: const TextStyle(fontSize: 14, color: Colors.grey, fontWeight: FontWeight.bold),
),
),
ListView.builder(
@@ -122,31 +99,15 @@ class DriftUserSelectionPage extends HookConsumerWidget {
return ListTile(
leading: buildTileIcon(users[index]),
dense: true,
title: Text(
users[index].name,
style: const TextStyle(
fontSize: 14,
fontWeight: FontWeight.bold,
),
),
subtitle: Text(
users[index].email,
style: const TextStyle(
fontSize: 12,
),
),
title: Text(users[index].name, style: const TextStyle(fontSize: 14, fontWeight: FontWeight.bold)),
subtitle: Text(users[index].email, style: const TextStyle(fontSize: 12)),
onTap: () {
if (sharedUsersList.value.contains(users[index])) {
sharedUsersList.value = sharedUsersList.value
.where(
(selectedUser) => selectedUser.id != users[index].id,
)
.where((selectedUser) => selectedUser.id != users[index].id)
.toSet();
} else {
sharedUsersList.value = {
...sharedUsersList.value,
users[index],
};
sharedUsersList.value = {...sharedUsersList.value, users[index]};
}
},
);
@@ -159,9 +120,7 @@ class DriftUserSelectionPage extends HookConsumerWidget {
return Scaffold(
appBar: AppBar(
title: const Text(
'invite_to_album',
).tr(),
title: const Text('invite_to_album').tr(),
elevation: 0,
centerTitle: false,
leading: IconButton(
@@ -173,10 +132,7 @@ class DriftUserSelectionPage extends HookConsumerWidget {
actions: [
TextButton(
onPressed: sharedUsersList.value.isEmpty ? null : addNewUsersHandler,
child: const Text(
"add",
style: TextStyle(fontSize: 14, fontWeight: FontWeight.bold),
).tr(),
child: const Text("add", style: TextStyle(fontSize: 14, fontWeight: FontWeight.bold)).tr(),
),
],
),

View File

@@ -15,22 +15,18 @@ class DriftVideoPage extends StatelessWidget {
Widget build(BuildContext context) {
return ProviderScope(
overrides: [
timelineServiceProvider.overrideWith(
(ref) {
final user = ref.watch(currentUserProvider);
if (user == null) {
throw Exception('User must be logged in to video');
}
timelineServiceProvider.overrideWith((ref) {
final user = ref.watch(currentUserProvider);
if (user == null) {
throw Exception('User must be logged in to video');
}
final timelineService = ref.watch(timelineFactoryProvider).video(user.id);
ref.onDispose(timelineService.dispose);
return timelineService;
},
),
final timelineService = ref.watch(timelineFactoryProvider).video(user.id);
ref.onDispose(timelineService.dispose);
return timelineService;
}),
],
child: Timeline(
appBar: MesmerizingSliverAppBar(title: 'videos'.t()),
),
child: Timeline(appBar: MesmerizingSliverAppBar(title: 'videos'.t())),
);
}
}

View File

@@ -17,13 +17,11 @@ class LocalTimelinePage extends StatelessWidget {
Widget build(BuildContext context) {
return ProviderScope(
overrides: [
timelineServiceProvider.overrideWith(
(ref) {
final timelineService = ref.watch(timelineFactoryProvider).localAlbum(albumId: album.id);
ref.onDispose(timelineService.dispose);
return timelineService;
},
),
timelineServiceProvider.overrideWith((ref) {
final timelineService = ref.watch(timelineFactoryProvider).localAlbum(albumId: album.id);
ref.onDispose(timelineService.dispose);
return timelineService;
}),
],
child: Timeline(
appBar: MesmerizingSliverAppBar(title: album.name),

View File

@@ -44,12 +44,7 @@ class DriftSearchPage extends HookConsumerWidget {
location: preFilter?.location ?? SearchLocationFilter(),
camera: preFilter?.camera ?? SearchCameraFilter(),
date: preFilter?.date ?? SearchDateFilter(),
display: preFilter?.display ??
SearchDisplayFilters(
isNotInAlbum: false,
isArchive: false,
isFavorite: false,
),
display: preFilter?.display ?? SearchDisplayFilters(isNotInAlbum: false, isArchive: false, isFavorite: false),
mediaType: preFilter?.mediaType ?? AssetType.other,
language: "${context.locale.languageCode}-${context.locale.countryCode}",
),
@@ -68,10 +63,7 @@ class DriftSearchPage extends HookConsumerWidget {
SnackBar searchInfoSnackBar(String message) {
return SnackBar(
content: Text(
message,
style: context.textTheme.labelLarge,
),
content: Text(message, style: context.textTheme.labelLarge),
showCloseIcon: true,
behavior: SnackBarBehavior.fixed,
closeIconColor: context.colorScheme.onSurface,
@@ -92,9 +84,7 @@ class DriftSearchPage extends HookConsumerWidget {
final hasResult = await ref.watch(paginatedSearchProvider.notifier).search(filter.value);
if (!hasResult) {
context.showSnackBar(
searchInfoSnackBar('search_no_result'.t(context: context)),
);
context.showSnackBar(searchInfoSnackBar('search_no_result'.t(context: context)));
}
previousFilter.value = filter.value;
@@ -106,9 +96,7 @@ class DriftSearchPage extends HookConsumerWidget {
final hasResult = await ref.watch(paginatedSearchProvider.notifier).search(filter.value);
if (!hasResult) {
context.showSnackBar(
searchInfoSnackBar('search_no_more_result'.t(context: context)),
);
context.showSnackBar(searchInfoSnackBar('search_no_more_result'.t(context: context)));
}
isSearching.value = false;
@@ -116,39 +104,26 @@ class DriftSearchPage extends HookConsumerWidget {
searchPreFilter() {
if (preFilter != null) {
Future.delayed(
Duration.zero,
() {
search();
Future.delayed(Duration.zero, () {
search();
if (preFilter!.location.city != null) {
locationCurrentFilterWidget.value = Text(
preFilter!.location.city!,
style: context.textTheme.labelLarge,
);
}
},
);
if (preFilter!.location.city != null) {
locationCurrentFilterWidget.value = Text(preFilter!.location.city!, style: context.textTheme.labelLarge);
}
});
}
}
useEffect(
() {
Future.microtask(
() => ref.invalidate(paginatedSearchProvider),
);
searchPreFilter();
useEffect(() {
Future.microtask(() => ref.invalidate(paginatedSearchProvider));
searchPreFilter();
return null;
},
[],
);
return null;
}, []);
showPeoplePicker() {
handleOnSelect(Set<PersonDto> value) {
filter.value = filter.value.copyWith(
people: value,
);
filter.value = filter.value.copyWith(people: value);
peopleCurrentFilterWidget.value = Text(
value.map((e) => e.name != '' ? e.name : 'no_name'.t(context: context)).join(', '),
@@ -157,9 +132,7 @@ class DriftSearchPage extends HookConsumerWidget {
}
handleClear() {
filter.value = filter.value.copyWith(
people: {},
);
filter.value = filter.value.copyWith(people: {});
peopleCurrentFilterWidget.value = null;
search();
@@ -175,10 +148,7 @@ class DriftSearchPage extends HookConsumerWidget {
expanded: true,
onSearch: search,
onClear: handleClear,
child: PeoplePicker(
onSelect: handleOnSelect,
filter: filter.value.people,
),
child: PeoplePicker(onSelect: handleOnSelect, filter: filter.value.people),
),
),
);
@@ -187,11 +157,7 @@ class DriftSearchPage extends HookConsumerWidget {
showLocationPicker() {
handleOnSelect(Map<String, String?> value) {
filter.value = filter.value.copyWith(
location: SearchLocationFilter(
country: value['country'],
city: value['city'],
state: value['state'],
),
location: SearchLocationFilter(country: value['country'], city: value['city'], state: value['state']),
);
final locationText = <String>[];
@@ -207,16 +173,11 @@ class DriftSearchPage extends HookConsumerWidget {
locationText.add(value['city']!);
}
locationCurrentFilterWidget.value = Text(
locationText.join(', '),
style: context.textTheme.labelLarge,
);
locationCurrentFilterWidget.value = Text(locationText.join(', '), style: context.textTheme.labelLarge);
}
handleClear() {
filter.value = filter.value.copyWith(
location: SearchLocationFilter(),
);
filter.value = filter.value.copyWith(location: SearchLocationFilter());
locationCurrentFilterWidget.value = null;
search();
@@ -233,15 +194,10 @@ class DriftSearchPage extends HookConsumerWidget {
child: Padding(
padding: const EdgeInsets.symmetric(vertical: 16.0),
child: Container(
padding: EdgeInsets.only(
bottom: context.viewInsets.bottom,
),
padding: EdgeInsets.only(bottom: context.viewInsets.bottom),
child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 16.0),
child: LocationPicker(
onSelected: handleOnSelect,
filter: filter.value.location,
),
child: LocationPicker(onSelected: handleOnSelect, filter: filter.value.location),
),
),
),
@@ -252,10 +208,7 @@ class DriftSearchPage extends HookConsumerWidget {
showCameraPicker() {
handleOnSelect(Map<String, String?> value) {
filter.value = filter.value.copyWith(
camera: SearchCameraFilter(
make: value['make'],
model: value['model'],
),
camera: SearchCameraFilter(make: value['make'], model: value['model']),
);
cameraCurrentFilterWidget.value = Text(
@@ -265,9 +218,7 @@ class DriftSearchPage extends HookConsumerWidget {
}
handleClear() {
filter.value = filter.value.copyWith(
camera: SearchCameraFilter(),
);
filter.value = filter.value.copyWith(camera: SearchCameraFilter());
cameraCurrentFilterWidget.value = null;
search();
@@ -283,10 +234,7 @@ class DriftSearchPage extends HookConsumerWidget {
onClear: handleClear,
child: Padding(
padding: const EdgeInsets.all(16.0),
child: CameraPicker(
onSelect: handleOnSelect,
filter: filter.value.camera,
),
child: CameraPicker(onSelect: handleOnSelect, filter: filter.value.camera),
),
),
);
@@ -318,9 +266,7 @@ class DriftSearchPage extends HookConsumerWidget {
);
if (date == null) {
filter.value = filter.value.copyWith(
date: SearchDateFilter(),
);
filter.value = filter.value.copyWith(date: SearchDateFilter());
dateRangeCurrentFilterWidget.value = null;
search();
@@ -330,13 +276,7 @@ class DriftSearchPage extends HookConsumerWidget {
filter.value = filter.value.copyWith(
date: SearchDateFilter(
takenAfter: date.start,
takenBefore: date.end.add(
const Duration(
hours: 23,
minutes: 59,
seconds: 59,
),
),
takenBefore: date.end.add(const Duration(hours: 23, minutes: 59, seconds: 59)),
),
);
@@ -365,24 +305,20 @@ class DriftSearchPage extends HookConsumerWidget {
// MEDIA PICKER
showMediaTypePicker() {
handleOnSelected(AssetType assetType) {
filter.value = filter.value.copyWith(
mediaType: assetType,
);
filter.value = filter.value.copyWith(mediaType: assetType);
mediaTypeCurrentFilterWidget.value = Text(
assetType == AssetType.image
? 'image'.t(context: context)
: assetType == AssetType.video
? 'video'.t(context: context)
: 'all'.t(context: context),
? 'video'.t(context: context)
: 'all'.t(context: context),
style: context.textTheme.labelLarge,
);
}
handleClear() {
filter.value = filter.value.copyWith(
mediaType: AssetType.other,
);
filter.value = filter.value.copyWith(mediaType: AssetType.other);
mediaTypeCurrentFilterWidget.value = null;
search();
@@ -394,10 +330,7 @@ class DriftSearchPage extends HookConsumerWidget {
title: 'search_filter_media_type_title'.t(context: context),
onSearch: search,
onClear: handleClear,
child: MediaTypePicker(
onSelect: handleOnSelected,
filter: filter.value.mediaType,
),
child: MediaTypePicker(onSelect: handleOnSelected, filter: filter.value.mediaType),
),
);
}
@@ -409,33 +342,19 @@ class DriftSearchPage extends HookConsumerWidget {
value.forEach((key, value) {
switch (key) {
case DisplayOption.notInAlbum:
filter.value = filter.value.copyWith(
display: filter.value.display.copyWith(
isNotInAlbum: value,
),
);
filter.value = filter.value.copyWith(display: filter.value.display.copyWith(isNotInAlbum: value));
if (value) {
filterText.add(
'search_filter_display_option_not_in_album'.t(context: context),
);
filterText.add('search_filter_display_option_not_in_album'.t(context: context));
}
break;
case DisplayOption.archive:
filter.value = filter.value.copyWith(
display: filter.value.display.copyWith(
isArchive: value,
),
);
filter.value = filter.value.copyWith(display: filter.value.display.copyWith(isArchive: value));
if (value) {
filterText.add('archive'.t(context: context));
}
break;
case DisplayOption.favorite:
filter.value = filter.value.copyWith(
display: filter.value.display.copyWith(
isFavorite: value,
),
);
filter.value = filter.value.copyWith(display: filter.value.display.copyWith(isFavorite: value));
if (value) {
filterText.add('favorite'.t(context: context));
}
@@ -448,19 +367,12 @@ class DriftSearchPage extends HookConsumerWidget {
return;
}
displayOptionCurrentFilterWidget.value = Text(
filterText.join(', '),
style: context.textTheme.labelLarge,
);
displayOptionCurrentFilterWidget.value = Text(filterText.join(', '), style: context.textTheme.labelLarge);
}
handleClear() {
filter.value = filter.value.copyWith(
display: SearchDisplayFilters(
isNotInAlbum: false,
isArchive: false,
isFavorite: false,
),
display: SearchDisplayFilters(isNotInAlbum: false, isArchive: false, isFavorite: false),
);
displayOptionCurrentFilterWidget.value = null;
@@ -473,10 +385,7 @@ class DriftSearchPage extends HookConsumerWidget {
title: 'display_options'.t(context: context),
onSearch: search,
onClear: handleClear,
child: DisplayOptionPicker(
onSelect: handleOnSelect,
filter: filter.value.display,
),
child: DisplayOptionPicker(onSelect: handleOnSelect, filter: filter.value.display),
),
);
}
@@ -484,27 +393,15 @@ class DriftSearchPage extends HookConsumerWidget {
handleTextSubmitted(String value) {
switch (textSearchType.value) {
case TextSearchType.context:
filter.value = filter.value.copyWith(
filename: '',
context: value,
description: '',
);
filter.value = filter.value.copyWith(filename: '', context: value, description: '');
break;
case TextSearchType.filename:
filter.value = filter.value.copyWith(
filename: value,
context: '',
description: '',
);
filter.value = filter.value.copyWith(filename: value, context: '', description: '');
break;
case TextSearchType.description:
filter.value = filter.value.copyWith(
filename: '',
context: '',
description: value,
);
filter.value = filter.value.copyWith(filename: '', context: '', description: value);
break;
}
@@ -512,10 +409,10 @@ class DriftSearchPage extends HookConsumerWidget {
}
IconData getSearchPrefixIcon() => switch (textSearchType.value) {
TextSearchType.context => Icons.image_search_rounded,
TextSearchType.filename => Icons.abc_rounded,
TextSearchType.description => Icons.text_snippet_outlined,
};
TextSearchType.context => Icons.image_search_rounded,
TextSearchType.filename => Icons.abc_rounded,
TextSearchType.description => Icons.text_snippet_outlined,
};
return Scaffold(
resizeToAvoidBottomInset: false,
@@ -528,21 +425,11 @@ class DriftSearchPage extends HookConsumerWidget {
style: MenuStyle(
elevation: const WidgetStatePropertyAll(1),
shape: WidgetStateProperty.all(
const RoundedRectangleBorder(
borderRadius: BorderRadius.all(
Radius.circular(24),
),
),
),
padding: const WidgetStatePropertyAll(
EdgeInsets.all(4),
const RoundedRectangleBorder(borderRadius: BorderRadius.all(Radius.circular(24))),
),
padding: const WidgetStatePropertyAll(EdgeInsets.all(4)),
),
builder: (
BuildContext context,
MenuController controller,
Widget? child,
) {
builder: (BuildContext context, MenuController controller, Widget? child) {
return IconButton(
onPressed: () {
if (controller.isOpen) {
@@ -616,13 +503,8 @@ class DriftSearchPage extends HookConsumerWidget {
],
title: Container(
decoration: BoxDecoration(
border: Border.all(
color: context.colorScheme.onSurface.withAlpha(0),
width: 0,
),
borderRadius: const BorderRadius.all(
Radius.circular(24),
),
border: Border.all(color: context.colorScheme.onSurface.withAlpha(0), width: 0),
borderRadius: const BorderRadius.all(Radius.circular(24)),
gradient: LinearGradient(
colors: [
context.colorScheme.primary.withValues(alpha: 0.075),
@@ -638,12 +520,7 @@ class DriftSearchPage extends HookConsumerWidget {
key: const Key('search_text_field'),
controller: textSearchController,
contentPadding: preFilter != null ? const EdgeInsets.only(left: 24) : const EdgeInsets.all(8),
prefixIcon: preFilter != null
? null
: Icon(
getSearchPrefixIcon(),
color: context.colorScheme.primary,
),
prefixIcon: preFilter != null ? null : Icon(getSearchPrefixIcon(), color: context.colorScheme.primary),
onSubmitted: handleTextSubmitted,
focusNode: ref.watch(searchInputFocusProvider),
),
@@ -705,10 +582,7 @@ class DriftSearchPage extends HookConsumerWidget {
),
),
if (isSearching.value)
const SliverFillRemaining(
hasScrollBody: false,
child: Center(child: CircularProgressIndicator()),
)
const SliverFillRemaining(hasScrollBody: false, child: Center(child: CircularProgressIndicator()))
else
_SearchResultGrid(onScrollEnd: loadMoreSearchResult),
],
@@ -747,19 +621,13 @@ class _SearchResultGrid extends ConsumerWidget {
child: SliverFillRemaining(
child: ProviderScope(
overrides: [
timelineServiceProvider.overrideWith(
(ref) {
final timelineService = ref.watch(timelineFactoryProvider).fromAssets(searchResult.assets);
ref.onDispose(timelineService.dispose);
return timelineService;
},
),
timelineServiceProvider.overrideWith((ref) {
final timelineService = ref.watch(timelineFactoryProvider).fromAssets(searchResult.assets);
ref.onDispose(timelineService.dispose);
return timelineService;
}),
],
child: Timeline(
key: ValueKey(searchResult.totalAssets),
appBar: null,
groupBy: GroupAssetsBy.none,
),
child: Timeline(key: ValueKey(searchResult.totalAssets), appBar: null, groupBy: GroupAssetsBy.none),
),
),
);
@@ -784,16 +652,10 @@ class _SearchEmptyContent extends StatelessWidget {
),
const SizedBox(height: 16),
Center(
child: Text(
'search_page_search_photos_videos'.t(context: context),
style: context.textTheme.labelLarge,
),
child: Text('search_page_search_photos_videos'.t(context: context), style: context.textTheme.labelLarge),
),
const SizedBox(height: 32),
const Padding(
padding: EdgeInsets.symmetric(horizontal: 16),
child: _QuickLinkList(),
),
const Padding(padding: EdgeInsets.symmetric(horizontal: 16), child: _QuickLinkList()),
],
),
);
@@ -807,13 +669,8 @@ class _QuickLinkList extends StatelessWidget {
Widget build(BuildContext context) {
return Container(
decoration: BoxDecoration(
borderRadius: const BorderRadius.all(
Radius.circular(20),
),
border: Border.all(
color: context.colorScheme.outline.withAlpha(10),
width: 1,
),
borderRadius: const BorderRadius.all(Radius.circular(20)),
border: Border.all(color: context.colorScheme.outline.withAlpha(10), width: 1),
gradient: LinearGradient(
colors: [
context.colorScheme.primary.withAlpha(10),
@@ -876,19 +733,9 @@ class _QuickLink extends StatelessWidget {
);
return ListTile(
shape: RoundedRectangleBorder(
borderRadius: borderRadius,
),
leading: Icon(
icon,
size: 26,
),
title: Text(
title,
style: context.textTheme.titleSmall?.copyWith(
fontWeight: FontWeight.w500,
),
),
shape: RoundedRectangleBorder(borderRadius: borderRadius),
leading: Icon(icon, size: 26),
title: Text(title, style: context.textTheme.titleSmall?.copyWith(fontWeight: FontWeight.w500)),
onTap: onTap,
);
}

View File

@@ -24,10 +24,7 @@ class PaginatedSearchNotifier extends StateNotifier<SearchResult> {
return false;
}
state = SearchResult(
assets: [...state.assets, ...result.assets],
nextPage: result.nextPage,
);
state = SearchResult(assets: [...state.assets, ...result.assets], nextPage: result.nextPage);
return true;
}