Skip to content

web should use SystemUiOverlayStyle instead of WidgetsApp.color to set status bar color #123365

@maRci002

Description

@maRci002

Use case

Currently, you can set the status bar color as follows:

  • primaryColor must be set on web
  • SystemUiOverlayStyle must be used in native applications
WEB APP
web_output.mp4
app_output.mp4
import 'dart:math' as math;

import 'package:flutter/material.dart';
import 'package:flutter/services.dart';

void main() {
  runApp(const ThemeProvider(child: MyApp()));
}

class ThemeProvider extends StatefulWidget {
  const ThemeProvider({super.key, required this.child});

  static ThemeProviderData of(BuildContext context) => context.dependOnInheritedWidgetOfExactType<ThemeProviderData>()!;

  final Widget child;

  @override
  State<ThemeProvider> createState() => _ThemeProviderState();
}

class _ThemeProviderState extends State<ThemeProvider> {
  var themeMode = ThemeMode.light;
  var lightTheme = ThemeData.light(useMaterial3: true).copyWith(primaryColor: Colors.blue);
  var darkTheme = ThemeData.dark(useMaterial3: true).copyWith(primaryColor: Colors.blue);

  void toggleThemeMode() {
    setState(() {
      themeMode = themeMode == ThemeMode.light ? ThemeMode.dark : ThemeMode.light;
    });
  }

  void changePrimaryColor(Color primaryColor) {
    setState(() {
      lightTheme = lightTheme.copyWith(primaryColor: primaryColor);
      darkTheme = lightTheme.copyWith(primaryColor: primaryColor);
    });
  }

  @override
  Widget build(BuildContext context) {
    return ThemeProviderData(
      themeMode: themeMode,
      lightTheme: lightTheme,
      darkTheme: darkTheme,
      toggleThemeMode: toggleThemeMode,
      changePrimaryColor: changePrimaryColor,
      child: widget.child,
    );
  }
}

class ThemeProviderData extends InheritedWidget {
  const ThemeProviderData({
    super.key,
    required this.themeMode,
    required this.lightTheme,
    required this.darkTheme,
    required this.toggleThemeMode,
    required this.changePrimaryColor,
    required super.child,
  });

  final ThemeMode themeMode;
  final ThemeData lightTheme;
  final ThemeData darkTheme;
  final VoidCallback toggleThemeMode;
  final ValueChanged<Color> changePrimaryColor;

  @override
  bool updateShouldNotify(ThemeProviderData oldWidget) =>
      themeMode != oldWidget.themeMode ||
      lightTheme != oldWidget.lightTheme ||
      darkTheme != oldWidget.darkTheme ||
      toggleThemeMode != oldWidget.toggleThemeMode ||
      changePrimaryColor != oldWidget.changePrimaryColor;
}

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

  @override
  Widget build(BuildContext context) {
    final themeProvider = ThemeProvider.of(context);

    return MaterialApp(
      themeMode: themeProvider.themeMode,
      theme: themeProvider.lightTheme,
      darkTheme: themeProvider.darkTheme,
      home: const MyHome(),
    );
  }
}

class MyHome extends StatefulWidget {
  const MyHome({super.key});

  @override
  State<MyHome> createState() => _MyHomeState();
}

class _MyHomeState extends State<MyHome> {
  final math.Random _random = math.Random();
  SystemUiOverlayStyle _currentStyle = SystemUiOverlayStyle.dark;

  Color get randomColor => Color.fromRGBO(_random.nextInt(255), _random.nextInt(255), _random.nextInt(255), 1);

  Color? appBarColor;

  void changeStatusBarColor() {
    setState(() {
      _currentStyle = _currentStyle.copyWith(statusBarColor: randomColor);
    });
  }

  void changeStatusBarColorBySystemCall() {
    SystemChrome.setSystemUIOverlayStyle(SystemUiOverlayStyle(statusBarColor: randomColor));
  }

  void changeAppBarBarColor() {
    setState(() {
      appBarColor = randomColor;
    });
  }

  void toggleThemeMode(BuildContext context) => ThemeProvider.of(context).toggleThemeMode();

  void changePrimaryColor(BuildContext context) => ThemeProvider.of(context).changePrimaryColor(randomColor);

  @override
  Widget build(BuildContext context) {
    return AnnotatedRegion<SystemUiOverlayStyle>(
      value: _currentStyle,
      child: Scaffold(
        appBar: AppBar(
          title: const Text('SystemOverlayStyle Test'),
          backgroundColor: appBarColor,
          systemOverlayStyle: _currentStyle,
        ),
        body: Center(
          child: Column(
            mainAxisSize: MainAxisSize.min,
            children: [
              ElevatedButton(
                onPressed: changeStatusBarColor,
                child: const Text('Change status bar color'),
              ),
              const SizedBox(height: 8),
              ElevatedButton(
                onPressed: changeStatusBarColorBySystemCall,
                child: const Text('Change status bar color by system call'),
              ),
              const SizedBox(height: 8),
              ElevatedButton(
                onPressed: changeAppBarBarColor,
                child: const Text('Change app bar color'),
              ),
              const SizedBox(height: 8),
              ElevatedButton(
                onPressed: () => toggleThemeMode(context),
                child: const Text('Toggle theme mode'),
              ),
              const SizedBox(height: 8),
              ElevatedButton(
                onPressed: () => changePrimaryColor(context),
                child: const Text('Change primary color'),
              ),
            ],
          ),
        ),
      ),
    );
  }
}

Proposal

Web should use SystemUiOverlayStyle to set status bar color just like native applications.

Metadata

Metadata

Labels

a: fidelityMatching the OEM platforms betterc: new featureNothing broken; request for a new capabilityc: proposalA detailed proposal for a change to Flutterplatform-webWeb applications specifically

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions