Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 2 additions & 3 deletions mobile/lib/domain/models/events.model.dart
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,8 @@ class ScrollToDateEvent extends Event {
}

// Asset Viewer Events
class ViewerOpenBottomSheetEvent extends Event {
final bool activitiesMode;
const ViewerOpenBottomSheetEvent({this.activitiesMode = false});
class ViewerShowDetailsEvent extends Event {
const ViewerShowDetailsEvent();
}

class ViewerReloadAssetEvent extends Event {
Expand Down
4 changes: 2 additions & 2 deletions mobile/lib/domain/services/timeline.service.dart
Original file line number Diff line number Diff line change
Expand Up @@ -183,8 +183,8 @@ class TimelineService {
return _buffer.slice(start, start + count);
}

// Pre-cache assets around the given index for asset viewer
Future<void> preCacheAssets(int index) => _mutex.run(() => _loadAssets(index, math.min(5, _totalAssets - index)));
// Preload assets around the given index for asset viewer
Future<void> preloadAssets(int index) => _mutex.run(() => _loadAssets(index, math.min(5, _totalAssets - index)));

BaseAsset getRandomAsset() => _buffer.elementAt(math.Random().nextInt(_buffer.length));

Expand Down
122 changes: 122 additions & 0 deletions mobile/lib/extensions/scroll_extensions.dart
Original file line number Diff line number Diff line change
Expand Up @@ -32,3 +32,125 @@ class FastClampingScrollPhysics extends ClampingScrollPhysics {
damping: 80,
);
}

class SnapScrollPhysics extends ScrollPhysics {
static const _minFlingVelocity = 700.0;
static const minSnapDistance = 30.0;

static final _spring = SpringDescription.withDampingRatio(mass: .5, stiffness: 300);

const SnapScrollPhysics({super.parent});

@override
SnapScrollPhysics applyTo(ScrollPhysics? ancestor) {
return SnapScrollPhysics(parent: buildParent(ancestor));
}

@override
Simulation? createBallisticSimulation(ScrollMetrics position, double velocity) {
assert(
position is SnapScrollPosition,
'SnapScrollPhysics can only be used with Scrollables that use a '
'controller whose createScrollPosition returns a SnapScrollPosition',
);

final snapOffset = (position as SnapScrollPosition).snapOffset;
if (snapOffset <= 0) {
return super.createBallisticSimulation(position, velocity);
}

if (position.pixels >= snapOffset) {
final simulation = super.createBallisticSimulation(position, velocity);
if (simulation == null || simulation.x(double.infinity) >= snapOffset) {
return simulation;
}
}

return ScrollSpringSimulation(
_spring,
position.pixels,
target(position, velocity, snapOffset),
velocity,
tolerance: toleranceFor(position),
);
}

static double target(ScrollMetrics position, double velocity, double snapOffset) {
if (velocity > _minFlingVelocity) return snapOffset;
if (velocity < -_minFlingVelocity) return position.pixels < snapOffset ? 0.0 : snapOffset;
return position.pixels < minSnapDistance ? 0.0 : snapOffset;
}
}

class SnapScrollPosition extends ScrollPositionWithSingleContext {
double snapOffset;

SnapScrollPosition({this.snapOffset = 0.0, required super.physics, required super.context, super.oldPosition});
}

class ProxyScrollController extends ScrollController {
final ScrollController scrollController;

ProxyScrollController({required this.scrollController});

SnapScrollPosition get snapPosition => position as SnapScrollPosition;

@override
ScrollPosition createScrollPosition(ScrollPhysics physics, ScrollContext context, ScrollPosition? oldPosition) {
return ProxyScrollPosition(
scrollController: scrollController,
physics: physics,
context: context,
oldPosition: oldPosition,
);
}

@override
void dispose() {
scrollController.dispose();
super.dispose();
}
}

class ProxyScrollPosition extends SnapScrollPosition {
final ScrollController scrollController;

ProxyScrollPosition({
required this.scrollController,
required super.physics,
required super.context,
super.oldPosition,
});

@override
double setPixels(double newPixels) {
final overscroll = super.setPixels(newPixels);
if (scrollController.hasClients && scrollController.position.pixels != pixels) {
scrollController.position.forcePixels(pixels);
}
return overscroll;
}

@override
void forcePixels(double value) {
super.forcePixels(value);
if (scrollController.hasClients && scrollController.position.pixels != pixels) {
scrollController.position.forcePixels(pixels);
}
}

@override
double get maxScrollExtent => scrollController.hasClients && scrollController.position.hasContentDimensions
? scrollController.position.maxScrollExtent
: super.maxScrollExtent;

@override
double get minScrollExtent => scrollController.hasClients && scrollController.position.hasContentDimensions
? scrollController.position.minScrollExtent
: super.minScrollExtent;

@override
double get viewportDimension => scrollController.hasClients && scrollController.position.hasViewportDimension
? scrollController.position.viewportDimension
: super.viewportDimension;
}
18 changes: 13 additions & 5 deletions mobile/lib/presentation/pages/drift_activities.page.dart
Original file line number Diff line number Diff line change
Expand Up @@ -14,13 +14,15 @@ import 'package:immich_mobile/providers/infrastructure/current_album.provider.da
@RoutePage()
class DriftActivitiesPage extends HookConsumerWidget {
final RemoteAlbum album;
final String? assetId;
final String? assetName;

const DriftActivitiesPage({super.key, required this.album});
const DriftActivitiesPage({super.key, required this.album, this.assetId, this.assetName});

@override
Widget build(BuildContext context, WidgetRef ref) {
final activityNotifier = ref.read(albumActivityProvider(album.id).notifier);
final activities = ref.watch(albumActivityProvider(album.id));
final activityNotifier = ref.read(albumActivityProvider(album.id, assetId).notifier);
final activities = ref.watch(albumActivityProvider(album.id, assetId));
final listViewScrollController = useScrollController();

void scrollToBottom() {
Expand All @@ -36,7 +38,13 @@ class DriftActivitiesPage extends HookConsumerWidget {
overrides: [currentRemoteAlbumScopedProvider.overrideWithValue(album)],
child: Scaffold(
appBar: AppBar(
title: Text(album.name),
title: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(album.name),
if (assetName != null) Text(assetName!, style: context.textTheme.bodySmall),
],
),
actions: [const LikeActivityActionButton(iconOnly: true)],
actionsPadding: const EdgeInsets.only(right: 8),
),
Expand All @@ -47,7 +55,7 @@ class DriftActivitiesPage extends HookConsumerWidget {
activityWidgets.add(
Padding(
padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 6),
child: CommentBubble(activity: activity),
child: CommentBubble(activity: activity, isAssetActivity: assetId != null),
),
);
}
Expand Down
2 changes: 1 addition & 1 deletion mobile/lib/presentation/pages/drift_memory.page.dart
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import 'package:immich_mobile/presentation/widgets/memory/memory_bottom_info.wid
import 'package:immich_mobile/presentation/widgets/memory/memory_card.widget.dart';
import 'package:immich_mobile/providers/asset_viewer/video_player_value_provider.dart';
import 'package:immich_mobile/providers/haptic_feedback.provider.dart';
import 'package:immich_mobile/providers/infrastructure/asset_viewer/current_asset.provider.dart';
import 'package:immich_mobile/providers/infrastructure/asset_viewer/asset.provider.dart';
import 'package:immich_mobile/widgets/memories/memory_epilogue.dart';
import 'package:immich_mobile/widgets/memories/memory_progress_indicator.dart';

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:immich_mobile/extensions/build_context_extensions.dart';
import 'package:immich_mobile/presentation/widgets/action_buttons/base_action_button.widget.dart';
import 'package:immich_mobile/presentation/widgets/action_buttons/unarchive_action_button.widget.dart';
import 'package:immich_mobile/providers/infrastructure/asset_viewer/current_asset.provider.dart';
import 'package:immich_mobile/providers/infrastructure/asset_viewer/asset.provider.dart';
import 'package:immich_mobile/presentation/widgets/album/album_selector.widget.dart';
import 'package:immich_mobile/providers/infrastructure/album.provider.dart';
import 'package:immich_mobile/providers/routes.provider.dart';
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:immich_mobile/extensions/translate_extensions.dart';
import 'package:immich_mobile/presentation/widgets/action_buttons/base_action_button.widget.dart';
import 'package:immich_mobile/presentation/widgets/images/image_provider.dart';
import 'package:immich_mobile/providers/infrastructure/asset_viewer/current_asset.provider.dart';
import 'package:immich_mobile/providers/infrastructure/asset_viewer/asset.provider.dart';
import 'package:immich_mobile/routing/router.dart';

class EditImageActionButton extends ConsumerWidget {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import 'package:immich_mobile/extensions/translate_extensions.dart';
import 'package:immich_mobile/models/activities/activity.model.dart';
import 'package:immich_mobile/presentation/widgets/action_buttons/base_action_button.widget.dart';
import 'package:immich_mobile/providers/activity.provider.dart';
import 'package:immich_mobile/providers/infrastructure/asset_viewer/current_asset.provider.dart';
import 'package:immich_mobile/providers/infrastructure/asset_viewer/asset.provider.dart';
import 'package:immich_mobile/providers/infrastructure/current_album.provider.dart';
import 'package:immich_mobile/providers/user.provider.dart';

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ import 'package:immich_mobile/providers/album/album_sort_by_options.provider.dar
import 'package:immich_mobile/providers/app_settings.provider.dart';
import 'package:immich_mobile/providers/infrastructure/album.provider.dart';
import 'package:immich_mobile/providers/infrastructure/asset.provider.dart';
import 'package:immich_mobile/providers/infrastructure/asset_viewer/current_asset.provider.dart';
import 'package:immich_mobile/providers/infrastructure/asset_viewer/asset.provider.dart';
import 'package:immich_mobile/providers/timeline/multiselect.provider.dart';
import 'package:immich_mobile/providers/user.provider.dart';
import 'package:immich_mobile/routing/router.dart';
Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
import 'package:flutter/material.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:immich_mobile/extensions/build_context_extensions.dart';
import 'package:immich_mobile/presentation/widgets/asset_viewer/asset_details/appears_in_details.widget.dart';
import 'package:immich_mobile/presentation/widgets/asset_viewer/asset_details/date_time_details.widget.dart';
import 'package:immich_mobile/presentation/widgets/asset_viewer/asset_details/drag_handle.widget.dart';
import 'package:immich_mobile/presentation/widgets/asset_viewer/asset_details/location_details.widget.dart';
import 'package:immich_mobile/presentation/widgets/asset_viewer/asset_details/people_details.widget.dart';
import 'package:immich_mobile/presentation/widgets/asset_viewer/asset_details/rating_details.widget.dart';
import 'package:immich_mobile/presentation/widgets/asset_viewer/asset_details/technical_details.widget.dart';
import 'package:immich_mobile/providers/infrastructure/asset_viewer/asset.provider.dart';

class AssetDetails extends ConsumerWidget {
final double minHeight;

const AssetDetails({required this.minHeight, super.key});

@override
Widget build(BuildContext context, WidgetRef ref) {
final asset = ref.watch(currentAssetNotifier);
if (asset == null) {
return const SizedBox.shrink();
}
return Container(
constraints: BoxConstraints(minHeight: minHeight),
decoration: BoxDecoration(
color: context.colorScheme.surface,
borderRadius: const BorderRadius.vertical(top: Radius.circular(20)),
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const DragHandle(),
const DateTimeDetails(),
const PeopleDetails(),
const LocationDetails(),
const TechnicalDetails(),
const RatingDetails(),
const AppearsInDetails(),
SizedBox(height: context.padding.bottom + 48),
],
),
);
}
}
Loading
Loading