Skip to content

Commit de145c2

Browse files
committed
feat: apply forced theme mode from FeatureAccess configuration
1 parent e5ab134 commit de145c2

5 files changed

Lines changed: 54 additions & 6 deletions

File tree

lib/app/view/app.dart

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,8 @@ class _AppState extends State<App> {
8585
Widget build(BuildContext context) {
8686
final isDeepLinkEnabled = EnvironmentConfig.APP_LINK_DOMAIN.isNotEmpty;
8787

88+
final featureAccess = context.watch<FeatureAccess>();
89+
8890
final materialApp = BlocBuilder<AppBloc, AppState>(
8991
buildWhen: (previous, current) => previous.themeSettings != current.themeSettings,
9092
builder: (context, state) {
@@ -98,13 +100,16 @@ class _AppState extends State<App> {
98100
previous.effectiveThemeMode != current.effectiveThemeMode,
99101
builder: (context, state) {
100102
final themeProvider = ThemeProvider.of(context);
103+
final forcedMode = featureAccess.supportedConfig.themeMode;
104+
final finalThemeMode = forcedMode == ThemeMode.system ? state.effectiveThemeMode : forcedMode;
105+
101106
return MaterialApp.router(
102107
locale: state.effectiveLocale,
103108
localizationsDelegates: AppLocalizations.localizationsDelegates,
104109
supportedLocales: AppLocalizations.supportedLocales,
105110
// restorationScopeId: 'App', // TODO: temporary comment to prevent AppShell's AutoRouter placeholder blink - additional investigation necessary
106111
title: EnvironmentConfig.APP_NAME,
107-
themeMode: state.effectiveThemeMode,
112+
themeMode: finalThemeMode,
108113
theme: themeProvider.light(),
109114
darkTheme: themeProvider.dark(),
110115
routerConfig: appRouter.config(

lib/data/feature_access.dart

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import 'dart:io';
22

33
import 'package:equatable/equatable.dart';
44
import 'package:flutter/foundation.dart';
5+
import 'package:flutter/material.dart';
56

67
import 'package:logging/logging.dart';
78

@@ -58,6 +59,7 @@ class FeatureAccess extends Equatable {
5859
this.termsConfig,
5960
this.systemNotificationsConfig,
6061
this.sipPresenceConfig,
62+
this.supportedConfig,
6163
);
6264

6365
final EmbeddedConfig embeddedConfig;
@@ -70,6 +72,7 @@ class FeatureAccess extends Equatable {
7072
final TermsConfig termsConfig;
7173
final SystemNotificationsConfig systemNotificationsConfig;
7274
final SipPresenceConfig sipPresenceConfig;
75+
final SupportedConfig supportedConfig;
7376

7477
static FeatureAccess create(
7578
AppConfig appConfig,
@@ -93,6 +96,7 @@ class FeatureAccess extends Equatable {
9396
final contactsConfig = ContactsMapper.map(appConfig);
9497
final systemNotificationsConfig = SystemNotificationsMapper.map(coreSupportSnapshot, appConfig);
9598
final sipPresenceConfig = SipPresenceMapper.map(coreSupportSnapshot, appConfig);
99+
final supportedConfig = SupportedMapper.map(appConfig.supported);
96100

97101
return FeatureAccess._(
98102
embeddedConfig,
@@ -105,6 +109,7 @@ class FeatureAccess extends Equatable {
105109
termsConfig,
106110
systemNotificationsConfig,
107111
sipPresenceConfig,
112+
supportedConfig,
108113
);
109114
} catch (e, stackTrace) {
110115
_logger.severe('Failed to initialize FeatureAccess', e, stackTrace);
@@ -502,6 +507,41 @@ abstract final class ContactsMapper {
502507
}
503508
}
504509

510+
/// Mapper responsible for constructing [SupportedConfig] from the raw list of [SupportedFeature].
511+
///
512+
/// This mapper parses the polymorphic list of features and maps them into a structured
513+
/// configuration object. It handles the resolution logic for each feature:
514+
///
515+
/// 1. **Theme Resolution**: Searches for [SupportedThemeMode]. If missing,
516+
/// it defaults to [ThemeModeConfig.system] (Standard Behavior).
517+
///
518+
/// 2. **Video Call Resolution**: Searches for [SupportedVideoCall]. If missing,
519+
/// it defaults to `false` (disabled), adhering to a "whitelist" approach where
520+
/// features must be explicitly enabled.
521+
abstract final class SupportedMapper {
522+
/// Maps a list of [SupportedFeature]s to a [SupportedConfig].
523+
static SupportedConfig map(List<SupportedFeature> supportedFeatures) {
524+
final themeFeature =
525+
supportedFeatures.firstWhere((e) => e is SupportedThemeMode, orElse: () => const SupportedFeature.themeMode())
526+
as SupportedThemeMode;
527+
528+
final videoCallFeature =
529+
supportedFeatures.firstWhere(
530+
(e) => e is SupportedVideoCall,
531+
orElse: () => const SupportedFeature.videoCall(enabled: false),
532+
)
533+
as SupportedVideoCall;
534+
535+
final configThemeMode = switch (themeFeature.mode) {
536+
ThemeModeConfig.auto => ThemeMode.system,
537+
ThemeModeConfig.light => ThemeMode.light,
538+
ThemeModeConfig.dark => ThemeMode.dark,
539+
};
540+
541+
return SupportedConfig(themeMode: configThemeMode, isVideoCallEnabled: videoCallFeature.enabled);
542+
}
543+
}
544+
505545
class FeatureChecker {
506546
const FeatureChecker(this._access);
507547

lib/models/feature_access/feature_access.dart

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,5 +12,6 @@ export 'messaging_config.dart';
1212
export 'settings_config.dart';
1313
export 'settings_feature.dart';
1414
export 'sip_presence_config.dart';
15+
export 'supported_feature.dart';
1516
export 'system_notifications_config.dart';
1617
export 'terms_config.dart';
Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,13 @@
1-
import 'package:webtrit_appearance_theme/models/theme_page_config.dart';
1+
import 'package:webtrit_phone/theme/theme.dart';
2+
23
import 'package:webtrit_phone/widgets/themed_scaffold.dart';
34

4-
extension ThemeModeOverrideExtension on ThemeModeOverride? {
5+
extension ThemeModeOverrideExtension on ThemeModeConfig? {
56
ContentThemeOverride toContentThemeOverride() {
67
return switch (this) {
7-
ThemeModeOverride.light => ContentThemeOverride.light,
8-
ThemeModeOverride.dark => ContentThemeOverride.dark,
9-
ThemeModeOverride.auto || null => ContentThemeOverride.auto,
8+
ThemeModeConfig.light => ContentThemeOverride.light,
9+
ThemeModeConfig.dark => ContentThemeOverride.dark,
10+
ThemeModeConfig.auto || null => ContentThemeOverride.auto,
1011
};
1112
}
1213
}

packages/webtrit_appearance_theme/lib/models/features_config/features_config.dart

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,3 +3,4 @@ export 'elevated_button_style_type.dart';
33
export 'embedded_resource.dart';
44
export 'embedded_resource_type.dart';
55
export 'metadata.dart';
6+
export 'supported_feature.dart';

0 commit comments

Comments
 (0)