Browse Source

chore(mobile): minor UI tweak (#3021)

* chore(mobile): minor UI tweak

* fix test

* refactor
Alex 2 năm trước cách đây
mục cha
commit
8e6c90e294

+ 10 - 0
mobile/ios/Podfile.lock

@@ -1,4 +1,7 @@
 PODS:
 PODS:
+  - connectivity_plus (0.0.1):
+    - Flutter
+    - ReachabilitySwift
   - device_info_plus (0.0.1):
   - device_info_plus (0.0.1):
     - Flutter
     - Flutter
   - Flutter (1.0.0)
   - Flutter (1.0.0)
@@ -33,6 +36,7 @@ PODS:
   - photo_manager (2.0.0):
   - photo_manager (2.0.0):
     - Flutter
     - Flutter
     - FlutterMacOS
     - FlutterMacOS
+  - ReachabilitySwift (5.0.0)
   - SAMKeychain (1.5.3)
   - SAMKeychain (1.5.3)
   - share_plus (0.0.1):
   - share_plus (0.0.1):
     - Flutter
     - Flutter
@@ -51,6 +55,7 @@ PODS:
     - Flutter
     - Flutter
 
 
 DEPENDENCIES:
 DEPENDENCIES:
+  - connectivity_plus (from `.symlinks/plugins/connectivity_plus/ios`)
   - device_info_plus (from `.symlinks/plugins/device_info_plus/ios`)
   - device_info_plus (from `.symlinks/plugins/device_info_plus/ios`)
   - Flutter (from `Flutter`)
   - Flutter (from `Flutter`)
   - flutter_native_splash (from `.symlinks/plugins/flutter_native_splash/ios`)
   - flutter_native_splash (from `.symlinks/plugins/flutter_native_splash/ios`)
@@ -75,10 +80,13 @@ DEPENDENCIES:
 SPEC REPOS:
 SPEC REPOS:
   trunk:
   trunk:
     - FMDB
     - FMDB
+    - ReachabilitySwift
     - SAMKeychain
     - SAMKeychain
     - Toast
     - Toast
 
 
 EXTERNAL SOURCES:
 EXTERNAL SOURCES:
+  connectivity_plus:
+    :path: ".symlinks/plugins/connectivity_plus/ios"
   device_info_plus:
   device_info_plus:
     :path: ".symlinks/plugins/device_info_plus/ios"
     :path: ".symlinks/plugins/device_info_plus/ios"
   Flutter:
   Flutter:
@@ -121,6 +129,7 @@ EXTERNAL SOURCES:
     :path: ".symlinks/plugins/wakelock/ios"
     :path: ".symlinks/plugins/wakelock/ios"
 
 
 SPEC CHECKSUMS:
 SPEC CHECKSUMS:
+  connectivity_plus: 07c49e96d7fc92bc9920617b83238c4d178b446a
   device_info_plus: e5c5da33f982a436e103237c0c85f9031142abed
   device_info_plus: e5c5da33f982a436e103237c0c85f9031142abed
   Flutter: f04841e97a9d0b0a8025694d0796dd46242b2854
   Flutter: f04841e97a9d0b0a8025694d0796dd46242b2854
   flutter_native_splash: 52501b97d1c0a5f898d687f1646226c1f93c56ef
   flutter_native_splash: 52501b97d1c0a5f898d687f1646226c1f93c56ef
@@ -136,6 +145,7 @@ SPEC CHECKSUMS:
   path_provider_ios: 14f3d2fd28c4fdb42f44e0f751d12861c43cee02
   path_provider_ios: 14f3d2fd28c4fdb42f44e0f751d12861c43cee02
   permission_handler_apple: 44366e37eaf29454a1e7b1b7d736c2cceaeb17ce
   permission_handler_apple: 44366e37eaf29454a1e7b1b7d736c2cceaeb17ce
   photo_manager: 4f6810b7dfc4feb03b461ac1a70dacf91fba7604
   photo_manager: 4f6810b7dfc4feb03b461ac1a70dacf91fba7604
+  ReachabilitySwift: 985039c6f7b23a1da463388634119492ff86c825
   SAMKeychain: 483e1c9f32984d50ca961e26818a534283b4cd5c
   SAMKeychain: 483e1c9f32984d50ca961e26818a534283b4cd5c
   share_plus: 056a1e8ac890df3e33cb503afffaf1e9b4fbae68
   share_plus: 056a1e8ac890df3e33cb503afffaf1e9b4fbae68
   shared_preferences_foundation: e2dae3258e06f44cc55f49d42024fd8dd03c590c
   shared_preferences_foundation: e2dae3258e06f44cc55f49d42024fd8dd03c590c

+ 2 - 6
mobile/lib/modules/album/views/sharing_page.dart

@@ -236,7 +236,7 @@ class SharingPage extends HookConsumerWidget {
           SliverToBoxAdapter(child: buildTopBottons()),
           SliverToBoxAdapter(child: buildTopBottons()),
           if (partner.isNotEmpty)
           if (partner.isNotEmpty)
             SliverPadding(
             SliverPadding(
-              padding: const EdgeInsets.only(left: 12, right: 12, bottom: 4),
+              padding: const EdgeInsets.all(12),
               sliver: SliverToBoxAdapter(
               sliver: SliverToBoxAdapter(
                 child: const Text(
                 child: const Text(
                   "partner_page_title",
                   "partner_page_title",
@@ -246,11 +246,7 @@ class SharingPage extends HookConsumerWidget {
             ),
             ),
           if (partner.isNotEmpty) PartnerList(partner: partner),
           if (partner.isNotEmpty) PartnerList(partner: partner),
           SliverPadding(
           SliverPadding(
-            padding: EdgeInsets.only(
-              left: 12,
-              right: 12,
-              top: partner.isEmpty ? 0 : 16,
-            ),
+            padding: const EdgeInsets.all(12),
             sliver: SliverToBoxAdapter(
             sliver: SliverToBoxAdapter(
               child: const Text(
               child: const Text(
                 "sharing_page_album",
                 "sharing_page_album",

+ 3 - 1
mobile/lib/modules/home/ui/asset_grid/group_divider_title.dart

@@ -1,4 +1,5 @@
 import 'package:flutter/material.dart';
 import 'package:flutter/material.dart';
+import 'package:flutter/services.dart';
 import 'package:hooks_riverpod/hooks_riverpod.dart';
 import 'package:hooks_riverpod/hooks_riverpod.dart';
 
 
 class GroupDividerTitle extends ConsumerWidget {
 class GroupDividerTitle extends ConsumerWidget {
@@ -20,6 +21,7 @@ class GroupDividerTitle extends ConsumerWidget {
   @override
   @override
   Widget build(BuildContext context, WidgetRef ref) {
   Widget build(BuildContext context, WidgetRef ref) {
     void handleTitleIconClick() {
     void handleTitleIconClick() {
+      HapticFeedback.heavyImpact();
       if (selected) {
       if (selected) {
         onDeselect();
         onDeselect();
       } else {
       } else {
@@ -30,7 +32,7 @@ class GroupDividerTitle extends ConsumerWidget {
     return Padding(
     return Padding(
       padding: const EdgeInsets.only(
       padding: const EdgeInsets.only(
         top: 12.0,
         top: 12.0,
-        bottom: 4.0,
+        bottom: 16.0,
         left: 12.0,
         left: 12.0,
         right: 12.0,
         right: 12.0,
       ),
       ),

+ 39 - 39
mobile/lib/modules/home/ui/asset_grid/immich_asset_grid_view.dart

@@ -19,6 +19,45 @@ typedef ImmichAssetGridSelectionListener = void Function(
   Set<Asset>,
   Set<Asset>,
 );
 );
 
 
+class ImmichAssetGridView extends StatefulWidget {
+  final RenderList renderList;
+  final int assetsPerRow;
+  final double margin;
+  final bool showStorageIndicator;
+  final ImmichAssetGridSelectionListener? listener;
+  final bool selectionActive;
+  final Future<void> Function()? onRefresh;
+  final Set<Asset>? preselectedAssets;
+  final bool canDeselect;
+  final bool dynamicLayout;
+  final bool showMultiSelectIndicator;
+  final void Function(ItemPosition start, ItemPosition end)?
+      visibleItemsListener;
+  final Widget? topWidget;
+
+  const ImmichAssetGridView({
+    super.key,
+    required this.renderList,
+    required this.assetsPerRow,
+    required this.showStorageIndicator,
+    this.listener,
+    this.margin = 5.0,
+    this.selectionActive = false,
+    this.onRefresh,
+    this.preselectedAssets,
+    this.canDeselect = true,
+    this.dynamicLayout = true,
+    this.showMultiSelectIndicator = true,
+    this.visibleItemsListener,
+    this.topWidget,
+  });
+
+  @override
+  State<StatefulWidget> createState() {
+    return ImmichAssetGridViewState();
+  }
+}
+
 class ImmichAssetGridViewState extends State<ImmichAssetGridView> {
 class ImmichAssetGridViewState extends State<ImmichAssetGridView> {
   final ItemScrollController _itemScrollController = ItemScrollController();
   final ItemScrollController _itemScrollController = ItemScrollController();
   final ItemPositionsListener _itemPositionsListener =
   final ItemPositionsListener _itemPositionsListener =
@@ -383,42 +422,3 @@ class ImmichAssetGridViewState extends State<ImmichAssetGridView> {
     );
     );
   }
   }
 }
 }
-
-class ImmichAssetGridView extends StatefulWidget {
-  final RenderList renderList;
-  final int assetsPerRow;
-  final double margin;
-  final bool showStorageIndicator;
-  final ImmichAssetGridSelectionListener? listener;
-  final bool selectionActive;
-  final Future<void> Function()? onRefresh;
-  final Set<Asset>? preselectedAssets;
-  final bool canDeselect;
-  final bool dynamicLayout;
-  final bool showMultiSelectIndicator;
-  final void Function(ItemPosition start, ItemPosition end)?
-      visibleItemsListener;
-  final Widget? topWidget;
-
-  const ImmichAssetGridView({
-    super.key,
-    required this.renderList,
-    required this.assetsPerRow,
-    required this.showStorageIndicator,
-    this.listener,
-    this.margin = 5.0,
-    this.selectionActive = false,
-    this.onRefresh,
-    this.preselectedAssets,
-    this.canDeselect = true,
-    this.dynamicLayout = true,
-    this.showMultiSelectIndicator = true,
-    this.visibleItemsListener,
-    this.topWidget,
-  });
-
-  @override
-  State<StatefulWidget> createState() {
-    return ImmichAssetGridViewState();
-  }
-}

+ 2 - 2
mobile/lib/modules/home/ui/home_page_app_bar.dart

@@ -71,8 +71,8 @@ class HomePageAppBar extends ConsumerWidget implements PreferredSizeWidget {
               ),
               ),
               if (serverInfoState.isVersionMismatch)
               if (serverInfoState.isVersionMismatch)
                 Positioned(
                 Positioned(
-                  bottom: 12,
-                  right: 12,
+                  bottom: 4,
+                  right: 6,
                   child: GestureDetector(
                   child: GestureDetector(
                     onTap: () => Scaffold.of(context).openDrawer(),
                     onTap: () => Scaffold.of(context).openDrawer(),
                     child: Material(
                     child: Material(

+ 5 - 1
mobile/lib/modules/memories/ui/memory_lane.dart

@@ -1,9 +1,11 @@
 import 'package:auto_route/auto_route.dart';
 import 'package:auto_route/auto_route.dart';
 import 'package:flutter/material.dart';
 import 'package:flutter/material.dart';
+import 'package:flutter/services.dart';
 import 'package:hooks_riverpod/hooks_riverpod.dart';
 import 'package:hooks_riverpod/hooks_riverpod.dart';
 import 'package:immich_mobile/modules/memories/providers/memory.provider.dart';
 import 'package:immich_mobile/modules/memories/providers/memory.provider.dart';
 import 'package:immich_mobile/routing/router.dart';
 import 'package:immich_mobile/routing/router.dart';
 import 'package:immich_mobile/shared/ui/immich_image.dart';
 import 'package:immich_mobile/shared/ui/immich_image.dart';
+import 'package:openapi/api.dart';
 
 
 class MemoryLane extends HookConsumerWidget {
 class MemoryLane extends HookConsumerWidget {
   const MemoryLane({super.key});
   const MemoryLane({super.key});
@@ -27,6 +29,7 @@ class MemoryLane extends HookConsumerWidget {
                         padding: const EdgeInsets.only(right: 8.0, bottom: 8),
                         padding: const EdgeInsets.only(right: 8.0, bottom: 8),
                         child: GestureDetector(
                         child: GestureDetector(
                           onTap: () {
                           onTap: () {
+                            HapticFeedback.heavyImpact();
                             AutoRouter.of(context).push(
                             AutoRouter.of(context).push(
                               VerticalRouteView(
                               VerticalRouteView(
                                 memories: memories,
                                 memories: memories,
@@ -53,6 +56,7 @@ class MemoryLane extends HookConsumerWidget {
                                     width: 130,
                                     width: 130,
                                     height: 200,
                                     height: 200,
                                     useGrayBoxPlaceholder: true,
                                     useGrayBoxPlaceholder: true,
+                                    type: ThumbnailFormat.JPEG,
                                   ),
                                   ),
                                 ),
                                 ),
                               ),
                               ),
@@ -66,7 +70,7 @@ class MemoryLane extends HookConsumerWidget {
                                   child: Text(
                                   child: Text(
                                     memory.title,
                                     memory.title,
                                     style: const TextStyle(
                                     style: const TextStyle(
-                                      fontWeight: FontWeight.w500,
+                                      fontWeight: FontWeight.bold,
                                       color: Colors.white,
                                       color: Colors.white,
                                       fontSize: 14,
                                       fontSize: 14,
                                     ),
                                     ),

+ 8 - 1
mobile/lib/modules/partner/ui/partner_list.dart

@@ -23,7 +23,14 @@ class PartnerList extends HookConsumerWidget {
     return ListTile(
     return ListTile(
       contentPadding: const EdgeInsets.symmetric(horizontal: 12.0),
       contentPadding: const EdgeInsets.symmetric(horizontal: 12.0),
       leading: userAvatar(context, p, radius: 30),
       leading: userAvatar(context, p, radius: 30),
-      title: Text("${p.firstName} ${p.lastName}"),
+      title: Text(
+        "${p.firstName} ${p.lastName}'s photos",
+        style: TextStyle(
+          fontWeight: FontWeight.bold,
+          fontSize: 14,
+          color: Theme.of(context).primaryColor,
+        ),
+      ),
       onTap: () => AutoRouter.of(context).push(PartnerDetailRoute(partner: p)),
       onTap: () => AutoRouter.of(context).push(PartnerDetailRoute(partner: p)),
     );
     );
   }
   }

+ 16 - 17
mobile/lib/modules/settings/ui/asset_list_settings/asset_list_layout_settings.dart

@@ -51,31 +51,34 @@ class LayoutSettings extends HookConsumerWidget {
       children: [
       children: [
         SwitchListTile.adaptive(
         SwitchListTile.adaptive(
           activeColor: Theme.of(context).primaryColor,
           activeColor: Theme.of(context).primaryColor,
-          title: const Text(
+          title: Text(
             "asset_list_layout_settings_dynamic_layout_title",
             "asset_list_layout_settings_dynamic_layout_title",
-            style: TextStyle(
-              fontSize: 12,
-            ),
+            style: Theme.of(context)
+                .textTheme
+                .labelLarge
+                ?.copyWith(fontWeight: FontWeight.bold),
           ).tr(),
           ).tr(),
           onChanged: switchChanged,
           onChanged: switchChanged,
           value: useDynamicLayout.value,
           value: useDynamicLayout.value,
         ),
         ),
+        const Divider(
+          indent: 18,
+          endIndent: 18,
+        ),
         ListTile(
         ListTile(
           title: const Text(
           title: const Text(
             "asset_list_layout_settings_group_by",
             "asset_list_layout_settings_group_by",
             style: TextStyle(
             style: TextStyle(
-              fontSize: 12,
+              fontSize: 16,
               fontWeight: FontWeight.bold,
               fontWeight: FontWeight.bold,
             ),
             ),
           ).tr(),
           ).tr(),
         ),
         ),
         RadioListTile(
         RadioListTile(
           activeColor: Theme.of(context).primaryColor,
           activeColor: Theme.of(context).primaryColor,
-          title: const Text(
+          title: Text(
             "asset_list_layout_settings_group_by_month_day",
             "asset_list_layout_settings_group_by_month_day",
-            style: TextStyle(
-              fontSize: 12,
-            ),
+            style: Theme.of(context).textTheme.labelLarge,
           ).tr(),
           ).tr(),
           value: GroupAssetsBy.day,
           value: GroupAssetsBy.day,
           groupValue: groupBy.value,
           groupValue: groupBy.value,
@@ -84,11 +87,9 @@ class LayoutSettings extends HookConsumerWidget {
         ),
         ),
         RadioListTile(
         RadioListTile(
           activeColor: Theme.of(context).primaryColor,
           activeColor: Theme.of(context).primaryColor,
-          title: const Text(
+          title: Text(
             "asset_list_layout_settings_group_by_month",
             "asset_list_layout_settings_group_by_month",
-            style: TextStyle(
-              fontSize: 12,
-            ),
+            style: Theme.of(context).textTheme.labelLarge,
           ).tr(),
           ).tr(),
           value: GroupAssetsBy.month,
           value: GroupAssetsBy.month,
           groupValue: groupBy.value,
           groupValue: groupBy.value,
@@ -97,11 +98,9 @@ class LayoutSettings extends HookConsumerWidget {
         ),
         ),
         RadioListTile(
         RadioListTile(
           activeColor: Theme.of(context).primaryColor,
           activeColor: Theme.of(context).primaryColor,
-          title: const Text(
+          title: Text(
             "asset_list_layout_settings_group_automatically",
             "asset_list_layout_settings_group_automatically",
-            style: TextStyle(
-              fontSize: 12,
-            ),
+            style: Theme.of(context).textTheme.labelLarge,
           ).tr(),
           ).tr(),
           value: GroupAssetsBy.auto,
           value: GroupAssetsBy.auto,
           groupValue: groupBy.value,
           groupValue: groupBy.value,

+ 5 - 4
mobile/lib/modules/settings/ui/asset_list_settings/asset_list_storage_indicator.dart

@@ -34,11 +34,12 @@ class StorageIndicator extends HookConsumerWidget {
 
 
     return SwitchListTile.adaptive(
     return SwitchListTile.adaptive(
       activeColor: Theme.of(context).primaryColor,
       activeColor: Theme.of(context).primaryColor,
-      title: const Text(
+      title: Text(
         "theme_setting_asset_list_storage_indicator_title",
         "theme_setting_asset_list_storage_indicator_title",
-        style: TextStyle(
-          fontSize: 12,
-        ),
+        style: Theme.of(context)
+            .textTheme
+            .labelLarge
+            ?.copyWith(fontWeight: FontWeight.bold),
       ).tr(),
       ).tr(),
       onChanged: switchChanged,
       onChanged: switchChanged,
       value: showStorageIndicator.value,
       value: showStorageIndicator.value,

+ 1 - 1
mobile/lib/modules/settings/ui/asset_list_settings/asset_list_tiles_per_row.dart

@@ -39,7 +39,7 @@ class TilesPerRow extends HookConsumerWidget {
           title: const Text(
           title: const Text(
             "theme_setting_asset_list_tiles_per_row_title",
             "theme_setting_asset_list_tiles_per_row_title",
             style: TextStyle(
             style: TextStyle(
-              fontSize: 12,
+              fontSize: 14,
               fontWeight: FontWeight.bold,
               fontWeight: FontWeight.bold,
             ),
             ),
           ).tr(args: ["${itemsValue.value.toInt()}"]),
           ).tr(args: ["${itemsValue.value.toInt()}"]),

+ 14 - 8
mobile/lib/modules/settings/ui/settings_switch_list_tile.dart

@@ -22,15 +22,21 @@ class SettingsSwitchListTile extends StatelessWidget {
   Widget build(BuildContext context) {
   Widget build(BuildContext context) {
     return SwitchListTile.adaptive(
     return SwitchListTile.adaptive(
       value: valueNotifier.value,
       value: valueNotifier.value,
-      onChanged: !enabled ? null : (value) {
-        valueNotifier.value = value;
-        appSettingService.setSetting(settingsEnum, value);
-      },
-      activeColor: Theme
-        .of(context)
-        .primaryColor,
+      onChanged: !enabled
+          ? null
+          : (value) {
+              valueNotifier.value = value;
+              appSettingService.setSetting(settingsEnum, value);
+            },
+      activeColor: Theme.of(context).primaryColor,
       dense: true,
       dense: true,
-      title: Text(title, style: const TextStyle(fontWeight: FontWeight.bold)),
+      title: Text(
+        title,
+        style: Theme.of(context)
+            .textTheme
+            .labelLarge
+            ?.copyWith(fontWeight: FontWeight.bold),
+      ),
       subtitle: subtitle != null ? Text(subtitle!) : null,
       subtitle: subtitle != null ? Text(subtitle!) : null,
     );
     );
   }
   }

+ 10 - 10
mobile/lib/modules/settings/ui/theme_setting/theme_setting.dart

@@ -40,12 +40,12 @@ class ThemeSetting extends HookConsumerWidget {
       children: [
       children: [
         SwitchListTile.adaptive(
         SwitchListTile.adaptive(
           activeColor: Theme.of(context).primaryColor,
           activeColor: Theme.of(context).primaryColor,
-          title: const Text(
+          title: Text(
             'theme_setting_system_theme_switch',
             'theme_setting_system_theme_switch',
-            style: TextStyle(
-              fontSize: 12.0,
-              fontWeight: FontWeight.bold,
-            ),
+            style: Theme.of(context)
+                .textTheme
+                .labelLarge
+                ?.copyWith(fontWeight: FontWeight.bold),
           ).tr(),
           ).tr(),
           value: currentTheme.value == ThemeMode.system,
           value: currentTheme.value == ThemeMode.system,
           onChanged: (bool isSystem) {
           onChanged: (bool isSystem) {
@@ -78,12 +78,12 @@ class ThemeSetting extends HookConsumerWidget {
         if (currentTheme.value != ThemeMode.system)
         if (currentTheme.value != ThemeMode.system)
           SwitchListTile.adaptive(
           SwitchListTile.adaptive(
             activeColor: Theme.of(context).primaryColor,
             activeColor: Theme.of(context).primaryColor,
-            title: const Text(
+            title: Text(
               'theme_setting_dark_mode_switch',
               'theme_setting_dark_mode_switch',
-              style: TextStyle(
-                fontSize: 12.0,
-                fontWeight: FontWeight.bold,
-              ),
+              style: Theme.of(context)
+                  .textTheme
+                  .labelLarge
+                  ?.copyWith(fontWeight: FontWeight.bold),
             ).tr(),
             ).tr(),
             value: ref.watch(immichThemeProvider) == ThemeMode.dark,
             value: ref.watch(immichThemeProvider) == ThemeMode.dark,
             onChanged: (bool isDark) {
             onChanged: (bool isDark) {

+ 1 - 1
mobile/lib/shared/ui/immich_image.dart

@@ -92,7 +92,7 @@ class ImmichImage extends StatelessWidget {
     return CachedNetworkImage(
     return CachedNetworkImage(
       imageUrl: thumbnailRequestUrl,
       imageUrl: thumbnailRequestUrl,
       httpHeaders: {"Authorization": "Bearer $token"},
       httpHeaders: {"Authorization": "Bearer $token"},
-      cacheKey: getThumbnailCacheKey(asset),
+      cacheKey: getThumbnailCacheKey(asset, type: type),
       width: width,
       width: width,
       height: height,
       height: height,
       // keeping memCacheWidth, memCacheHeight, maxWidthDiskCache and
       // keeping memCacheWidth, memCacheHeight, maxWidthDiskCache and