Skip to content

Make CupertinoAlertDialog clearly visible in dark mode #80921

Closed

Description

@mleonhard

Steps to Reproduce

Run the following program in Simulator or on your iOS device, in dark mode. Hold down the Cancel button and take a screenshot.

Flutter main.dart
import 'package:flutter/cupertino.dart'
    show
    showCupertinoDialog,
    CupertinoAlertDialog,
    CupertinoApp,
    CupertinoButton,
    CupertinoDialogAction,
    CupertinoNavigationBar,
    CupertinoPage,
    CupertinoPageScaffold,
    CupertinoTheme,
    CupertinoThemeData;
import 'package:flutter/foundation.dart'
    show
    debugBrightnessOverride,
    kReleaseMode;
import 'package:flutter/widgets.dart'
    show
    runApp,
    Builder,
    BuildContext,
    Color,
    DefaultTextStyle,
    Key,
    MediaQuery,
    MediaQueryData,
    Page,
    State,
    StatefulWidget,
    StatelessWidget,
    Text,
    Navigator,
    Widget,
    WidgetsBinding,
    WidgetsBindingObserver;
import 'dart:ui' show Brightness;

// Copied from flutter/lib/src/widgets/app.dart:_MediaQueryFromWindow .
class MediaQueryFromWindow extends StatefulWidget {
  const MediaQueryFromWindow({Key key, this.child}) : super(key: key);

  final Widget child;

  @override
  MediaQueryFromWindowsState createState() => MediaQueryFromWindowsState();
}

class MediaQueryFromWindowsState extends State<MediaQueryFromWindow>
    with WidgetsBindingObserver {
  @override
  void initState() {
    super.initState();
    WidgetsBinding.instance.addObserver(this);
  }

  @override
  void didChangeAccessibilityFeatures() {
    setState(() {});
  }

  @override
  void didChangeMetrics() {
    setState(() {});
  }

  @override
  void didChangeTextScaleFactor() {
    setState(() {});
  }

  @override
  void didChangePlatformBrightness() {
    setState(() {});
  }

  @override
  Widget build(BuildContext context) {
    MediaQueryData data = MediaQueryData.fromWindow(
        WidgetsBinding.instance.window);
    if (!kReleaseMode) {
      data = data.copyWith(platformBrightness: debugBrightnessOverride);
    }
    return MediaQuery(
      data: data,
      child: widget.child,
    );
  }

  @override
  void dispose() {
    WidgetsBinding.instance.removeObserver(this);
    super.dispose();
  }
}

Page homePage() =>
    CupertinoPage(
      title: 'Page1',
      child: Builder(builder: (BuildContext ctx) =>
          CupertinoPageScaffold(
            navigationBar: CupertinoNavigationBar(),
            child: CupertinoButton(
              child: Text('Button1'),
              onPressed: () =>
                  showCupertinoDialog(
                    context: ctx,
                    builder: (BuildContext ctx) =>
                        CupertinoAlertDialog(
                          title: Text('Alert1'),
                          content: Text('Content1'),
                          actions: [
                            CupertinoDialogAction(
                              isDefaultAction: false,
                              isDestructiveAction: false,
                              child: Text('Disabled1'),
                            ),
                            CupertinoDialogAction(
                              isDefaultAction: false,
                              isDestructiveAction: false,
                              onPressed: () =>
                                  Navigator.pop(
                                      ctx, false),
                              child: Text('Action1'),
                            ),
                            CupertinoDialogAction(
                              isDefaultAction: false,
                              isDestructiveAction: true,
                              onPressed: () =>
                                  Navigator.pop(
                                      ctx, false),
                              child: Text('Destructive1'),
                            ),
                            CupertinoDialogAction(
                              isDefaultAction: true,
                              isDestructiveAction: false,
                              onPressed: () =>
                                  Navigator.pop(
                                      ctx, false),
                              child: Text('Cancel1'),
                            ),
                          ],
                        ),
                  ),
            ),
          ),
      ),
    );

class AppWidget extends StatelessWidget {
  @override
  Widget build(BuildContext ctx) {
    final isLight = MediaQuery
        .of(ctx)
        .platformBrightness == Brightness.light;
    final cupertinoThemeData = isLight ? CupertinoThemeData(
      // Light
      primaryColor: Color(0xff664600),
      barBackgroundColor: Color(0xffFFF0D0),
    ) : CupertinoThemeData(
      // Dark
      primaryColor: Color(0xffFFF0D0),
      barBackgroundColor: Color(0xff664600),
    );
    return CupertinoApp(
      theme: cupertinoThemeData,
      title: 'App1',
      home: Builder(builder: (BuildContext ctx) =>
          DefaultTextStyle(
            style: CupertinoTheme
                .of(ctx)
                .textTheme
                .textStyle,
            child: Navigator(
              pages: [homePage()],
              onPopPage: (route, result) => true,
            ),
          ),
      ),
    );
  }
}

void main() {
  runApp(MediaQueryFromWindow(child: AppWidget()));
}

Actual results:

The Flutter app dialog on the right has two problems:

  1. The dialog background is very dark. Some users may be confused. They may not realize that a dialog has appeared.
  2. The buttons are separated by very faint lines. Users could have trouble hitting the right button.

A very minor additional difference: when pressing a button, the button background lightens only a little bit.

Native Flutter v2.0.5
IMG_3547 IMG_3549
Logs
$ flutter doctor -v
[✓] Flutter (Channel stable, 2.0.5, on Mac OS X 10.15.7 19H524 darwin-x64, locale en)
    • Flutter version 2.0.5 at /Users/user/tools/flutter
    • Framework revision adc687823a (6 days ago), 2021-04-16 09:40:20 -0700
    • Engine revision b09f014e96
    • Dart version 2.12.3

[✓] Android toolchain - develop for Android devices (Android SDK version 31.0.0-rc2)
    • Android SDK at /Users/user/Library/Android/sdk
    • Platform android-30, build-tools 31.0.0-rc2
    • Java binary at: /Applications/Android Studio.app/Contents/jre/jdk/Contents/Home/bin/java
    • Java version OpenJDK Runtime Environment (build 1.8.0_242-release-1644-b3-6915495)
    • All Android licenses accepted.

[✓] Xcode - develop for iOS and macOS
    • Xcode at /Applications/Xcode.app/Contents/Developer
    • Xcode 12.4, Build version 12D4e
    • CocoaPods version 1.10.1

[✓] Android Studio (version 4.1)
    • Android Studio at /Applications/Android Studio.app/Contents
    • Flutter plugin can be installed from:
      🔨 https://plugins.jetbrains.com/plugin/9212-flutter
    • Dart plugin can be installed from:
      🔨 https://plugins.jetbrains.com/plugin/6351-dart
    • Java version OpenJDK Runtime Environment (build 1.8.0_242-release-1644-b3-6915495)

[✓] Connected device (1 available)
    • Michael’s iPhone (mobile) • **** • ios            • iOS 14.4.2

• No issues found!

Fix

flutter/lib/src/cupertino/dialog.dart :

const Color _kDialogColor = CupertinoDynamicColor.withBrightness(
  color: Color(0xCCF2F2F2),
  darkColor: Color(0xBF1E1E1E), // <--- Change to 0xCC2d2d2d.
);

const Color _kDialogPressedColor = CupertinoDynamicColor.withBrightness(
  color: Color(0xFFE1E1E1),
  darkColor: Color(0xFF2E2E2E), // <-- Change to 0xFF404040.
);

flutter/lib/src/cupertino/colors.dart :

  static const CupertinoDynamicColor separator = CupertinoDynamicColor(
    debugLabel: 'separator',
    color: Color.fromARGB(73, 60, 60, 67),
    darkColor: Color.fromARGB(153, 84, 84, 88),
    highContrastColor: Color.fromARGB(94, 60, 60, 67),
    darkHighContrastColor: Color.fromARGB(173, 84, 84, 88),
    elevatedColor: Color.fromARGB(73, 60, 60, 67),
    darkElevatedColor: Color.fromARGB(153, 84, 84, 88), // <-- Change to 210, 210, 210.
    highContrastElevatedColor: Color.fromARGB(94, 60, 60, 67),
    darkHighContrastElevatedColor: Color.fromARGB(173, 84, 84, 88),
  );

With these changes, the Flutter app better matches the native iOS dialog.

Native Patched Flutter v2.0.5
IMG_3547 IMG_3553

Activity

  1. pedromassangocode commented on Apr 22, 2021

    @pedromassangocode

    I can also notice that the Flutter version has no the right transparency percentage.

    Related #61164.

  2. added
    p: cupertino_uicupertino_ui package in flutter/packages
    frameworkflutter/packages/flutter repository. See also f: labels.
    has reproducible stepsThe issue has been confirmed reproducible and is ready to work on
    a: fidelityMatching the OEM platforms better
    a: qualityA truly polished experience
    and removed
    in triagePresently being triaged by the triage team
    on Apr 22, 2021
  3. 2 remaining items

  4. ziqq commented on Nov 9, 2023

    @ziqq
    Contributor

    Hello everyone, any news about this issue?

  5. victorsanni commented on Oct 2, 2024

    @victorsanni
    Contributor

    Hi @mleonhard, would you be able to open a PR with your suggested fixes? Otherwise, this seems like a candidate for the 'good first issue' label.

  6. dkwingsmt commented on Nov 4, 2024

    @dkwingsmt
    Contributor

    The separator issue can be considered a duplicated of #80921. Let's move to that issue for tracking.

  7. added
    P2Important issues not at the top of the work list
    on Nov 7, 2024
  8. added a commit that references this issue on Nov 12, 2024
    9a2e249
  9. github-actions commented on Nov 26, 2024

    @github-actions

    This thread has been automatically locked since there has not been any recent activity after it was closed. If you are still experiencing a similar issue, please open a new bug, including the output of flutter doctor -v and a minimal reproduction of the issue.

  10. locked as resolved and limited conversation to collaborators on Nov 26, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    P2Important issues not at the top of the work lista: fidelityMatching the OEM platforms bettera: qualityA truly polished experiencefound in release: 2.0Found to occur in 2.0found in release: 2.2Found to occur in 2.2frameworkflutter/packages/flutter repository. See also f: labels.has reproducible stepsThe issue has been confirmed reproducible and is ready to work onp: cupertino_uicupertino_ui package in flutter/packagesteam-designOwned by Design Languages teamtriaged-designTriaged by Design Languages team

    Type

    No type

    Projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions