1
0
mirror of https://github.com/immich-app/immich.git synced 2024-11-28 09:33:27 +02:00

Add mobile dark mode and user setting (#468)

* styling light and dark theme

* Icon topbar

* Fixed app bar title dark theme

* Fixed issue with getting thumbnail for things

* Refactor sharing page

* Refactor scroll thumb

* Refactor chip in auto  backup indiation button

* Refactor sharing page

* Added theme toggle

* Up version for testflight build

* Refactor backup controller page

* Refactor album selection page

* refactor album pages

* Refactor gradient color profile header

* Added theme switcher

* Register app theme correctly

* Added locale to the app

* Added translation key

* Styling for bottomsheet colors

* up server version

* Fixed font size

* Fixed overlapsed sliverappbar on photos screen
This commit is contained in:
Alex 2022-08-15 18:53:30 -05:00 committed by GitHub
parent 30f069a5db
commit c1b22125fd
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
47 changed files with 536 additions and 307 deletions

View File

@ -30,8 +30,8 @@ platform :android do
task: 'bundle',
build_type: 'Release',
properties: {
"android.injected.version.code" => 32,
"android.injected.version.name" => "1.22.0",
"android.injected.version.code" => 33,
"android.injected.version.name" => "1.23.0",
}
)
upload_to_play_store(skip_upload_apk: true, skip_upload_images: true, skip_upload_screenshots: true, aab: '../build/app/outputs/bundle/release/app-release.aab')

View File

@ -48,7 +48,7 @@
"control_bottom_app_bar_delete": "Delete",
"create_shared_album_page_share": "Share",
"create_shared_album_page_create": "Create",
"create_shared_album_page_share_add_assets": "ADD ASSETS",
"create_shared_album_page_share_add_assets": "ADD PHOTOS",
"create_shared_album_page_share_select_photos": "Select Photos",
"daily_title_text_date": "E, MMM dd",
"daily_title_text_date_year": "E, MMM dd, yyyy",
@ -113,5 +113,14 @@
"library_page_new_album": "New album",
"create_album_page_untitled": "Untitled",
"share_dialog_preparing": "Preparing...",
"control_bottom_app_bar_share": "Share"
"control_bottom_app_bar_share": "Share",
"setting_pages_app_bar_settings": "Settings",
"theme_setting_theme_title": "Theme",
"theme_setting_theme_subtitle": "Choose the app's theme setting",
"theme_setting_system_theme_switch": "Automatic (Follow system setting)",
"theme_setting_dark_mode_switch": "Dark mode",
"theme_setting_image_viewer_quality_title": "Image viewer quality",
"theme_setting_image_viewer_quality_subtitle": "Adjust the quality of the detail image viewer",
"theme_setting_three_stage_loading_title": "Enable three-stage loading",
"theme_setting_three_stage_loading_subtitle": "The three-stage loading delivers the best quality image in exchange for a slower loading speed"
}

View File

@ -19,7 +19,7 @@ platform :ios do
desc "iOS Beta"
lane :beta do
increment_version_number(
version_number: "1.22.0"
version_number: "1.23.0"
)
increment_build_number(
build_number: latest_testflight_build_number + 1,

View File

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

View File

@ -7,7 +7,6 @@ import 'package:flutter/services.dart';
import 'package:flutter_displaymode/flutter_displaymode.dart';
import 'package:hive_flutter/hive_flutter.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:immich_mobile/constants/immich_colors.dart';
import 'package:immich_mobile/modules/backup/models/hive_backup_albums.model.dart';
import 'package:immich_mobile/modules/backup/providers/backup.provider.dart';
import 'package:immich_mobile/modules/login/models/hive_saved_login_info.model.dart';
@ -19,8 +18,10 @@ import 'package:immich_mobile/shared/providers/asset.provider.dart';
import 'package:immich_mobile/shared/providers/release_info.provider.dart';
import 'package:immich_mobile/shared/providers/server_info.provider.dart';
import 'package:immich_mobile/shared/providers/websocket.provider.dart';
import 'package:immich_mobile/modules/settings/services/app_settings.service.dart';
import 'package:immich_mobile/shared/views/immich_loading_overlay.dart';
import 'package:immich_mobile/shared/views/version_announcement_overlay.dart';
import 'package:immich_mobile/utils/immich_app_theme.dart';
import 'constants/hive_box.dart';
void main() async {
@ -50,8 +51,11 @@ void main() async {
Locale('da', 'DK'),
Locale('de', 'DE'),
Locale('es', 'ES'),
Locale('fi', 'FI'),
Locale('fr', 'FR'),
Locale('it', 'IT'),
Locale('ja', 'JP'),
Locale('pl', 'PL')
];
if (kReleaseMode && Platform.isAndroid) {
@ -130,7 +134,6 @@ class ImmichAppState extends ConsumerState<ImmichApp>
@override
initState() {
super.initState();
initApp().then((_) => debugPrint("App Init Completed"));
}
@ -155,23 +158,9 @@ class ImmichAppState extends ConsumerState<ImmichApp>
MaterialApp.router(
title: 'Immich',
debugShowCheckedModeBanner: false,
theme: ThemeData(
useMaterial3: true,
brightness: Brightness.light,
primarySwatch: Colors.indigo,
fontFamily: 'WorkSans',
snackBarTheme: const SnackBarThemeData(
contentTextStyle: TextStyle(fontFamily: 'WorkSans'),
),
scaffoldBackgroundColor: immichBackgroundColor,
appBarTheme: const AppBarTheme(
backgroundColor: immichBackgroundColor,
foregroundColor: Colors.indigo,
elevation: 1,
centerTitle: true,
systemOverlayStyle: SystemUiOverlayStyle.dark,
),
),
themeMode: ref.watch(immichThemeProvider),
darkTheme: immichDarkTheme,
theme: immichLightTheme,
routeInformationParser: router.defaultRouteParser(),
routerDelegate: router.delegate(
navigatorObservers: () => [TabNavigationObserver(ref: ref)],

View File

@ -14,6 +14,8 @@ class AlbumActionOutlinedButton extends StatelessWidget {
@override
Widget build(BuildContext context) {
final isDarkTheme = Theme.of(context).brightness == Brightness.dark;
return Padding(
padding: const EdgeInsets.only(right: 8.0),
child: OutlinedButton.icon(
@ -22,19 +24,23 @@ class AlbumActionOutlinedButton extends StatelessWidget {
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(25),
),
side: const BorderSide(
side: BorderSide(
width: 1,
color: Color.fromARGB(255, 215, 215, 215),
color: isDarkTheme
? const Color.fromARGB(255, 63, 63, 63)
: const Color.fromARGB(255, 206, 206, 206),
),
),
icon: Icon(iconData, size: 15),
icon: Icon(
iconData,
size: 15,
color: Theme.of(context).primaryColor,
),
label: Text(
labelText,
style: const TextStyle(
fontSize: 12,
fontWeight: FontWeight.bold,
color: Colors.black87,
),
style: Theme.of(context).textTheme.labelSmall?.copyWith(
fontWeight: FontWeight.bold,
),
),
onPressed: onPressed,
),

View File

@ -52,7 +52,6 @@ class AlbumThumbnailCard extends StatelessWidget {
album.albumName,
style: const TextStyle(
fontWeight: FontWeight.bold,
fontSize: 12,
),
),
),
@ -65,14 +64,14 @@ class AlbumThumbnailCard extends StatelessWidget {
? 'album_thumbnail_card_item'
: 'album_thumbnail_card_items',
style: const TextStyle(
fontSize: 10,
fontSize: 12,
),
).tr(args: ['${album.assetCount}']),
if (album.shared)
const Text(
'album_thumbnail_card_shared',
style: TextStyle(
fontSize: 10,
fontSize: 12,
),
).tr()
],

View File

@ -19,6 +19,8 @@ class AlbumTitleTextField extends ConsumerWidget {
@override
Widget build(BuildContext context, WidgetRef ref) {
final isDarkTheme = Theme.of(context).brightness == Brightness.dark;
return TextField(
onChanged: (v) {
if (v.isEmpty) {
@ -51,7 +53,10 @@ class AlbumTitleTextField extends ConsumerWidget {
albumTitleController.clear();
isAlbumTitleEmpty.value = true;
},
icon: const Icon(Icons.cancel_rounded),
icon: Icon(
Icons.cancel_rounded,
color: Theme.of(context).primaryColor,
),
splashRadius: 10,
)
: null,
@ -65,7 +70,9 @@ class AlbumTitleTextField extends ConsumerWidget {
),
hintText: 'share_add_title'.tr(),
focusColor: Colors.grey[300],
fillColor: Colors.grey[200],
fillColor: isDarkTheme
? const Color.fromARGB(255, 32, 33, 35)
: Colors.grey[200],
filled: isAlbumTitleTextFieldFocus.value,
),
);

View File

@ -150,7 +150,7 @@ class AlbumViewerAppbar extends HookConsumerWidget with PreferredSizeWidget {
void _buildBottomSheet() {
showModalBottomSheet(
backgroundColor: immichBackgroundColor,
backgroundColor: Theme.of(context).scaffoldBackgroundColor,
isScrollControlled: false,
context: context,
builder: (context) {

View File

@ -18,6 +18,7 @@ class AlbumViewerEditableTitle extends HookConsumerWidget {
Widget build(BuildContext context, WidgetRef ref) {
final titleTextEditController =
useTextEditingController(text: albumInfo.albumName);
final isDarkTheme = Theme.of(context).brightness == Brightness.dark;
void onFocusModeChange() {
if (!titleFocusNode.hasFocus && titleTextEditController.text.isEmpty) {
@ -65,7 +66,10 @@ class AlbumViewerEditableTitle extends HookConsumerWidget {
onPressed: () {
titleTextEditController.clear();
},
icon: const Icon(Icons.cancel_rounded),
icon: Icon(
Icons.cancel_rounded,
color: Theme.of(context).primaryColor,
),
splashRadius: 10,
)
: null,
@ -78,7 +82,9 @@ class AlbumViewerEditableTitle extends HookConsumerWidget {
borderRadius: BorderRadius.circular(10),
),
focusColor: Colors.grey[300],
fillColor: Colors.grey[200],
fillColor: isDarkTheme
? const Color.fromARGB(255, 32, 33, 35)
: Colors.grey[200],
filled: titleFocusNode.hasFocus,
hintText: 'share_add_title'.tr(),
),

View File

@ -35,13 +35,7 @@ class SharingSliverAppBar extends StatelessWidget {
Expanded(
child: Padding(
padding: const EdgeInsets.only(right: 4.0),
child: TextButton.icon(
style: ButtonStyle(
backgroundColor: MaterialStateProperty.all(
Theme.of(context).primaryColor.withAlpha(20),
),
// foregroundColor: MaterialStateProperty.all(Colors.white),
),
child: ElevatedButton.icon(
onPressed: () {
AutoRouter.of(context)
.push(CreateAlbumRoute(isSharedAlbum: true));
@ -52,8 +46,12 @@ class SharingSliverAppBar extends StatelessWidget {
),
label: const Text(
"sharing_silver_appbar_create_shared_album",
style:
TextStyle(fontWeight: FontWeight.bold, fontSize: 12),
maxLines: 1,
style: TextStyle(
fontWeight: FontWeight.bold,
fontSize: 11,
// color: Theme.of(context).primaryColor,
),
).tr(),
),
),
@ -61,13 +59,7 @@ class SharingSliverAppBar extends StatelessWidget {
Expanded(
child: Padding(
padding: const EdgeInsets.only(left: 4.0),
child: TextButton.icon(
style: ButtonStyle(
backgroundColor: MaterialStateProperty.all(
Theme.of(context).primaryColor.withAlpha(20),
),
// foregroundColor: MaterialStateProperty.all(Colors.white),
),
child: ElevatedButton.icon(
onPressed: null,
icon: const Icon(
Icons.swap_horizontal_circle_outlined,
@ -75,8 +67,11 @@ class SharingSliverAppBar extends StatelessWidget {
),
label: const Text(
"sharing_silver_appbar_share_partner",
style:
TextStyle(fontWeight: FontWeight.bold, fontSize: 12),
style: TextStyle(
fontWeight: FontWeight.bold,
fontSize: 11,
),
maxLines: 1,
).tr(),
),
),

View File

@ -3,7 +3,6 @@ import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/material.dart';
import 'package:flutter_hooks/flutter_hooks.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:immich_mobile/constants/immich_colors.dart';
import 'package:immich_mobile/modules/home/ui/draggable_scrollbar.dart';
import 'package:immich_mobile/modules/login/providers/authentication.provider.dart';
import 'package:immich_mobile/modules/album/models/asset_selection_page_result.model.dart';
@ -242,7 +241,7 @@ class AlbumViewerPage extends HookConsumerWidget {
titleFocusNode.unfocus();
},
child: DraggableScrollbar.semicircle(
backgroundColor: Theme.of(context).primaryColor,
backgroundColor: Theme.of(context).hintColor,
controller: scrollController,
heightScrollThumb: 48.0,
child: CustomScrollView(
@ -255,7 +254,7 @@ class AlbumViewerPage extends HookConsumerWidget {
minHeight: 50,
maxHeight: 50,
child: Container(
color: immichBackgroundColor,
color: Theme.of(context).scaffoldBackgroundColor,
child: _buildControlButton(albumInfo),
),
),

View File

@ -43,7 +43,7 @@ class AssetSelectionPage extends HookConsumerWidget {
return Stack(
children: [
DraggableScrollbar.semicircle(
backgroundColor: Theme.of(context).primaryColor,
backgroundColor: Theme.of(context).hintColor,
controller: scrollController,
heightScrollThumb: 48.0,
child: CustomScrollView(

View File

@ -27,6 +27,7 @@ class CreateAlbumPage extends HookConsumerWidget {
final isAlbumTitleEmpty = useState(true);
final selectedAssets =
ref.watch(assetSelectionProvider).selectedNewAssetsForAlbum;
final isDarkTheme = Theme.of(context).brightness == Brightness.dark;
_showSelectUserPage() {
AutoRouter.of(context).push(const SelectUserForSharingRoute());
@ -75,9 +76,12 @@ class CreateAlbumPage extends HookConsumerWidget {
return SliverToBoxAdapter(
child: Padding(
padding: const EdgeInsets.only(top: 200, left: 18),
child: const Text(
child: Text(
'create_shared_album_page_share_add_assets',
style: TextStyle(fontSize: 12),
style: Theme.of(context).textTheme.headline2?.copyWith(
fontSize: 12,
fontWeight: FontWeight.normal,
),
).tr(),
),
);
@ -96,24 +100,28 @@ class CreateAlbumPage extends HookConsumerWidget {
alignment: Alignment.centerLeft,
padding:
const EdgeInsets.symmetric(vertical: 22, horizontal: 16),
side: const BorderSide(
color: Color.fromARGB(255, 206, 206, 206),
side: BorderSide(
color: isDarkTheme
? const Color.fromARGB(255, 63, 63, 63)
: const Color.fromARGB(255, 206, 206, 206),
),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(5),
),
),
onPressed: _onSelectPhotosButtonPressed,
icon: const Icon(Icons.add_rounded),
icon: Icon(
Icons.add_rounded,
color: Theme.of(context).primaryColor,
),
label: Padding(
padding: const EdgeInsets.only(left: 8.0),
child: Text(
'create_shared_album_page_share_select_photos',
style: TextStyle(
fontSize: 16,
color: Colors.grey[700],
fontWeight: FontWeight.bold,
),
style: Theme.of(context).textTheme.labelLarge?.copyWith(
fontSize: 16,
fontWeight: FontWeight.bold,
),
).tr(),
),
),
@ -190,6 +198,7 @@ class CreateAlbumPage extends HookConsumerWidget {
appBar: AppBar(
elevation: 0,
centerTitle: false,
backgroundColor: Theme.of(context).scaffoldBackgroundColor,
leading: IconButton(
onPressed: () {
ref.watch(assetSelectionProvider.notifier).removeAll();
@ -197,9 +206,11 @@ class CreateAlbumPage extends HookConsumerWidget {
},
icon: const Icon(Icons.close_rounded),
),
title: const Text(
title: Text(
'share_create_album',
style: TextStyle(color: Colors.black),
style: Theme.of(context).textTheme.headline2?.copyWith(
color: Theme.of(context).primaryColor,
),
).tr(),
actions: [
if (isSharedAlbum)
@ -209,8 +220,9 @@ class CreateAlbumPage extends HookConsumerWidget {
: null,
child: Text(
'create_shared_album_page_share'.tr(),
style: const TextStyle(
style: TextStyle(
fontWeight: FontWeight.bold,
color: Theme.of(context).primaryColor,
),
),
),
@ -234,9 +246,9 @@ class CreateAlbumPage extends HookConsumerWidget {
child: CustomScrollView(
slivers: [
SliverAppBar(
backgroundColor: Theme.of(context).scaffoldBackgroundColor,
elevation: 5,
automaticallyImplyLeading: false,
// leading: Container(),
pinned: true,
floating: false,
bottom: PreferredSize(

View File

@ -23,7 +23,7 @@ class LibraryPage extends HookConsumerWidget {
);
Widget _buildAppBar() {
return SliverAppBar(
return const SliverAppBar(
centerTitle: true,
floating: true,
pinned: false,
@ -35,7 +35,6 @@ class LibraryPage extends HookConsumerWidget {
fontFamily: 'SnowburstOne',
fontWeight: FontWeight.bold,
fontSize: 22,
color: Theme.of(context).primaryColor,
),
),
);
@ -72,7 +71,6 @@ class LibraryPage extends HookConsumerWidget {
child: const Text(
'library_page_new_album',
style: TextStyle(
fontSize: 12,
fontWeight: FontWeight.bold,
),
).tr(),

View File

@ -136,9 +136,9 @@ class SelectUserForSharingPage extends HookConsumerWidget {
return Scaffold(
appBar: AppBar(
title: const Text(
title: Text(
'share_invite',
style: TextStyle(color: Colors.black),
style: TextStyle(color: Theme.of(context).primaryColor),
).tr(),
elevation: 0,
centerTitle: false,
@ -150,11 +150,18 @@ class SelectUserForSharingPage extends HookConsumerWidget {
),
actions: [
TextButton(
style: TextButton.styleFrom(
primary: Theme.of(context).primaryColor,
),
onPressed:
sharedUsersList.value.isEmpty ? null : _createSharedAlbum,
child: const Text(
"share_create_album",
style: TextStyle(fontSize: 14, fontWeight: FontWeight.bold),
style: TextStyle(
fontSize: 14,
fontWeight: FontWeight.bold,
// color: Theme.of(context).primaryColor,
),
).tr(),
)
],

View File

@ -61,11 +61,9 @@ class SharingPage extends HookConsumerWidget {
sharedAlbums[index].albumName,
maxLines: 1,
overflow: TextOverflow.ellipsis,
style: TextStyle(
fontSize: 16,
fontWeight: FontWeight.bold,
color: Colors.grey.shade800,
),
style: Theme.of(context).textTheme.bodyMedium?.copyWith(
fontWeight: FontWeight.bold,
),
),
onTap: () {
AutoRouter.of(context)
@ -87,7 +85,7 @@ class SharingPage extends HookConsumerWidget {
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(10), // if you need this
side: const BorderSide(
color: Colors.black12,
color: Colors.grey,
width: 1,
),
),
@ -97,30 +95,26 @@ class SharingPage extends HookConsumerWidget {
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Padding(
padding: const EdgeInsets.only(left: 5.0, bottom: 5),
const Padding(
padding: EdgeInsets.only(left: 5.0, bottom: 5),
child: Icon(
Icons.offline_share_outlined,
size: 50,
color: Theme.of(context).primaryColor.withAlpha(200),
// color: Theme.of(context).primaryColor,
),
),
Padding(
padding: const EdgeInsets.all(8.0),
child: Text(
'sharing_page_empty_list',
style: TextStyle(
fontSize: 12,
color: Theme.of(context).primaryColor,
fontWeight: FontWeight.bold,
),
style: Theme.of(context).textTheme.headline3,
).tr(),
),
Padding(
padding: const EdgeInsets.all(8.0),
child: Text(
'sharing_page_description',
style: TextStyle(fontSize: 12, color: Colors.grey[700]),
style: Theme.of(context).textTheme.bodyMedium,
).tr(),
),
],

View File

@ -11,7 +11,8 @@ import 'package:immich_mobile/modules/asset_viewer/ui/top_control_app_bar.dart';
import 'package:immich_mobile/modules/asset_viewer/views/image_viewer_page.dart';
import 'package:immich_mobile/modules/asset_viewer/views/video_viewer_page.dart';
import 'package:immich_mobile/modules/home/services/asset.service.dart';
import 'package:immich_mobile/shared/services/app_settings.service.dart';
import 'package:immich_mobile/modules/settings/providers/app_settings.provider.dart';
import 'package:immich_mobile/modules/settings/services/app_settings.service.dart';
import 'package:openapi/api.dart';
// ignore: must_be_immutable

View File

@ -24,6 +24,7 @@ class AlbumInfoCard extends HookConsumerWidget {
ref.watch(backupProvider).selectedBackupAlbums.contains(albumInfo);
final bool isExcluded =
ref.watch(backupProvider).excludedBackupAlbums.contains(albumInfo);
final isDarkTheme = Theme.of(context).brightness == Brightness.dark;
ColorFilter selectedFilter = ColorFilter.mode(
Theme.of(context).primaryColor.withAlpha(100),
@ -39,11 +40,11 @@ class AlbumInfoCard extends HookConsumerWidget {
return Chip(
visualDensity: VisualDensity.compact,
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(5)),
label: const Text(
label: Text(
"album_info_card_backup_album_included",
style: TextStyle(
fontSize: 10,
color: Colors.white,
color: isDarkTheme ? Colors.black : Colors.white,
fontWeight: FontWeight.bold,
),
).tr(),
@ -53,11 +54,11 @@ class AlbumInfoCard extends HookConsumerWidget {
return Chip(
visualDensity: VisualDensity.compact,
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(5)),
label: const Text(
label: Text(
"album_info_card_backup_album_excluded",
style: TextStyle(
fontSize: 10,
color: Colors.white,
color: isDarkTheme ? Colors.black : Colors.white,
fontWeight: FontWeight.bold,
),
).tr(),
@ -141,8 +142,10 @@ class AlbumInfoCard extends HookConsumerWidget {
margin: const EdgeInsets.all(1),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(12), // if you need this
side: const BorderSide(
color: Color(0xFFC9C9C9),
side: BorderSide(
color: isDarkTheme
? const Color.fromARGB(255, 37, 35, 35)
: const Color(0xFFC9C9C9),
width: 1,
),
),
@ -219,8 +222,9 @@ class AlbumInfoCard extends HookConsumerWidget {
),
IconButton(
onPressed: () {
AutoRouter.of(context)
.push(AlbumPreviewRoute(album: albumInfo));
AutoRouter.of(context).push(
AlbumPreviewRoute(album: albumInfo),
);
},
icon: Icon(
Icons.image_outlined,

View File

@ -35,7 +35,7 @@ class BackupInfoCard extends StatelessWidget {
padding: const EdgeInsets.only(top: 8.0),
child: Text(
subtitle,
style: const TextStyle(color: Color(0xFF808080), fontSize: 12),
style: const TextStyle(fontSize: 12),
),
),
trailing: Column(

View File

@ -4,6 +4,7 @@ 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/shared/ui/immich_loading_indicator.dart';
@ -16,6 +17,7 @@ class BackupAlbumSelectionPage extends HookConsumerWidget {
final availableAlbums = ref.watch(backupProvider).availableAlbums;
final selectedBackupAlbums = ref.watch(backupProvider).selectedBackupAlbums;
final excludedBackupAlbums = ref.watch(backupProvider).excludedBackupAlbums;
final isDarkTheme = Theme.of(context).brightness == Brightness.dark;
useEffect(
() {
@ -81,14 +83,16 @@ class BackupAlbumSelectionPage extends HookConsumerWidget {
),
label: Text(
album.name,
style: const TextStyle(
style: TextStyle(
fontSize: 10,
color: Colors.white,
color: Theme.of(context).brightness == Brightness.dark
? Colors.black
: Colors.white,
fontWeight: FontWeight.bold,
),
),
backgroundColor: Theme.of(context).primaryColor,
deleteIconColor: Colors.white,
deleteIconColor: isDarkTheme ? Colors.black : Colors.white,
deleteIcon: const Icon(
Icons.cancel_rounded,
size: 15,
@ -119,14 +123,15 @@ class BackupAlbumSelectionPage extends HookConsumerWidget {
),
label: Text(
album.name,
style: const TextStyle(
style: TextStyle(
fontSize: 10,
color: Colors.white,
color: isDarkTheme ? Colors.black : immichBackgroundColor,
fontWeight: FontWeight.bold,
),
),
backgroundColor: Colors.red[300],
deleteIconColor: Colors.white,
deleteIconColor:
isDarkTheme ? Colors.black : immichBackgroundColor,
deleteIcon: const Icon(
Icons.cancel_rounded,
size: 15,
@ -154,11 +159,16 @@ class BackupAlbumSelectionPage extends HookConsumerWidget {
physics: const ClampingScrollPhysics(),
children: [
Padding(
padding:
const EdgeInsets.symmetric(vertical: 8.0, horizontal: 16.0),
padding: const EdgeInsets.symmetric(
vertical: 8.0,
horizontal: 16.0,
),
child: const Text(
"backup_album_selection_page_selection_info",
style: TextStyle(fontWeight: FontWeight.bold, fontSize: 14),
style: TextStyle(
fontWeight: FontWeight.bold,
fontSize: 14,
),
).tr(),
),
// Selected Album Chips
@ -178,9 +188,11 @@ class BackupAlbumSelectionPage extends HookConsumerWidget {
child: Card(
margin: const EdgeInsets.all(0),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(5), // if you need this
side: const BorderSide(
color: Color.fromARGB(255, 235, 235, 235),
borderRadius: BorderRadius.circular(5),
side: BorderSide(
color: isDarkTheme
? const Color.fromARGB(255, 0, 0, 0)
: const Color.fromARGB(255, 235, 235, 235),
width: 1,
),
),
@ -190,12 +202,11 @@ class BackupAlbumSelectionPage extends HookConsumerWidget {
children: [
ListTile(
visualDensity: VisualDensity.compact,
title: Text(
title: const Text(
"backup_album_selection_page_total_assets",
style: TextStyle(
fontWeight: FontWeight.bold,
fontSize: 14,
color: Colors.grey[700],
),
).tr(),
trailing: Text(
@ -257,11 +268,10 @@ class BackupAlbumSelectionPage extends HookConsumerWidget {
content: SingleChildScrollView(
child: ListBody(
children: [
Text(
const Text(
'backup_album_selection_page_assets_scatter',
style: TextStyle(
fontSize: 14,
color: Colors.grey[700],
),
).tr(),
],

View File

@ -82,7 +82,7 @@ class BackupControllerPage extends HookConsumerWidget {
);
}
ListTile _buildBackupController() {
ListTile _buildAutoBackupController() {
var backUpOption = authenticationState.deviceInfo.isAutoBackup
? "backup_controller_page_status_on".tr()
: "backup_controller_page_status_off".tr();
@ -114,13 +114,7 @@ class BackupControllerPage extends HookConsumerWidget {
).tr(),
Padding(
padding: const EdgeInsets.only(top: 8.0),
child: OutlinedButton(
style: OutlinedButton.styleFrom(
side: const BorderSide(
width: 1,
color: Color.fromARGB(255, 220, 220, 220),
),
),
child: ElevatedButton(
onPressed: () {
if (isAutoBackup) {
ref
@ -134,7 +128,10 @@ class BackupControllerPage extends HookConsumerWidget {
},
child: Text(
backupBtnText,
style: const TextStyle(fontWeight: FontWeight.bold),
style: const TextStyle(
fontWeight: FontWeight.bold,
fontSize: 12,
),
),
),
)
@ -232,33 +229,24 @@ class BackupControllerPage extends HookConsumerWidget {
children: [
const Text(
"backup_controller_page_to_backup",
style: TextStyle(color: Color(0xFF808080), fontSize: 12),
style: TextStyle(fontSize: 12),
).tr(),
_buildSelectedAlbumName(),
_buildExcludedAlbumName()
],
),
),
trailing: OutlinedButton(
style: OutlinedButton.styleFrom(
enableFeedback: true,
side: const BorderSide(
width: 1,
color: Color.fromARGB(255, 220, 220, 220),
),
),
trailing: ElevatedButton(
onPressed: () {
AutoRouter.of(context).push(const BackupAlbumSelectionRoute());
},
child: Padding(
padding: const EdgeInsets.symmetric(
vertical: 16.0,
child: const Text(
"backup_controller_page_select",
style: TextStyle(
fontWeight: FontWeight.bold,
fontSize: 12,
),
child: const Text(
"backup_controller_page_select",
style: TextStyle(fontWeight: FontWeight.bold),
).tr(),
),
).tr(),
),
),
);
@ -324,14 +312,14 @@ class BackupControllerPage extends HookConsumerWidget {
padding: const EdgeInsets.only(top: 8.0),
child: Table(
border: TableBorder.all(
color: Colors.black12,
color: Theme.of(context).primaryColorLight,
width: 1,
),
children: [
TableRow(
decoration: BoxDecoration(
color: Colors.grey[100],
),
decoration: const BoxDecoration(
// color: Colors.grey[100],
),
children: [
TableCell(
verticalAlignment: TableCellVerticalAlignment.middle,
@ -355,9 +343,9 @@ class BackupControllerPage extends HookConsumerWidget {
],
),
TableRow(
decoration: BoxDecoration(
color: Colors.grey[200],
),
decoration: const BoxDecoration(
// color: Colors.grey[200],
),
children: [
TableCell(
verticalAlignment: TableCellVerticalAlignment.middle,
@ -384,9 +372,9 @@ class BackupControllerPage extends HookConsumerWidget {
],
),
TableRow(
decoration: BoxDecoration(
color: Colors.grey[100],
),
decoration: const BoxDecoration(
// color: Colors.grey[100],
),
children: [
TableCell(
child: Padding(
@ -463,7 +451,7 @@ class BackupControllerPage extends HookConsumerWidget {
"${backupState.allUniqueAssets.length - backupState.selectedAlbumsBackupAssetsIds.length}",
),
const Divider(),
_buildBackupController(),
_buildAutoBackupController(),
const Divider(),
_buildStorageInformation(),
const Divider(),
@ -479,7 +467,7 @@ class BackupControllerPage extends HookConsumerWidget {
style: ElevatedButton.styleFrom(
primary: Colors.red[300],
onPrimary: Colors.grey[50],
padding: const EdgeInsets.all(14),
// padding: const EdgeInsets.all(14),
),
onPressed: () {
ref.read(backupProvider.notifier).cancelBackup();
@ -493,11 +481,6 @@ class BackupControllerPage extends HookConsumerWidget {
).tr(),
)
: ElevatedButton(
style: ElevatedButton.styleFrom(
primary: Theme.of(context).primaryColor,
onPrimary: Colors.grey[50],
padding: const EdgeInsets.all(14),
),
onPressed: shouldBackup ? startBackup : null,
child: const Text(
"backup_controller_page_start_backup",

View File

@ -1,11 +1,9 @@
import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/material.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:immich_mobile/modules/home/providers/home_page_state.provider.dart';
import 'package:immich_mobile/modules/home/ui/delete_diaglog.dart';
import '../../../shared/providers/asset.provider.dart';
import '../providers/home_page_state.provider.dart';
class ControlBottomAppBar extends ConsumerWidget {
const ControlBottomAppBar({Key? key}) : super(key: key);
@ -19,10 +17,10 @@ class ControlBottomAppBar extends ConsumerWidget {
height: MediaQuery.of(context).size.height * 0.15,
decoration: BoxDecoration(
borderRadius: const BorderRadius.only(
topLeft: Radius.circular(15),
topRight: Radius.circular(15),
topLeft: Radius.circular(8),
topRight: Radius.circular(8),
),
color: Colors.grey[300]?.withOpacity(0.98),
color: Theme.of(context).scaffoldBackgroundColor.withOpacity(0.95),
),
child: Column(
children: [

View File

@ -86,7 +86,6 @@ class DailyTitleText extends ConsumerWidget {
style: const TextStyle(
fontSize: 14,
fontWeight: FontWeight.bold,
color: Colors.black87,
),
),
const Spacer(),

View File

@ -14,32 +14,22 @@ class DisableMultiSelectButton extends ConsumerWidget {
@override
Widget build(BuildContext context, WidgetRef ref) {
return Positioned(
top: 0,
top: 10,
left: 0,
child: Padding(
padding: const EdgeInsets.only(left: 16.0, top: 46),
child: Material(
elevation: 20,
borderRadius: BorderRadius.circular(35),
child: Container(
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(35),
color: Colors.grey[100],
),
child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 4.0),
child: TextButton.icon(
onPressed: () {
onPressed();
},
icon: const Icon(Icons.close_rounded),
label: Text(
'$selectedItemCount',
style: const TextStyle(
fontWeight: FontWeight.w600,
fontSize: 18,
),
),
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,
),
),
),

View File

@ -30,6 +30,7 @@ class ImmichSliverAppBar extends ConsumerWidget {
floating: true,
pinned: false,
snap: false,
backgroundColor: Theme.of(context).appBarTheme.backgroundColor,
shape: const RoundedRectangleBorder(
borderRadius: BorderRadius.all(Radius.circular(5)),
),
@ -57,7 +58,7 @@ class ImmichSliverAppBar extends ConsumerWidget {
child: GestureDetector(
onTap: () => Scaffold.of(context).openDrawer(),
child: Material(
color: Colors.grey[200],
// color: Colors.grey[200],
elevation: 1,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(50.0),
@ -77,13 +78,12 @@ class ImmichSliverAppBar extends ConsumerWidget {
);
},
),
title: Text(
title: const Text(
'IMMICH',
style: TextStyle(
fontFamily: 'SnowburstOne',
fontWeight: FontWeight.bold,
fontSize: 22,
color: Theme.of(context).primaryColor,
),
),
actions: [
@ -112,12 +112,13 @@ class ImmichSliverAppBar extends ConsumerWidget {
? const Icon(Icons.backup_rounded)
: Badge(
padding: const EdgeInsets.all(4),
elevation: 2,
elevation: 3,
position: BadgePosition.bottomEnd(bottom: -4, end: -4),
badgeColor: Colors.white,
badgeContent: const Icon(
Icons.cloud_off_rounded,
size: 8,
color: Colors.indigo,
),
child: const Icon(Icons.backup_rounded),
),

View File

@ -22,7 +22,7 @@ class MonthlyTitleText extends StatelessWidget {
style: TextStyle(
fontSize: 26,
fontWeight: FontWeight.bold,
color: Theme.of(context).primaryColor,
color: Theme.of(context).textTheme.headline1?.color,
),
),
),

View File

@ -22,17 +22,16 @@ class ProfileDrawer extends HookConsumerWidget {
height: double.infinity,
child: Icon(
Icons.logout_rounded,
color: Colors.grey[700],
color: Theme.of(context).textTheme.labelMedium?.color,
size: 20,
),
),
title: Text(
"profile_drawer_sign_out",
style: TextStyle(
color: Colors.grey[700],
fontSize: 12,
fontWeight: FontWeight.bold,
),
style: Theme.of(context)
.textTheme
.labelLarge
?.copyWith(fontWeight: FontWeight.bold),
).tr(),
onTap: () async {
bool res = await ref.watch(authenticationProvider.notifier).logout();
@ -54,17 +53,16 @@ class ProfileDrawer extends HookConsumerWidget {
height: double.infinity,
child: Icon(
Icons.settings_rounded,
color: Colors.grey[700],
color: Theme.of(context).textTheme.labelMedium?.color,
size: 20,
),
),
title: Text(
"profile_drawer_settings",
style: TextStyle(
color: Colors.grey[700],
fontSize: 12,
fontWeight: FontWeight.bold,
),
style: Theme.of(context)
.textTheme
.labelLarge
?.copyWith(fontWeight: FontWeight.bold),
).tr(),
onTap: () {
AutoRouter.of(context).push(const SettingsRoute());

View File

@ -23,6 +23,7 @@ class ProfileDrawerHeader extends HookConsumerWidget {
final uploadProfileImageStatus =
ref.watch(uploadProfileImageProvider).status;
var dummmy = Random().nextInt(1024);
final isDarkMode = Theme.of(context).brightness == Brightness.dark;
_buildUserProfileImage() {
if (authState.profileImagePath.isEmpty) {
@ -104,13 +105,19 @@ class ProfileDrawerHeader extends HookConsumerWidget {
);
return DrawerHeader(
decoration: const BoxDecoration(
decoration: BoxDecoration(
gradient: LinearGradient(
colors: [
Color.fromARGB(255, 216, 219, 238),
Color.fromARGB(255, 242, 242, 242),
Colors.white,
],
colors: isDarkMode
? [
const Color.fromARGB(255, 22, 25, 48),
const Color.fromARGB(255, 13, 13, 13),
const Color.fromARGB(255, 0, 0, 0),
]
: [
const Color.fromARGB(255, 216, 219, 238),
const Color.fromARGB(255, 242, 242, 242),
Colors.white,
],
begin: Alignment.centerRight,
end: Alignment.centerLeft,
),
@ -129,8 +136,8 @@ class ProfileDrawerHeader extends HookConsumerWidget {
child: GestureDetector(
onTap: _pickUserProfileImage,
child: Material(
color: Colors.grey[50],
elevation: 2,
color: Colors.grey[100],
elevation: 3,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(50.0),
),
@ -157,7 +164,7 @@ class ProfileDrawerHeader extends HookConsumerWidget {
),
Text(
authState.userEmail,
style: TextStyle(color: Colors.grey[800], fontSize: 12),
style: Theme.of(context).textTheme.labelMedium,
)
],
),

View File

@ -38,7 +38,7 @@ class ServerInfoBox extends HookConsumerWidget {
padding: const EdgeInsets.all(8.0),
child: Card(
elevation: 0,
color: Colors.grey[100],
color: Theme.of(context).scaffoldBackgroundColor,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(5), // if you need this
side: const BorderSide(
@ -65,7 +65,10 @@ class ServerInfoBox extends HookConsumerWidget {
),
),
),
const Divider(),
const Divider(
color: Color.fromARGB(101, 201, 201, 201),
thickness: 1,
),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
@ -87,7 +90,10 @@ class ServerInfoBox extends HookConsumerWidget {
),
],
),
const Divider(),
const Divider(
color: Color.fromARGB(101, 201, 201, 201),
thickness: 1,
),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [

View File

@ -117,9 +117,9 @@ class HomePage extends HookConsumerWidget {
],
),
Padding(
padding: const EdgeInsets.only(top: 50.0),
padding: const EdgeInsets.only(top: 60.0, bottom: 30.0),
child: DraggableScrollbar.semicircle(
backgroundColor: Theme.of(context).primaryColor,
backgroundColor: Theme.of(context).hintColor,
controller: scrollController,
heightScrollThumb: 48.0,
child: CustomScrollView(

View File

@ -26,7 +26,7 @@ class ThumbnailWithInfo extends StatelessWidget {
child: Padding(
padding: const EdgeInsets.only(right: 8.0),
child: SizedBox(
width: MediaQuery.of(context).size.width / 2,
width: MediaQuery.of(context).size.width / 3,
child: Stack(
alignment: Alignment.bottomCenter,
children: [
@ -58,7 +58,7 @@ class ThumbnailWithInfo extends StatelessWidget {
style: const TextStyle(
color: Colors.white,
fontWeight: FontWeight.bold,
fontSize: 16,
fontSize: 14,
),
),
),

View File

@ -29,6 +29,8 @@ class SearchPage extends HookConsumerWidget {
AsyncValue<List<CuratedObjectsResponseDto>> curatedObjects =
ref.watch(getCuratedObjectProvider);
double imageSize = MediaQuery.of(context).size.width / 3;
useEffect(
() {
searchFocusNode = FocusNode();
@ -46,15 +48,15 @@ class SearchPage extends HookConsumerWidget {
_buildPlaces() {
return curatedLocation.when(
loading: () => const SizedBox(
height: 200,
child: Center(child: ImmichLoadingIndicator()),
loading: () => SizedBox(
height: imageSize,
child: const Center(child: ImmichLoadingIndicator()),
),
error: (err, stack) => Text('Error: $err'),
data: (curatedLocations) {
return curatedLocations.isNotEmpty
? SizedBox(
height: MediaQuery.of(context).size.width / 2,
height: imageSize,
child: ListView.builder(
padding: const EdgeInsets.only(left: 16),
scrollDirection: Axis.horizontal,
@ -76,7 +78,7 @@ class SearchPage extends HookConsumerWidget {
),
)
: SizedBox(
height: MediaQuery.of(context).size.width / 2,
height: imageSize,
child: ListView.builder(
padding: const EdgeInsets.only(left: 16),
scrollDirection: Axis.horizontal,
@ -105,7 +107,7 @@ class SearchPage extends HookConsumerWidget {
data: (objects) {
return objects.isNotEmpty
? SizedBox(
height: MediaQuery.of(context).size.width / 2,
height: imageSize,
child: ListView.builder(
padding: const EdgeInsets.only(left: 16),
scrollDirection: Axis.horizontal,
@ -113,7 +115,7 @@ class SearchPage extends HookConsumerWidget {
itemBuilder: ((context, index) {
var curatedObjectInfo = objects[index];
var thumbnailRequestUrl =
'${box.get(serverEndpointKey)}/asset/file?aid=${curatedObjectInfo.deviceAssetId}&did=${curatedObjectInfo.deviceId}&isThumb=true';
'${box.get(serverEndpointKey)}/asset/thumbnail/${curatedObjectInfo.id}';
return ThumbnailWithInfo(
imageUrl: thumbnailRequestUrl,
@ -131,7 +133,8 @@ class SearchPage extends HookConsumerWidget {
),
)
: SizedBox(
height: MediaQuery.of(context).size.width / 2,
// height: imageSize,
width: imageSize,
child: ListView.builder(
padding: const EdgeInsets.only(left: 16),
scrollDirection: Axis.horizontal,
@ -163,12 +166,13 @@ class SearchPage extends HookConsumerWidget {
child: Stack(
children: [
ListView(
shrinkWrap: true,
children: [
Padding(
padding: const EdgeInsets.all(16.0),
child: const Text(
"search_page_places",
style: TextStyle(fontWeight: FontWeight.bold, fontSize: 16),
style: TextStyle(fontWeight: FontWeight.bold, fontSize: 14),
).tr(),
),
_buildPlaces(),
@ -176,7 +180,7 @@ class SearchPage extends HookConsumerWidget {
padding: const EdgeInsets.all(16.0),
child: const Text(
"search_page_things",
style: TextStyle(fontWeight: FontWeight.bold, fontSize: 16),
style: TextStyle(fontWeight: FontWeight.bold, fontSize: 14),
).tr(),
),
_buildThings()

View File

@ -172,7 +172,7 @@ class SearchResultPage extends HookConsumerWidget {
});
return DraggableScrollbar.semicircle(
backgroundColor: Theme.of(context).primaryColor,
backgroundColor: Theme.of(context).hintColor,
controller: scrollController,
heightScrollThumb: 48.0,
child: CustomScrollView(

View File

@ -0,0 +1,4 @@
import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:immich_mobile/modules/settings/services/app_settings.service.dart';
final appSettingsServiceProvider = Provider((ref) => AppSettingsService());

View File

@ -5,7 +5,7 @@ import 'package:immich_mobile/constants/hive_box.dart';
enum AppSettingsEnum {
threeStageLoading, // true, false,
themeMode, // "light","dark"
themeMode, // "light","dark","system"
}
class AppSettingsService {
@ -61,8 +61,8 @@ class AppSettingsService {
// Default value of themeMode is "light"
if (settingType == AppSettingsEnum.themeMode) {
hiveBox.put(settingKey, "light");
return "light";
hiveBox.put(settingKey, "system");
return "system";
}
}
@ -75,5 +75,3 @@ class AppSettingsService {
}
}
}
final appSettingsServiceProvider = Provider((ref) => AppSettingsService());

View File

@ -1,3 +1,4 @@
import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/material.dart';
import 'package:immich_mobile/modules/settings/ui/image_viewer_quality_setting/three_stage_loading.dart';
@ -8,20 +9,21 @@ class ImageViewerQualitySetting extends StatelessWidget {
@override
Widget build(BuildContext context) {
return const ExpansionTile(
title: Text(
'Image viewer quality',
return ExpansionTile(
textColor: Theme.of(context).primaryColor,
title: const Text(
'theme_setting_image_viewer_quality_title',
style: TextStyle(
fontWeight: FontWeight.bold,
),
),
subtitle: Text(
'Adjust the quality of the detail image viewer',
).tr(),
subtitle: const Text(
'theme_setting_image_viewer_quality_subtitle',
style: TextStyle(
fontSize: 13,
),
),
children: [
).tr(),
children: const [
ThreeStageLoading(),
],
);

View File

@ -1,7 +1,9 @@
import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/material.dart';
import 'package:flutter_hooks/flutter_hooks.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:immich_mobile/shared/services/app_settings.service.dart';
import 'package:immich_mobile/modules/settings/providers/app_settings.provider.dart';
import 'package:immich_mobile/modules/settings/services/app_settings.service.dart';
class ThreeStageLoading extends HookConsumerWidget {
const ThreeStageLoading({
@ -35,18 +37,18 @@ class ThreeStageLoading extends HookConsumerWidget {
return SwitchListTile.adaptive(
title: const Text(
"Enable three stage loading",
"theme_setting_three_stage_loading_title",
style: TextStyle(
fontSize: 12,
fontWeight: FontWeight.bold,
),
),
).tr(),
subtitle: const Text(
"The three-stage loading delivers the best quality image in exchange for a slower loading speed",
"theme_setting_three_stage_loading_subtitle",
style: TextStyle(
fontSize: 12,
),
),
).tr(),
value: isEnable.value,
onChanged: onSwitchChanged,
);

View File

@ -0,0 +1,107 @@
import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/material.dart';
import 'package:flutter_hooks/flutter_hooks.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:immich_mobile/modules/settings/providers/app_settings.provider.dart';
import 'package:immich_mobile/modules/settings/ui/image_viewer_quality_setting/three_stage_loading.dart';
import 'package:immich_mobile/modules/settings/services/app_settings.service.dart';
import 'package:immich_mobile/utils/immich_app_theme.dart';
class ThemeSetting extends HookConsumerWidget {
const ThemeSetting({
Key? key,
}) : super(key: key);
@override
Widget build(BuildContext context, WidgetRef ref) {
final currentTheme = useState<ThemeMode>(ThemeMode.system);
useEffect(
() {
currentTheme.value = ref.read(immichThemeProvider);
return null;
},
[],
);
return ExpansionTile(
textColor: Theme.of(context).primaryColor,
title: const Text(
'theme_setting_theme_title',
style: TextStyle(
fontWeight: FontWeight.bold,
),
).tr(),
subtitle: const Text(
'theme_setting_theme_subtitle',
style: TextStyle(
fontSize: 13,
),
).tr(),
children: [
SwitchListTile.adaptive(
activeColor: Theme.of(context).primaryColor,
title: const Text(
'theme_setting_system_theme_switch',
style: TextStyle(
fontSize: 12.0,
fontWeight: FontWeight.bold,
),
).tr(),
value: currentTheme.value == ThemeMode.system,
onChanged: (bool isSystem) {
var currentSystemBrightness =
MediaQuery.of(context).platformBrightness;
if (isSystem) {
currentTheme.value = ThemeMode.system;
ref.watch(immichThemeProvider.notifier).state = ThemeMode.system;
ref
.watch(appSettingsServiceProvider)
.setSetting(AppSettingsEnum.themeMode, "system");
} else {
if (currentSystemBrightness == Brightness.light) {
currentTheme.value = ThemeMode.light;
ref.watch(immichThemeProvider.notifier).state = ThemeMode.light;
ref
.watch(appSettingsServiceProvider)
.setSetting(AppSettingsEnum.themeMode, "light");
} else if (currentSystemBrightness == Brightness.dark) {
currentTheme.value = ThemeMode.dark;
ref.watch(immichThemeProvider.notifier).state = ThemeMode.dark;
ref
.watch(appSettingsServiceProvider)
.setSetting(AppSettingsEnum.themeMode, "dark");
}
}
},
),
if (currentTheme.value != ThemeMode.system)
SwitchListTile.adaptive(
activeColor: Theme.of(context).primaryColor,
title: const Text(
'theme_setting_dark_mode_switch',
style: TextStyle(
fontSize: 12.0,
fontWeight: FontWeight.bold,
),
).tr(),
value: ref.watch(immichThemeProvider) == ThemeMode.dark,
onChanged: (bool isDark) {
if (isDark) {
ref.watch(immichThemeProvider.notifier).state = ThemeMode.dark;
ref
.watch(appSettingsServiceProvider)
.setSetting(AppSettingsEnum.themeMode, "dark");
} else {
ref.watch(immichThemeProvider.notifier).state = ThemeMode.light;
ref
.watch(appSettingsServiceProvider)
.setSetting(AppSettingsEnum.themeMode, "light");
}
},
),
],
);
}
}

View File

@ -1,6 +1,8 @@
import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/material.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:immich_mobile/modules/settings/ui/image_viewer_quality_setting/image_viewer_quality_setting.dart';
import 'package:immich_mobile/modules/settings/ui/theme_setting/theme_setting.dart';
class SettingsPage extends HookConsumerWidget {
const SettingsPage({Key? key}) : super(key: key);
@ -20,12 +22,12 @@ class SettingsPage extends HookConsumerWidget {
automaticallyImplyLeading: false,
centerTitle: false,
title: const Text(
'Settings',
'setting_pages_app_bar_settings',
style: TextStyle(
fontSize: 16,
fontWeight: FontWeight.bold,
),
),
).tr(),
),
body: ListView(
children: [
@ -33,10 +35,7 @@ class SettingsPage extends HookConsumerWidget {
context: context,
tiles: [
const ImageViewerQualitySetting(),
const SettingListTile(
title: 'Theme',
subtitle: 'Choose between light and dark theme',
),
const ThemeSetting(),
],
).toList(),
],
@ -44,38 +43,3 @@ class SettingsPage extends HookConsumerWidget {
);
}
}
class SettingListTile extends StatelessWidget {
const SettingListTile({
required this.title,
required this.subtitle,
Key? key,
}) : super(key: key);
final String title;
final String subtitle;
@override
Widget build(BuildContext context) {
return ListTile(
dense: true,
title: Text(
title,
style: const TextStyle(
fontWeight: FontWeight.bold,
),
),
subtitle: Text(
subtitle,
style: const TextStyle(
fontSize: 12,
),
),
trailing: const Icon(
Icons.keyboard_arrow_right_rounded,
size: 24,
),
onTap: () {},
);
}
}

View File

@ -4,7 +4,6 @@ import 'package:flutter_hooks/flutter_hooks.dart';
import 'package:hive_flutter/hive_flutter.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:immich_mobile/constants/hive_box.dart';
import 'package:immich_mobile/constants/immich_colors.dart';
import 'package:immich_mobile/modules/backup/providers/backup.provider.dart';
import 'package:immich_mobile/modules/login/models/hive_saved_login_info.model.dart';
import 'package:immich_mobile/modules/login/providers/authentication.provider.dart';
@ -49,7 +48,6 @@ class SplashScreenPage extends HookConsumerWidget {
);
return Scaffold(
backgroundColor: immichBackgroundColor,
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,

View File

@ -2,7 +2,6 @@ import 'package:auto_route/auto_route.dart';
import 'package:easy_localization/easy_localization.dart';
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/home/providers/home_page_state.provider.dart';
import 'package:immich_mobile/routing/router.dart';
@ -36,8 +35,6 @@ class TabControllerPage extends ConsumerWidget {
bottomNavigationBar: isMultiSelectEnable
? null
: BottomNavigationBar(
type: BottomNavigationBarType.fixed,
backgroundColor: immichBackgroundColor,
selectedLabelStyle: const TextStyle(
fontSize: 13,
fontWeight: FontWeight.w600,

View File

@ -0,0 +1,133 @@
import 'package:flutter/material.dart';
import 'package:flutter/services.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';
final immichThemeProvider = StateProvider<ThemeMode>((ref) {
var themeMode = ref
.watch(appSettingsServiceProvider)
.getSetting(AppSettingsEnum.themeMode);
debugPrint("Current themeMode $themeMode");
if (themeMode == "light") {
return ThemeMode.light;
} else if (themeMode == "dark") {
return ThemeMode.dark;
} else {
return ThemeMode.system;
}
});
ThemeData immichDarkTheme = ThemeData(
useMaterial3: true,
brightness: Brightness.dark,
primarySwatch: Colors.indigo,
primaryColor: immichDarkThemePrimaryColor,
scaffoldBackgroundColor: immichDarkBackgroundColor,
hintColor: Colors.grey[600],
fontFamily: 'WorkSans',
snackBarTheme: const SnackBarThemeData(
contentTextStyle: TextStyle(fontFamily: 'WorkSans'),
),
appBarTheme: AppBarTheme(
titleTextStyle: TextStyle(
fontFamily: 'WorkSans',
color: immichDarkThemePrimaryColor,
),
backgroundColor: const Color.fromARGB(255, 32, 33, 35),
foregroundColor: immichDarkThemePrimaryColor,
elevation: 1,
centerTitle: true,
systemOverlayStyle: SystemUiOverlayStyle.light,
),
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(
headline1: const TextStyle(
fontSize: 26,
fontWeight: FontWeight.bold,
color: Color.fromARGB(255, 255, 255, 255),
),
headline2: const TextStyle(
fontSize: 14,
fontWeight: FontWeight.bold,
color: Color.fromARGB(255, 148, 151, 155),
),
headline3: TextStyle(
fontSize: 12,
fontWeight: FontWeight.bold,
color: immichDarkThemePrimaryColor,
),
),
cardColor: Colors.grey[900],
elevatedButtonTheme: ElevatedButtonThemeData(
style: ElevatedButton.styleFrom(
onPrimary: Colors.black87,
primary: immichDarkThemePrimaryColor,
),
),
);
ThemeData immichLightTheme = ThemeData(
useMaterial3: true,
brightness: Brightness.light,
primarySwatch: Colors.indigo,
hintColor: Colors.indigo,
fontFamily: 'WorkSans',
scaffoldBackgroundColor: immichBackgroundColor,
snackBarTheme: const SnackBarThemeData(
contentTextStyle: TextStyle(fontFamily: 'WorkSans'),
),
appBarTheme: AppBarTheme(
titleTextStyle: const TextStyle(
fontFamily: 'WorkSans',
color: Colors.indigo,
),
backgroundColor: immichBackgroundColor,
foregroundColor: Colors.indigo,
elevation: 1,
centerTitle: true,
systemOverlayStyle: SystemUiOverlayStyle.dark,
),
bottomNavigationBarTheme: BottomNavigationBarThemeData(
type: BottomNavigationBarType.fixed,
backgroundColor: immichBackgroundColor,
selectedItemColor: Colors.indigo,
),
drawerTheme: DrawerThemeData(
backgroundColor: immichBackgroundColor,
),
textTheme: const TextTheme(
headline1: TextStyle(
fontSize: 26,
fontWeight: FontWeight.bold,
color: Colors.indigo,
),
headline2: TextStyle(
fontSize: 14,
fontWeight: FontWeight.bold,
color: Colors.black87,
),
headline3: TextStyle(
fontSize: 12,
fontWeight: FontWeight.bold,
color: Colors.indigo,
),
),
elevatedButtonTheme: ElevatedButtonThemeData(
style: ElevatedButton.styleFrom(
primary: Colors.indigo,
onPrimary: Colors.white,
),
),
);

View File

@ -2,7 +2,7 @@ name: immich_mobile
description: Immich - selfhosted backup media file on mobile phone
publish_to: "none"
version: 1.22.0+32
version: 1.23.0+33
environment:
sdk: ">=2.17.0 <3.0.0"

View File

@ -10,7 +10,7 @@ export interface IServerVersion {
export const serverVersion: IServerVersion = {
major: 1,
minor: 22,
minor: 23,
patch: 0,
build: 0,
};