Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(mobile): Add Partner Sharing Avatars to Timeline and Info Cards #12089

Open
wants to merge 6 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 5 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
10 changes: 9 additions & 1 deletion mobile/assets/i18n/en-US.json
Original file line number Diff line number Diff line change
Expand Up @@ -387,6 +387,7 @@
"partner_page_title": "Partner",
"partners": "Partners",
"people": "People",
"partner_sharing_dialog_title": "Partner Sharing",
"permission_onboarding_back": "Back",
"permission_onboarding_continue_anyway": "Continue anyway",
"permission_onboarding_get_started": "Get started",
Expand Down Expand Up @@ -574,11 +575,16 @@
"sync_albums": "Sync albums",
"sync_albums_manual_subtitle": "Sync all uploaded videos and photos to the selected backup albums",
"sync_upload_album_setting_subtitle": "Create and upload your photos and videos to the selected albums on Immich",
"sharing_silver_appbar_shared_links": "Shared links",
"storage_asset_local": "On Device (Not backed up)",
"storage_asset_remote": "Immich Server only",
"storage_asset_merged": "Backed up to Immich Server",
"storage_asset_partner": "From Partner Sharing",
"tab_controller_nav_library": "Library",
"tab_controller_nav_photos": "Photos",
"tab_controller_nav_search": "Search",
"tab_controller_nav_sharing": "Sharing",
"theme_setting_asset_list_storage_indicator_title": "Show storage indicator on asset tiles",
"theme_setting_asset_list_storage_indicator_title": "Show storage indicator",
"theme_setting_asset_list_tiles_per_row_title": "Number of assets per row ({})",
"theme_setting_colorful_interface_subtitle": "Apply primary color to background surfaces.",
"theme_setting_colorful_interface_title": "Colorful interface",
Expand All @@ -593,6 +599,8 @@
"theme_setting_theme_title": "Theme",
"theme_setting_three_stage_loading_subtitle": "Three-stage loading might increase the loading performance but causes significantly higher network load",
"theme_setting_three_stage_loading_title": "Enable three-stage loading",
"timeline_settings_title": "Tile Options",
"timeline_show_partner_switch": "Show user thumbnails",
"translated_text_options": "Options",
"trash": "Trash",
"trash_emptied": "Emptied trash",
Expand Down
1 change: 1 addition & 0 deletions mobile/lib/entities/store.entity.dart
Original file line number Diff line number Diff line change
Expand Up @@ -218,6 +218,7 @@ enum StoreKey<T> {
logLevel<int>(115, type: int),
preferRemoteImage<bool>(116, type: bool),
loopVideo<bool>(117, type: bool),
showPartnerIconInTimeline<bool>(118, type: bool),
// map related settings
mapShowFavoriteOnly<bool>(118, type: bool),
mapRelativeDate<int>(119, type: int),
Expand Down
2 changes: 2 additions & 0 deletions mobile/lib/interfaces/user.interface.dart
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ import 'package:immich_mobile/interfaces/database.interface.dart';
abstract interface class IUserRepository implements IDatabaseRepository {
Future<User?> get(String id);

Future<User?> getByIsarId(int id);

Future<List<User>> getByIds(List<String> ids);

Future<List<User>> getAll({bool self = true, UserSort? sortBy});
Expand Down
4 changes: 2 additions & 2 deletions mobile/lib/pages/library/library.page.dart
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ import 'package:immich_mobile/services/api.service.dart';
import 'package:immich_mobile/utils/image_url_builder.dart';
import 'package:immich_mobile/widgets/album/album_thumbnail_card.dart';
import 'package:immich_mobile/widgets/common/immich_app_bar.dart';
import 'package:immich_mobile/widgets/common/user_avatar.dart';
import 'package:immich_mobile/widgets/common/user_circle_avatar.dart';
import 'package:immich_mobile/widgets/map/map_thumbnail.dart';
import 'package:maplibre_gl/maplibre_gl.dart';

Expand Down Expand Up @@ -171,7 +171,7 @@ class PartnerList extends ConsumerWidget {
left: 12.0,
right: 18.0,
),
leading: userAvatar(context, partner, radius: 16),
leading: UserCircleAvatar(user: partner, radius: 16),
title: Text(
"partner_list_user_photos",
style: TextStyle(
Expand Down
6 changes: 3 additions & 3 deletions mobile/lib/pages/library/partner/partner.page.dart
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import 'package:immich_mobile/services/partner.service.dart';
import 'package:immich_mobile/entities/user.entity.dart';
import 'package:immich_mobile/widgets/common/confirm_dialog.dart';
import 'package:immich_mobile/widgets/common/immich_toast.dart';
import 'package:immich_mobile/widgets/common/user_avatar.dart';
import 'package:immich_mobile/widgets/common/user_circle_avatar.dart';

@RoutePage()
class PartnerPage extends HookConsumerWidget {
Expand Down Expand Up @@ -42,7 +42,7 @@ class PartnerPage extends HookConsumerWidget {
children: [
Padding(
padding: const EdgeInsets.only(right: 8),
child: userAvatar(context, u),
child: UserCircleAvatar(user: u),
),
Text(u.name),
],
Expand Down Expand Up @@ -99,7 +99,7 @@ class PartnerPage extends HookConsumerWidget {
itemCount: users.length,
itemBuilder: ((context, index) {
return ListTile(
leading: userAvatar(context, users[index]),
leading: UserCircleAvatar(user: users[index]),
title: Text(
users[index].email,
style: context.textTheme.bodyLarge,
Expand Down
1 change: 1 addition & 0 deletions mobile/lib/pages/library/partner/partner_detail.page.dart
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,7 @@ class PartnerDetailPage extends HookConsumerWidget {
onRefresh: () => ref.read(assetProvider.notifier).getAllAsset(),
deleteEnabled: false,
favoriteEnabled: false,
showUserThumbnail: false,
),
);
}
Expand Down
5 changes: 5 additions & 0 deletions mobile/lib/repositories/user.repository.dart
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,11 @@ class UserRepository extends DatabaseRepository implements IUserRepository {
@override
Future<User?> get(String id) => db.users.getById(id);

@override
Future<User?> getByIsarId(int id) {
return db.users.where().isarIdEqualTo(id).findFirst();
}

@override
Future<List<User>> getAll({bool self = true, UserSort? sortBy}) {
final baseQuery = db.users.where();
Expand Down
5 changes: 5 additions & 0 deletions mobile/lib/services/app_settings.service.dart
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,11 @@ enum AppSettingsEnum<T> {
mapRelativeDate<int>(StoreKey.mapRelativeDate, null, 0),
allowSelfSignedSSLCert<bool>(StoreKey.selfSignedCert, null, false),
ignoreIcloudAssets<bool>(StoreKey.ignoreIcloudAssets, null, false),
showPartnerIconInTimeline<bool>(
StoreKey.showPartnerIconInTimeline,
null,
true,
),
selectedAlbumSortReverse<bool>(
StoreKey.selectedAlbumSortReverse,
null,
Expand Down
4 changes: 4 additions & 0 deletions mobile/lib/services/user.service.dart
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,10 @@ class UserService {
Future<List<User>> getUsers({bool self = false}) =>
_userRepository.getAll(self: self);

Future<User?> getUser(String id) async => await _userRepository.get(id);
Future<User?> getUserbyId(int id) async =>
await _userRepository.getByIsarId(id);

Future<({String profileImagePath})?> uploadProfileImage(XFile image) async {
try {
return await _userApiRepository.createProfileImage(
Expand Down
12 changes: 12 additions & 0 deletions mobile/lib/utils/storage_indicator.dart
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/material.dart';
import 'package:immich_mobile/entities/asset.entity.dart';

Expand All @@ -12,3 +13,14 @@ IconData storageIcon(Asset asset) {
return Icons.cloud_done_outlined;
}
}

String storageText(Asset asset) {
switch (asset.storage) {
case AssetState.local:
return "storage_asset_local".tr();
case AssetState.remote:
return "storage_asset_remote".tr();
case AssetState.merged:
return "storage_asset_merged".tr();
}
}
4 changes: 4 additions & 0 deletions mobile/lib/widgets/asset_grid/immich_asset_grid.dart
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ class ImmichAssetGrid extends HookConsumerWidget {
final int? assetsPerRow;
final double margin;
final bool? showStorageIndicator;
final bool? showUserThumbnail;
final ImmichAssetGridSelectionListener? listener;
final bool selectionActive;
final List<Asset>? assets;
Expand All @@ -41,6 +42,7 @@ class ImmichAssetGrid extends HookConsumerWidget {
this.renderList,
this.assetsPerRow,
this.showStorageIndicator,
this.showUserThumbnail,
this.listener,
this.margin = 2.0,
this.selectionActive = false,
Expand Down Expand Up @@ -105,6 +107,8 @@ class ImmichAssetGrid extends HookConsumerWidget {
listener: listener,
showStorageIndicator: showStorageIndicator ??
settings.getSetting(AppSettingsEnum.storageIndicator),
showUserThumbnail: showUserThumbnail ??
settings.getSetting(AppSettingsEnum.showPartnerIconInTimeline),
renderList: renderList,
margin: margin,
selectionActive: selectionActive,
Expand Down
9 changes: 9 additions & 0 deletions mobile/lib/widgets/asset_grid/immich_asset_grid_view.dart
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ class ImmichAssetGridView extends ConsumerStatefulWidget {
final int assetsPerRow;
final double margin;
final bool showStorageIndicator;
final bool showUserThumbnail;
final ImmichAssetGridSelectionListener? listener;
final bool selectionActive;
final Future<void> Function()? onRefresh;
Expand All @@ -61,6 +62,7 @@ class ImmichAssetGridView extends ConsumerStatefulWidget {
required this.renderList,
required this.assetsPerRow,
required this.showStorageIndicator,
required this.showUserThumbnail,
this.listener,
this.margin = 5.0,
this.selectionActive = false,
Expand Down Expand Up @@ -187,6 +189,7 @@ class ImmichAssetGridViewState extends ConsumerState<ImmichAssetGridView> {
final section = widget.renderList.elements[index];
return _Section(
showStorageIndicator: widget.showStorageIndicator,
showUserThumbnail: widget.showUserThumbnail,
selectedAssets: _selectedAssets,
selectionActive: widget.selectionActive,
sectionIndex: index,
Expand Down Expand Up @@ -601,6 +604,7 @@ class _Section extends StatelessWidget {
final bool showStack;
final int heroOffset;
final bool showStorageIndicator;
final bool showUserThumbnail;

const _Section({
required this.section,
Expand All @@ -618,6 +622,7 @@ class _Section extends StatelessWidget {
required this.showStack,
required this.heroOffset,
required this.showStorageIndicator,
required this.showUserThumbnail,
});

@override
Expand Down Expand Up @@ -680,6 +685,7 @@ class _Section extends StatelessWidget {
showStack: showStack,
heroOffset: heroOffset,
showStorageIndicator: showStorageIndicator,
showUserThumbnail: showUserThumbnail,
selectionActive: selectionActive,
onSelect: (asset) => selectAssets([asset]),
onDeselect: (asset) => deselectAssets([asset]),
Expand Down Expand Up @@ -763,6 +769,7 @@ class _AssetRow extends StatelessWidget {
final RenderList renderList;
final bool selectionActive;
final bool showStorageIndicator;
final bool showUserThumbnail;
final int heroOffset;
final bool showStack;
final Function(Asset)? onSelect;
Expand All @@ -782,6 +789,7 @@ class _AssetRow extends StatelessWidget {
required this.renderList,
required this.selectionActive,
required this.showStorageIndicator,
required this.showUserThumbnail,
required this.heroOffset,
required this.showStack,
required this.isSelectionActive,
Expand Down Expand Up @@ -859,6 +867,7 @@ class _AssetRow extends StatelessWidget {
asset: asset,
multiselectEnabled: selectionActive,
isSelected: isSelectionActive && selectedAssets.contains(asset),
showUserThumbnail: showUserThumbnail,
showStorageIndicator: showStorageIndicator,
heroOffset: heroOffset,
showStack: showStack,
Expand Down
3 changes: 3 additions & 0 deletions mobile/lib/widgets/asset_grid/multiselect_grid.dart
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ class MultiselectGrid extends HookConsumerWidget {
this.buildLoadingIndicator,
this.onRemoveFromAlbum,
this.topWidget,
this.showUserThumbnail = true,
this.stackEnabled = false,
this.archiveEnabled = false,
this.deleteEnabled = true,
Expand All @@ -51,6 +52,7 @@ class MultiselectGrid extends HookConsumerWidget {
final Future<bool> Function(Iterable<Asset>)? onRemoveFromAlbum;
final Widget? topWidget;
final bool stackEnabled;
final bool showUserThumbnail;
final bool archiveEnabled;
final bool unarchive;
final bool deleteEnabled;
Expand Down Expand Up @@ -406,6 +408,7 @@ class MultiselectGrid extends HookConsumerWidget {
: ImmichAssetGrid(
renderList: data,
listener: selectionListener,
showUserThumbnail: showUserThumbnail,
selectionActive: selectionEnabledHook.value,
onRefresh: onRefresh == null
? null
Expand Down
Loading
Loading