mirror of
https://github.com/immich-app/immich
synced 2026-08-15 13:03:57 +00:00
fix: riverpod reactivity regression from lint fixes (#30734)
Co-authored-by: shenlong-tanwen <139912620+shalong-tanwen@users.noreply.github.com>
This commit is contained in:
parent
610bcfa6d0
commit
ce705dcc06
6 changed files with 100 additions and 52 deletions
|
|
@ -316,12 +316,11 @@ class _BackupAlbumSelectionCard extends ConsumerWidget {
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context, WidgetRef ref) {
|
Widget build(BuildContext context, WidgetRef ref) {
|
||||||
|
final backupAlbums = ref.watch(backupAlbumProvider);
|
||||||
|
|
||||||
Widget buildSelectedAlbumName() {
|
Widget buildSelectedAlbumName() {
|
||||||
String text = context.t.backup_controller_page_backup_selected;
|
String text = context.t.backup_controller_page_backup_selected;
|
||||||
final albums = ref
|
final albums = backupAlbums.where((album) => album.backupSelection == BackupSelection.selected).toList();
|
||||||
.read(backupAlbumProvider)
|
|
||||||
.where((album) => album.backupSelection == BackupSelection.selected)
|
|
||||||
.toList();
|
|
||||||
|
|
||||||
if (albums.isNotEmpty) {
|
if (albums.isNotEmpty) {
|
||||||
for (var album in albums) {
|
for (var album in albums) {
|
||||||
|
|
@ -352,10 +351,7 @@ class _BackupAlbumSelectionCard extends ConsumerWidget {
|
||||||
|
|
||||||
Widget buildExcludedAlbumName() {
|
Widget buildExcludedAlbumName() {
|
||||||
String text = context.t.backup_controller_page_excluded;
|
String text = context.t.backup_controller_page_excluded;
|
||||||
final albums = ref
|
final albums = backupAlbums.where((album) => album.backupSelection == BackupSelection.excluded).toList();
|
||||||
.read(backupAlbumProvider)
|
|
||||||
.where((album) => album.backupSelection == BackupSelection.excluded)
|
|
||||||
.toList();
|
|
||||||
|
|
||||||
if (albums.isNotEmpty) {
|
if (albums.isNotEmpty) {
|
||||||
for (var album in albums) {
|
for (var album in albums) {
|
||||||
|
|
|
||||||
|
|
@ -32,6 +32,8 @@ class DriftAlbumOptionsPage extends HookConsumerWidget {
|
||||||
final userId = ref.watch(authProvider).userId;
|
final userId = ref.watch(authProvider).userId;
|
||||||
final activityEnabled = useState(album.isActivityEnabled);
|
final activityEnabled = useState(album.isActivityEnabled);
|
||||||
final isOwner = album.ownerId == userId;
|
final isOwner = album.ownerId == userId;
|
||||||
|
final owner = isOwner ? ref.watch(currentUserProvider) : null;
|
||||||
|
final allUsers = isOwner ? null : ref.watch(driftUsersProvider);
|
||||||
|
|
||||||
void showErrorMessage() {
|
void showErrorMessage() {
|
||||||
ContextHelper(context).pop();
|
ContextHelper(context).pop();
|
||||||
|
|
@ -141,7 +143,6 @@ class DriftAlbumOptionsPage extends HookConsumerWidget {
|
||||||
|
|
||||||
Widget buildOwnerInfo() {
|
Widget buildOwnerInfo() {
|
||||||
if (isOwner) {
|
if (isOwner) {
|
||||||
final owner = ref.read(currentUserProvider);
|
|
||||||
return ListTile(
|
return ListTile(
|
||||||
leading: owner != null ? UserCircleAvatar(user: owner) : const SizedBox(),
|
leading: owner != null ? UserCircleAvatar(user: owner) : const SizedBox(),
|
||||||
title: Text(album.ownerName, style: const TextStyle(fontWeight: FontWeight.w500)),
|
title: Text(album.ownerName, style: const TextStyle(fontWeight: FontWeight.w500)),
|
||||||
|
|
@ -149,8 +150,11 @@ class DriftAlbumOptionsPage extends HookConsumerWidget {
|
||||||
trailing: Text(context.t.owner, style: context.textTheme.labelLarge),
|
trailing: Text(context.t.owner, style: context.textTheme.labelLarge),
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
final usersProvider = ref.read(driftUsersProvider);
|
if (allUsers == null) {
|
||||||
return usersProvider.maybeWhen(
|
return const SizedBox();
|
||||||
|
}
|
||||||
|
|
||||||
|
return allUsers.maybeWhen(
|
||||||
data: (users) {
|
data: (users) {
|
||||||
final user = users.firstWhereOrNull((u) => u.id == album.ownerId);
|
final user = users.firstWhereOrNull((u) => u.id == album.ownerId);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -7,6 +7,7 @@ import 'package:flutter/material.dart';
|
||||||
import 'package:flutter/services.dart';
|
import 'package:flutter/services.dart';
|
||||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||||
import 'package:immich_mobile/constants/enums.dart';
|
import 'package:immich_mobile/constants/enums.dart';
|
||||||
|
import 'package:immich_mobile/domain/models/asset/base_asset.model.dart';
|
||||||
import 'package:immich_mobile/domain/models/config/slideshow_config.dart';
|
import 'package:immich_mobile/domain/models/config/slideshow_config.dart';
|
||||||
import 'package:immich_mobile/domain/services/timeline.service.dart';
|
import 'package:immich_mobile/domain/services/timeline.service.dart';
|
||||||
import 'package:immich_mobile/extensions/build_context_extensions.dart';
|
import 'package:immich_mobile/extensions/build_context_extensions.dart';
|
||||||
|
|
@ -295,14 +296,7 @@ class _DriftSlideshowPageState extends ConsumerState<DriftSlideshowPage> with Si
|
||||||
color: context.colorScheme.primary,
|
color: context.colorScheme.primary,
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
return LinearProgressIndicator(
|
return _VideoProgressBar(asset: asset);
|
||||||
color: context.colorScheme.primary,
|
|
||||||
borderRadius: BorderRadius.zero,
|
|
||||||
minHeight: 5,
|
|
||||||
value:
|
|
||||||
ref.read(videoPlayerProvider(asset.id).select((s) => s.position)).inMilliseconds /
|
|
||||||
asset.duration.inMilliseconds,
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -374,25 +368,13 @@ class _DriftSlideshowPageState extends ConsumerState<DriftSlideshowPage> with Si
|
||||||
builder: (context, value, _) => buildPhotoView(scale * (1.0 + value * _kenBurnsZoom)),
|
builder: (context, value, _) => buildPhotoView(scale * (1.0 + value * _kenBurnsZoom)),
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
final status = ref.read(videoPlayerProvider(asset.id).select((s) => s.status));
|
return _VideoChild(
|
||||||
final position = ref.read(videoPlayerProvider(asset.id)).position;
|
asset: asset,
|
||||||
|
isCurrent: isCurrent,
|
||||||
if (status == VideoPlaybackStatus.completed && isCurrent && position.inMicroseconds > 0) {
|
scale: scale,
|
||||||
unawaited(_nextPage());
|
imageProvider: imageProvider,
|
||||||
} else if (status == VideoPlaybackStatus.playing) {
|
onTapUp: _onTapUp,
|
||||||
unawaited(ref.read(videoPlayerProvider(asset.id).notifier).setLoop(false));
|
onCompleted: _nextPage,
|
||||||
}
|
|
||||||
|
|
||||||
return PhotoView.customChild(
|
|
||||||
onTapUp: (_, _, _) => _onTapUp(),
|
|
||||||
disableScaleGestures: true,
|
|
||||||
filterQuality: FilterQuality.high,
|
|
||||||
initialScale: scale,
|
|
||||||
child: NativeVideoViewer(
|
|
||||||
asset: asset,
|
|
||||||
isCurrent: isCurrent,
|
|
||||||
image: Image(image: imageProvider, fit: BoxFit.contain, alignment: Alignment.center),
|
|
||||||
),
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -477,6 +459,67 @@ class _DriftSlideshowPageState extends ConsumerState<DriftSlideshowPage> with Si
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class _VideoChild extends ConsumerWidget {
|
||||||
|
final BaseAsset asset;
|
||||||
|
final bool isCurrent;
|
||||||
|
final PhotoViewComputedScale scale;
|
||||||
|
final ImageProvider imageProvider;
|
||||||
|
final VoidCallback onTapUp;
|
||||||
|
final VoidCallback onCompleted;
|
||||||
|
|
||||||
|
const _VideoChild({
|
||||||
|
required this.asset,
|
||||||
|
required this.isCurrent,
|
||||||
|
required this.scale,
|
||||||
|
required this.imageProvider,
|
||||||
|
required this.onTapUp,
|
||||||
|
required this.onCompleted,
|
||||||
|
});
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context, WidgetRef ref) {
|
||||||
|
ref.listen(videoPlayerProvider(asset.id).select((s) => s.status), (_, status) {
|
||||||
|
if (status == VideoPlaybackStatus.completed) {
|
||||||
|
if (isCurrent && ref.read(videoPlayerProvider(asset.id)).position.inMicroseconds > 0) {
|
||||||
|
onCompleted();
|
||||||
|
}
|
||||||
|
} else if (status == VideoPlaybackStatus.playing) {
|
||||||
|
unawaited(ref.read(videoPlayerProvider(asset.id).notifier).setLoop(false));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return PhotoView.customChild(
|
||||||
|
onTapUp: (_, _, _) => onTapUp(),
|
||||||
|
disableScaleGestures: true,
|
||||||
|
filterQuality: FilterQuality.high,
|
||||||
|
initialScale: scale,
|
||||||
|
child: NativeVideoViewer(
|
||||||
|
asset: asset,
|
||||||
|
isCurrent: isCurrent,
|
||||||
|
image: Image(image: imageProvider, fit: BoxFit.contain, alignment: Alignment.center),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class _VideoProgressBar extends ConsumerWidget {
|
||||||
|
final BaseAsset asset;
|
||||||
|
|
||||||
|
const _VideoProgressBar({required this.asset});
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context, WidgetRef ref) {
|
||||||
|
final position = ref.watch(videoPlayerProvider(asset.id).select((s) => s.position));
|
||||||
|
|
||||||
|
return LinearProgressIndicator(
|
||||||
|
color: context.colorScheme.primary,
|
||||||
|
borderRadius: BorderRadius.zero,
|
||||||
|
minHeight: 5,
|
||||||
|
value: position.inMilliseconds / asset.duration.inMilliseconds,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Progress bar for image slides, driven by an explicit [AnimationController].
|
/// Progress bar for image slides, driven by an explicit [AnimationController].
|
||||||
///
|
///
|
||||||
/// [TweenAnimationBuilder] creates its controller internally with the default
|
/// [TweenAnimationBuilder] creates its controller internally with the default
|
||||||
|
|
|
||||||
|
|
@ -52,6 +52,7 @@ class DriftUserSelectionPage extends HookConsumerWidget {
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context, WidgetRef ref) {
|
Widget build(BuildContext context, WidgetRef ref) {
|
||||||
final AsyncValue<List<UserDto>> suggestedShareUsers = ref.watch(driftUsersProvider);
|
final AsyncValue<List<UserDto>> suggestedShareUsers = ref.watch(driftUsersProvider);
|
||||||
|
final sharedUsers = ref.watch(remoteAlbumSharedUsersProvider(album.id));
|
||||||
final sharedUsersList = useState<Set<UserDto>>({});
|
final sharedUsersList = useState<Set<UserDto>>({});
|
||||||
|
|
||||||
void addNewUsersHandler() {
|
void addNewUsersHandler() {
|
||||||
|
|
@ -136,9 +137,6 @@ class DriftUserSelectionPage extends HookConsumerWidget {
|
||||||
),
|
),
|
||||||
body: suggestedShareUsers.widgetWhen(
|
body: suggestedShareUsers.widgetWhen(
|
||||||
onData: (users) {
|
onData: (users) {
|
||||||
// Get shared users for this album from the database
|
|
||||||
final sharedUsers = ref.read(remoteAlbumSharedUsersProvider(album.id));
|
|
||||||
|
|
||||||
return sharedUsers.when(
|
return sharedUsers.when(
|
||||||
data: (albumSharedUsers) {
|
data: (albumSharedUsers) {
|
||||||
// Filter out users that are already shared with this album and the owner
|
// Filter out users that are already shared with this album and the owner
|
||||||
|
|
|
||||||
|
|
@ -742,9 +742,7 @@ class _SearchResultGrid extends ConsumerWidget {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
Widget? _bottomWidget(BuildContext context, WidgetRef ref) {
|
Widget? _bottomWidget(BuildContext context, {required bool isLoading, required bool hasMore}) {
|
||||||
final isLoading = ref.read(paginatedSearchProvider.select((s) => s.isLoading));
|
|
||||||
|
|
||||||
if (isLoading) {
|
if (isLoading) {
|
||||||
return const SliverFillRemaining(
|
return const SliverFillRemaining(
|
||||||
hasScrollBody: false,
|
hasScrollBody: false,
|
||||||
|
|
@ -755,8 +753,6 @@ class _SearchResultGrid extends ConsumerWidget {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
final hasMore = ref.read(paginatedSearchProvider.select((s) => s.nextPage != null));
|
|
||||||
|
|
||||||
if (hasMore) {
|
if (hasMore) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
@ -778,6 +774,7 @@ class _SearchResultGrid extends ConsumerWidget {
|
||||||
Widget build(BuildContext context, WidgetRef ref) {
|
Widget build(BuildContext context, WidgetRef ref) {
|
||||||
final hasAssets = ref.watch(paginatedSearchProvider.select((s) => s.assets.isNotEmpty));
|
final hasAssets = ref.watch(paginatedSearchProvider.select((s) => s.assets.isNotEmpty));
|
||||||
final isLoading = ref.watch(paginatedSearchProvider.select((s) => s.isLoading));
|
final isLoading = ref.watch(paginatedSearchProvider.select((s) => s.isLoading));
|
||||||
|
final hasMore = ref.watch(paginatedSearchProvider.select((s) => s.nextPage != null));
|
||||||
|
|
||||||
if (!hasAssets && !isLoading) {
|
if (!hasAssets && !isLoading) {
|
||||||
return const _SearchNoResults();
|
return const _SearchNoResults();
|
||||||
|
|
@ -807,7 +804,7 @@ class _SearchResultGrid extends ConsumerWidget {
|
||||||
bottomSheet: const GeneralBottomSheet(minChildSize: 0.20),
|
bottomSheet: const GeneralBottomSheet(minChildSize: 0.20),
|
||||||
snapToMonth: false,
|
snapToMonth: false,
|
||||||
loadingWidget: const SizedBox.shrink(),
|
loadingWidget: const SizedBox.shrink(),
|
||||||
bottomSliverWidget: _bottomWidget(context, ref),
|
bottomSliverWidget: _bottomWidget(context, isLoading: isLoading, hasMore: hasMore),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|
|
||||||
|
|
@ -177,7 +177,15 @@ class _BackupIndicator extends ConsumerWidget {
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context, WidgetRef ref) {
|
Widget build(BuildContext context, WidgetRef ref) {
|
||||||
final indicatorIcon = _getBackupBadgeIcon(context, ref);
|
final backupEnabled = ref.watch(appConfigProvider.select((c) => c.backup.enabled));
|
||||||
|
final hasError = ref.watch(driftBackupProvider.select((state) => state.error != BackupError.none));
|
||||||
|
final isUploading = ref.watch(driftBackupProvider.select((state) => state.uploadItems.isNotEmpty));
|
||||||
|
final indicatorIcon = _getBackupBadgeIcon(
|
||||||
|
context,
|
||||||
|
backupEnabled: backupEnabled,
|
||||||
|
hasError: hasError,
|
||||||
|
isUploading: isUploading,
|
||||||
|
);
|
||||||
|
|
||||||
return IconButton(
|
return IconButton(
|
||||||
onPressed: () => context.pushRoute(const DriftBackupRoute()),
|
onPressed: () => context.pushRoute(const DriftBackupRoute()),
|
||||||
|
|
@ -192,12 +200,14 @@ class _BackupIndicator extends ConsumerWidget {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
Widget? _getBackupBadgeIcon(BuildContext context, WidgetRef ref) {
|
Widget? _getBackupBadgeIcon(
|
||||||
final backupEnabled = ref.read(appConfigProvider.select((c) => c.backup.enabled));
|
BuildContext context, {
|
||||||
final hasError = ref.read(driftBackupProvider.select((state) => state.error != BackupError.none));
|
required bool backupEnabled,
|
||||||
|
required bool hasError,
|
||||||
|
required bool isUploading,
|
||||||
|
}) {
|
||||||
final isDarkTheme = context.isDarkTheme;
|
final isDarkTheme = context.isDarkTheme;
|
||||||
final iconColor = isDarkTheme ? Colors.white : Colors.black;
|
final iconColor = isDarkTheme ? Colors.white : Colors.black;
|
||||||
final isUploading = ref.read(driftBackupProvider.select((state) => state.uploadItems.isNotEmpty));
|
|
||||||
|
|
||||||
if (!backupEnabled) {
|
if (!backupEnabled) {
|
||||||
return _BadgeLabel(
|
return _BadgeLabel(
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue