mirror of
https://github.com/immich-app/immich.git
synced 2025-12-12 07:41:02 -08:00
refactor: use custom rating bar & provider
This commit is contained in:
@@ -4,7 +4,6 @@ import 'package:auto_route/auto_route.dart';
|
||||
import 'package:collection/collection.dart';
|
||||
import 'package:easy_localization/easy_localization.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_rating_bar/flutter_rating_bar.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';
|
||||
@@ -17,6 +16,7 @@ import 'package:immich_mobile/presentation/widgets/album/album_tile.dart';
|
||||
import 'package:immich_mobile/presentation/widgets/asset_viewer/asset_viewer.state.dart';
|
||||
import 'package:immich_mobile/presentation/widgets/asset_viewer/bottom_sheet/sheet_location_details.widget.dart';
|
||||
import 'package:immich_mobile/presentation/widgets/asset_viewer/bottom_sheet/sheet_people_details.widget.dart';
|
||||
import 'package:immich_mobile/presentation/widgets/asset_viewer/rating_bar.widget.dart';
|
||||
import 'package:immich_mobile/presentation/widgets/asset_viewer/sheet_tile.widget.dart';
|
||||
import 'package:immich_mobile/presentation/widgets/bottom_sheet/base_bottom_sheet.widget.dart';
|
||||
import 'package:immich_mobile/providers/infrastructure/action.provider.dart';
|
||||
@@ -56,12 +56,6 @@ class AssetDetailBottomSheet extends ConsumerWidget {
|
||||
final currentAlbum = ref.watch(currentRemoteAlbumProvider);
|
||||
final isArchived = asset is RemoteAsset && asset.visibility == AssetVisibility.archive;
|
||||
final advancedTroubleshooting = ref.watch(settingsProvider.notifier).get(Setting.advancedTroubleshooting);
|
||||
final isRatingEnabled = ref
|
||||
.watch(userMetadataProvider(ref.watch(currentUserProvider)?.id ?? ''))
|
||||
.maybeWhen(
|
||||
data: (metadataList) => metadataList.any((meta) => meta.preferences?.ratingsEnabled ?? false),
|
||||
orElse: () => false,
|
||||
);
|
||||
|
||||
final buttonContext = ActionButtonContext(
|
||||
asset: asset,
|
||||
@@ -79,7 +73,7 @@ class AssetDetailBottomSheet extends ConsumerWidget {
|
||||
|
||||
return BaseBottomSheet(
|
||||
actions: actions,
|
||||
slivers: [_AssetDetailBottomSheet(isRatingEnabled: isRatingEnabled)],
|
||||
slivers: [const _AssetDetailBottomSheet()],
|
||||
controller: controller,
|
||||
initialChildSize: initialChildSize,
|
||||
minChildSize: 0.1,
|
||||
@@ -93,9 +87,7 @@ class AssetDetailBottomSheet extends ConsumerWidget {
|
||||
}
|
||||
|
||||
class _AssetDetailBottomSheet extends ConsumerWidget {
|
||||
final bool isRatingEnabled;
|
||||
|
||||
const _AssetDetailBottomSheet({required this.isRatingEnabled});
|
||||
const _AssetDetailBottomSheet();
|
||||
|
||||
String _getDateTime(BuildContext ctx, BaseAsset asset, ExifInfo? exifInfo) {
|
||||
DateTime dateTime = asset.createdAt.toLocal();
|
||||
@@ -243,6 +235,9 @@ class _AssetDetailBottomSheet extends ConsumerWidget {
|
||||
final cameraTitle = _getCameraInfoTitle(exifInfo);
|
||||
final lensTitle = exifInfo?.lens != null && exifInfo!.lens!.isNotEmpty ? exifInfo.lens : null;
|
||||
final isOwner = ref.watch(currentUserProvider)?.id == (asset is RemoteAsset ? asset.ownerId : null);
|
||||
final isRatingEnabled = ref
|
||||
.watch(userMetadataPreferencesProvider(ref.watch(currentUserProvider)?.id ?? ''))
|
||||
.maybeWhen(data: (prefs) => prefs?.ratingsEnabled ?? false, orElse: () => false);
|
||||
|
||||
// Build file info tile based on asset type
|
||||
Widget buildFileInfoTile() {
|
||||
@@ -350,11 +345,11 @@ class _AssetDetailBottomSheet extends ConsumerWidget {
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 8),
|
||||
RatingBar.builder(
|
||||
RatingBar(
|
||||
initialRating: exifInfo?.rating?.toDouble() ?? 0,
|
||||
itemBuilder: (context, _) => Icon(Icons.star, color: context.themeData.colorScheme.primary),
|
||||
filledColor: context.themeData.colorScheme.primary,
|
||||
unfilledColor: context.themeData.colorScheme.onSurface.withAlpha(100),
|
||||
itemSize: 32,
|
||||
glow: false,
|
||||
onRatingUpdate: (rating) async {
|
||||
await ref.read(actionProvider.notifier).updateRating(ActionSource.viewer, rating.round());
|
||||
},
|
||||
|
||||
@@ -0,0 +1,84 @@
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
class RatingBar extends StatefulWidget {
|
||||
final double initialRating;
|
||||
final int itemCount;
|
||||
final double itemSize;
|
||||
final Color filledColor;
|
||||
final Color unfilledColor;
|
||||
final ValueChanged<int>? onRatingUpdate;
|
||||
final Widget? itemBuilder;
|
||||
|
||||
const RatingBar({
|
||||
super.key,
|
||||
this.initialRating = 0.0,
|
||||
this.itemCount = 5,
|
||||
this.itemSize = 40.0,
|
||||
this.filledColor = Colors.amber,
|
||||
this.unfilledColor = Colors.grey,
|
||||
this.onRatingUpdate,
|
||||
this.itemBuilder,
|
||||
});
|
||||
|
||||
@override
|
||||
State<RatingBar> createState() => _RatingBarState();
|
||||
}
|
||||
|
||||
class _RatingBarState extends State<RatingBar> {
|
||||
late double _currentRating;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
_currentRating = widget.initialRating;
|
||||
}
|
||||
|
||||
void _updateRating(Offset localPosition, bool isRTL, {bool isTap = false}) {
|
||||
final totalWidth = widget.itemCount * widget.itemSize;
|
||||
double dx = localPosition.dx;
|
||||
|
||||
if (isRTL) dx = totalWidth - dx;
|
||||
|
||||
double newRating;
|
||||
|
||||
if (dx <= 0) {
|
||||
newRating = 0;
|
||||
} else if (dx >= totalWidth) {
|
||||
newRating = widget.itemCount.toDouble();
|
||||
} else {
|
||||
int tappedIndex = (dx ~/ widget.itemSize).clamp(0, widget.itemCount - 1);
|
||||
newRating = tappedIndex + 1.0;
|
||||
|
||||
if (isTap && newRating == _currentRating && _currentRating != 0) {
|
||||
newRating = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (_currentRating != newRating) {
|
||||
setState(() {
|
||||
_currentRating = newRating;
|
||||
});
|
||||
widget.onRatingUpdate?.call(newRating.round());
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final isRTL = Directionality.of(context) == TextDirection.rtl;
|
||||
|
||||
return GestureDetector(
|
||||
behavior: HitTestBehavior.opaque,
|
||||
onTapDown: (details) => _updateRating(details.localPosition, isRTL, isTap: true),
|
||||
onPanUpdate: (details) => _updateRating(details.localPosition, isRTL, isTap: false),
|
||||
child: Row(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
textDirection: isRTL ? TextDirection.rtl : TextDirection.ltr,
|
||||
children: List.generate(widget.itemCount, (index) {
|
||||
bool filled = _currentRating > index;
|
||||
return widget.itemBuilder ??
|
||||
Icon(Icons.star, size: widget.itemSize, color: filled ? widget.filledColor : widget.unfilledColor);
|
||||
}),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -11,3 +11,9 @@ final userMetadataProvider = FutureProvider.family<List<UserMetadata>, String>((
|
||||
final repository = ref.watch(userMetadataRepository);
|
||||
return repository.getUserMetadata(userId);
|
||||
});
|
||||
|
||||
final userMetadataPreferencesProvider = FutureProvider.family<Preferences?, String>((ref, String userId) async {
|
||||
final metadataList = await ref.watch(userMetadataProvider(userId).future);
|
||||
final metadataWithPrefs = metadataList.firstWhere((meta) => meta.preferences != null);
|
||||
return metadataWithPrefs.preferences;
|
||||
});
|
||||
|
||||
@@ -665,14 +665,6 @@ packages:
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.0.27"
|
||||
flutter_rating_bar:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: flutter_rating_bar
|
||||
sha256: d2af03469eac832c591a1eba47c91ecc871fe5708e69967073c043b2d775ed93
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "4.0.1"
|
||||
flutter_riverpod:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
||||
@@ -33,7 +33,6 @@ dependencies:
|
||||
flutter_displaymode: ^0.7.0
|
||||
flutter_hooks: ^0.21.3+1
|
||||
flutter_local_notifications: ^17.2.1+2
|
||||
flutter_rating_bar: ^4.0.1
|
||||
flutter_secure_storage: ^9.2.4
|
||||
flutter_svg: ^2.2.1
|
||||
flutter_udid: ^4.0.0
|
||||
|
||||
Reference in New Issue
Block a user