From 3d62857afc81b49697225e5b374fa239678760a5 Mon Sep 17 00:00:00 2001 From: Hope Kagame Opiyo <57757012+root458@users.noreply.github.com> Date: Sun, 18 Aug 2024 17:27:47 +0300 Subject: [PATCH] Light mode & dark mode theming (#92) * Fetch app theme * Set up appbar theming * Set up theme data * Set up feedback button theming * Add XLarge border radius * Set up about screen theming * Set up bottom nav theming --- lib/common/utils/misc.dart | 9 +++++ lib/common/widgets/app_bar/app_bar.dart | 9 +++-- .../widgets/app_bar/feedback_button.dart | 15 ++++---- .../widgets/bottom_nav/bottom_nav_bar.dart | 10 +++--- lib/core/theme/theme_data.dart | 26 ++++++++++---- lib/core/theme/theme_styles.dart | 7 ++++ lib/features/about/ui/about_screen.dart | 16 +++++---- lib/features/about/ui/organising_team.dart | 36 ++++++++++++------- .../home/widgets/organizers_card.dart | 14 ++++---- 9 files changed, 95 insertions(+), 47 deletions(-) diff --git a/lib/common/utils/misc.dart b/lib/common/utils/misc.dart index 056bf15..5def7bb 100644 --- a/lib/common/utils/misc.dart +++ b/lib/common/utils/misc.dart @@ -1,5 +1,6 @@ import 'dart:math'; import 'package:dio/dio.dart'; +import 'package:flutter/material.dart'; import 'package:path_provider/path_provider.dart'; import 'package:share_plus/share_plus.dart'; import 'package:url_launcher/url_launcher.dart'; @@ -37,4 +38,12 @@ class Misc { return files; } + + /// Returns (isLightMode, colorScheme) + static (bool, ColorScheme) getTheme(BuildContext context) { + final isLightMode = Theme.of(context).brightness == Brightness.light; + final colorScheme = Theme.of(context).colorScheme; + + return (isLightMode, colorScheme); + } } diff --git a/lib/common/widgets/app_bar/app_bar.dart b/lib/common/widgets/app_bar/app_bar.dart index 709ddfb..5dd72af 100644 --- a/lib/common/widgets/app_bar/app_bar.dart +++ b/lib/common/widgets/app_bar/app_bar.dart @@ -1,6 +1,7 @@ import 'package:flutter/material.dart'; import 'package:flutter_svg/svg.dart'; import 'package:fluttercon/common/utils/constants/app_assets.dart'; +import 'package:fluttercon/common/utils/misc.dart'; import 'package:fluttercon/common/widgets/app_bar/feedback_button.dart'; import 'package:fluttercon/common/widgets/app_bar/session_filter.dart'; import 'package:fluttercon/common/widgets/app_bar/user_profile_icon.dart'; @@ -25,15 +26,19 @@ class CustomAppBar extends StatelessWidget implements PreferredSizeWidget { @override Widget build(BuildContext context) { + final (isLightMode, colorScheme) = Misc.getTheme(context); return AppBar( automaticallyImplyLeading: false, - surfaceTintColor: Colors.white, + surfaceTintColor: colorScheme.surface, + backgroundColor: colorScheme.surface, title: Row( children: [ GestureDetector( onTap: () {}, child: Image.asset( - AppAssets.droidconLogo, + isLightMode + ? AppAssets.droidconLogo + : AppAssets.droidconLogoWhite, scale: 2, ), ), diff --git a/lib/common/widgets/app_bar/feedback_button.dart b/lib/common/widgets/app_bar/feedback_button.dart index 5e2b8dd..f866ff2 100644 --- a/lib/common/widgets/app_bar/feedback_button.dart +++ b/lib/common/widgets/app_bar/feedback_button.dart @@ -1,4 +1,5 @@ import 'package:flutter/material.dart'; +import 'package:fluttercon/common/utils/misc.dart'; import 'package:fluttercon/common/widgets/bottom_nav/app_nav_icon.dart'; import 'package:fluttercon/core/theme/theme_colors.dart'; import 'package:fluttercon/l10n/l10n.dart'; @@ -11,7 +12,7 @@ class FeedbackButton extends StatelessWidget { @override Widget build(BuildContext context) { final l10n = context.l10n; - + final (_, colorScheme) = Misc.getTheme(context); return selectedIndex == 0 ? const SizedBox() : InkWell( @@ -31,16 +32,14 @@ class FeedbackButton extends StatelessWidget { AppNavIcon( 'smiley-outline', height: 12, - color: Theme.of(context).brightness == Brightness.light - ? Colors.white - : Colors.black, + color: colorScheme.onSurface, ), Text( l10n.feedback, - style: Theme.of(context) - .textTheme - .bodyMedium - ?.copyWith(fontSize: 12), + style: Theme.of(context).textTheme.bodyMedium?.copyWith( + fontSize: 12, + color: colorScheme.onSurface, + ), ), const AppNavIcon( 'send', diff --git a/lib/common/widgets/bottom_nav/bottom_nav_bar.dart b/lib/common/widgets/bottom_nav/bottom_nav_bar.dart index a90af1a..749e128 100644 --- a/lib/common/widgets/bottom_nav/bottom_nav_bar.dart +++ b/lib/common/widgets/bottom_nav/bottom_nav_bar.dart @@ -1,4 +1,5 @@ import 'package:flutter/material.dart'; +import 'package:fluttercon/common/utils/misc.dart'; import 'package:fluttercon/common/widgets/bottom_nav/app_nav_icon.dart'; import 'package:fluttercon/common/widgets/page_item.dart'; import 'package:fluttercon/core/theme/theme_colors.dart'; @@ -79,6 +80,7 @@ class _CustomBottomNavigationBarState extends State { @override Widget build(BuildContext context) { + final (_, colorScheme) = Misc.getTheme(context); return GestureDetector( onHorizontalDragStart: _handleDragStart, onHorizontalDragUpdate: _handleDragUpdate, @@ -89,10 +91,10 @@ class _CustomBottomNavigationBarState extends State { : null, child: BottomNavigationBar( type: BottomNavigationBarType.fixed, - backgroundColor: Colors.white, + backgroundColor: colorScheme.surface, currentIndex: widget.selectedIndex, selectedItemColor: ThemeColors.orangeDroidconColor, - unselectedItemColor: ThemeColors.greyDarkThemeBackground, + unselectedItemColor: colorScheme.onSurface, unselectedLabelStyle: const TextStyle(fontSize: 12), selectedLabelStyle: const TextStyle(fontSize: 12), onTap: widget.onPageChange, @@ -104,9 +106,7 @@ class _CustomBottomNavigationBarState extends State { padding: const EdgeInsets.all(8), child: AppNavIcon( page.icon, - color: isActive - ? ThemeColors.blueDroidconColor - : ThemeColors.greyTextColor, + color: isActive ? colorScheme.primary : colorScheme.onSurface, ), ), ); diff --git a/lib/core/theme/theme_data.dart b/lib/core/theme/theme_data.dart index 717c54e..3b4029e 100644 --- a/lib/core/theme/theme_data.dart +++ b/lib/core/theme/theme_data.dart @@ -6,6 +6,18 @@ import 'package:google_fonts/google_fonts.dart'; class AppTheme { AppTheme._(); + // On the colorScheme, add the color for light the theme + // And the corresponding color for dark theme on the same property + // Example: + // + // Light theme + // surface: Colors.white, + // onSurface: Colors.black, + // + // Dark theme + // surface: ThemeColors.blackColor, + // onSurface: Colors.white, + static ThemeData lightTheme() { return ThemeData( scaffoldBackgroundColor: Colors.white, @@ -15,9 +27,9 @@ class AppTheme { primaryContainer: ThemeColors.blueDroidconColor, onPrimary: Colors.white, secondary: ThemeColors.blueGreenDroidconColor, - secondaryContainer: ThemeColors.blueGreenDroidconColor, + secondaryContainer: ThemeColors.lightGrayColor, onSecondary: Colors.black, - surface: Colors.grey, + surface: Colors.white, onSurface: Colors.black, error: Colors.red, onError: Colors.white, @@ -45,14 +57,14 @@ class AppTheme { return ThemeData( scaffoldBackgroundColor: ThemeColors.greyDarkThemeBackground, colorScheme: const ColorScheme( - brightness: Brightness.light, - primary: ThemeColors.blueDroidconColor, + brightness: Brightness.dark, + primary: ThemeColors.blueGreenDroidconColor, primaryContainer: ThemeColors.blueDroidconColor, onPrimary: Colors.black, - secondary: ThemeColors.blueGreenDroidconColor, - secondaryContainer: ThemeColors.blueGreenDroidconColor, + secondary: ThemeColors.blueDroidconColor, + secondaryContainer: Colors.black, onSecondary: Colors.white, - surface: Colors.grey, + surface: ThemeColors.blackColor, onSurface: Colors.white, error: Colors.red, onError: Colors.white, diff --git a/lib/core/theme/theme_styles.dart b/lib/core/theme/theme_styles.dart index c2db255..cb3a6c5 100644 --- a/lib/core/theme/theme_styles.dart +++ b/lib/core/theme/theme_styles.dart @@ -109,4 +109,11 @@ class Corners { static BorderRadius get s10Border => BorderRadius.all(s10Radius); static Radius get s10Radius => const Radius.circular(s10); + + /// XLarge + static const double s12 = 12; + + static BorderRadius get s12Border => BorderRadius.all(s12Radius); + + static Radius get s12Radius => const Radius.circular(s12); } diff --git a/lib/features/about/ui/about_screen.dart b/lib/features/about/ui/about_screen.dart index 0e31040..a0a322e 100644 --- a/lib/features/about/ui/about_screen.dart +++ b/lib/features/about/ui/about_screen.dart @@ -1,9 +1,8 @@ import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:fluttercon/common/utils/constants/app_assets.dart'; +import 'package:fluttercon/common/utils/misc.dart'; import 'package:fluttercon/common/widgets/app_bar/app_bar.dart'; - -import 'package:fluttercon/core/theme/theme_colors.dart'; import 'package:fluttercon/features/about/cubit/fetch_individual_organisers_cubit.dart'; import 'package:fluttercon/features/about/ui/organising_team.dart'; import 'package:fluttercon/features/home/widgets/organizers_card.dart'; @@ -18,13 +17,16 @@ class AboutScreen extends StatefulWidget { class _AboutScreenState extends State { @override void initState() { - context.read().fetchIndividualOrganisers(); super.initState(); + + context.read().fetchIndividualOrganisers(); } @override Widget build(BuildContext context) { + final (_, colorScheme) = Misc.getTheme(context); return Scaffold( + backgroundColor: colorScheme.surface, appBar: const CustomAppBar(selectedIndex: 3), body: CustomScrollView( slivers: [ @@ -36,7 +38,7 @@ class _AboutScreenState extends State { child: Text( 'About', style: Theme.of(context).textTheme.titleLarge?.copyWith( - color: ThemeColors.blueDroidconColor, + color: colorScheme.primary, fontWeight: FontWeight.bold, ), ), @@ -65,7 +67,9 @@ class _AboutScreenState extends State { 'packed program of tech talks, workshops, and panels, ' "forming one of the continent's largest mobile developer " 'gatherings.', - style: Theme.of(context).textTheme.bodyMedium, + style: Theme.of(context).textTheme.bodyMedium?.copyWith( + color: colorScheme.onSurface, + ), ), ), ), @@ -76,7 +80,7 @@ class _AboutScreenState extends State { child: Text( 'Organizing Team', style: Theme.of(context).textTheme.titleLarge?.copyWith( - color: ThemeColors.blueDroidconColor, + color: colorScheme.primary, fontWeight: FontWeight.bold, ), ), diff --git a/lib/features/about/ui/organising_team.dart b/lib/features/about/ui/organising_team.dart index b789735..89b70c0 100644 --- a/lib/features/about/ui/organising_team.dart +++ b/lib/features/about/ui/organising_team.dart @@ -1,8 +1,10 @@ import 'package:cached_network_image/cached_network_image.dart'; import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; +import 'package:fluttercon/common/utils/misc.dart'; import 'package:fluttercon/common/utils/router.dart'; import 'package:fluttercon/core/theme/theme_colors.dart'; +import 'package:fluttercon/core/theme/theme_styles.dart'; import 'package:fluttercon/features/about/cubit/fetch_individual_organisers_cubit.dart'; import 'package:go_router/go_router.dart'; @@ -22,6 +24,7 @@ class _OrganisingTeamViewState extends State { @override Widget build(BuildContext context) { + final (_, colorScheme) = Misc.getTheme(context); return BlocBuilder( builder: (context, state) => state.maybeWhen( @@ -39,18 +42,19 @@ class _OrganisingTeamViewState extends State { ), child: Column( children: [ - ClipRRect( - borderRadius: BorderRadius.circular(25), - child: Container( - constraints: BoxConstraints( - maxWidth: MediaQuery.sizeOf(context).width / 4.5, - ), - decoration: BoxDecoration( - border: Border.all( - color: ThemeColors.tealColor, - width: 2, - ), + Container( + constraints: BoxConstraints( + maxWidth: MediaQuery.sizeOf(context).width / 4.5, + ), + decoration: BoxDecoration( + border: Border.all( + color: ThemeColors.tealColor, + width: 2, ), + borderRadius: Corners.s12Border, + ), + child: ClipRRect( + borderRadius: Corners.s10Border, child: CachedNetworkImage( fit: BoxFit.cover, imageUrl: individualOrganisers[index].photo, @@ -60,12 +64,18 @@ class _OrganisingTeamViewState extends State { Text( individualOrganisers[index].name, maxLines: 1, - style: const TextStyle(fontSize: 12), + style: TextStyle( + fontSize: 12, + color: colorScheme.onSurface, + ), ), Text( individualOrganisers[index].designation, maxLines: 1, - style: const TextStyle(fontSize: 12), + style: TextStyle( + fontSize: 12, + color: colorScheme.onSurface, + ), ), ], ), diff --git a/lib/features/home/widgets/organizers_card.dart b/lib/features/home/widgets/organizers_card.dart index 010f30a..4856926 100644 --- a/lib/features/home/widgets/organizers_card.dart +++ b/lib/features/home/widgets/organizers_card.dart @@ -3,7 +3,7 @@ import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:flutter_svg/svg.dart'; import 'package:fluttercon/common/data/models/models.dart'; -import 'package:fluttercon/core/theme/theme_colors.dart'; +import 'package:fluttercon/common/utils/misc.dart'; import 'package:fluttercon/features/home/cubit/fetch_organisers_cubit.dart'; class OrganizersCard extends StatefulWidget { @@ -16,12 +16,14 @@ class OrganizersCard extends StatefulWidget { class _OrganizersCardState extends State { @override void initState() { - context.read().fetchOrganisers(); super.initState(); + + context.read().fetchOrganisers(); } @override Widget build(BuildContext context) { + final (_, colorScheme) = Misc.getTheme(context); final size = MediaQuery.sizeOf(context); //Widget to only rebuild when size changes @@ -31,16 +33,16 @@ class _OrganizersCardState extends State { padding: const EdgeInsets.all(10), decoration: BoxDecoration( borderRadius: BorderRadius.circular(10), - color: ThemeColors.lightGrayColor, + color: colorScheme.secondaryContainer, ), child: Column( children: [ const Spacer(), - const Text( + Text( 'Organised by:', style: TextStyle( fontWeight: FontWeight.bold, - color: ThemeColors.blueColor, + color: colorScheme.primary, fontSize: 18, ), ), @@ -61,7 +63,7 @@ class _OrganizersCardState extends State { message, style: Theme.of(context).textTheme.titleMedium?.copyWith( fontWeight: FontWeight.bold, - color: ThemeColors.blueColor, + color: colorScheme.primary, fontSize: 18, ), ),