stryder-dev / flutter_platform_widgets

Target the specific design of Material for Android and Cupertino for iOS widgets through a common set of Platform aware widgets
MIT License
1.59k stars 173 forks source link

Material Dark Theme Overrides Cupertino Dark Theme on iOS #420

Open LeonManolo opened 1 year ago

LeonManolo commented 1 year ago

Hello,

I've encountered an issue when using both the Material dark theme and Cupertino dark theme simultaneously on iOS. Specifically, the Material dark theme appears to override the Cupertino dark theme, as shown in the attached screenshot

Here's a snippet of the relevant code:

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

  @override
  Widget build(BuildContext context) {
    return PlatformProvider(
      settings: PlatformSettingsData(
        iosUsesMaterialWidgets: true,
      ),
      builder: (context) => PlatformTheme(
        themeMode: ThemeMode.system,
        materialLightTheme: const LightMaterialAppTheme().themeData,
        materialDarkTheme: const DarkMaterialAppTheme().themeData,
        cupertinoLightTheme: const LightCupertinoAppTheme().themeData,
        cupertinoDarkTheme: MaterialBasedCupertinoThemeData(
          materialTheme: ThemeData.dark().copyWith(
            cupertinoOverrideTheme: CupertinoThemeData(
              primaryColor: CupertinoColors.systemRed, // as an example
              // more theme data...
            ),
          ),
        ),
        // rest of the code...
      ),
    );
  }
}

In this setup, the primary color should be red. However, as demonstrated in the screenshot, this is not the case. This issue does not occur on Android, nor does it occur with the light mode themes where the Cupertino theme isn't overridden by the Material theme.

The only workaround I've found is to conditionally set the Material dark theme to null on iOS, as shown in the following code snippet:

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

  @override
  Widget build(BuildContext context) {
    return PlatformProvider(
      settings: PlatformSettingsData(
        iosUsesMaterialWidgets: true,
        //iosUseZeroPaddingForAppbarPlatformIcon: true,
      ),
      builder: (context) => PlatformTheme(
        themeMode: ThemeMode.system,
        materialLightTheme: const LightMaterialAppTheme().themeData,
        materialDarkTheme:
        // temporary fix, because material dark mode overrides cupertino dark mode
            Platform.isAndroid ? const DarkMaterialAppTheme().themeData : null,
        cupertinoLightTheme: const LightCupertinoAppTheme().themeData,
        cupertinoDarkTheme: MaterialBasedCupertinoThemeData(
          materialTheme: ThemeData.dark().copyWith(
            cupertinoOverrideTheme: CupertinoThemeData(
              primaryColor: CupertinoColors.systemIndigo,
              barBackgroundColor:
              CupertinoThemeData(brightness: Brightness.dark).barBackgroundColor,
              scaffoldBackgroundColor: CupertinoColors.systemBackground,
              textTheme: CupertinoTextThemeData(
                textStyle: CupertinoThemeData(brightness: Brightness.dark).textTheme.textStyle,
                navActionTextStyle: CupertinoThemeData(brightness: Brightness.dark)
                    .textTheme.navActionTextStyle
                    .copyWith(color: const Color(0xF0F9F9F9)),
                navLargeTitleTextStyle: CupertinoThemeData(brightness: Brightness.dark)
                    .textTheme.navLargeTitleTextStyle
                    .copyWith(color: const Color(0xF0F9F9F9)),
              ),
            ),
          ),
        ),
        matchCupertinoSystemChromeBrightness: false,
        builder: (context) => PlatformApp(
          // needed to get the cupertino modal shrink effect
          onGenerateRoute: (settings) => MaterialWithModalsPageRoute(
            builder: (context) => FlowBuilder<AppStatus>(
              state: context.select((AppBloc bloc) => bloc.state.status),
              onGeneratePages: onGenerateAppViewPages,
            ),
          ),
          localizationsDelegates: const <LocalizationsDelegate<dynamic>>[
            DefaultMaterialLocalizations.delegate,
            DefaultWidgetsLocalizations.delegate,
            DefaultCupertinoLocalizations.delegate,
          ],
        ),
      ),
    );
  }
}

This workaround allows the Cupertino dark theme to render correctly:

Any guidance or suggestions for addressing this issue would be greatly appreciated, thanks!

aqwert commented 1 year ago

What version of the package are you using. There was a fix around this area with v3.3.4. See https://github.com/stryder-dev/flutter_platform_widgets/issues/402

LeonManolo commented 1 year ago

Thats the version Im using: flutter_platform_widgets: ^3.3.4

Dark-Schneider-666 commented 3 months ago

Still happens using version 7.0.1. Currently I fixed this using this function when creating the app:

// fixes the current bug of PlatformTheme with materialDarkTheme overriding cupertinoDarkTheme
  ThemeData? getMaterialThemeData(Brightness brightness) {
    if (Platform.isIOS) {
      return null;
    } else {
      return switch (brightness) {
        Brightness.dark => ThemeData.dark(),
        Brightness.light => ThemeData.light(),
      };
    }
  }

Then construct with:

@override
Widget build(BuildContext context) {
    return PlatformProvider(
        builder: (context) => PlatformTheme(
          themeMode: ThemeMode.system,
          cupertinoDarkTheme:
              const CupertinoThemeData(brightness: Brightness.dark),
          cupertinoLightTheme:
              const CupertinoThemeData(brightness: Brightness.light),
          materialDarkTheme: getMaterialThemeData(Brightness.dark),
          materialLightTheme: getMaterialThemeData(Brightness.light),
          builder: (context) => PlatformApp(
...

With this, the app uses the system theme and adapts to the device theme system setting if changed. Noticed that if not defined the values it always uses the Light mode by default.

But I think all the setting the ThemeMode.system and setting manually the system light and dark mode should be made by default by the PlatformTheme by its own.

This can be achieved in a single call with something like this:

import 'dart:io';

import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter_platform_widgets/flutter_platform_widgets.dart';

PlatformTheme platformThemeSystem({required WidgetBuilder builder}) {
  return PlatformTheme(
    builder: builder,
    themeMode: ThemeMode.system,
    cupertinoDarkTheme: const CupertinoThemeData(brightness: Brightness.dark),
    cupertinoLightTheme: const CupertinoThemeData(brightness: Brightness.light),
    materialDarkTheme: Platform.isIOS ? null : ThemeData.dark(),
    materialLightTheme: Platform.isIOS ? null : ThemeData.light(),
  );
}

Then just:

@override
Widget build(BuildContext context) {
    return PlatformProvider(
        builder: (context) => platformThemeSystem(
          builder: (context) => PlatformApp(
...

Hope this helps.