diff --git a/lib/app/shared/enum/status/mnemonic_status.dart b/lib/app/shared/enum/status/mnemonic_status.dart index 47d3ae4a6..587b63ed3 100644 --- a/lib/app/shared/enum/status/mnemonic_status.dart +++ b/lib/app/shared/enum/status/mnemonic_status.dart @@ -1,4 +1,5 @@ -import 'dart:ui'; + +import 'package:flutter/material.dart'; enum MnemonicStatus { unselected, @@ -17,14 +18,14 @@ extension MnemonicStatusX on MnemonicStatus { } } - Color get color { + Color color(BuildContext context) { switch (this) { case MnemonicStatus.unselected: - return const Color(0xff86809D); + return Theme.of(context).colorScheme.secondaryContainer; case MnemonicStatus.wrongSelection: - return const Color(0xffFF0045); + return Theme.of(context).colorScheme.error; case MnemonicStatus.selected: - return const Color(0xff6600FF); + return Theme.of(context).colorScheme.primary; } } } diff --git a/lib/app/shared/widget/back_leading_button.dart b/lib/app/shared/widget/back_leading_button.dart index 4dd9030de..58d40b17e 100644 --- a/lib/app/shared/widget/back_leading_button.dart +++ b/lib/app/shared/widget/back_leading_button.dart @@ -14,7 +14,7 @@ class BackLeadingButton extends StatelessWidget { @override Widget build(BuildContext context) { - final colorValue = color ?? Theme.of(context).colorScheme.onPrimary; + final colorValue = color ?? Theme.of(context).colorScheme.onSurface; return IconButton( padding: padding, onPressed: onPressed ?? () => Navigator.of(context).pop(), diff --git a/lib/app/shared/widget/base/background_card.dart b/lib/app/shared/widget/base/background_card.dart index 6ab3b67ef..0b192a734 100644 --- a/lib/app/shared/widget/base/background_card.dart +++ b/lib/app/shared/widget/base/background_card.dart @@ -26,7 +26,7 @@ class BackgroundCard extends StatelessWidget { height: height, width: width, decoration: BoxDecoration( - color: color ?? Theme.of(context).colorScheme.surfaceBright, + color: color ?? Theme.of(context).colorScheme.secondaryContainer, borderRadius: const BorderRadius.all(Radius.circular(15)), ), child: child, diff --git a/lib/app/shared/widget/custom_app_bar.dart b/lib/app/shared/widget/custom_app_bar.dart index d402238bc..07384fda1 100644 --- a/lib/app/shared/widget/custom_app_bar.dart +++ b/lib/app/shared/widget/custom_app_bar.dart @@ -50,7 +50,9 @@ class CustomAppBar extends PreferredSize { title ?? '', maxLines: 2, textAlign: TextAlign.center, - style: Theme.of(context).textTheme.headlineMedium, + style: Theme.of(context).textTheme.headlineMedium!.copyWith( + fontWeight: FontWeight.bold, + ), ), ), ], diff --git a/lib/app/shared/widget/wallet_logo.dart b/lib/app/shared/widget/wallet_logo.dart index 41f58bdc4..23b2c9001 100644 --- a/lib/app/shared/widget/wallet_logo.dart +++ b/lib/app/shared/widget/wallet_logo.dart @@ -43,25 +43,33 @@ class WalletLogo extends StatelessWidget { return Column( children: [ Center( - child: SizedBox( - width: width, - height: height, - child: profileModel.profileType == ProfileType.enterprise - ? CachedImageFromNetwork( - image, - fit: BoxFit.contain, - width: width, - bgColor: Colors.transparent, - height: height, - errorMessage: '', - showLoading: false, - ) - : Image.asset( - image, - fit: BoxFit.contain, - width: width, - height: height, - ), + child: ColorFiltered( + colorFilter: ColorFilter.mode( + profileModel.profileType == ProfileType.enterprise + ? Colors.transparent + : Theme.of(context).colorScheme.primary, + BlendMode.srcIn, + ), + child: SizedBox( + width: width, + height: height, + child: profileModel.profileType == ProfileType.enterprise + ? CachedImageFromNetwork( + image, + fit: BoxFit.contain, + width: width, + bgColor: Colors.transparent, + height: height, + errorMessage: '', + showLoading: false, + ) + : Image.asset( + image, + fit: BoxFit.contain, + width: width, + height: height, + ), + ), ), ), // if (showPoweredBy && diff --git a/lib/app/view/app.dart b/lib/app/view/app.dart index 673d739e5..ba1f79845 100644 --- a/lib/app/view/app.dart +++ b/lib/app/view/app.dart @@ -24,6 +24,8 @@ import 'package:altme/route/route.dart'; import 'package:altme/scan/scan.dart'; import 'package:altme/splash/splash.dart'; import 'package:altme/theme/app_theme/app_theme.dart'; +import 'package:altme/theme/theme_cubit.dart'; +import 'package:altme/theme/theme_repository.dart'; import 'package:altme/wallet/wallet.dart'; import 'package:beacon_flutter/beacon_flutter.dart'; @@ -39,239 +41,255 @@ import 'package:polygonid/polygonid.dart'; import 'package:secure_storage/secure_storage.dart'; class App extends StatelessWidget { - const App({super.key, this.flavorMode = FlavorMode.production}); + const App({ + super.key, + this.flavorMode = FlavorMode.production, + required this.themeRepository, + }); final FlavorMode flavorMode; + final ThemeRepository themeRepository; @override Widget build(BuildContext context) { final secureStorageProvider = getSecureStorage; - return MultiBlocProvider( - providers: [ - BlocProvider( - create: (context) => FlavorCubit(flavorMode), - ), - BlocProvider( - create: (context) => - LangCubit(secureStorageProvider: getSecureStorage), - ), - BlocProvider(create: (context) => RouteCubit()), - BlocProvider( - create: (context) => BeaconCubit(beacon: Beacon()), - ), - BlocProvider( - create: (context) => WalletConnectCubit( - secureStorageProvider: secureStorageProvider, - connectedDappRepository: - ConnectedDappRepository(secureStorageProvider), - routeCubit: context.read(), + return RepositoryProvider.value( + value: themeRepository, + child: MultiBlocProvider( + providers: [ + BlocProvider( + create: (context) => ThemeCubit( + themeRepository: context.read(), + )..getCurrentTheme(), ), - ), - BlocProvider(create: (context) => DeepLinkCubit()), - BlocProvider( - create: (context) => QueryByExampleCubit(), - ), - BlocProvider( - create: (context) => ProfileCubit( - secureStorageProvider: secureStorageProvider, - oidc4vc: OIDC4VC(), - didKitProvider: DIDKitProvider(), - langCubit: context.read(), - jwtDecode: JWTDecode(), + BlocProvider( + create: (context) => FlavorCubit(flavorMode), ), - ), - BlocProvider( - create: (context) { - return AdvanceSettingsCubit( - secureStorageProvider: getSecureStorage, - ); - }, - ), - BlocProvider( - create: (context) => KycVerificationCubit( - profileCubit: context.read(), - client: DioClient( + BlocProvider( + create: (context) => + LangCubit(secureStorageProvider: getSecureStorage), + ), + BlocProvider(create: (context) => RouteCubit()), + BlocProvider( + create: (context) => BeaconCubit(beacon: Beacon()), + ), + BlocProvider( + create: (context) => WalletConnectCubit( secureStorageProvider: secureStorageProvider, - dio: Dio(), + connectedDappRepository: + ConnectedDappRepository(secureStorageProvider), + routeCubit: context.read(), ), ), - ), - BlocProvider( - create: (context) => HomeCubit( - client: DioClient( - baseUrl: Urls.issuerBaseUrl, + BlocProvider(create: (context) => DeepLinkCubit()), + BlocProvider( + create: (context) => QueryByExampleCubit(), + ), + BlocProvider( + create: (context) => ProfileCubit( secureStorageProvider: secureStorageProvider, - dio: Dio(), + oidc4vc: OIDC4VC(), + didKitProvider: DIDKitProvider(), + langCubit: context.read(), + jwtDecode: JWTDecode(), ), - secureStorageProvider: secureStorageProvider, - oidc4vc: OIDC4VC(), - didKitProvider: DIDKitProvider(), - profileCubit: context.read(), ), - ), - BlocProvider( - create: (context) => OnboardingCubit(), - ), - BlocProvider( - lazy: false, - create: (context) => WalletCubit( - secureStorageProvider: secureStorageProvider, - homeCubit: context.read(), - keyGenerator: KeyGenerator(), - walletConnectCubit: context.read(), + BlocProvider( + create: (context) { + return AdvanceSettingsCubit( + secureStorageProvider: getSecureStorage, + ); + }, + ), + BlocProvider( + create: (context) => KycVerificationCubit( + profileCubit: context.read(), + client: DioClient( + secureStorageProvider: secureStorageProvider, + dio: Dio(), + ), + ), ), - ), - BlocProvider( - lazy: false, - create: (context) => CredentialsCubit( - credentialsRepository: CredentialsRepository(secureStorageProvider), - secureStorageProvider: secureStorageProvider, - keyGenerator: KeyGenerator(), - didKitProvider: DIDKitProvider(), - oidc4vc: OIDC4VC(), - advanceSettingsCubit: context.read(), - jwtDecode: JWTDecode(), - profileCubit: context.read(), - walletCubit: context.read(), + BlocProvider( + create: (context) => HomeCubit( + client: DioClient( + baseUrl: Urls.issuerBaseUrl, + secureStorageProvider: secureStorageProvider, + dio: Dio(), + ), + secureStorageProvider: secureStorageProvider, + oidc4vc: OIDC4VC(), + didKitProvider: DIDKitProvider(), + profileCubit: context.read(), + ), ), - ), - BlocProvider( - create: (context) => ManageNetworkCubit( - secureStorageProvider: secureStorageProvider, - walletCubit: context.read(), + BlocProvider( + create: (context) => OnboardingCubit(), ), - ), - BlocProvider( - create: (context) => PolygonIdCubit( - client: DioClient( + BlocProvider( + lazy: false, + create: (context) => WalletCubit( secureStorageProvider: secureStorageProvider, - dio: Dio(), + homeCubit: context.read(), + keyGenerator: KeyGenerator(), + walletConnectCubit: context.read(), ), - secureStorageProvider: secureStorageProvider, - polygonId: PolygonId(), - credentialsCubit: context.read(), - profileCubit: context.read(), - walletCubit: context.read(), ), - ), - BlocProvider( - create: (context) => EnterpriseCubit( - client: DioClient( + BlocProvider( + lazy: false, + create: (context) => CredentialsCubit( + credentialsRepository: + CredentialsRepository(secureStorageProvider), secureStorageProvider: secureStorageProvider, - dio: Dio(), + keyGenerator: KeyGenerator(), + didKitProvider: DIDKitProvider(), + oidc4vc: OIDC4VC(), + advanceSettingsCubit: context.read(), + jwtDecode: JWTDecode(), + profileCubit: context.read(), + walletCubit: context.read(), ), - profileCubit: context.read(), - credentialsCubit: context.read(), ), - ), - BlocProvider( - create: (context) => ScanCubit( - client: DioClient( - baseUrl: Urls.checkIssuerTalaoUrl, + BlocProvider( + create: (context) => ManageNetworkCubit( secureStorageProvider: secureStorageProvider, - dio: Dio(), + walletCubit: context.read(), ), - credentialsCubit: context.read(), - didKitProvider: DIDKitProvider(), - secureStorageProvider: secureStorageProvider, - profileCubit: context.read(), - walletCubit: context.read(), - oidc4vc: OIDC4VC(), - jwtDecode: JWTDecode(), ), - ), - BlocProvider( - create: (context) => QRCodeScanCubit( - client: DioClient( - baseUrl: Urls.checkIssuerTalaoUrl, + BlocProvider( + create: (context) => PolygonIdCubit( + client: DioClient( + secureStorageProvider: secureStorageProvider, + dio: Dio(), + ), secureStorageProvider: secureStorageProvider, - dio: Dio(), + polygonId: PolygonId(), + credentialsCubit: context.read(), + profileCubit: context.read(), + walletCubit: context.read(), ), - requestClient: DioClient( + ), + BlocProvider( + create: (context) => EnterpriseCubit( + client: DioClient( + secureStorageProvider: secureStorageProvider, + dio: Dio(), + ), + profileCubit: context.read(), + credentialsCubit: context.read(), + ), + ), + BlocProvider( + create: (context) => ScanCubit( + client: DioClient( + baseUrl: Urls.checkIssuerTalaoUrl, + secureStorageProvider: secureStorageProvider, + dio: Dio(), + ), + credentialsCubit: context.read(), + didKitProvider: DIDKitProvider(), secureStorageProvider: secureStorageProvider, - dio: Dio(), + profileCubit: context.read(), + walletCubit: context.read(), + oidc4vc: OIDC4VC(), + jwtDecode: JWTDecode(), ), - scanCubit: context.read(), - queryByExampleCubit: context.read(), - deepLinkCubit: context.read(), - jwtDecode: JWTDecode(), - profileCubit: context.read(), - credentialsCubit: context.read(), - beacon: Beacon(), - walletConnectCubit: context.read(), - secureStorageProvider: secureStorageProvider, - polygonIdCubit: context.read(), - didKitProvider: DIDKitProvider(), - oidc4vc: OIDC4VC(), - walletCubit: context.read(), - enterpriseCubit: context.read(), ), - ), - BlocProvider( - create: (context) => AllTokensCubit( - secureStorageProvider: secureStorageProvider, - client: DioClient( - baseUrl: Urls.coinGeckoBase, + BlocProvider( + create: (context) => QRCodeScanCubit( + client: DioClient( + baseUrl: Urls.checkIssuerTalaoUrl, + secureStorageProvider: secureStorageProvider, + dio: Dio(), + ), + requestClient: DioClient( + secureStorageProvider: secureStorageProvider, + dio: Dio(), + ), + scanCubit: context.read(), + queryByExampleCubit: context.read(), + deepLinkCubit: context.read(), + jwtDecode: JWTDecode(), + profileCubit: context.read(), + credentialsCubit: context.read(), + beacon: Beacon(), + walletConnectCubit: context.read(), secureStorageProvider: secureStorageProvider, - dio: Dio(), + polygonIdCubit: context.read(), + didKitProvider: DIDKitProvider(), + oidc4vc: OIDC4VC(), + walletCubit: context.read(), + enterpriseCubit: context.read(), ), ), - ), - BlocProvider( - create: (_) => MnemonicNeedVerificationCubit(), - ), - BlocProvider( - create: (context) => TokensCubit( - allTokensCubit: context.read(), - networkCubit: context.read(), - mnemonicNeedVerificationCubit: - context.read(), - secureStorageProvider: secureStorageProvider, - client: DioClient( - baseUrl: context.read().state.network.apiUrl, + BlocProvider( + create: (context) => AllTokensCubit( secureStorageProvider: secureStorageProvider, - dio: Dio(), + client: DioClient( + baseUrl: Urls.coinGeckoBase, + secureStorageProvider: secureStorageProvider, + dio: Dio(), + ), ), - walletCubit: context.read(), ), - ), - BlocProvider( - create: (context) => NftCubit( - client: DioClient( - baseUrl: context.read().state.network.apiUrl, + BlocProvider( + create: (_) => MnemonicNeedVerificationCubit(), + ), + BlocProvider( + create: (context) => TokensCubit( + allTokensCubit: context.read(), + networkCubit: context.read(), + mnemonicNeedVerificationCubit: + context.read(), secureStorageProvider: secureStorageProvider, - dio: Dio(), + client: DioClient( + baseUrl: + context.read().state.network.apiUrl, + secureStorageProvider: secureStorageProvider, + dio: Dio(), + ), + walletCubit: context.read(), + ), + ), + BlocProvider( + create: (context) => NftCubit( + client: DioClient( + baseUrl: + context.read().state.network.apiUrl, + secureStorageProvider: secureStorageProvider, + dio: Dio(), + ), + walletCubit: context.read(), + manageNetworkCubit: context.read(), ), - walletCubit: context.read(), - manageNetworkCubit: context.read(), ), - ), - BlocProvider( - lazy: false, - create: (context) => AltmeChatSupportCubit( - secureStorageProvider: getSecureStorage, - matrixChat: MatrixChatImpl(), - profileCubit: context.read(), + BlocProvider( + lazy: false, + create: (context) => AltmeChatSupportCubit( + secureStorageProvider: getSecureStorage, + matrixChat: MatrixChatImpl(), + profileCubit: context.read(), + ), ), - ), - BlocProvider( - create: (context) => SplashCubit( - secureStorageProvider: secureStorageProvider, - homeCubit: context.read(), - walletCubit: context.read(), - credentialsCubit: context.read(), - client: DioClient( - baseUrl: Urls.checkIssuerTalaoUrl, + BlocProvider( + create: (context) => SplashCubit( secureStorageProvider: secureStorageProvider, - dio: Dio(), + homeCubit: context.read(), + walletCubit: context.read(), + credentialsCubit: context.read(), + client: DioClient( + baseUrl: Urls.checkIssuerTalaoUrl, + secureStorageProvider: secureStorageProvider, + dio: Dio(), + ), + altmeChatSupportCubit: context.read(), + profileCubit: context.read(), ), - altmeChatSupportCubit: context.read(), - profileCubit: context.read(), ), - ), - BlocProvider(create: (context) => HomeTabbarCubit()), - ], - child: const MaterialAppDefinition(), + BlocProvider(create: (context) => HomeTabbarCubit()), + ], + child: const MaterialAppDefinition(), + ), ); } } @@ -287,20 +305,37 @@ class MaterialAppDefinition extends StatelessWidget { context.read().checkLocale(); } - return MaterialApp( - locale: state.locale, - title: 'AltMe', - darkTheme: AppTheme.darkThemeData, - navigatorObservers: [MyRouteObserver(context)], - themeMode: ThemeMode.dark, - localizationsDelegates: const [ - AppLocalizations.delegate, - GlobalMaterialLocalizations.delegate, - GlobalWidgetsLocalizations.delegate, - GlobalCupertinoLocalizations.delegate, - ], - supportedLocales: AppLocalizations.supportedLocales, - home: const SplashPage(), + return BlocBuilder( + builder: (themeContext, themeState) { + return BlocBuilder( + builder: (profileContext, profileState) { + return MaterialApp( + locale: state.locale, + title: 'AltMe', + theme: AppTheme.seedThemeData( + Brightness.light, + profileState + .model.profileSetting.generalOptions.primaryColor, + ), + darkTheme: AppTheme.seedThemeData( + Brightness.dark, + profileState + .model.profileSetting.generalOptions.primaryColor, + ), + navigatorObservers: [MyRouteObserver(context)], + themeMode: themeState.themeMode, + localizationsDelegates: const [ + AppLocalizations.delegate, + GlobalMaterialLocalizations.delegate, + GlobalWidgetsLocalizations.delegate, + GlobalCupertinoLocalizations.delegate, + ], + supportedLocales: AppLocalizations.supportedLocales, + home: const SplashPage(), + ); + }, + ); + }, ); }, ); diff --git a/lib/dashboard/discover/view/discover_tab_page.dart b/lib/dashboard/discover/view/discover_tab_page.dart index 8096c730a..9c63e0c96 100644 --- a/lib/dashboard/discover/view/discover_tab_page.dart +++ b/lib/dashboard/discover/view/discover_tab_page.dart @@ -54,6 +54,7 @@ class _DiscoverTabPageViewState extends State padding: const EdgeInsets.symmetric(horizontal: Sizes.spaceSmall), child: TabBar( + dividerColor: Colors.transparent, controller: _tabController, padding: const EdgeInsets.symmetric( horizontal: Sizes.space2XSmall, diff --git a/lib/dashboard/discover/widgets/discover_credential_category_item.dart b/lib/dashboard/discover/widgets/discover_credential_category_item.dart index 7b7679762..12647a354 100644 --- a/lib/dashboard/discover/widgets/discover_credential_category_item.dart +++ b/lib/dashboard/discover/widgets/discover_credential_category_item.dart @@ -48,7 +48,7 @@ class DiscoverCredentialCategoryItem extends StatelessWidget { credentialCategoryConfig.discoverSubTitle, maxLines: 3, style: Theme.of(context).textTheme.titleMedium!.copyWith( - color: Theme.of(context).colorScheme.secondaryContainer, + color: Theme.of(context).colorScheme.secondary, ), ), ), diff --git a/lib/dashboard/drawer/about_altme/about_altme/view/about_altme_menu.dart b/lib/dashboard/drawer/about_altme/about_altme/view/about_altme_menu.dart index ca5839bad..43df5b544 100644 --- a/lib/dashboard/drawer/about_altme/about_altme/view/about_altme_menu.dart +++ b/lib/dashboard/drawer/about_altme/about_altme/view/about_altme_menu.dart @@ -43,9 +43,8 @@ class AboutAltmeView extends StatelessWidget { body: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ - BackLeadingButton( + const BackLeadingButton( padding: EdgeInsets.zero, - color: Theme.of(context).colorScheme.onPrimary, ), const DrawerLogo(), const AppVersionDrawer(), diff --git a/lib/dashboard/drawer/blockchain_settings/blockchain_settings/view/blockchain_settings_menu.dart b/lib/dashboard/drawer/blockchain_settings/blockchain_settings/view/blockchain_settings_menu.dart index 0aca6d109..6f36a6648 100644 --- a/lib/dashboard/drawer/blockchain_settings/blockchain_settings/view/blockchain_settings_menu.dart +++ b/lib/dashboard/drawer/blockchain_settings/blockchain_settings/view/blockchain_settings_menu.dart @@ -36,9 +36,8 @@ class BlockchainSettingsView extends StatelessWidget { body: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ - BackLeadingButton( + const BackLeadingButton( padding: EdgeInsets.zero, - color: Theme.of(context).colorScheme.onPrimary, ), const DrawerLogo(), DrawerItem( diff --git a/lib/dashboard/drawer/help_center/help_center/view/help_center_menu.dart b/lib/dashboard/drawer/help_center/help_center/view/help_center_menu.dart index b2db6592f..956294a55 100644 --- a/lib/dashboard/drawer/help_center/help_center/view/help_center_menu.dart +++ b/lib/dashboard/drawer/help_center/help_center/view/help_center_menu.dart @@ -66,9 +66,8 @@ class HelpCenterView extends StatelessWidget { body: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ - BackLeadingButton( + const BackLeadingButton( padding: EdgeInsets.zero, - color: Theme.of(context).colorScheme.onPrimary, ), const DrawerLogo(), if (helpCenterOptions.displayChatSupport) ...[ diff --git a/lib/dashboard/drawer/profile/view/pick_profile_menu.dart b/lib/dashboard/drawer/profile/view/pick_profile_menu.dart index dd49a8857..3fa0e7900 100644 --- a/lib/dashboard/drawer/profile/view/pick_profile_menu.dart +++ b/lib/dashboard/drawer/profile/view/pick_profile_menu.dart @@ -31,15 +31,14 @@ class PickProfileMenuView extends StatelessWidget { scrollView: true, titleAlignment: Alignment.topCenter, padding: const EdgeInsets.symmetric(horizontal: Sizes.spaceSmall), - body: Column( + body: const Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ BackLeadingButton( padding: EdgeInsets.zero, - color: Theme.of(context).colorScheme.onPrimary, ), - const DrawerLogo(), - const ProfileSelectorWidget(), + DrawerLogo(), + ProfileSelectorWidget(), ], ), ); diff --git a/lib/dashboard/drawer/profile/widget/profile_selector_widget.dart b/lib/dashboard/drawer/profile/widget/profile_selector_widget.dart index cdb21a765..3dcca9c6b 100644 --- a/lib/dashboard/drawer/profile/widget/profile_selector_widget.dart +++ b/lib/dashboard/drawer/profile/widget/profile_selector_widget.dart @@ -104,20 +104,14 @@ class ProfileSelectorWidget extends StatelessWidget { l10n: l10n, name: profile.enterpriseWalletName ?? '', ), - style: Theme.of(context) - .textTheme - .bodyLarge - ?.copyWith( - color: - Theme.of(context).colorScheme.onPrimary, - ), + style: Theme.of(context).textTheme.bodyLarge, ), trailing: Icon( state.model.profileType == profileType ? Icons.radio_button_checked : Icons.radio_button_unchecked, size: Sizes.icon2x, - color: Theme.of(context).colorScheme.onPrimary, + color: Theme.of(context).colorScheme.primary, ), ), ], diff --git a/lib/dashboard/drawer/src/view/check_linkedin_profile.dart b/lib/dashboard/drawer/src/view/check_linkedin_profile.dart index 841c0439d..5661d5f6e 100644 --- a/lib/dashboard/drawer/src/view/check_linkedin_profile.dart +++ b/lib/dashboard/drawer/src/view/check_linkedin_profile.dart @@ -37,9 +37,8 @@ class CheckForLinkedInProfileView extends StatelessWidget { child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ - BackLeadingButton( + const BackLeadingButton( padding: EdgeInsets.zero, - color: Theme.of(context).colorScheme.onPrimary, ), WalletLogo( profileModel: context.read().state.model, diff --git a/lib/dashboard/drawer/src/view/drawer_page.dart b/lib/dashboard/drawer/src/view/drawer_page.dart index ac0b8af75..172a303e3 100644 --- a/lib/dashboard/drawer/src/view/drawer_page.dart +++ b/lib/dashboard/drawer/src/view/drawer_page.dart @@ -43,15 +43,12 @@ class DrawerView extends StatelessWidget { child: SafeArea( child: Padding( padding: const EdgeInsets.symmetric(horizontal: 15), - child: SingleChildScrollView( - child: Column( - children: [ - Align( - alignment: Alignment.topLeft, - child: BackLeadingButton( - padding: EdgeInsets.zero, - color: Theme.of(context).colorScheme.onPrimary, - ), + child: ListView( + children: [ + const Align( + alignment: Alignment.topLeft, + child: BackLeadingButton( + padding: EdgeInsets.zero, ), const DrawerLogo(), diff --git a/lib/dashboard/drawer/src/widgets/drawer_category_item.dart b/lib/dashboard/drawer/src/widgets/drawer_category_item.dart index 9e1a8c28d..7a05a8d6a 100644 --- a/lib/dashboard/drawer/src/widgets/drawer_category_item.dart +++ b/lib/dashboard/drawer/src/widgets/drawer_category_item.dart @@ -25,7 +25,7 @@ class DrawerCategoryItem extends StatelessWidget { child: Container( padding: padding, decoration: BoxDecoration( - color: Theme.of(context).colorScheme.surfaceBright, + color: Theme.of(context).colorScheme.secondaryContainer, borderRadius: const BorderRadius.all( Radius.circular(Sizes.normalRadius), ), @@ -39,7 +39,7 @@ class DrawerCategoryItem extends StatelessWidget { children: [ Text( title, - style: Theme.of(context).textTheme.headlineSmall, + style: Theme.of(context).textTheme.titleLarge, ), if (subTitle != null) ...[ const SizedBox(height: Sizes.space2XSmall), diff --git a/lib/dashboard/drawer/src/widgets/drawer_item.dart b/lib/dashboard/drawer/src/widgets/drawer_item.dart index 2dc081ca7..6acad3b22 100644 --- a/lib/dashboard/drawer/src/widgets/drawer_item.dart +++ b/lib/dashboard/drawer/src/widgets/drawer_item.dart @@ -26,7 +26,7 @@ class DrawerItem extends StatelessWidget { padding: const EdgeInsets.all(Sizes.spaceNormal), margin: const EdgeInsets.all(Sizes.spaceXSmall), decoration: BoxDecoration( - color: Theme.of(context).colorScheme.surfaceBright, + color: Theme.of(context).colorScheme.secondaryContainer, borderRadius: const BorderRadius.all( Radius.circular( Sizes.normalRadius, diff --git a/lib/dashboard/drawer/ssi/backup/src/view/backup_menu.dart b/lib/dashboard/drawer/ssi/backup/src/view/backup_menu.dart index 5b144597f..780ddff33 100644 --- a/lib/dashboard/drawer/ssi/backup/src/view/backup_menu.dart +++ b/lib/dashboard/drawer/ssi/backup/src/view/backup_menu.dart @@ -35,9 +35,8 @@ class BackupView extends StatelessWidget { child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ - BackLeadingButton( + const BackLeadingButton( padding: EdgeInsets.zero, - color: Theme.of(context).colorScheme.onPrimary, ), WalletLogo( profileModel: context.read().state.model, diff --git a/lib/dashboard/drawer/ssi/manage_did/view/did_menu.dart b/lib/dashboard/drawer/ssi/manage_did/view/did_menu.dart index 20865d7bf..efc1204d5 100644 --- a/lib/dashboard/drawer/ssi/manage_did/view/did_menu.dart +++ b/lib/dashboard/drawer/ssi/manage_did/view/did_menu.dart @@ -36,9 +36,8 @@ class DidView extends StatelessWidget { child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ - BackLeadingButton( + const BackLeadingButton( padding: EdgeInsets.zero, - color: Theme.of(context).colorScheme.onPrimary, ), WalletLogo( profileModel: context.read().state.model, diff --git a/lib/dashboard/drawer/ssi/restore/src/view/restore_menu.dart b/lib/dashboard/drawer/ssi/restore/src/view/restore_menu.dart index 50d34bc43..c3bdd7a8f 100644 --- a/lib/dashboard/drawer/ssi/restore/src/view/restore_menu.dart +++ b/lib/dashboard/drawer/ssi/restore/src/view/restore_menu.dart @@ -35,9 +35,8 @@ class RestoreView extends StatelessWidget { child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ - BackLeadingButton( + const BackLeadingButton( padding: EdgeInsets.zero, - color: Theme.of(context).colorScheme.onPrimary, ), WalletLogo( profileModel: context.read().state.model, diff --git a/lib/dashboard/drawer/ssi/src/view/ssi_menu.dart b/lib/dashboard/drawer/ssi/src/view/ssi_menu.dart index 76f95e041..1745f4584 100644 --- a/lib/dashboard/drawer/ssi/src/view/ssi_menu.dart +++ b/lib/dashboard/drawer/ssi/src/view/ssi_menu.dart @@ -44,9 +44,8 @@ class SSIView extends StatelessWidget { body: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ - BackLeadingButton( + const BackLeadingButton( padding: EdgeInsets.zero, - color: Theme.of(context).colorScheme.onPrimary, ), const DrawerLogo(), if (displayManageDecentralizedId) diff --git a/lib/dashboard/drawer/wallet_security/advanced_security_settings/view/advanced_security_settings_menu.dart b/lib/dashboard/drawer/wallet_security/advanced_security_settings/view/advanced_security_settings_menu.dart index f53bbd2c6..8b8fd1655 100644 --- a/lib/dashboard/drawer/wallet_security/advanced_security_settings/view/advanced_security_settings_menu.dart +++ b/lib/dashboard/drawer/wallet_security/advanced_security_settings/view/advanced_security_settings_menu.dart @@ -37,9 +37,8 @@ class AdvancedSecuritySettingsView extends StatelessWidget { child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ - BackLeadingButton( + const BackLeadingButton( padding: EdgeInsets.zero, - color: Theme.of(context).colorScheme.onPrimary, ), WalletLogo( profileModel: context.read().state.model, diff --git a/lib/dashboard/drawer/wallet_security/src/view/wallet_security_menu.dart b/lib/dashboard/drawer/wallet_security/src/view/wallet_security_menu.dart index df5275e3d..e7669f557 100644 --- a/lib/dashboard/drawer/wallet_security/src/view/wallet_security_menu.dart +++ b/lib/dashboard/drawer/wallet_security/src/view/wallet_security_menu.dart @@ -39,9 +39,8 @@ class WalletSecurityView extends StatelessWidget { body: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ - BackLeadingButton( + const BackLeadingButton( padding: EdgeInsets.zero, - color: Theme.of(context).colorScheme.onPrimary, ), const DrawerLogo(), DrawerItem( diff --git a/lib/dashboard/drawer/wallet_settings/view/language_settings.dart b/lib/dashboard/drawer/wallet_settings/view/language_settings.dart new file mode 100644 index 000000000..ff7df7040 --- /dev/null +++ b/lib/dashboard/drawer/wallet_settings/view/language_settings.dart @@ -0,0 +1,44 @@ +import 'package:altme/app/app.dart'; +import 'package:altme/dashboard/dashboard.dart'; +import 'package:flutter/material.dart'; + +class LanguageSettings extends StatelessWidget { + const LanguageSettings({super.key}); + + static Route route() { + return MaterialPageRoute( + settings: const RouteSettings(name: '/LanguageSettings'), + builder: (_) => const LanguageSettings(), + ); + } + + @override + Widget build(BuildContext context) { + return const WalletSettingsMenuView(); + } +} + +class WalletSettingsMenuView extends StatelessWidget { + const WalletSettingsMenuView({super.key}); + + @override + Widget build(BuildContext context) { + return BasePage( + backgroundColor: Theme.of(context).colorScheme.surface, + useSafeArea: true, + scrollView: true, + titleAlignment: Alignment.topCenter, + padding: const EdgeInsets.symmetric(horizontal: Sizes.spaceSmall), + body: const Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + BackLeadingButton( + padding: EdgeInsets.zero, + ), + DrawerLogo(), + LanguageSelectorWidget(), + ], + ), + ); + } +} diff --git a/lib/dashboard/drawer/wallet_settings/view/theme_settings.dart b/lib/dashboard/drawer/wallet_settings/view/theme_settings.dart new file mode 100644 index 000000000..b30d65f13 --- /dev/null +++ b/lib/dashboard/drawer/wallet_settings/view/theme_settings.dart @@ -0,0 +1,45 @@ +import 'package:altme/app/app.dart'; +import 'package:altme/dashboard/dashboard.dart'; +import 'package:altme/dashboard/drawer/wallet_settings/widget/theme_selector_widget.dart'; +import 'package:flutter/material.dart'; + +class ThemeSettings extends StatelessWidget { + const ThemeSettings({super.key}); + + static Route route() { + return MaterialPageRoute( + settings: const RouteSettings(name: '/ThemeSettings'), + builder: (_) => const ThemeSettings(), + ); + } + + @override + Widget build(BuildContext context) { + return const WalletSettingsMenuView(); + } +} + +class WalletSettingsMenuView extends StatelessWidget { + const WalletSettingsMenuView({super.key}); + + @override + Widget build(BuildContext context) { + return BasePage( + backgroundColor: Theme.of(context).colorScheme.surface, + useSafeArea: true, + scrollView: true, + titleAlignment: Alignment.topCenter, + padding: const EdgeInsets.symmetric(horizontal: Sizes.spaceSmall), + body: const Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + BackLeadingButton( + padding: EdgeInsets.zero, + ), + DrawerLogo(), + ThemeSelectorWidget(), + ], + ), + ); + } +} diff --git a/lib/dashboard/drawer/wallet_settings/view/wallet_settings_menu.dart b/lib/dashboard/drawer/wallet_settings/view/wallet_settings_menu.dart index d119899a3..e0e397ce7 100644 --- a/lib/dashboard/drawer/wallet_settings/view/wallet_settings_menu.dart +++ b/lib/dashboard/drawer/wallet_settings/view/wallet_settings_menu.dart @@ -1,5 +1,8 @@ import 'package:altme/app/app.dart'; import 'package:altme/dashboard/dashboard.dart'; +import 'package:altme/dashboard/drawer/wallet_settings/view/language_settings.dart'; +import 'package:altme/dashboard/drawer/wallet_settings/view/theme_settings.dart'; +import 'package:altme/l10n/l10n.dart'; import 'package:flutter/material.dart'; class WalletSettingsMenu extends StatelessWidget { @@ -7,7 +10,7 @@ class WalletSettingsMenu extends StatelessWidget { static Route route() { return MaterialPageRoute( - settings: const RouteSettings(name: '/WalletSettingsMenu'), + settings: const RouteSettings(name: '/LanguageSettings'), builder: (_) => const WalletSettingsMenu(), ); } @@ -23,6 +26,8 @@ class WalletSettingsMenuView extends StatelessWidget { @override Widget build(BuildContext context) { + final l10n = context.l10n; + return BasePage( backgroundColor: Theme.of(context).colorScheme.surface, useSafeArea: true, @@ -32,12 +37,24 @@ class WalletSettingsMenuView extends StatelessWidget { body: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ - BackLeadingButton( + const BackLeadingButton( padding: EdgeInsets.zero, - color: Theme.of(context).colorScheme.onPrimary, ), const DrawerLogo(), - const LanguageSelectorWidget(), + DrawerItem( + title: l10n.languageSettings, + subtitle: l10n.languageSettingsDescription, + onTap: () async { + await Navigator.of(context).push(LanguageSettings.route()); + }, + ), + DrawerItem( + title: l10n.themeSettings, + subtitle: l10n.themeSettingsDescription, + onTap: () async { + await Navigator.of(context).push(ThemeSettings.route()); + }, + ), ], ), ); diff --git a/lib/dashboard/drawer/wallet_settings/widget/language_selector_widget.dart b/lib/dashboard/drawer/wallet_settings/widget/language_selector_widget.dart index 06cda769c..f3ca26f69 100644 --- a/lib/dashboard/drawer/wallet_settings/widget/language_selector_widget.dart +++ b/lib/dashboard/drawer/wallet_settings/widget/language_selector_widget.dart @@ -38,7 +38,7 @@ class LanguageSelectorWidget extends StatelessWidget { crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( - l10n.walletSettingsDescription, + l10n.languageSettingsDescription, style: Theme.of(context).textTheme.titleMedium, ), ], @@ -87,17 +87,13 @@ class LanguageSelectorWidget extends StatelessWidget { style: Theme.of(context) .textTheme .bodyLarge - ?.copyWith( - color: - Theme.of(context).colorScheme.onPrimary, - ), ), trailing: Icon( state.languageType == languageType ? Icons.radio_button_checked : Icons.radio_button_unchecked, size: Sizes.icon2x, - color: Theme.of(context).colorScheme.onPrimary, + color: Theme.of(context).colorScheme.primary, ), ), ], diff --git a/lib/dashboard/drawer/wallet_settings/widget/theme_selector_widget.dart b/lib/dashboard/drawer/wallet_settings/widget/theme_selector_widget.dart new file mode 100644 index 000000000..8d4fb4e13 --- /dev/null +++ b/lib/dashboard/drawer/wallet_settings/widget/theme_selector_widget.dart @@ -0,0 +1,115 @@ +import 'package:altme/app/app.dart'; +import 'package:altme/l10n/l10n.dart'; +import 'package:altme/lang/cubit/lang_cubit.dart'; +import 'package:altme/lang/cubit/lang_state.dart'; +import 'package:altme/theme/theme_cubit.dart'; + +import 'package:flutter/material.dart'; +import 'package:flutter_bloc/flutter_bloc.dart'; + +class ThemeSelectorWidget extends StatelessWidget { + const ThemeSelectorWidget({super.key}); + + @override + Widget build(BuildContext context) { + final l10n = context.l10n; + return BlocBuilder( + builder: (context, state) { + return Column( + crossAxisAlignment: CrossAxisAlignment.stretch, + mainAxisSize: MainAxisSize.max, + children: [ + Container( + padding: const EdgeInsets.all(Sizes.spaceSmall), + margin: const EdgeInsets.all(Sizes.spaceXSmall), + decoration: BoxDecoration( + color: Theme.of(context).colorScheme.surface, + borderRadius: const BorderRadius.all( + Radius.circular(Sizes.largeRadius), + ), + ), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + const SizedBox(height: 10), + Padding( + padding: const EdgeInsets.symmetric(horizontal: 10), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + l10n.themeSettingsDescription, + style: Theme.of(context).textTheme.titleMedium, + ), + ], + ), + ), + const SizedBox(height: 10), + ListView( + shrinkWrap: true, + physics: const ScrollPhysics(), + padding: EdgeInsets.zero, + children: [ + ThemeModeLine( + label: l10n.darkThemeText, + themeMode: ThemeMode.dark, + ), + ThemeModeLine( + label: l10n.lightThemeText, + themeMode: ThemeMode.light, + ), + ThemeModeLine( + label: l10n.systemThemeText, + themeMode: ThemeMode.system, + ), + ], + ), + ], + ), + ), + ], + ); + }, + ); + } +} + +class ThemeModeLine extends StatelessWidget { + const ThemeModeLine({ + super.key, + required this.label, + required this.themeMode, + }); + final String label; + final ThemeMode themeMode; + + @override + Widget build(BuildContext context) { + return ListTile( + onTap: () async { + context.read().switchTheme(themeMode); + }, + shape: const RoundedRectangleBorder( + side: BorderSide( + color: Color(0xFFDDDDEE), + width: 0.5, + ), + ), + title: Text( + label, + style: Theme.of(context).textTheme.bodyLarge, + ), + trailing: BlocBuilder( + builder: (context, state) { + return Icon( + state.themeMode == themeMode + ? Icons.radio_button_checked + : Icons.radio_button_unchecked, + size: Sizes.icon2x, + color: Theme.of(context).colorScheme.primary, + ); + }, + ), + ); + } +} diff --git a/lib/dashboard/home/tab_bar/tab_controller/view/tab_controller_page.dart b/lib/dashboard/home/tab_bar/tab_controller/view/tab_controller_page.dart index f0c4bc8ea..b89f20b2b 100644 --- a/lib/dashboard/home/tab_bar/tab_controller/view/tab_controller_page.dart +++ b/lib/dashboard/home/tab_bar/tab_controller/view/tab_controller_page.dart @@ -50,6 +50,7 @@ class _TabControllerViewState extends State Padding( padding: const EdgeInsets.symmetric(horizontal: Sizes.spaceSmall), child: TabBar( + dividerColor: Colors.transparent, controller: _tabController, padding: const EdgeInsets.symmetric( horizontal: Sizes.space2XSmall, diff --git a/lib/dashboard/home/tab_bar/tab_controller/widgets/tab_bar.dart b/lib/dashboard/home/tab_bar/tab_controller/widgets/tab_bar.dart index 3f3b82dd6..6ff2f7e73 100644 --- a/lib/dashboard/home/tab_bar/tab_controller/widgets/tab_bar.dart +++ b/lib/dashboard/home/tab_bar/tab_controller/widgets/tab_bar.dart @@ -48,7 +48,16 @@ class MyTab extends StatelessWidget { mainAxisAlignment: MainAxisAlignment.center, crossAxisAlignment: CrossAxisAlignment.center, children: [ - Image.asset(icon, height: Sizes.icon), + if (isSelected) + ColorFiltered( + colorFilter: ColorFilter.mode( + Theme.of(context).colorScheme.primary, + BlendMode.color, + ), + child: Image.asset(icon, height: Sizes.icon), + ) + else + Image.asset(icon, height: Sizes.icon), const SizedBox( width: Sizes.spaceXSmall, ), diff --git a/lib/dashboard/profile/models/profile_setting.dart b/lib/dashboard/profile/models/profile_setting.dart index 95b0751c4..308dec7d8 100644 --- a/lib/dashboard/profile/models/profile_setting.dart +++ b/lib/dashboard/profile/models/profile_setting.dart @@ -349,6 +349,7 @@ class GeneralOptions extends Equatable { required this.published, required this.profileId, required this.customerPlan, + required this.primaryColor, }); factory GeneralOptions.fromJson(Map json) => @@ -366,6 +367,7 @@ class GeneralOptions extends Equatable { published: DateTime.now(), profileId: '', customerPlan: '', + primaryColor: '', ); final WalletAppType walletType; @@ -379,6 +381,7 @@ class GeneralOptions extends Equatable { final DateTime published; final String profileId; final String customerPlan; + final String primaryColor; Map toJson() => _$GeneralOptionsToJson(this); @@ -394,6 +397,7 @@ class GeneralOptions extends Equatable { DateTime? published, String? profileId, String? customerPlan, + String? primaryColor, }) { return GeneralOptions( walletType: walletType ?? this.walletType, @@ -407,6 +411,7 @@ class GeneralOptions extends Equatable { published: published ?? this.published, profileId: profileId ?? this.profileId, customerPlan: customerPlan ?? this.customerPlan, + primaryColor: primaryColor ?? this.primaryColor, ); } @@ -423,6 +428,7 @@ class GeneralOptions extends Equatable { published, profileId, customerPlan, + primaryColor, ]; } @@ -570,9 +576,8 @@ class CustomOidc4VcProfile extends Equatable { @JsonKey(name: 'client_secret') final String? clientSecret; final bool cryptoHolderBinding; - final DidKeyType - defaultDid; - // TODO(bibash): temporary solution to avoid who have chosen 12 + final DidKeyType defaultDid; + // TODO(bibash): temporary solution to avoid who have chosen 12 @JsonKey( includeFromJson: true, fromJson: oidc4vciDraftFromJson, diff --git a/lib/dashboard/src/view/dashboard_page.dart b/lib/dashboard/src/view/dashboard_page.dart index d59d7496b..9e0bb9fac 100644 --- a/lib/dashboard/src/view/dashboard_page.dart +++ b/lib/dashboard/src/view/dashboard_page.dart @@ -165,7 +165,7 @@ class _DashboardViewState extends State { canPop: false, onPopInvoked: (_) async { if (scaffoldKey.currentState!.isDrawerOpen) { - Navigator.of(context).pop(); + // Navigator.of(context).pop(); } }, child: BasePage( diff --git a/lib/dashboard/src/widgets/bottom_bar_item.dart b/lib/dashboard/src/widgets/bottom_bar_item.dart index 6c932b422..3c82738fa 100644 --- a/lib/dashboard/src/widgets/bottom_bar_item.dart +++ b/lib/dashboard/src/widgets/bottom_bar_item.dart @@ -39,11 +39,8 @@ class BottomBarItem extends StatelessWidget { child: ImageIcon( AssetImage(icon), color: isSelected - ? Theme.of(context).colorScheme.onPrimary - : Theme.of(context) - .colorScheme - .onSurface - .withOpacity(0.6), + ? Theme.of(context).colorScheme.primary + : Theme.of(context).colorScheme.onPrimaryContainer, size: 20, ), ), @@ -53,12 +50,11 @@ class BottomBarItem extends StatelessWidget { softWrap: false, overflow: TextOverflow.fade, style: Theme.of(context).textTheme.bodySmall!.copyWith( + fontWeight: + isSelected ? FontWeight.bold : FontWeight.normal, color: isSelected - ? Theme.of(context).colorScheme.onPrimary - : Theme.of(context) - .colorScheme - .onSurface - .withOpacity(0.6), + ? Theme.of(context).colorScheme.primary + : Theme.of(context).colorScheme.onPrimaryContainer, ), ), ], diff --git a/lib/l10n/arb/app_en.arb b/lib/l10n/arb/app_en.arb index e6f2c67b9..b1ae1f5ac 100644 --- a/lib/l10n/arb/app_en.arb +++ b/lib/l10n/arb/app_en.arb @@ -1034,7 +1034,7 @@ "proofTypeSubtitle": "Default: jwt\nSelect one of the proof type.", "thisWalleIsAlreadyConfigured": "This wallet is already configured", "walletSettings": "Wallet Settings", - "walletSettingsDescription": "Choose your language", + "walletSettingsDescription": "Choose your language and theme", "languageSelectorTitle": "Language", "french": "Français", "spanish": "Español", @@ -1075,5 +1075,13 @@ "count": {}, "plural": {} } - } + }, + "languageSettings": "Language Settings", + "languageSettingsDescription": "Choose your language", + "themeSettings": "Theme Settings", + "themeSettingsDescription": "Choose your theme", + "darkThemeText": "Dark Theme", + "lightThemeText": "Light Theme", + "systemThemeText": "Phone Theme" + } diff --git a/lib/l10n/untranslated.json b/lib/l10n/untranslated.json index f3ccf8ad7..44852abd9 100644 --- a/lib/l10n/untranslated.json +++ b/lib/l10n/untranslated.json @@ -14,7 +14,11 @@ "pincodeSerie", "pincodeSequence", "pincodeDifferent", - "codeSecretIncorrectDescription" + "codeSecretIncorrectDescription", + "languageSettings", + "languageSettingsDescription", + "themeSettings", + "themeSettingsDescription" ], "es": [ @@ -32,7 +36,11 @@ "pincodeSerie", "pincodeSequence", "pincodeDifferent", - "codeSecretIncorrectDescription" + "codeSecretIncorrectDescription", + "languageSettings", + "languageSettingsDescription", + "themeSettings", + "themeSettingsDescription" ], "fr": [ @@ -63,6 +71,10 @@ "pincodeSerie", "pincodeSequence", "pincodeDifferent", - "codeSecretIncorrectDescription" + "codeSecretIncorrectDescription", + "languageSettings", + "languageSettingsDescription", + "themeSettings", + "themeSettingsDescription" ] } diff --git a/lib/main.dart b/lib/main.dart index aa2914187..0b966a60e 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -7,7 +7,24 @@ import 'package:altme/app/app.dart'; import 'package:altme/bootstrap.dart'; +import 'package:altme/theme/theme_repository.dart'; +import 'package:flutter/material.dart'; +import 'package:shared_preferences/shared_preferences.dart'; -void main() { - bootstrap(() => const App(flavorMode: FlavorMode.production)); +Future main() async { + // required when using any plugin. In our case, it's shared_preferences + WidgetsFlutterBinding.ensureInitialized(); + + // Creating an instance of ThemeRepository that will invoke the _init() method + // and populate the stream controller in the repository. + final themeRepository = ThemeRepository( + sharedPreferences: await SharedPreferences.getInstance(), + ); + + await bootstrap( + () => App( + flavorMode: FlavorMode.production, + themeRepository: themeRepository, + ), + ); } diff --git a/lib/main_development.dart b/lib/main_development.dart index db5b7eb29..f7191eee6 100644 --- a/lib/main_development.dart +++ b/lib/main_development.dart @@ -7,7 +7,24 @@ import 'package:altme/app/app.dart'; import 'package:altme/bootstrap.dart'; +import 'package:altme/theme/theme_repository.dart'; +import 'package:flutter/material.dart'; +import 'package:shared_preferences/shared_preferences.dart'; -void main() { - bootstrap(() => const App(flavorMode: FlavorMode.development)); +Future main() async { + // required when using any plugin. In our case, it's shared_preferences + WidgetsFlutterBinding.ensureInitialized(); + + // Creating an instance of ThemeRepository that will invoke the _init() method + // and populate the stream controller in the repository. + final themeRepository = ThemeRepository( + sharedPreferences: await SharedPreferences.getInstance(), + ); + + await bootstrap( + () => App( + flavorMode: FlavorMode.development, + themeRepository: themeRepository, + ), + ); } diff --git a/lib/main_production.dart b/lib/main_production.dart index aa2914187..0b966a60e 100644 --- a/lib/main_production.dart +++ b/lib/main_production.dart @@ -7,7 +7,24 @@ import 'package:altme/app/app.dart'; import 'package:altme/bootstrap.dart'; +import 'package:altme/theme/theme_repository.dart'; +import 'package:flutter/material.dart'; +import 'package:shared_preferences/shared_preferences.dart'; -void main() { - bootstrap(() => const App(flavorMode: FlavorMode.production)); +Future main() async { + // required when using any plugin. In our case, it's shared_preferences + WidgetsFlutterBinding.ensureInitialized(); + + // Creating an instance of ThemeRepository that will invoke the _init() method + // and populate the stream controller in the repository. + final themeRepository = ThemeRepository( + sharedPreferences: await SharedPreferences.getInstance(), + ); + + await bootstrap( + () => App( + flavorMode: FlavorMode.production, + themeRepository: themeRepository, + ), + ); } diff --git a/lib/main_staging.dart b/lib/main_staging.dart index 86ac92700..6eeca15b5 100644 --- a/lib/main_staging.dart +++ b/lib/main_staging.dart @@ -7,11 +7,24 @@ import 'package:altme/app/app.dart'; import 'package:altme/bootstrap.dart'; +import 'package:altme/theme/theme_repository.dart'; +import 'package:flutter/material.dart'; +import 'package:shared_preferences/shared_preferences.dart'; -void main() { - bootstrap( - () => const App( +Future main() async { + // required when using any plugin. In our case, it's shared_preferences + WidgetsFlutterBinding.ensureInitialized(); + + // Creating an instance of ThemeRepository that will invoke the _init() method + // and populate the stream controller in the repository. + final themeRepository = ThemeRepository( + sharedPreferences: await SharedPreferences.getInstance(), + ); + + await bootstrap( + () => App( flavorMode: FlavorMode.staging, + themeRepository: themeRepository, ), ); } diff --git a/lib/onboarding/verify_phrase/view/onboarding_verify_phrase.dart b/lib/onboarding/verify_phrase/view/onboarding_verify_phrase.dart index a7fd2db43..5841d50ef 100644 --- a/lib/onboarding/verify_phrase/view/onboarding_verify_phrase.dart +++ b/lib/onboarding/verify_phrase/view/onboarding_verify_phrase.dart @@ -184,7 +184,8 @@ class _OnBoardingVerifyPhraseViewState widget.mnemonic[col1Mnemonics.order - 1], showOrder: col1Mnemonics.mnemonicStatus.showOrder, - color: col1Mnemonics.mnemonicStatus.color, + color: col1Mnemonics.mnemonicStatus + .color(context), onTap: () { widget.onBoardingVerifyPhraseCubit.verify( mnemonic: widget.mnemonic, @@ -202,7 +203,8 @@ class _OnBoardingVerifyPhraseViewState widget.mnemonic[col2Mnemonics.order - 1], showOrder: col2Mnemonics.mnemonicStatus.showOrder, - color: col2Mnemonics.mnemonicStatus.color, + color: col2Mnemonics.mnemonicStatus + .color(context), onTap: () { widget.onBoardingVerifyPhraseCubit.verify( mnemonic: widget.mnemonic, @@ -220,7 +222,8 @@ class _OnBoardingVerifyPhraseViewState widget.mnemonic[col3Mnemonics.order - 1], showOrder: col3Mnemonics.mnemonicStatus.showOrder, - color: col3Mnemonics.mnemonicStatus.color, + color: col3Mnemonics.mnemonicStatus + .color(context), onTap: () { widget.onBoardingVerifyPhraseCubit.verify( mnemonic: widget.mnemonic, diff --git a/lib/pin_code/widgets/circle_ui_config.dart b/lib/pin_code/widgets/circle_ui_config.dart index 190f80d75..9306f2e75 100644 --- a/lib/pin_code/widgets/circle_ui_config.dart +++ b/lib/pin_code/widgets/circle_ui_config.dart @@ -3,16 +3,14 @@ import 'package:flutter/material.dart'; @immutable class CircleUIConfig { const CircleUIConfig({ - this.borderColor = Colors.white, + this.borderColor, this.borderWidth = 1.5, - this.fillColor = const Color(0xFF6600FF), - this.defaultColor = Colors.white, + this.fillColor, this.circleSize = 22, }); - final Color borderColor; - final Color fillColor; - final Color defaultColor; + final Color? borderColor; + final Color? fillColor; final double borderWidth; final double circleSize; } @@ -33,21 +31,25 @@ class Circle extends StatelessWidget { @override Widget build(BuildContext context) { + final fillColor = + circleUIConfig.fillColor ?? Theme.of(context).colorScheme.primary; + final borderColor = + circleUIConfig.borderColor ?? Theme.of(context).colorScheme.onPrimary; return Container( margin: EdgeInsets.only(bottom: extraSize), width: circleUIConfig.circleSize, height: circleUIConfig.circleSize, decoration: BoxDecoration( - color: filled ? circleUIConfig.fillColor : null, + color: filled ? fillColor : null, shape: BoxShape.circle, border: Border.all( color: filled ? allowAction - ? circleUIConfig.fillColor - : circleUIConfig.fillColor.withOpacity(0.1) + ? fillColor + : fillColor.withOpacity(0.1) : allowAction - ? circleUIConfig.borderColor - : circleUIConfig.borderColor.withOpacity(0.1), + ? borderColor + : borderColor.withOpacity(0.1), width: circleUIConfig.borderWidth, ), ), diff --git a/lib/theme/app_theme/app_theme.dart b/lib/theme/app_theme/app_theme.dart index 2d674b168..4fcd52c1d 100644 --- a/lib/theme/app_theme/app_theme.dart +++ b/lib/theme/app_theme/app_theme.dart @@ -1,11 +1,11 @@ import 'package:flutter/material.dart'; import 'package:google_fonts/google_fonts.dart'; -abstract class AppTheme { - static ThemeData get darkThemeData { +class AppTheme { + static ThemeData defaultThemeData(Brightness brightness) { final theme = ThemeData( useMaterial3: true, - brightness: Brightness.dark, + brightness: brightness, dividerColor: const Color(0xFF605A71), highlightColor: const Color(0xFF36334E), colorScheme: ColorScheme( @@ -18,14 +18,18 @@ abstract class AppTheme { onSecondary: const Color(0xffFFFFFF), tertiary: const Color(0xff18ACFF), onTertiary: const Color(0xffD1CCE3), - surface: const Color(0xff0B0514), - onSurface: const Color(0xffEDEAF5), + surface: brightness == Brightness.dark + ? const Color(0xff0B0514) + : const Color(0xffEDEAF5), + onSurface: brightness == Brightness.light + ? const Color(0xff0B0514) + : const Color(0xffEDEAF5), error: const Color(0xffcf6679), onError: Colors.black, shadow: const Color(0xff1D1D1D).withOpacity(0.1), surfaceBright: const Color(0xff232630), surfaceDim: const Color(0xff271C38), - brightness: Brightness.dark, + brightness: brightness, ), // textTheme: GoogleFonts.nunitoTextTheme(), iconTheme: const IconThemeData(color: Color(0xff6600FF)), @@ -37,10 +41,37 @@ abstract class AppTheme { fontWeight: FontWeight.w400, ), ), - tabBarTheme: const TabBarTheme(dividerColor: Colors.transparent), + tabBarTheme: const TabBarTheme(), ); return theme.copyWith( textTheme: GoogleFonts.nunitoTextTheme(theme.textTheme), ); } + + static ThemeData seedThemeData(Brightness brightness, String primaryColor) { + if (primaryColor.startsWith('#')) { + final seedColor = Color( + int.parse(primaryColor.substring(1, 7), radix: 16) + 0xFF000000, + ); + final theme = ThemeData( + useMaterial3: true, + brightness: brightness, + snackBarTheme: SnackBarThemeData( + contentTextStyle: GoogleFonts.roboto( + fontSize: 12, + fontWeight: FontWeight.w400, + ), + ), + tabBarTheme: const TabBarTheme(dividerColor: Colors.transparent), + ); + return theme.copyWith( + textTheme: GoogleFonts.robotoTextTheme(theme.textTheme), + colorScheme: ColorScheme.fromSeed( + seedColor: seedColor, + brightness: brightness, + ), + ); + } + return defaultThemeData(brightness); + } } diff --git a/lib/theme/theme_cubit.dart b/lib/theme/theme_cubit.dart new file mode 100644 index 000000000..f3d296060 --- /dev/null +++ b/lib/theme/theme_cubit.dart @@ -0,0 +1,41 @@ +import 'dart:async'; + +import 'package:altme/theme/theme_repository.dart'; +import 'package:equatable/equatable.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_bloc/flutter_bloc.dart'; + +part 'theme_state.dart'; + +// https://dev.to/b_plab98/theme-switching-persisting-in-flutter-using-cubits-and-stream-5553 +// https://medium.com/flutter-community/create-a-theme-and-primary-color-switcher-for-your-flutter-app-using-provider-fd334dd7d761 + +class ThemeCubit extends Cubit { + ThemeCubit({ + required ThemePersistence themeRepository, + }) : _themeRepository = themeRepository, + super(const ThemeState()); + + final ThemePersistence _themeRepository; + late StreamSubscription _themeSubscription; + + void getCurrentTheme() { + // Since `getTheme()` returns a stream, we listen to the output + _themeSubscription = _themeRepository.getTheme().listen( + (themeMode) { + emit(state.copyWith(themeMode: themeMode)); + }, + ); + } + + void switchTheme(ThemeMode themeMode) { + _themeRepository.saveTheme(themeMode); + } + + @override + Future close() { + _themeSubscription.cancel(); + _themeRepository.dispose(); + return super.close(); + } +} diff --git a/lib/theme/theme_repository.dart b/lib/theme/theme_repository.dart new file mode 100644 index 000000000..af24c2d14 --- /dev/null +++ b/lib/theme/theme_repository.dart @@ -0,0 +1,68 @@ +import 'dart:async'; + +import 'package:flutter/material.dart'; +import 'package:shared_preferences/shared_preferences.dart'; + +abstract class ThemePersistence { + Stream getTheme(); + Future saveTheme(ThemeMode theme); + void dispose(); +} + +class ThemeRepository implements ThemePersistence { + ThemeRepository({ + required SharedPreferences sharedPreferences, + }) : _sharedPreferences = sharedPreferences { + _init(); + } + + final SharedPreferences _sharedPreferences; + + static const _kThemePersistenceKey = '__theme_persistence_key__'; + + final _controller = StreamController(); + + String? _getValue(String key) { + try { + return _sharedPreferences.getString(key); + } catch (_) { + return null; + } + } + + Future _setValue(String key, String value) => + _sharedPreferences.setString(key, value); + + void _init() { + final themeString = _getValue(_kThemePersistenceKey); + + if (themeString != null) { + switch (themeString) { + case 'light': + _controller.add(ThemeMode.light); + case 'dark': + _controller.add(ThemeMode.dark); + case 'system': + _controller.add(ThemeMode.system); + default: + _controller.add(ThemeMode.dark); + } + } else { + _controller.add(ThemeMode.dark); + } + } + + @override + Stream getTheme() async* { + yield* _controller.stream; + } + + @override + Future saveTheme(ThemeMode theme) { + _controller.add(theme); + return _setValue(_kThemePersistenceKey, theme.name); + } + + @override + void dispose() => _controller.close(); +} diff --git a/lib/theme/theme_state.dart b/lib/theme/theme_state.dart new file mode 100644 index 000000000..7670309c2 --- /dev/null +++ b/lib/theme/theme_state.dart @@ -0,0 +1,16 @@ +part of 'theme_cubit.dart'; + +class ThemeState extends Equatable { + const ThemeState( + {this.themeMode = ThemeMode.dark,}); // Default theme = light theme + + final ThemeMode themeMode; + + // `copyWith()` method allows us to emit brand new instance of ThemeState + ThemeState copyWith({ThemeMode? themeMode}) => ThemeState( + themeMode: themeMode ?? this.themeMode, + ); + + @override + List get props => [themeMode]; +} diff --git a/pubspec.lock b/pubspec.lock index a3abf64fa..0f51292d4 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -302,10 +302,10 @@ packages: dependency: transitive description: name: camera_android - sha256: "3af7f0b55f184d392d2eec238aaa30552ebeef2915e5e094f5488bf50d6d7ca2" + sha256: ca42d500c1b58c1ab90ef819909b4de769bcb388a643b692a639c36954a3dc78 url: "https://pub.dev" source: hosted - version: "0.10.9+3" + version: "0.10.9+5" camera_avfoundation: dependency: transitive description: @@ -1429,10 +1429,10 @@ packages: dependency: transitive description: name: local_auth_android - sha256: "48dfb2d954da8ef6a77adfc93a29998f7729e9308eaa817e91dea4500317b2c8" + sha256: b77dc490fef9214e785c326bf11fa733feaa47675d0433f05f48b5caa486c8f7 url: "https://pub.dev" source: hosted - version: "1.0.39" + version: "1.0.40" local_auth_darwin: dependency: transitive description: @@ -1716,10 +1716,10 @@ packages: dependency: transitive description: name: path_provider_android - sha256: "9c96da072b421e98183f9ea7464898428e764bc0ce5567f27ec8693442e72514" + sha256: bca87b0165ffd7cdb9cad8edd22d18d2201e886d9a9f19b4fb3452ea7df3a72a url: "https://pub.dev" source: hosted - version: "2.2.5" + version: "2.2.6" path_provider_foundation: dependency: transitive description: @@ -2104,7 +2104,7 @@ packages: source: hosted version: "3.4.0" shared_preferences: - dependency: transitive + dependency: "direct main" description: name: shared_preferences sha256: d3bbe5553a986e83980916ded2f0b435ef2e1893dfaa29d5a7a790d0eca12180 diff --git a/pubspec.yaml b/pubspec.yaml index a3da5ee20..f1288af52 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -99,6 +99,7 @@ dependencies: secure_storage: path: packages/secure_storage share_plus: ^7.0.2 + shared_preferences: ^2.2.3 shimmer: ^3.0.0 stream_channel: ^2.1.1 switcher: ^1.0.0 diff --git a/test/app/shared/widget/wallet_logo_test.dart b/test/app/shared/widget/wallet_logo_test.dart index 5821e5eb0..845453258 100644 --- a/test/app/shared/widget/wallet_logo_test.dart +++ b/test/app/shared/widget/wallet_logo_test.dart @@ -200,6 +200,7 @@ void main() { published: DateTime.now(), profileId: '', customerPlan: '', + primaryColor: '', ), helpCenterOptions: HelpCenterOptions.initial(), selfSovereignIdentityOptions: diff --git a/test/app/view/app_test.dart b/test/app/view/app_test.dart index 846497f80..4c392141c 100644 --- a/test/app/view/app_test.dart +++ b/test/app/view/app_test.dart @@ -6,12 +6,27 @@ // https://opensource.org/licenses/MIT. import 'package:altme/app/app.dart'; +import 'package:altme/theme/theme_repository.dart'; +import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; +import 'package:shared_preferences/shared_preferences.dart'; void main() { group('App', () { test('default flavor is FlavorMode.production', () async { - expect(const App().flavorMode, FlavorMode.production); + WidgetsFlutterBinding.ensureInitialized(); + SharedPreferences.setMockInitialValues({'test': 1}); + // Creating an instance of ThemeRepository that will invoke the _init() + // method and populate the stream controller in the repository. + final themeRepository = ThemeRepository( + sharedPreferences: await SharedPreferences.getInstance(), + ); + + expect( + App( + themeRepository: themeRepository, + ).flavorMode, + FlavorMode.production); }); // testWidgets('renders SplashPage', (tester) async { diff --git a/test/theme/app_theme_test.dart b/test/theme/app_theme_test.dart index 836980483..12606b56a 100644 --- a/test/theme/app_theme_test.dart +++ b/test/theme/app_theme_test.dart @@ -1,5 +1,4 @@ import 'package:altme/theme/app_theme/app_theme.dart'; -import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; void main() { @@ -8,97 +7,4 @@ void main() { expect(AppTheme, isNotNull); }); - test('CustomColorScheme Test', () { - const colorScheme = ColorScheme.dark(); - - expect(colorScheme.error, const Color(0xFFFF0045)); - expect(colorScheme.onTertiary, const Color(0xFF00B267)); - expect(colorScheme.error, const Color(0xFFFF0045)); - expect(colorScheme.onErrorContainer, const Color(0xFFFF5F0A)); - expect(colorScheme.primary, const Color(0xFF2C7DF7)); - expect(colorScheme.onSurface.withOpacity(0.6), const Color(0xFFD1CCE3)); - expect(colorScheme.onSurface.withOpacity(0.6), const Color(0xFF86809D)); - expect(colorScheme.secondary, const Color(0xFF5F556F)); - expect(colorScheme.surface, const Color(0xff271C38)); - expect(colorScheme.surface, const Color(0xFF251F38)); - expect(colorScheme.surface, const Color(0xFF322643)); - expect(colorScheme.onSurface.withOpacity(0.6), const Color(0xFFA79ABA)); - expect(colorScheme.primary, const Color(0xFF0045FF)); - expect(colorScheme.onTertiary, const Color(0xFF00B267)); - expect(colorScheme.onSurface.withOpacity(0.12), equals(Colors.grey[200])); - expect(colorScheme.onSurface, equals(Colors.white)); - expect(Colors.transparent, equals(Colors.transparent)); - expect(colorScheme.onSurface.withOpacity(0.12), const Color(0xFF6A5F7B)); - expect(colorScheme.onSurface.withOpacity(0.38), const Color(0xFF000000)); - expect(colorScheme.surface, const Color(0xff0A0F19)); - expect(colorScheme.surface, const Color(0xff25095B)); - expect(Colors.transparent, equals(Colors.transparent)); - expect(colorScheme.primary, const Color(0xFF6600FF)); - expect(colorScheme.onPrimary, equals(Colors.white)); - expect(colorScheme.surface, const Color(0xff25095B)); - expect(colorScheme.surface, equals(colorScheme.surface)); - expect( - colorScheme.surface.withOpacity(0.07), - equals(const Color(0xff707070).withOpacity(0.07)), - ); - expect(colorScheme.surface, const Color(0xff232630)); - expect(colorScheme.onSurface, equals(Colors.white)); - expect(colorScheme.onSurface.withOpacity(0.6), const Color(0xff86809D)); - expect(colorScheme.onSurface, const Color(0xffF1EFF8)); - expect(colorScheme.surface, equals(colorScheme.surface)); - expect(colorScheme.surface, const Color(0xff0B0514)); - expect(colorScheme.onSurface.withOpacity(0.12), const Color(0xFFDDCEF4)); - expect( - colorScheme.onSurface.withOpacity(0.2), - const Color(0xFFFFFFFF).withOpacity(0.2), - ); - expect(colorScheme.onSurface, equals(Colors.white)); - expect(colorScheme.onSurface, equals(Colors.white)); - expect(colorScheme.onSurface.withOpacity(0.6), const Color(0xFFD1CCE3)); - expect(colorScheme.primary, const Color(0xff517bff)); - expect(colorScheme.onSurface, equals(Colors.white)); - expect(colorScheme.onSurface.withOpacity(0.6), const Color(0xFF8B8C92)); - expect(colorScheme.onSurface, const Color(0xFF212121)); - expect(colorScheme.onSurface.withOpacity(0.12), const Color(0xFF424242)); - expect( - colorScheme.primary.withOpacity(0.05), - equals(const Color(0xff3700b3).withOpacity(0.05)), - ); - expect(colorScheme.onErrorContainer, const Color(0xFFFFB83D)); - expect(colorScheme.onSurface, const Color(0xFF212121)); - expect(colorScheme.onTertiary, equals(Colors.green)); - expect(colorScheme.onErrorContainer, equals(Colors.orange)); - expect(colorScheme.error, equals(Colors.red)); - expect(colorScheme.onSurface.withOpacity(0.38), const Color(0xFF424242)); - expect(colorScheme.error, equals(Colors.red)); - expect(colorScheme.onErrorContainer, equals(Colors.yellow)); - expect(colorScheme.outline, equals(Colors.cyan)); - expect(colorScheme.onTertiary, equals(Colors.green)); - expect(colorScheme.surface, const Color(0xff2B1C48)); - expect( - colorScheme.shadow.withOpacity(0.16), - const Color(0xff000000).withOpacity(0.16), - ); - expect(colorScheme.primary, const Color(0xff430F91)); - expect(colorScheme.onSurface, const Color(0xffF5F5F5)); - expect(colorScheme.secondaryContainer, const Color(0xFF280164)); - expect(colorScheme.surface, const Color(0xFF211F33)); - expect( - colorScheme.onSurface.withOpacity(0.15), - equals(Colors.grey.withOpacity(0.15)), - ); - expect(colorScheme.primary, const Color(0xff18ACFF)); - expect(colorScheme.primaryContainer, const Color(0xff6600FF)); - expect(colorScheme.onSurface.withOpacity(0.12), const Color(0xff524B67)); - expect(colorScheme.surface, const Color(0xff322643)); - expect(colorScheme.surface, const Color(0xff322643)); - expect(colorScheme.onSurface, const Color(0xffD1CCE3)); - expect(colorScheme.onSurface, const Color(0xffFFFFFF)); - expect(colorScheme.onSurface.withOpacity(0.6), const Color(0xFF616161)); - expect(colorScheme.onSurface, const Color(0xFF212121)); - expect(colorScheme.onTertiary, const Color(0xFF08B530)); - expect(colorScheme.error, const Color(0xFFFF0045)); - expect(colorScheme.onSurface.withOpacity(0.6), const Color(0xff86809D)); - expect(colorScheme.surface, const Color(0xFF211F33)); - }); }