jonataslaw / getx

Open screens/snackbars/dialogs/bottomSheets without context, manage states and inject dependencies easily with Get.
MIT License
10.04k stars 1.58k forks source link

Need change dark mode theme #3105

Open BppleMan opened 1 month ago

BppleMan commented 1 month ago

Currently, both MaterialApp and GetMaterialApp support setting theme and darkTheme separately, but Get._rootController can only use changeTheme, so I seem to have to [use any higher level widget than GetMaterialApp in order to update it].

I think it should be more intuitive to call changeTheme in lightMode and changeDarkThme in darkMode, isn't it?

https://github.com/jonataslaw/getx/blob/9d2b87242aa5d5b54aebd4d635d1e16835635c49/lib/get_navigation/src/root/root_controller.dart#L59-L70

Can I only changeThemeMode(ThemeMode.dark) first and then changeTheme, this will call update twice, is there any problem?

allasca commented 1 month ago

I use this

class MainApp extends StatelessWidget {
  const MainApp({super.key});

  @override
  Widget build(BuildContext context) {
    return GetBuilder(
        init: MainController(),
        builder: (_) {
          return GetMaterialApp(
            title: "Lestaripedia",
            theme: ThemeData(
              colorScheme: ColorScheme.fromSeed(
                seedColor: Colors.green,
                brightness: Brightness.light,
              ),
              useMaterial3: true,
            ),
            darkTheme: ThemeData(
              colorScheme: ColorScheme.fromSeed(
                seedColor: Colors.green,
                brightness: Brightness.dark,
              ),
              useMaterial3: true,
            ),
            themeMode: _.isDarkMode.value ? ThemeMode.dark : ThemeMode.light,
            home: const LoginUi(),
          );
        });
  }
}

just need to call update()

abetoluwani commented 1 month ago

1. Create a Theme Folder

Create a folder named theme inside your lib directory.

2. Define Themes in Separate Files

Inside the theme folder, create a file app_theme.dart and define your themes there.

File: lib/theme/app_theme.dart

import 'package:flutter/material.dart';
import '../widgets/space.dart';
import 'colors.dart';

class AppTheme {
  static ThemeData get theme {
    return ThemeData(
      scaffoldBackgroundColor: AppColors.white,
      dialogBackgroundColor: AppColors.white,
      dialogTheme: const DialogTheme(
        backgroundColor: AppColors.white,
        surfaceTintColor: AppColors.white,
      ),
      primaryColor: AppColors.primary,
      cardColor: AppColors.white,
      appBarTheme: const AppBarTheme(
        backgroundColor: AppColors.white,
        iconTheme: IconThemeData(color: AppColors.black),
        surfaceTintColor: Colors.transparent,
      ),
      chipTheme: ChipThemeData(
        padding: simPad(5, 5),
        shape: const StadiumBorder(
          side: BorderSide.none,
        ),
        side: BorderSide.none,
      ),
      primaryColorLight: AppColors.white,
      popupMenuTheme: const PopupMenuThemeData(color: AppColors.white),
    );
  }

  static ThemeData get darkTheme {
    return ThemeData(
      scaffoldBackgroundColor: AppColors.black,
      dialogBackgroundColor: AppColors.grey900,
      dialogTheme: const DialogTheme(
        backgroundColor: AppColors.grey900,
        surfaceTintColor: AppColors.grey900,
      ),
      primaryColor: AppColors.primary,
      cardColor: AppColors.grey850,
      appBarTheme: const AppBarTheme(
        backgroundColor: AppColors.grey900,
        elevation: 0,
        surfaceTintColor: Colors.transparent,
        iconTheme: IconThemeData(color: AppColors.white),
      ),
      chipTheme: ChipThemeData(
        shape: RoundedRectangleBorder(
          borderRadius: BorderRadius.circular(10),
        ),
      ),
      dividerColor: AppColors.grey200,
      primaryColorLight: AppColors.white,
      popupMenuTheme: const PopupMenuThemeData(color: AppColors.grey900),
    );
  }
}

3. Update Your Main App File

Modify your main.dart file to use the new theme setup.

File: lib/main.dart

import 'package:flutter/material.dart';
import 'package:flutter_screenutil/flutter_screenutil.dart';
import 'package:get/get.dart';
import 'theme/app_theme.dart';
import 'routes/app_pages.dart'; // Ensure this is the correct path to your routes file
import 'bindings/splashscreen_binding.dart'; // Ensure this is the correct path to your binding file

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  @override
  Widget build(BuildContext context) {
    return ScreenUtilInit(
      designSize: const Size(375, 812),
      minTextAdapt: true,
      splitScreenMode: false,
      builder: (_, child) {
        return GetMaterialApp(
          debugShowCheckedModeBanner: false,
          initialRoute: AppPages.INITIAL,
          initialBinding: SplashscreenBinding(),
          getPages: AppPages.routes,
          darkTheme: AppTheme.darkTheme,
          theme: AppTheme.theme,
        );
      },
    );
  }
}

void main() {
  runApp(const MyApp());
}

4. Define Colors

Ensure that you have a colors file where you define all your color constants.

File: lib/theme/colors.dart

import 'package:flutter/material.dart';

class AppColors {
  static const Color white = Colors.white;
  static const Color black = Colors.black;
  static const Color primary = Colors.blue; // Replace with your primary color
  static const Color grey200 = Color(0xFFEEEEEE);
  static const Color grey850 = Color(0xFF1C1C1C);
  static const Color grey900 = Color(0xFF121212);
}

5. Ensure simPad Utility

Ensure you have the simPad function or a similar utility for padding.

File: lib/widgets/space.dart

import 'package:flutter/material.dart';

// Assuming simPad is a predefined utility function
EdgeInsets simPad(double horizontal, double vertical) {
  return EdgeInsets.symmetric(horizontal: horizontal, vertical: vertical);
}

With these steps, your project will have a well-structured theme folder, allowing you to manage light and dark themes effectively. The predefined simPad and AppColors are utilized as expected but are not necessary

abetoluwani commented 1 month ago

@allasca @jasonlaw @BppleMan @lsm i thinkthis should solve it

BppleMan commented 1 month ago

I use this

class MainApp extends StatelessWidget {
  const MainApp({super.key});

  @override
  Widget build(BuildContext context) {
    return GetBuilder(
        init: MainController(),
        builder: (_) {
          return GetMaterialApp(
            title: "Lestaripedia",
            theme: ThemeData(
              colorScheme: ColorScheme.fromSeed(
                seedColor: Colors.green,
                brightness: Brightness.light,
              ),
              useMaterial3: true,
            ),
            darkTheme: ThemeData(
              colorScheme: ColorScheme.fromSeed(
                seedColor: Colors.green,
                brightness: Brightness.dark,
              ),
              useMaterial3: true,
            ),
            themeMode: _.isDarkMode.value ? ThemeMode.dark : ThemeMode.light,
            home: const LoginUi(),
          );
        });
  }
}

just need to call update()

I prefer this solution at the moment, because I have already reserved a series of ThemeData, I just want to simply replace the entire ThemeData, not the Color, in the app running. thanks @abetoluwani

abetoluwani commented 1 month ago

Yeah i forgot to add @BppleMan

themeMode: ThemeMode.system,

this would automatically select the theme data for any theme data you create

halloweens1 commented 3 weeks ago

Ran into same issue, I've debugged that Get.changeTheme, which leads to GetMaterialController's method setTheme, I found out that darkTheme's value will be always null, cuz I couldn't find where sets its value, I did double check it, turned out the same result, I don't know whether I'm right or not, I highly suspect that if statement about darkTheme == null is the reason for having no effect after applying Get.changeTheme in dark mode, cuz it only changes the theme, not the darkTheme, due to the darkTheme's value is always null.