flutter_platform_widgets icon indicating copy to clipboard operation
flutter_platform_widgets copied to clipboard

Material Dark Theme Overrides Cupertino Dark Theme on iOS

Open LeonManolo opened this issue 2 years ago • 3 comments

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!

LeonManolo avatar Jun 21 '23 10:06 LeonManolo

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

aqwert avatar Jun 23 '23 01:06 aqwert

Thats the version Im using: flutter_platform_widgets: ^3.3.4

LeonManolo avatar Jun 26 '23 15:06 LeonManolo

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.

Dark-Schneider-666 avatar Aug 14 '24 16:08 Dark-Schneider-666