Bläddra i källkod

wip(mobile): unify-colors

shalong-tanwen 1 år sedan
förälder
incheckning
d20801c65c
36 ändrade filer med 407 tillägg och 503 borttagningar
  1. 0 5
      mobile/lib/constants/immich_colors.dart
  2. 20 12
      mobile/lib/modules/album/ui/album_thumbnail_card.dart
  3. 33 24
      mobile/lib/modules/album/ui/album_thumbnail_listtile.dart
  4. 1 1
      mobile/lib/modules/album/views/album_viewer_page.dart
  5. 48 57
      mobile/lib/modules/album/views/library_page.dart
  6. 10 9
      mobile/lib/modules/album/views/sharing_page.dart
  7. 2 4
      mobile/lib/modules/backup/views/backup_album_selection_page.dart
  8. 20 17
      mobile/lib/modules/home/ui/asset_grid/disable_multi_select_button.dart
  9. 10 1
      mobile/lib/modules/home/ui/asset_grid/draggable_scrollbar_custom.dart
  10. 5 2
      mobile/lib/modules/home/ui/asset_grid/group_divider_title.dart
  11. 6 9
      mobile/lib/modules/home/ui/asset_grid/immich_asset_grid_view.dart
  12. 13 13
      mobile/lib/modules/home/ui/asset_grid/thumbnail_image.dart
  13. 0 3
      mobile/lib/modules/home/ui/control_bottom_app_bar.dart
  14. 7 4
      mobile/lib/modules/login/ui/login_form.dart
  15. 4 3
      mobile/lib/modules/map/views/map_page.dart
  16. 1 1
      mobile/lib/modules/memories/ui/memory_lane.dart
  17. 9 5
      mobile/lib/modules/partner/views/partner_page.dart
  18. 2 2
      mobile/lib/modules/search/ui/curated_people_row.dart
  19. 16 7
      mobile/lib/modules/search/ui/thumbnail_with_info.dart
  20. 0 1
      mobile/lib/modules/settings/ui/advanced_settings/advanced_settings.dart
  21. 0 4
      mobile/lib/modules/settings/ui/asset_list_settings/asset_list_layout_settings.dart
  22. 0 1
      mobile/lib/modules/settings/ui/asset_list_settings/asset_list_storage_indicator.dart
  23. 0 1
      mobile/lib/modules/settings/ui/asset_list_settings/asset_list_tiles_per_row.dart
  24. 0 1
      mobile/lib/modules/settings/ui/notification_setting/notification_setting.dart
  25. 20 18
      mobile/lib/modules/settings/ui/settings_switch_list_tile.dart
  26. 0 3
      mobile/lib/modules/settings/ui/theme_setting/theme_setting.dart
  27. 4 7
      mobile/lib/shared/ui/app_bar_dialog/app_bar_dialog.dart
  28. 2 5
      mobile/lib/shared/ui/app_bar_dialog/app_bar_profile_info.dart
  29. 3 7
      mobile/lib/shared/ui/app_bar_dialog/app_bar_server_info.dart
  30. 1 1
      mobile/lib/shared/ui/drag_sheet.dart
  31. 10 13
      mobile/lib/shared/ui/immich_app_bar.dart
  32. 10 6
      mobile/lib/shared/ui/immich_image.dart
  33. 1 1
      mobile/lib/shared/ui/photo_view/src/photo_view_default_widgets.dart
  34. 3 2
      mobile/lib/shared/views/splash_screen.dart
  35. 5 9
      mobile/lib/shared/views/tab_controller_page.dart
  36. 141 244
      mobile/lib/utils/immich_app_theme.dart

+ 0 - 5
mobile/lib/constants/immich_colors.dart

@@ -1,5 +0,0 @@
-import 'package:flutter/material.dart';
-
-Color immichBackgroundColor = const Color(0xFFf6f8fe);
-Color immichDarkBackgroundColor = const Color.fromARGB(255, 0, 0, 0);
-Color immichDarkThemePrimaryColor = const Color.fromARGB(255, 173, 203, 250);

+ 20 - 12
mobile/lib/modules/album/ui/album_thumbnail_card.dart

@@ -28,25 +28,33 @@ class AlbumThumbnailCard extends StatelessWidget {
         var cardSize = constraints.maxWidth;
 
         buildEmptyThumbnail() {
-          return Container(
+          return SizedBox(
             height: cardSize,
             width: cardSize,
-            decoration: BoxDecoration(
-              color: isDarkMode ? Colors.grey[800] : Colors.grey[200],
-            ),
-            child: Center(
-              child: Icon(
-                Icons.no_photography,
-                size: cardSize * .15,
+            child: Card(
+              shape: RoundedRectangleBorder(
+                borderRadius: BorderRadius.circular(20.0),
+              ),
+              child: Center(
+                child: Icon(
+                  Icons.no_photography,
+                  size: cardSize * .15,
+                ),
               ),
             ),
           );
         }
 
-        buildAlbumThumbnail() => ImmichImage(
-              album.thumbnail.value,
-              width: cardSize,
-              height: cardSize,
+        buildAlbumThumbnail() => Card(
+              clipBehavior: Clip.hardEdge,
+              shape: RoundedRectangleBorder(
+                borderRadius: BorderRadius.circular(20),
+              ),
+              child: ImmichImage(
+                album.thumbnail.value,
+                width: cardSize,
+                height: cardSize,
+              ),
             );
 
         buildAlbumTextRow() {

+ 33 - 24
mobile/lib/modules/album/ui/album_thumbnail_listtile.dart

@@ -21,39 +21,48 @@ class AlbumThumbnailListTile extends StatelessWidget {
   @override
   Widget build(BuildContext context) {
     var cardSize = 68.0;
-    var isDarkMode = Theme.of(context).brightness == Brightness.dark;
 
     buildEmptyThumbnail() {
-      return Container(
-        decoration: BoxDecoration(
-          color: isDarkMode ? Colors.grey[800] : Colors.grey[200],
-        ),
-        child: SizedBox(
-          height: cardSize,
-          width: cardSize,
-          child: const Center(
-            child: Icon(Icons.no_photography),
+      return SizedBox(
+        height: cardSize,
+        width: cardSize,
+        child: Card(
+          shape: RoundedRectangleBorder(
+            borderRadius: BorderRadius.circular(20.0),
+          ),
+          child: Center(
+            child: Icon(
+              Icons.no_photography,
+              size: cardSize * .15,
+            ),
           ),
         ),
       );
     }
 
     buildAlbumThumbnail() {
-      return CachedNetworkImage(
-        width: cardSize,
-        height: cardSize,
-        fit: BoxFit.cover,
-        fadeInDuration: const Duration(milliseconds: 200),
-        imageUrl: getAlbumThumbnailUrl(
-          album,
-          type: ThumbnailFormat.JPEG,
+      return Card(
+        clipBehavior: Clip.hardEdge,
+        shape: RoundedRectangleBorder(
+          borderRadius: BorderRadius.circular(12),
+        ),
+        child: CachedNetworkImage(
+          width: cardSize,
+          height: cardSize,
+          fit: BoxFit.cover,
+          fadeInDuration: const Duration(milliseconds: 200),
+          imageUrl: getAlbumThumbnailUrl(
+            album,
+            type: ThumbnailFormat.JPEG,
+          ),
+          httpHeaders: {
+            "Authorization": "Bearer ${Store.get(StoreKey.accessToken)}",
+          },
+          cacheKey:
+              getAlbumThumbNailCacheKey(album, type: ThumbnailFormat.JPEG),
+          errorWidget: (context, url, error) =>
+              const Icon(Icons.image_not_supported_outlined),
         ),
-        httpHeaders: {
-          "Authorization": "Bearer ${Store.get(StoreKey.accessToken)}",
-        },
-        cacheKey: getAlbumThumbNailCacheKey(album, type: ThumbnailFormat.JPEG),
-        errorWidget: (context, url, error) =>
-            const Icon(Icons.image_not_supported_outlined),
       );
     }
 

+ 1 - 1
mobile/lib/modules/album/views/album_viewer_page.dart

@@ -151,7 +151,7 @@ class AlbumViewerPage extends HookConsumerWidget {
                 titleFocusNode: titleFocusNode,
               )
             : Padding(
-                padding: const EdgeInsets.only(left: 8.0),
+                padding: const EdgeInsets.only(left: 8.0, bottom: 20.0),
                 child: Text(
                   album.name,
                   style: const TextStyle(

+ 48 - 57
mobile/lib/modules/album/views/library_page.dart

@@ -21,7 +21,6 @@ class LibraryPage extends HookConsumerWidget {
     final trashEnabled =
         ref.watch(serverInfoProvider.select((v) => v.serverFeatures.trash));
     final albums = ref.watch(albumProvider);
-    var isDarkMode = Theme.of(context).brightness == Brightness.dark;
     var settings = ref.watch(appSettingsServiceProvider);
 
     useEffect(
@@ -138,51 +137,55 @@ class LibraryPage extends HookConsumerWidget {
     }
 
     Widget buildCreateAlbumButton() {
-      return GestureDetector(
-        onTap: () {
-          AutoRouter.of(context).push(CreateAlbumRoute(isSharedAlbum: false));
-        },
-        child: Padding(
-          padding: const EdgeInsets.only(bottom: 32),
-          child: Column(
-            mainAxisAlignment: MainAxisAlignment.start,
-            crossAxisAlignment: CrossAxisAlignment.start,
-            children: [
-              Expanded(
-                child: Container(
-                  decoration: BoxDecoration(
-                    border: Border.all(
-                      color: isDarkMode
-                          ? const Color.fromARGB(255, 53, 53, 53)
-                          : const Color.fromARGB(255, 203, 203, 203),
+      return LayoutBuilder(
+        builder: (context, constraints) {
+          var cardSize = constraints.maxWidth;
+
+          return GestureDetector(
+            onTap: () {
+              AutoRouter.of(context)
+                  .push(CreateAlbumRoute(isSharedAlbum: false));
+            },
+            child: Padding(
+              padding: const EdgeInsets.only(bottom: 32),
+              child: Column(
+                mainAxisAlignment: MainAxisAlignment.start,
+                crossAxisAlignment: CrossAxisAlignment.start,
+                children: [
+                  SizedBox(
+                    height: cardSize,
+                    width: cardSize,
+                    child: Card(
+                      shape: RoundedRectangleBorder(
+                        borderRadius: BorderRadius.circular(20.0),
+                      ),
+                      child: Center(
+                        child: Icon(
+                          Icons.add_rounded,
+                          size: 28,
+                          color: Theme.of(context).primaryColor,
+                        ),
+                      ),
                     ),
-                    color: isDarkMode ? Colors.grey[900] : Colors.grey[50],
-                    borderRadius: BorderRadius.circular(20),
                   ),
-                  child: Center(
-                    child: Icon(
-                      Icons.add_rounded,
-                      size: 28,
-                      color: Theme.of(context).primaryColor,
+                  Padding(
+                    padding: const EdgeInsets.only(
+                      top: 8.0,
+                      bottom: 16,
+                      left: 8.0,
                     ),
+                    child: const Text(
+                      'library_page_new_album',
+                      style: TextStyle(
+                        fontWeight: FontWeight.bold,
+                      ),
+                    ).tr(),
                   ),
-                ),
-              ),
-              Padding(
-                padding: const EdgeInsets.only(
-                  top: 8.0,
-                  bottom: 16,
-                ),
-                child: const Text(
-                  'library_page_new_album',
-                  style: TextStyle(
-                    fontWeight: FontWeight.bold,
-                  ),
-                ).tr(),
+                ],
               ),
-            ],
-          ),
-        ),
+            ),
+          );
+        },
       );
     }
 
@@ -192,30 +195,19 @@ class LibraryPage extends HookConsumerWidget {
       Function() onClick,
     ) {
       return Expanded(
-        child: OutlinedButton.icon(
+        child: ElevatedButton.icon(
           onPressed: onClick,
           label: Padding(
             padding: const EdgeInsets.only(left: 8.0),
             child: Text(
               label,
-              style: TextStyle(
-                fontWeight: FontWeight.bold,
-                fontSize: 13.0,
-                color: isDarkMode ? Colors.white : Colors.grey[800],
-              ),
-            ),
-          ),
-          style: OutlinedButton.styleFrom(
-            padding: const EdgeInsets.symmetric(vertical: 12, horizontal: 16),
-            backgroundColor: isDarkMode ? Colors.grey[900] : Colors.grey[50],
-            side: BorderSide(
-              color: isDarkMode ? Colors.grey[800]! : Colors.grey[300]!,
             ),
-            alignment: Alignment.centerLeft,
           ),
+          style: Theme.of(context).elevatedButtonTheme.style?.copyWith(
+                alignment: Alignment.centerLeft,
+              ),
           icon: Icon(
             icon,
-            color: Theme.of(context).primaryColor,
           ),
         ),
       );
@@ -293,7 +285,6 @@ class LibraryPage extends HookConsumerWidget {
             sliver: SliverGrid(
               gridDelegate: const SliverGridDelegateWithMaxCrossAxisExtent(
                 maxCrossAxisExtent: 250,
-                mainAxisSpacing: 12,
                 crossAxisSpacing: 12,
                 childAspectRatio: .7,
               ),

+ 10 - 9
mobile/lib/modules/album/views/sharing_page.dart

@@ -134,13 +134,12 @@ class SharingPage extends HookConsumerWidget {
                   Icons.photo_album_outlined,
                   size: 20,
                 ),
+                style: Theme.of(context).elevatedButtonTheme.style?.copyWith(
+                      alignment: Alignment.centerLeft,
+                    ),
                 label: const Text(
                   "sharing_silver_appbar_create_shared_album",
                   maxLines: 1,
-                  style: TextStyle(
-                    fontWeight: FontWeight.bold,
-                    fontSize: 11,
-                  ),
                 ).tr(),
               ),
             ),
@@ -153,12 +152,11 @@ class SharingPage extends HookConsumerWidget {
                   Icons.link,
                   size: 20,
                 ),
+                style: Theme.of(context).elevatedButtonTheme.style?.copyWith(
+                      alignment: Alignment.centerLeft,
+                    ),
                 label: const Text(
                   "sharing_silver_appbar_shared_links",
-                  style: TextStyle(
-                    fontWeight: FontWeight.bold,
-                    fontSize: 11,
-                  ),
                   maxLines: 1,
                 ).tr(),
               ),
@@ -198,7 +196,10 @@ class SharingPage extends HookConsumerWidget {
                     padding: const EdgeInsets.all(8.0),
                     child: Text(
                       'sharing_page_empty_list',
-                      style: Theme.of(context).textTheme.displaySmall,
+                      style: Theme.of(context)
+                          .textTheme
+                          .displaySmall
+                          ?.copyWith(color: Theme.of(context).primaryColor),
                     ).tr(),
                   ),
                   Padding(

+ 2 - 4
mobile/lib/modules/backup/views/backup_album_selection_page.dart

@@ -4,7 +4,6 @@ import 'package:flutter/material.dart';
 import 'package:flutter_hooks/flutter_hooks.dart';
 import 'package:fluttertoast/fluttertoast.dart';
 import 'package:hooks_riverpod/hooks_riverpod.dart';
-import 'package:immich_mobile/constants/immich_colors.dart';
 import 'package:immich_mobile/modules/backup/providers/backup.provider.dart';
 import 'package:immich_mobile/modules/backup/ui/album_info_card.dart';
 import 'package:immich_mobile/modules/backup/ui/album_info_list_tile.dart';
@@ -148,13 +147,12 @@ class BackupAlbumSelectionPage extends HookConsumerWidget {
                 album.name,
                 style: TextStyle(
                   fontSize: 10,
-                  color: isDarkTheme ? Colors.black : immichBackgroundColor,
+                  color: Theme.of(context).colorScheme.surface,
                   fontWeight: FontWeight.bold,
                 ),
               ),
               backgroundColor: Colors.red[300],
-              deleteIconColor:
-                  isDarkTheme ? Colors.black : immichBackgroundColor,
+              deleteIconColor: Theme.of(context).colorScheme.surface,
               deleteIcon: const Icon(
                 Icons.cancel_rounded,
                 size: 15,

+ 20 - 17
mobile/lib/modules/home/ui/asset_grid/disable_multi_select_button.dart

@@ -1,7 +1,6 @@
 import 'package:flutter/material.dart';
-import 'package:hooks_riverpod/hooks_riverpod.dart';
 
-class DisableMultiSelectButton extends ConsumerWidget {
+class DisableMultiSelectButton extends StatelessWidget {
   const DisableMultiSelectButton({
     Key? key,
     required this.onPressed,
@@ -12,25 +11,29 @@ class DisableMultiSelectButton extends ConsumerWidget {
   final int selectedItemCount;
 
   @override
-  Widget build(BuildContext context, WidgetRef ref) {
+  Widget build(BuildContext context) {
     return Padding(
-        padding: const EdgeInsets.only(left: 16.0, top: 16.0),
-        child: Padding(
-          padding: const EdgeInsets.symmetric(horizontal: 4.0),
-          child: ElevatedButton.icon(
-            onPressed: () {
-              onPressed();
-            },
-            icon: const Icon(Icons.close_rounded),
-            label: Text(
-              '$selectedItemCount',
-              style: const TextStyle(
-                fontWeight: FontWeight.w600,
-                fontSize: 18,
-              ),
+      padding: const EdgeInsets.only(left: 16.0, top: 16.0),
+      child: Padding(
+        padding: const EdgeInsets.symmetric(horizontal: 4.0),
+        child: ElevatedButton.icon(
+          style: ElevatedButton.styleFrom(
+            foregroundColor: Theme.of(context).colorScheme.surface,
+            backgroundColor: Theme.of(context).colorScheme.primary,
+          ),
+          onPressed: () {
+            onPressed();
+          },
+          icon: const Icon(Icons.close_rounded),
+          label: Text(
+            '$selectedItemCount',
+            style: const TextStyle(
+              fontWeight: FontWeight.w600,
+              fontSize: 18,
             ),
           ),
         ),
+      ),
     );
   }
 }

+ 10 - 1
mobile/lib/modules/home/ui/asset_grid/draggable_scrollbar_custom.dart

@@ -6,6 +6,7 @@ import 'package:scrollable_positioned_list/scrollable_positioned_list.dart';
 /// Build the Scroll Thumb and label using the current configuration
 typedef ScrollThumbBuilder = Widget Function(
   Color backgroundColor,
+  Color foregroundColor,
   Animation<double> thumbAnimation,
   Animation<double> labelAnimation,
   double height, {
@@ -33,6 +34,9 @@ class DraggableScrollbar extends StatefulWidget {
   /// The background color of the label and thumb
   final Color backgroundColor;
 
+  /// The foreground color of the arrows in the thumb
+  final Color foregroundColor;
+
   /// The amount of padding that should surround the thumb
   final EdgeInsetsGeometry? padding;
 
@@ -66,6 +70,7 @@ class DraggableScrollbar extends StatefulWidget {
     required this.scrollStateListener,
     this.heightScrollThumb = 48.0,
     this.backgroundColor = Colors.white,
+    this.foregroundColor = Colors.white,
     this.padding,
     this.scrollbarAnimationDuration = const Duration(milliseconds: 300),
     this.scrollbarTimeToFade = const Duration(milliseconds: 600),
@@ -85,6 +90,7 @@ class DraggableScrollbar extends StatefulWidget {
   static buildScrollThumbAndLabel({
     required Widget scrollThumb,
     required Color backgroundColor,
+    required Color foregroundColor,
     required Animation<double>? thumbAnimation,
     required Animation<double>? labelAnimation,
     required Text? labelText,
@@ -123,6 +129,7 @@ class DraggableScrollbar extends StatefulWidget {
   ) {
     return (
       Color backgroundColor,
+      Color foregroundColor,
       Animation<double> thumbAnimation,
       Animation<double> labelAnimation,
       double height, {
@@ -131,7 +138,7 @@ class DraggableScrollbar extends StatefulWidget {
     }) {
       final scrollThumb = CustomPaint(
         key: scrollThumbKey,
-        foregroundPainter: ArrowCustomPainter(Colors.white),
+        foregroundPainter: ArrowCustomPainter(foregroundColor),
         child: Material(
           elevation: 4.0,
           color: backgroundColor,
@@ -150,6 +157,7 @@ class DraggableScrollbar extends StatefulWidget {
       return buildScrollThumbAndLabel(
         scrollThumb: scrollThumb,
         backgroundColor: backgroundColor,
+        foregroundColor: foregroundColor,
         thumbAnimation: thumbAnimation,
         labelAnimation: labelAnimation,
         labelText: labelText,
@@ -286,6 +294,7 @@ class DraggableScrollbarState extends State<DraggableScrollbar>
                     padding: widget.padding,
                     child: widget.scrollThumbBuilder(
                       widget.backgroundColor,
+                      widget.foregroundColor,
                       _thumbAnimation,
                       _labelAnimation,
                       widget.heightScrollThumb,

+ 5 - 2
mobile/lib/modules/home/ui/asset_grid/group_divider_title.dart

@@ -53,9 +53,12 @@ class GroupDividerTitle extends ConsumerWidget {
                     Icons.check_circle_rounded,
                     color: Theme.of(context).primaryColor,
                   )
-                : const Icon(
+                : Icon(
                     Icons.check_circle_outline_rounded,
-                    color: Colors.grey,
+                    color: Theme.of(context)
+                        .colorScheme
+                        .onBackground
+                        .withAlpha(100),
                   ),
           ),
         ],

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

@@ -221,11 +221,7 @@ class ImmichAssetGridViewState extends State<ImmichAssetGridView> {
       padding: const EdgeInsets.only(left: 12.0, top: 24.0),
       child: Text(
         title,
-        style: TextStyle(
-          fontSize: 26,
-          fontWeight: FontWeight.bold,
-          color: Theme.of(context).textTheme.displayLarge?.color,
-        ),
+        style: Theme.of(context).textTheme.titleLarge,
       ),
     );
   }
@@ -243,7 +239,7 @@ class ImmichAssetGridViewState extends State<ImmichAssetGridView> {
               bottom: widget.margin,
               right: i + 1 == num ? 0.0 : widget.margin,
             ),
-            color: Colors.grey,
+            color: Theme.of(context).colorScheme.surfaceVariant,
           ),
       ],
     );
@@ -328,8 +324,8 @@ class ImmichAssetGridViewState extends State<ImmichAssetGridView> {
 
     return Text(
       DateFormat.yMMMM().format(date),
-      style: const TextStyle(
-        color: Colors.white,
+      style: TextStyle(
+        color: Theme.of(context).colorScheme.onPrimary,
         fontWeight: FontWeight.bold,
       ),
     );
@@ -372,7 +368,8 @@ class ImmichAssetGridViewState extends State<ImmichAssetGridView> {
             scrollStateListener: dragScrolling,
             itemPositionsListener: _itemPositionsListener,
             controller: _itemScrollController,
-            backgroundColor: Theme.of(context).hintColor,
+            backgroundColor: Theme.of(context).colorScheme.primary,
+            foregroundColor: Theme.of(context).colorScheme.onPrimary,
             labelTextBuilder: _labelBuilder,
             labelConstraints: const BoxConstraints(maxHeight: 28),
             scrollbarAnimationDuration: const Duration(milliseconds: 300),

+ 13 - 13
mobile/lib/modules/home/ui/asset_grid/thumbnail_image.dart

@@ -43,9 +43,6 @@ class ThumbnailImage extends StatelessWidget {
 
   @override
   Widget build(BuildContext context) {
-    final isDarkTheme = Theme.of(context).brightness == Brightness.dark;
-    final assetContainerColor =
-        isDarkTheme ? Colors.blueGrey : Theme.of(context).primaryColorLight;
     // Assets from response DTOs do not have an isar id, querying which would give us the default autoIncrement id
     final isFromDto = asset.id == Isar.autoIncrement;
 
@@ -54,11 +51,13 @@ class ThumbnailImage extends StatelessWidget {
         return Container(
           decoration: BoxDecoration(
             shape: BoxShape.circle,
-            color: assetContainerColor,
+            color: Theme.of(context).colorScheme.surfaceVariant,
           ),
           child: Icon(
             Icons.check_circle_rounded,
-            color: Theme.of(context).primaryColor,
+            color: onDeselect == null
+                ? Theme.of(context).colorScheme.primary.withAlpha(120)
+                : Theme.of(context).colorScheme.primary,
           ),
         );
       } else {
@@ -132,9 +131,10 @@ class ThumbnailImage extends StatelessWidget {
     }
 
     Widget buildImage() {
-      final image = SizedBox(
+      final image = Container(
         width: 300,
         height: 300,
+        color: Theme.of(context).colorScheme.surfaceVariant,
         child: Hero(
           tag: isFromDto
               ? '${asset.remoteId}-$heroOffset'
@@ -153,9 +153,9 @@ class ThumbnailImage extends StatelessWidget {
         decoration: BoxDecoration(
           border: Border.all(
             width: 0,
-            color: onDeselect == null ? Colors.grey : assetContainerColor,
+            color: Theme.of(context).colorScheme.surfaceVariant,
           ),
-          color: onDeselect == null ? Colors.grey : assetContainerColor,
+          color: Theme.of(context).colorScheme.surfaceVariant,
         ),
         child: ClipRRect(
           borderRadius: const BorderRadius.only(
@@ -197,14 +197,14 @@ class ThumbnailImage extends StatelessWidget {
       },
       child: Stack(
         children: [
-          Container(
+          AnimatedContainer(
+            duration: const Duration(milliseconds: 300),
+            curve: Curves.decelerate,
             decoration: BoxDecoration(
               border: multiselectEnabled && isSelected
                   ? Border.all(
-                      color: onDeselect == null
-                          ? Colors.grey
-                          : assetContainerColor,
-                      width: 8,
+                      color: Theme.of(context).colorScheme.surfaceVariant,
+                      width: 12,
                     )
                   : const Border(),
             ),

+ 0 - 3
mobile/lib/modules/home/ui/control_bottom_app_bar.dart

@@ -42,7 +42,6 @@ class ControlBottomAppBar extends ConsumerWidget {
 
   @override
   Widget build(BuildContext context, WidgetRef ref) {
-    var isDarkMode = Theme.of(context).brightness == Brightness.dark;
     var hasRemote =
         selectionAssetState.hasRemote || selectionAssetState.hasMerged;
     var hasLocal = selectionAssetState.hasLocal;
@@ -128,8 +127,6 @@ class ControlBottomAppBar extends ConsumerWidget {
         ScrollController scrollController,
       ) {
         return Card(
-          color: isDarkMode ? Colors.grey[900] : Colors.grey[100],
-          surfaceTintColor: Colors.transparent,
           elevation: 18.0,
           shape: const RoundedRectangleBorder(
             borderRadius: BorderRadius.only(

+ 7 - 4
mobile/lib/modules/login/ui/login_form.dart

@@ -127,9 +127,9 @@ class LoginForm extends HookConsumerWidget {
     );
 
     populateTestLoginInfo() {
-      usernameController.text = 'testuser@email.com';
-      passwordController.text = 'password';
-      serverEndpointController.text = 'http://10.1.15.216:2283/api';
+      usernameController.text = 'demo@immich.app';
+      passwordController.text = 'demo';
+      serverEndpointController.text = 'https://demo.immich.app';
     }
 
     login() async {
@@ -303,7 +303,10 @@ class LoginForm extends HookConsumerWidget {
           children: [
             Text(
               serverEndpointController.text,
-              style: Theme.of(context).textTheme.displaySmall,
+              style: Theme.of(context)
+                  .textTheme
+                  .displaySmall
+                  ?.copyWith(color: Theme.of(context).primaryColor),
               textAlign: TextAlign.center,
             ),
             if (isPasswordLoginEnable.value) ...[

+ 4 - 3
mobile/lib/modules/map/views/map_page.dart

@@ -120,6 +120,7 @@ class MapPageState extends ConsumerState<MapPage> {
     final selectedAssets = useState(<Asset>{});
     final showLoadingIndicator = useState(false);
     final refetchMarkers = useState(true);
+    final themeData = isDarkTheme ? immichDarkTheme : immichLightTheme;
 
     if (refetchMarkers.value) {
       mapMarkerData.value = ref.watch(mapMarkersProvider).when(
@@ -189,7 +190,7 @@ class MapPageState extends ConsumerState<MapPage> {
           showDialog(
             context: context,
             builder: (context) => Theme(
-              data: isDarkTheme ? immichDarkTheme : immichLightTheme,
+              data: themeData,
               child: LocationServiceDisabledDialog(),
             ),
           );
@@ -203,7 +204,7 @@ class MapPageState extends ConsumerState<MapPage> {
           shouldRequestPermission = await showDialog(
             context: context,
             builder: (context) => Theme(
-              data: isDarkTheme ? immichDarkTheme : immichLightTheme,
+              data: themeData,
               child: LocationPermissionDisabledDialog(),
             ),
           );
@@ -438,7 +439,7 @@ class MapPageState extends ConsumerState<MapPage> {
       ),
       child: Theme(
         // Override app theme based on map theme
-        data: isDarkTheme ? immichDarkTheme : immichLightTheme,
+        data: themeData,
         child: Scaffold(
           appBar: MapAppBar(
             isDarkTheme: isDarkTheme,

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

@@ -17,7 +17,7 @@ class MemoryLane extends HookConsumerWidget {
         .whenData(
           (memories) => memories != null
               ? Container(
-                  margin: const EdgeInsets.only(top: 10),
+                  margin: const EdgeInsets.only(top: 10, left: 10),
                   height: 200,
                   child: ListView.builder(
                     scrollDirection: Axis.horizontal,

+ 9 - 5
mobile/lib/modules/partner/views/partner_page.dart

@@ -118,6 +118,7 @@ class PartnerPage extends HookConsumerWidget {
             Padding(
               padding: const EdgeInsets.symmetric(horizontal: 16.0),
               child: Column(
+                crossAxisAlignment: CrossAxisAlignment.start,
                 children: [
                   Padding(
                     padding: const EdgeInsets.symmetric(vertical: 8),
@@ -126,12 +127,15 @@ class PartnerPage extends HookConsumerWidget {
                       style: TextStyle(fontSize: 14),
                     ).tr(),
                   ),
-                  ElevatedButton.icon(
-                    onPressed: availableUsers.whenOrNull(
-                      data: (data) => addNewUsersHandler,
+                  Align(
+                    alignment: Alignment.center,
+                    child: ElevatedButton.icon(
+                      onPressed: availableUsers.whenOrNull(
+                        data: (data) => addNewUsersHandler,
+                      ),
+                      icon: const Icon(Icons.person_add),
+                      label: const Text("partner_page_add_partner").tr(),
                     ),
-                    icon: const Icon(Icons.person_add),
-                    label: const Text("partner_page_add_partner").tr(),
                   ),
                 ],
               ),

+ 2 - 2
mobile/lib/modules/search/ui/curated_people_row.dart

@@ -30,8 +30,8 @@ class CuratedPeopleRow extends StatelessWidget {
         child: Padding(
           padding: const EdgeInsets.symmetric(horizontal: 16.0),
           child: SizedBox(
-            width: imageSize,
-            height: imageSize,
+            width: 120,
+            height: 120,
             child: ThumbnailWithInfo(
               textInfo: '',
               onTap: () {},

+ 16 - 7
mobile/lib/modules/search/ui/thumbnail_with_info.dart

@@ -22,8 +22,6 @@ class ThumbnailWithInfo extends StatelessWidget {
 
   @override
   Widget build(BuildContext context) {
-    var isDarkMode = Theme.of(context).brightness == Brightness.dark;
-    var textAndIconColor = isDarkMode ? Colors.grey[100] : Colors.grey[700];
     return GestureDetector(
       onTap: () {
         onTap();
@@ -34,7 +32,7 @@ class ThumbnailWithInfo extends StatelessWidget {
           Container(
             decoration: BoxDecoration(
               borderRadius: BorderRadius.circular(borderRadius),
-              color: isDarkMode ? Colors.grey[900] : Colors.grey[100],
+              color: Theme.of(context).colorScheme.surfaceVariant,
             ),
             child: imageUrl != null
                 ? ClipRRect(
@@ -43,6 +41,17 @@ class ThumbnailWithInfo extends StatelessWidget {
                       width: double.infinity,
                       height: double.infinity,
                       fit: BoxFit.cover,
+                      placeholder: (context, url) {
+                        return SizedBox.square(
+                          dimension: 250,
+                          child: DecoratedBox(
+                            decoration: BoxDecoration(
+                              color:
+                                  Theme.of(context).colorScheme.surfaceVariant,
+                            ),
+                          ),
+                        );
+                      },
                       imageUrl: imageUrl!,
                       httpHeaders: {
                         "Authorization":
@@ -55,7 +64,7 @@ class ThumbnailWithInfo extends StatelessWidget {
                 : Center(
                     child: Icon(
                       noImageIcon ?? Icons.not_listed_location,
-                      color: textAndIconColor,
+                      color: Theme.of(context).primaryColor,
                     ),
                   ),
           ),
@@ -67,10 +76,10 @@ class ThumbnailWithInfo extends StatelessWidget {
                 begin: FractionalOffset.topCenter,
                 end: FractionalOffset.bottomCenter,
                 colors: [
-                  Colors.grey.withOpacity(0.0),
+                  Theme.of(context).colorScheme.surfaceVariant.withOpacity(0.0),
                   textInfo == ''
-                      ? Colors.black.withOpacity(0.1)
-                      : Colors.black.withOpacity(0.5),
+                      ? Theme.of(context).colorScheme.surface.withOpacity(0.1)
+                      : Theme.of(context).colorScheme.surface.withOpacity(0.6),
                 ],
                 stops: const [0.0, 1.0],
               ),

+ 0 - 1
mobile/lib/modules/settings/ui/advanced_settings/advanced_settings.dart

@@ -86,7 +86,6 @@ class AdvancedSettings extends HookConsumerWidget {
             min: 1.0,
             divisions: 7,
             label: logLevel,
-            activeColor: Theme.of(context).primaryColor,
           ),
         ),
         SettingsSwitchListTile(

+ 0 - 4
mobile/lib/modules/settings/ui/asset_list_settings/asset_list_layout_settings.dart

@@ -50,7 +50,6 @@ class LayoutSettings extends HookConsumerWidget {
     return Column(
       children: [
         SwitchListTile.adaptive(
-          activeColor: Theme.of(context).primaryColor,
           title: Text(
             "asset_list_layout_settings_dynamic_layout_title",
             style: Theme.of(context)
@@ -75,7 +74,6 @@ class LayoutSettings extends HookConsumerWidget {
           ).tr(),
         ),
         RadioListTile(
-          activeColor: Theme.of(context).primaryColor,
           title: Text(
             "asset_list_layout_settings_group_by_month_day",
             style: Theme.of(context).textTheme.labelLarge,
@@ -86,7 +84,6 @@ class LayoutSettings extends HookConsumerWidget {
           controlAffinity: ListTileControlAffinity.trailing,
         ),
         RadioListTile(
-          activeColor: Theme.of(context).primaryColor,
           title: Text(
             "asset_list_layout_settings_group_by_month",
             style: Theme.of(context).textTheme.labelLarge,
@@ -97,7 +94,6 @@ class LayoutSettings extends HookConsumerWidget {
           controlAffinity: ListTileControlAffinity.trailing,
         ),
         RadioListTile(
-          activeColor: Theme.of(context).primaryColor,
           title: Text(
             "asset_list_layout_settings_group_automatically",
             style: Theme.of(context).textTheme.labelLarge,

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

@@ -33,7 +33,6 @@ class StorageIndicator extends HookConsumerWidget {
     );
 
     return SwitchListTile.adaptive(
-      activeColor: Theme.of(context).primaryColor,
       title: Text(
         "theme_setting_asset_list_storage_indicator_title",
         style: Theme.of(context)

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

@@ -51,7 +51,6 @@ class TilesPerRow extends HookConsumerWidget {
           max: 6,
           divisions: 4,
           label: "${itemsValue.value.toInt()}",
-          activeColor: Theme.of(context).primaryColor,
         ),
       ],
     );

+ 0 - 1
mobile/lib/modules/settings/ui/notification_setting/notification_setting.dart

@@ -149,7 +149,6 @@ class NotificationSetting extends HookConsumerWidget {
             max: 5.0,
             divisions: 5,
             label: formattedValue,
-            activeColor: Theme.of(context).primaryColor,
           ),
         ),
       ],

+ 20 - 18
mobile/lib/modules/settings/ui/settings_switch_list_tile.dart

@@ -23,29 +23,31 @@ class SettingsSwitchListTile extends StatelessWidget {
   @override
   Widget build(BuildContext context) {
     return SwitchListTile.adaptive(
-      selectedTileColor: enabled ? null : Theme.of(context).disabledColor,
       value: valueNotifier.value,
-      onChanged: (bool value) {
-        if (enabled) {
-          valueNotifier.value = value;
-          appSettingService.setSetting(settingsEnum, value);
-        }
-        if (onChanged != null) {
-          onChanged!(value);
-        }
-      },
-      activeColor: enabled
-          ? Theme.of(context).primaryColor
-          : Theme.of(context).disabledColor,
+      onChanged: enabled
+          ? (bool value) {
+              valueNotifier.value = value;
+              appSettingService.setSetting(settingsEnum, value);
+              if (onChanged != null) {
+                onChanged!(value);
+              }
+            }
+          : null,
       dense: true,
       title: Text(
         title,
-        style: Theme.of(context)
-            .textTheme
-            .labelLarge
-            ?.copyWith(fontWeight: FontWeight.bold),
+        style: Theme.of(context).textTheme.labelLarge?.copyWith(
+              fontWeight: FontWeight.bold,
+              color: enabled
+                  ? null
+                  : Theme.of(context).colorScheme.onSurface.withAlpha(100),
+            ),
       ),
-      subtitle: subtitle != null ? Text(subtitle!) : null,
+      subtitle: subtitle != null
+          ? Text(
+              subtitle!,
+            )
+          : null,
     );
   }
 }

+ 0 - 3
mobile/lib/modules/settings/ui/theme_setting/theme_setting.dart

@@ -24,7 +24,6 @@ class ThemeSetting extends HookConsumerWidget {
     );
 
     return ExpansionTile(
-      textColor: Theme.of(context).primaryColor,
       title: const Text(
         'theme_setting_theme_title',
         style: TextStyle(
@@ -39,7 +38,6 @@ class ThemeSetting extends HookConsumerWidget {
       ).tr(),
       children: [
         SwitchListTile.adaptive(
-          activeColor: Theme.of(context).primaryColor,
           title: Text(
             'theme_setting_system_theme_switch',
             style: Theme.of(context)
@@ -77,7 +75,6 @@ class ThemeSetting extends HookConsumerWidget {
         ),
         if (currentTheme.value != ThemeMode.system)
           SwitchListTile.adaptive(
-            activeColor: Theme.of(context).primaryColor,
             title: Text(
               'theme_setting_dark_mode_switch',
               style: Theme.of(context)

+ 4 - 7
mobile/lib/shared/ui/app_bar_dialog/app_bar_dialog.dart

@@ -23,7 +23,6 @@ class ImmichAppBarDialog extends HookConsumerWidget {
   Widget build(BuildContext context, WidgetRef ref) {
     BackUpState backupState = ref.watch(backupProvider);
     final theme = Theme.of(context);
-    bool isDarkTheme = theme.brightness == Brightness.dark;
     bool isHorizontal = MediaQuery.of(context).size.width > 600;
     final horizontalPadding = isHorizontal ? 100.0 : 20.0;
     final user = ref.watch(currentUserProvider);
@@ -135,11 +134,8 @@ class ImmichAppBarDialog extends HookConsumerWidget {
         padding: const EdgeInsets.symmetric(horizontal: 10.0, vertical: 3),
         child: Container(
           padding: const EdgeInsets.symmetric(vertical: 4),
-          decoration: BoxDecoration(
-            color: isDarkTheme
-                ? Theme.of(context).scaffoldBackgroundColor
-                : const Color.fromARGB(255, 225, 229, 240),
-          ),
+          decoration:
+              BoxDecoration(color: Theme.of(context).colorScheme.surface),
           child: ListTile(
             minLeadingWidth: 50,
             leading: Icon(
@@ -161,7 +157,8 @@ class ImmichAppBarDialog extends HookConsumerWidget {
                     child: LinearProgressIndicator(
                       minHeight: 5.0,
                       value: backupState.serverInfo.diskUsagePercentage / 100.0,
-                      backgroundColor: Colors.grey,
+                      backgroundColor:
+                          Theme.of(context).colorScheme.onSurface.withAlpha(50),
                       color: theme.primaryColor,
                     ),
                   ),

+ 2 - 5
mobile/lib/shared/ui/app_bar_dialog/app_bar_profile_info.dart

@@ -18,7 +18,6 @@ class AppBarProfileInfoBox extends HookConsumerWidget {
     AuthenticationState authState = ref.watch(authenticationProvider);
     final uploadProfileImageStatus =
         ref.watch(uploadProfileImageProvider).status;
-    final isDarkMode = Theme.of(context).brightness == Brightness.dark;
     final user = Store.tryGet(StoreKey.currentUser);
 
     buildUserProfileImage() {
@@ -91,9 +90,7 @@ class AppBarProfileInfoBox extends HookConsumerWidget {
       child: Container(
         width: double.infinity,
         decoration: BoxDecoration(
-          color: Theme.of(context).brightness == Brightness.dark
-              ? Theme.of(context).scaffoldBackgroundColor
-              : const Color.fromARGB(255, 225, 229, 240),
+          color: Theme.of(context).colorScheme.surface,
           borderRadius: const BorderRadius.only(
             topLeft: Radius.circular(10),
             topRight: Radius.circular(10),
@@ -111,7 +108,7 @@ class AppBarProfileInfoBox extends HookConsumerWidget {
                   bottom: -5,
                   right: -8,
                   child: Material(
-                    color: isDarkMode ? Colors.blueGrey[800] : Colors.white,
+                    color: Theme.of(context).colorScheme.primaryContainer,
                     elevation: 3,
                     shape: RoundedRectangleBorder(
                       borderRadius: BorderRadius.circular(50.0),

+ 3 - 7
mobile/lib/shared/ui/app_bar_dialog/app_bar_server_info.dart

@@ -39,9 +39,7 @@ class AppBarServerInfo extends HookConsumerWidget {
       padding: const EdgeInsets.only(left: 10.0, right: 10.0, bottom: 10.0),
       child: Container(
         decoration: BoxDecoration(
-          color: Theme.of(context).brightness == Brightness.dark
-              ? Theme.of(context).scaffoldBackgroundColor
-              : const Color.fromARGB(255, 225, 229, 240),
+          color: Theme.of(context).colorScheme.surface,
           borderRadius: const BorderRadius.only(
             bottomLeft: Radius.circular(10),
             bottomRight: Radius.circular(10),
@@ -139,7 +137,7 @@ class AppBarServerInfo extends HookConsumerWidget {
                       child: Text(
                         serverInfoState.serverVersion.major > 0
                             ? "${serverInfoState.serverVersion.major}.${serverInfoState.serverVersion.minor}.${serverInfoState.serverVersion.patch}"
-                            : "?",
+                            : "--",
                         style: TextStyle(
                           fontSize: 11,
                           color: Theme.of(context)
@@ -190,9 +188,7 @@ class AppBarServerInfo extends HookConsumerWidget {
                           borderRadius: BorderRadius.circular(10),
                         ),
                         textStyle: TextStyle(
-                          color: Theme.of(context).brightness == Brightness.dark
-                              ? Colors.black
-                              : Colors.white,
+                          color: Theme.of(context).colorScheme.onPrimary,
                           fontWeight: FontWeight.bold,
                         ),
                         message: getServerUrl() ?? '--',

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

@@ -9,7 +9,7 @@ class CustomDraggingHandle extends StatelessWidget {
       height: 5,
       width: 30,
       decoration: BoxDecoration(
-        color: Colors.grey[500],
+        color: Theme.of(context).dividerColor,
         borderRadius: BorderRadius.circular(16),
       ),
     );

+ 10 - 13
mobile/lib/shared/ui/immich_app_bar.dart

@@ -28,7 +28,6 @@ class ImmichAppBar extends ConsumerWidget implements PreferredSizeWidget {
     final ServerInfo serverInfoState = ref.watch(serverInfoProvider);
     AuthenticationState authState = ref.watch(authenticationProvider);
     final user = Store.tryGet(StoreKey.currentUser);
-    final isDarkMode = Theme.of(context).brightness == Brightness.dark;
     const widgetSize = 30.0;
 
     buildProfileIndicator() {
@@ -69,9 +68,7 @@ class ImmichAppBar extends ConsumerWidget implements PreferredSizeWidget {
       );
     }
 
-    getBackupBadgeIcon() {
-      final iconColor = isDarkMode ? Colors.white : Colors.black;
-
+    Widget? getBackupBadgeIcon() {
       if (isEnableAutoBackup) {
         if (backupState.backupProgress == BackUpProgressEnum.inProgress) {
           return Container(
@@ -79,7 +76,7 @@ class ImmichAppBar extends ConsumerWidget implements PreferredSizeWidget {
             child: CircularProgressIndicator(
               strokeWidth: 2,
               strokeCap: StrokeCap.round,
-              valueColor: AlwaysStoppedAnimation<Color>(iconColor),
+              color: Theme.of(context).colorScheme.onSurfaceVariant,
             ),
           );
         } else if (backupState.backupProgress !=
@@ -88,7 +85,7 @@ class ImmichAppBar extends ConsumerWidget implements PreferredSizeWidget {
           return Icon(
             Icons.check_outlined,
             size: 9,
-            color: iconColor,
+            color: Theme.of(context).colorScheme.onSurfaceVariant,
           );
         }
       }
@@ -97,14 +94,14 @@ class ImmichAppBar extends ConsumerWidget implements PreferredSizeWidget {
         return Icon(
           Icons.cloud_off_rounded,
           size: 9,
-          color: iconColor,
+          color: Theme.of(context).colorScheme.onSurfaceVariant,
         );
       }
+      return null;
     }
 
     buildBackupIndicator() {
       final indicatorIcon = getBackupBadgeIcon();
-      final badgeBackground = isDarkMode ? Colors.blueGrey[800] : Colors.white;
 
       return InkWell(
         onTap: () => AutoRouter.of(context).push(const BackupControllerRoute()),
@@ -114,11 +111,11 @@ class ImmichAppBar extends ConsumerWidget implements PreferredSizeWidget {
             width: widgetSize / 2,
             height: widgetSize / 2,
             decoration: BoxDecoration(
-              color: badgeBackground,
               border: Border.all(
-                color: isDarkMode ? Colors.black : Colors.grey,
+                color: Theme.of(context).colorScheme.surface,
               ),
               borderRadius: BorderRadius.circular(widgetSize / 2),
+              color: Theme.of(context).colorScheme.surfaceVariant,
             ),
             child: indicatorIcon,
           ),
@@ -126,10 +123,9 @@ class ImmichAppBar extends ConsumerWidget implements PreferredSizeWidget {
           alignment: Alignment.bottomRight,
           isLabelVisible: indicatorIcon != null,
           offset: const Offset(2, 2),
-          child: Icon(
+          child: const Icon(
             Icons.backup_rounded,
             size: widgetSize,
-            color: Theme.of(context).primaryColor,
           ),
         ),
       );
@@ -158,12 +154,13 @@ class ImmichAppBar extends ConsumerWidget implements PreferredSizeWidget {
               ),
               Container(
                 margin: const EdgeInsets.only(left: 10),
-                child: const Text(
+                child: Text(
                   'IMMICH',
                   style: TextStyle(
                     fontFamily: 'SnowburstOne',
                     fontWeight: FontWeight.bold,
                     fontSize: 24,
+                    color: Theme.of(context).primaryColor,
                   ),
                 ),
               ),

+ 10 - 6
mobile/lib/shared/ui/immich_image.dart

@@ -32,8 +32,8 @@ class ImmichImage extends StatelessWidget {
   Widget build(BuildContext context) {
     if (this.asset == null) {
       return Container(
-        decoration: const BoxDecoration(
-          color: Colors.grey,
+        decoration: BoxDecoration(
+          color: Theme.of(context).colorScheme.surfaceVariant,
         ),
         child: SizedBox(
           width: width,
@@ -60,10 +60,12 @@ class ImmichImage extends StatelessWidget {
           return Stack(
             children: [
               if (useGrayBoxPlaceholder)
-                const SizedBox.square(
+                SizedBox.square(
                   dimension: 250,
                   child: DecoratedBox(
-                    decoration: BoxDecoration(color: Colors.grey),
+                    decoration: BoxDecoration(
+                      color: Theme.of(context).colorScheme.surfaceVariant,
+                    ),
                   ),
                 ),
               if (useProgressIndicator)
@@ -109,10 +111,12 @@ class ImmichImage extends StatelessWidget {
         return Stack(
           children: [
             if (useGrayBoxPlaceholder)
-              const SizedBox.square(
+              SizedBox.square(
                 dimension: 250,
                 child: DecoratedBox(
-                  decoration: BoxDecoration(color: Colors.grey),
+                  decoration: BoxDecoration(
+                    color: Theme.of(context).colorScheme.surfaceVariant,
+                  ),
                 ),
               ),
             if (useProgressIndicator)

+ 1 - 1
mobile/lib/shared/ui/photo_view/src/photo_view_default_widgets.dart

@@ -13,7 +13,7 @@ class PhotoViewDefaultError extends StatelessWidget {
       child: Center(
         child: Icon(
           Icons.broken_image,
-          color: Colors.grey[400],
+          color: Theme.of(context).primaryColor,
           size: 40.0,
         ),
       ),

+ 3 - 2
mobile/lib/shared/views/splash_screen.dart

@@ -79,8 +79,9 @@ class SplashScreenPage extends HookConsumerWidget {
       [],
     );
 
-    return const Scaffold(
-      body: Center(
+    return Scaffold(
+      appBar: AppBar(),
+      body: const Center(
         child: Image(
           image: AssetImage('assets/immich-logo-no-outline.png'),
           width: 80,

+ 5 - 9
mobile/lib/shared/views/tab_controller_page.dart

@@ -24,7 +24,7 @@ class TabControllerPage extends HookConsumerWidget {
         children: [
           icon,
           Positioned(
-            right: -14,
+            right: -16,
             child: SizedBox(
               height: 12,
               width: 12,
@@ -114,9 +114,8 @@ class TabControllerPage extends HookConsumerWidget {
               Icons.photo_library_outlined,
             ),
             selectedIcon: buildIcon(
-              Icon(
+              const Icon(
                 Icons.photo_library,
-                color: Theme.of(context).primaryColor,
               ),
             ),
           ),
@@ -125,9 +124,8 @@ class TabControllerPage extends HookConsumerWidget {
             icon: const Icon(
               Icons.search_rounded,
             ),
-            selectedIcon: Icon(
+            selectedIcon: const Icon(
               Icons.search,
-              color: Theme.of(context).primaryColor,
             ),
           ),
           NavigationDestination(
@@ -135,9 +133,8 @@ class TabControllerPage extends HookConsumerWidget {
             icon: const Icon(
               Icons.group_outlined,
             ),
-            selectedIcon: Icon(
+            selectedIcon: const Icon(
               Icons.group,
-              color: Theme.of(context).primaryColor,
             ),
           ),
           NavigationDestination(
@@ -146,9 +143,8 @@ class TabControllerPage extends HookConsumerWidget {
               Icons.photo_album_outlined,
             ),
             selectedIcon: buildIcon(
-              Icon(
+              const Icon(
                 Icons.photo_album_rounded,
-                color: Theme.of(context).primaryColor,
               ),
             ),
           ),

+ 141 - 244
mobile/lib/utils/immich_app_theme.dart

@@ -1,6 +1,5 @@
 import 'package:flutter/material.dart';
 import 'package:hooks_riverpod/hooks_riverpod.dart';
-import 'package:immich_mobile/constants/immich_colors.dart';
 import 'package:immich_mobile/modules/settings/providers/app_settings.provider.dart';
 import 'package:immich_mobile/modules/settings/services/app_settings.service.dart';
 
@@ -20,259 +19,157 @@ final immichThemeProvider = StateProvider<ThemeMode>((ref) {
   }
 });
 
-ThemeData base = ThemeData(
-  chipTheme: const ChipThemeData(
-    side: BorderSide.none,
-  ),
-  sliderTheme: const SliderThemeData(
-    thumbShape: RoundSliderThumbShape(enabledThumbRadius: 7),
-    trackHeight: 2.0,
-  ),
+ColorScheme _lightColorScheme = const ColorScheme(
+  brightness: Brightness.light,
+  primary: Color(0xff4755b5),
+  onPrimary: Color(0xffffffff),
+  primaryContainer: Color(0xffdfe0ff),
+  onPrimaryContainer: Color(0xff000d60),
+  secondary: Color(0xff5b5d72),
+  onSecondary: Color(0xffffffff),
+  secondaryContainer: Color(0xFFD6D8FF),
+  onSecondaryContainer: Color(0xff181a2c),
+  tertiary: Color(0xff77536c),
+  onTertiary: Color(0xffffffff),
+  tertiaryContainer: Color(0xffffd7f0),
+  onTertiaryContainer: Color(0xff2d1127),
+  error: Color(0xffba1a1a),
+  onError: Color(0xffffffff),
+  errorContainer: Color(0xffffdad6),
+  onErrorContainer: Color(0xff410002),
+  background: Color(0xfff9f6fc),
+  onBackground: Color(0xff1b1b1f),
+  surface: Color(0xfff9f6fc),
+  onSurface: Color(0xff1b1b1f),
+  surfaceVariant: Color(0xffdeddea),
+  onSurfaceVariant: Color(0xff46464f),
+  outline: Color(0xff777680),
+  outlineVariant: Color(0xffc7c5d0),
+  shadow: Color(0xff000000),
+  scrim: Color(0xff000000),
+  inverseSurface: Color(0xff303137),
+  onInverseSurface: Color(0xfff3f0f4),
+  inversePrimary: Color(0xffbcc3ff),
+  surfaceTint: Color(0xff4755b5),
 );
 
-ThemeData immichLightTheme = ThemeData(
-  useMaterial3: true,
-  brightness: Brightness.light,
-  primarySwatch: Colors.indigo,
-  primaryColor: Colors.indigo,
-  hintColor: Colors.indigo,
-  focusColor: Colors.indigo,
-  splashColor: Colors.indigo.withOpacity(0.15),
-  fontFamily: 'WorkSans',
-  scaffoldBackgroundColor: immichBackgroundColor,
-  snackBarTheme: const SnackBarThemeData(
-    contentTextStyle: TextStyle(
-      fontFamily: 'WorkSans',
-      color: Colors.indigo,
-      fontWeight: FontWeight.bold,
-    ),
-    backgroundColor: Colors.white,
-  ),
-  appBarTheme: AppBarTheme(
-    titleTextStyle: const TextStyle(
-      fontFamily: 'WorkSans',
-      color: Colors.indigo,
-      fontWeight: FontWeight.bold,
-      fontSize: 18,
-    ),
-    backgroundColor: immichBackgroundColor,
-    foregroundColor: Colors.indigo,
-    elevation: 0,
-    scrolledUnderElevation: 0,
-    centerTitle: true,
-  ),
-  bottomNavigationBarTheme: BottomNavigationBarThemeData(
-    type: BottomNavigationBarType.fixed,
-    backgroundColor: immichBackgroundColor,
-    selectedItemColor: Colors.indigo,
-  ),
-  cardTheme: const CardTheme(
-    surfaceTintColor: Colors.transparent,
-  ),
-  drawerTheme: DrawerThemeData(
-    backgroundColor: immichBackgroundColor,
-  ),
-  textTheme: const TextTheme(
-    displayLarge: TextStyle(
-      fontSize: 26,
-      fontWeight: FontWeight.bold,
-      color: Colors.indigo,
-    ),
-    displayMedium: TextStyle(
-      fontSize: 14,
-      fontWeight: FontWeight.bold,
-      color: Colors.black87,
-    ),
-    displaySmall: TextStyle(
-      fontSize: 12,
-      fontWeight: FontWeight.bold,
-      color: Colors.indigo,
-    ),
-    titleSmall: TextStyle(
-      fontSize: 16.0,
-      fontWeight: FontWeight.bold,
-    ),
-    titleMedium: TextStyle(
-      fontSize: 18.0,
-      fontWeight: FontWeight.bold,
-    ),
-    titleLarge: TextStyle(
-      fontSize: 26.0,
-      fontWeight: FontWeight.bold,
-    ),
-  ),
-  elevatedButtonTheme: ElevatedButtonThemeData(
-    style: ElevatedButton.styleFrom(
-      backgroundColor: Colors.indigo,
-      foregroundColor: Colors.white,
-    ),
-  ),
-  chipTheme: base.chipTheme,
-  sliderTheme: base.sliderTheme,
-  popupMenuTheme: const PopupMenuThemeData(
-    shape: RoundedRectangleBorder(
-      borderRadius: BorderRadius.all(Radius.circular(10)),
+ColorScheme _darkColorScheme = const ColorScheme(
+  brightness: Brightness.dark,
+  primary: Color(0xffa4c8ff),
+  onPrimary: Color(0xff00315e),
+  primaryContainer: Color(0xFF182C40),
+  onPrimaryContainer: Color(0xffd4e3ff),
+  secondary: Color(0xffbcc7dc),
+  onSecondary: Color(0xff37474f),
+  secondaryContainer: Color(0xff3d4758),
+  onSecondaryContainer: Color(0xffd8e3f8),
+  tertiary: Color(0xffdabde2),
+  onTertiary: Color(0xff3d2946),
+  tertiaryContainer: Color(0xff543f5e),
+  onTertiaryContainer: Color(0xfff6d9ff),
+  error: Color(0xffffb4ab),
+  onError: Color(0xff690005),
+  errorContainer: Color(0xff93000a),
+  onErrorContainer: Color(0xffffb4ab),
+  background: Color(0xff101214),
+  onBackground: Color(0xffe2e2e5),
+  surface: Color(0xff101214),
+  onSurface: Color(0xffe2e2e5),
+  surfaceVariant: Color(0xff363c42),
+  onSurfaceVariant: Color(0xffc1c7ce),
+  outline: Color(0xff8b9198),
+  outlineVariant: Color(0xff41474d),
+  shadow: Color(0xff000000),
+  scrim: Color(0xff000000),
+  inverseSurface: Color(0xffeeeef1),
+  onInverseSurface: Color(0xff2e3133),
+  inversePrimary: Color(0xff1c5fa5),
+  surfaceTint: Color(0xff90caf9),
+);
+
+ThemeData getThemeForScheme(ColorScheme scheme) {
+  return ThemeData(
+    useMaterial3: true,
+    brightness: scheme.brightness,
+    colorScheme: scheme,
+    primaryColor: scheme.primary,
+    scaffoldBackgroundColor: scheme.background,
+    fontFamily: 'WorkSans',
+    appBarTheme: AppBarTheme(
+      iconTheme: IconThemeData(color: scheme.primary),
+      titleTextStyle: TextStyle(
+        fontSize: 18.0,
+        fontWeight: FontWeight.bold,
+        color: scheme.primary,
+      ),
     ),
-    surfaceTintColor: Colors.transparent,
-    color: Colors.white,
-  ),
-  navigationBarTheme: NavigationBarThemeData(
-    indicatorColor: Colors.indigo.withOpacity(0.15),
-    iconTheme: MaterialStatePropertyAll(
-      IconThemeData(color: Colors.grey[700]),
+    cardTheme: const CardTheme(elevation: 2.0),
+    elevatedButtonTheme: ElevatedButtonThemeData(
+      style: ElevatedButton.styleFrom(
+        visualDensity: VisualDensity.standard,
+        textStyle: const TextStyle(
+          fontWeight: FontWeight.bold,
+          fontSize: 11,
+        ),
+        shadowColor: scheme.shadow,
+        foregroundColor: scheme.onPrimary,
+        backgroundColor: scheme.primary,
+      ),
     ),
-    backgroundColor: immichBackgroundColor,
-    surfaceTintColor: Colors.transparent,
-    labelTextStyle: MaterialStatePropertyAll(
-      TextStyle(
+    navigationBarTheme: NavigationBarThemeData(
+      iconTheme: MaterialStateProperty.resolveWith<IconThemeData?>((states) {
+        if (states.contains(MaterialState.selected)) {
+          return IconThemeData(color: scheme.primary);
+        }
+        return null;
+      }),
+    ),
+    textTheme: TextTheme(
+      displayLarge: TextStyle(
+        fontSize: 26,
+        fontWeight: FontWeight.bold,
+        color: scheme.primary,
+      ),
+      displayMedium: const TextStyle(
+        fontSize: 14,
+        fontWeight: FontWeight.bold,
+      ),
+      displaySmall: const TextStyle(
         fontSize: 12,
-        fontWeight: FontWeight.w600,
-        color: Colors.grey[700],
+        fontWeight: FontWeight.bold,
       ),
-    ),
-  ),
-  dialogTheme: const DialogTheme(
-    surfaceTintColor: Colors.transparent,
-  ),
-  inputDecorationTheme: const InputDecorationTheme(
-    focusedBorder: OutlineInputBorder(
-      borderSide: BorderSide(
-        color: Colors.indigo,
+      titleSmall: const TextStyle(
+        fontSize: 16.0,
+        fontWeight: FontWeight.bold,
+      ),
+      titleMedium: const TextStyle(
+        fontSize: 18.0,
+        fontWeight: FontWeight.bold,
+      ),
+      titleLarge: TextStyle(
+        fontSize: 26.0,
+        fontWeight: FontWeight.bold,
+        color: scheme.primary,
       ),
     ),
-    labelStyle: TextStyle(
-      color: Colors.indigo,
-    ),
-    hintStyle: TextStyle(
-      fontSize: 14.0,
-      fontWeight: FontWeight.normal,
-    ),
-  ),
-  textSelectionTheme: const TextSelectionThemeData(
-    cursorColor: Colors.indigo,
-  ),
-);
-
-ThemeData immichDarkTheme = ThemeData(
-  useMaterial3: true,
-  brightness: Brightness.dark,
-  primarySwatch: Colors.indigo,
-  primaryColor: immichDarkThemePrimaryColor,
-  scaffoldBackgroundColor: immichDarkBackgroundColor,
-  hintColor: Colors.grey[600],
-  fontFamily: 'WorkSans',
-  snackBarTheme: SnackBarThemeData(
-    contentTextStyle: TextStyle(
-      fontFamily: 'WorkSans',
-      color: immichDarkThemePrimaryColor,
-      fontWeight: FontWeight.bold,
-    ),
-    backgroundColor: Colors.grey[900],
-  ),
-  textButtonTheme: TextButtonThemeData(
-    style: TextButton.styleFrom(
-      foregroundColor: immichDarkThemePrimaryColor,
-    ),
-  ),
-  appBarTheme: AppBarTheme(
-    titleTextStyle: TextStyle(
-      fontFamily: 'WorkSans',
-      color: immichDarkThemePrimaryColor,
-      fontWeight: FontWeight.bold,
-      fontSize: 18,
-    ),
-    backgroundColor: const Color.fromARGB(255, 32, 33, 35),
-    foregroundColor: immichDarkThemePrimaryColor,
-    elevation: 0,
-    scrolledUnderElevation: 0,
-    centerTitle: true,
-  ),
-  bottomNavigationBarTheme: BottomNavigationBarThemeData(
-    type: BottomNavigationBarType.fixed,
-    backgroundColor: const Color.fromARGB(255, 35, 36, 37),
-    selectedItemColor: immichDarkThemePrimaryColor,
-  ),
-  drawerTheme: DrawerThemeData(
-    backgroundColor: immichDarkBackgroundColor,
-    scrimColor: Colors.white.withOpacity(0.1),
-  ),
-  textTheme: TextTheme(
-    displayLarge: const TextStyle(
-      fontSize: 26,
-      fontWeight: FontWeight.bold,
-      color: Color.fromARGB(255, 255, 255, 255),
-    ),
-    displayMedium: const TextStyle(
-      fontSize: 14,
-      fontWeight: FontWeight.bold,
-      color: Color.fromARGB(255, 255, 255, 255),
-    ),
-    displaySmall: TextStyle(
-      fontSize: 12,
-      fontWeight: FontWeight.bold,
-      color: immichDarkThemePrimaryColor,
-    ),
-    titleSmall: const TextStyle(
-      fontSize: 16.0,
-      fontWeight: FontWeight.bold,
-    ),
-    titleMedium: const TextStyle(
-      fontSize: 18.0,
-      fontWeight: FontWeight.bold,
-    ),
-    titleLarge: const TextStyle(
-      fontSize: 26.0,
-      fontWeight: FontWeight.bold,
-    ),
-  ),
-  cardColor: Colors.grey[900],
-  elevatedButtonTheme: ElevatedButtonThemeData(
-    style: ElevatedButton.styleFrom(
-      foregroundColor: Colors.black87,
-      backgroundColor: immichDarkThemePrimaryColor,
-    ),
-  ),
-  chipTheme: base.chipTheme,
-  sliderTheme: base.sliderTheme,
-  popupMenuTheme: const PopupMenuThemeData(
-    shape: RoundedRectangleBorder(
-      borderRadius: BorderRadius.all(Radius.circular(10)),
+    chipTheme: const ChipThemeData(
+      side: BorderSide.none,
     ),
-    surfaceTintColor: Colors.transparent,
-  ),
-  navigationBarTheme: NavigationBarThemeData(
-    indicatorColor: immichDarkThemePrimaryColor.withOpacity(0.4),
-    iconTheme: MaterialStatePropertyAll(
-      IconThemeData(color: Colors.grey[500]),
+    sliderTheme: const SliderThemeData(
+      thumbShape: RoundSliderThumbShape(enabledThumbRadius: 7),
+      trackHeight: 2.0,
     ),
-    backgroundColor: Colors.grey[900],
-    surfaceTintColor: Colors.transparent,
-    labelTextStyle: MaterialStatePropertyAll(
-      TextStyle(
-        fontSize: 12,
-        fontWeight: FontWeight.w600,
-        color: Colors.grey[500],
+    inputDecorationTheme: InputDecorationTheme(
+      labelStyle: TextStyle(
+        color: scheme.primary,
       ),
-    ),
-  ),
-  dialogTheme: const DialogTheme(
-    surfaceTintColor: Colors.transparent,
-  ),
-  inputDecorationTheme: InputDecorationTheme(
-    focusedBorder: OutlineInputBorder(
-      borderSide: BorderSide(
-        color: immichDarkThemePrimaryColor,
+      hintStyle: const TextStyle(
+        fontSize: 14.0,
+        fontWeight: FontWeight.normal,
       ),
     ),
-    labelStyle: TextStyle(
-      color: immichDarkThemePrimaryColor,
-    ),
-    hintStyle: const TextStyle(
-      fontSize: 14.0,
-      fontWeight: FontWeight.normal,
-    ),
-  ),
-  textSelectionTheme: TextSelectionThemeData(
-    cursorColor: immichDarkThemePrimaryColor,
-  ),
-);
+  );
+}
+
+ThemeData immichLightTheme = getThemeForScheme(_lightColorScheme);
+ThemeData immichDarkTheme = getThemeForScheme(_darkColorScheme);