mirror of
https://github.com/immich-app/immich
synced 2026-08-15 13:03:57 +00:00
The widget is not recreated correctly when videoPlayName changes, which can cause weird behaviour with hooks and timers (like timers not firing when they should do). Using a key forces flutter to recreate the widget properly and allow the assumptions in build to work correctly.
87 lines
3.9 KiB
Dart
87 lines
3.9 KiB
Dart
import 'package:flutter/material.dart';
|
|
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
|
import 'package:immich_mobile/constants/enums.dart';
|
|
import 'package:immich_mobile/domain/models/asset/base_asset.model.dart';
|
|
import 'package:immich_mobile/extensions/build_context_extensions.dart';
|
|
import 'package:immich_mobile/presentation/widgets/action_buttons/delete_action_button.widget.dart';
|
|
import 'package:immich_mobile/presentation/widgets/action_buttons/delete_local_action_button.widget.dart';
|
|
import 'package:immich_mobile/presentation/widgets/action_buttons/edit_image_action_button.widget.dart';
|
|
import 'package:immich_mobile/presentation/widgets/action_buttons/share_action_button.widget.dart';
|
|
import 'package:immich_mobile/presentation/widgets/action_buttons/upload_action_button.widget.dart';
|
|
import 'package:immich_mobile/presentation/widgets/action_buttons/add_action_button.widget.dart';
|
|
import 'package:immich_mobile/providers/asset_viewer/asset_viewer.provider.dart';
|
|
import 'package:immich_mobile/providers/infrastructure/readonly_mode.provider.dart';
|
|
import 'package:immich_mobile/providers/routes.provider.dart';
|
|
import 'package:immich_mobile/providers/user.provider.dart';
|
|
import 'package:immich_mobile/widgets/asset_viewer/video_controls.dart';
|
|
|
|
class ViewerBottomBar extends ConsumerWidget {
|
|
const ViewerBottomBar({super.key});
|
|
|
|
@override
|
|
Widget build(BuildContext context, WidgetRef ref) {
|
|
final asset = ref.watch(assetViewerProvider.select((s) => s.currentAsset));
|
|
if (asset == null) {
|
|
return const SizedBox.shrink();
|
|
}
|
|
|
|
final isReadonlyModeEnabled = ref.watch(readonlyModeProvider);
|
|
final user = ref.watch(currentUserProvider);
|
|
final isOwner = asset is RemoteAsset && asset.ownerId == user?.id;
|
|
final showingDetails = ref.watch(assetViewerProvider.select((s) => s.showingDetails));
|
|
final isInLockedView = ref.watch(inLockedViewProvider);
|
|
|
|
final originalTheme = context.themeData;
|
|
|
|
final actions = <Widget>[
|
|
const ShareActionButton(source: ActionSource.viewer),
|
|
|
|
if (!isInLockedView) ...[
|
|
if (asset.isLocalOnly) const UploadActionButton(source: ActionSource.viewer),
|
|
if (asset.type == AssetType.image) const EditImageActionButton(),
|
|
if (asset.hasRemote) AddActionButton(originalTheme: originalTheme),
|
|
|
|
if (isOwner) ...[
|
|
asset.isLocalOnly
|
|
? const DeleteLocalActionButton(source: ActionSource.viewer)
|
|
: const DeleteActionButton(source: ActionSource.viewer, showConfirmation: true),
|
|
],
|
|
],
|
|
];
|
|
|
|
return AnimatedSwitcher(
|
|
duration: Durations.short4,
|
|
child: showingDetails
|
|
? const SizedBox.shrink()
|
|
: Theme(
|
|
data: context.themeData.copyWith(
|
|
iconTheme: const IconThemeData(size: 22, color: Colors.white),
|
|
textTheme: context.themeData.textTheme.copyWith(
|
|
labelLarge: context.themeData.textTheme.labelLarge?.copyWith(color: Colors.white),
|
|
),
|
|
),
|
|
child: Container(
|
|
decoration: const BoxDecoration(
|
|
gradient: LinearGradient(
|
|
begin: Alignment.bottomCenter,
|
|
end: Alignment.topCenter,
|
|
colors: [Colors.black45, Colors.black12, Colors.transparent],
|
|
stops: [0.0, 0.7, 1.0],
|
|
),
|
|
),
|
|
child: SafeArea(
|
|
top: false,
|
|
child: Column(
|
|
mainAxisSize: MainAxisSize.min,
|
|
children: [
|
|
if (asset.isVideo) VideoControls(key: ValueKey(asset.heroTag), videoPlayerName: asset.heroTag),
|
|
if (!isReadonlyModeEnabled)
|
|
Row(mainAxisAlignment: MainAxisAlignment.spaceEvenly, children: actions),
|
|
],
|
|
),
|
|
),
|
|
),
|
|
),
|
|
);
|
|
}
|
|
}
|