Skip to content

Commit

Permalink
feat(YaruWindowControl): follow system settings
Browse files Browse the repository at this point in the history
Fixes #532
  • Loading branch information
Feichtmeier committed Nov 30, 2024
1 parent ca0e8ee commit b3a6f03
Show file tree
Hide file tree
Showing 8 changed files with 247 additions and 79 deletions.
7 changes: 7 additions & 0 deletions example/lib/example.dart
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@ class _MasterDetailPage extends StatelessWidget {
buildFloatingActionButton(context, pageItems[index]),
),
appBar: YaruWindowTitleBar(
style: getStyle(context),
title: const Text('Yaru'),
border: BorderSide.none,
backgroundColor: YaruMasterDetailTheme.of(context).sideBarColor,
Expand Down Expand Up @@ -94,6 +95,12 @@ class _MasterDetailPage extends StatelessWidget {
),
);
}

YaruTitleBarStyle getStyle(BuildContext context) {
return YaruTheme.maybeOf(context)?.hasLeftWindowControls == true
? YaruTitleBarStyle.onlyLeftWindowControls
: YaruTitleBarStyle.undecorated;
}
}

class _CompactPage extends StatefulWidget {
Expand Down
2 changes: 1 addition & 1 deletion example/lib/pages/search_field_page.dart
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ class _SearchFieldPageState extends State<SearchFieldPage> {
shadowColor: light ? Colors.black : null,
titlePadding: EdgeInsets.zero,
title: YaruDialogTitleBar(
heroTag: 'bar2',
rightHeroTag: 'bar2',
titleSpacing: 0,
centerTitle: true,
title: _fieldSearchActive
Expand Down
2 changes: 2 additions & 0 deletions lib/src/settings/gtk_constants.dart
Original file line number Diff line number Diff line change
@@ -1,2 +1,4 @@
const kSchemaInterface = 'org.gnome.desktop.interface';
const kSchemeWmPreferences = 'org.gnome.desktop.wm.preferences';
const kAccentColorKey = 'accent-color';
const kButtonLayoutKey = 'button-layout';
85 changes: 70 additions & 15 deletions lib/src/settings/inherited_theme.dart
Original file line number Diff line number Diff line change
Expand Up @@ -142,33 +142,51 @@ class YaruTheme extends StatefulWidget {
class _YaruThemeState extends State<YaruTheme> {
YaruVariant? _variant;
YaruSettings? _settings;
StreamSubscription<String?>? _themeNameSubscription;
StreamSubscription<String?>? _accentColorSubScription;
final Map<String, List<String>?> _customTitleButtonLayout = {
'left': null,
'right': null,
};
StreamSubscription<String?>? _themeNameSub;
StreamSubscription<String?>? _accentColorSub;
StreamSubscription<String?>? _buttonLayoutSub;

@override
void initState() {
super.initState();
if (widget.data.variant == null && canDetectVariant()) {
if (canDetectGnome()) {
_settings = widget._settings ?? YaruSettings();
_settings?.init();
_variant = resolveAccentColorVariant(_settings?.getAccentColor()) ??
resolveGtkThemeVariant(_settings?.getThemeName());
_accentColorSubScription ??=
_settings!.accentColorChanged.listen(updateVariant);
_themeNameSubscription ??=
_settings!.themeNameChanged.listen(updateVariant);
if (widget.data.variant == null) {
_variant = resolveAccentColorVariant(_settings?.getAccentColor()) ??
resolveGtkThemeVariant(_settings?.getThemeName());
_accentColorSub ??= _settings!.accentColorChanged.listen(updateVariant);
_themeNameSub ??= _settings!.themeNameChanged.listen(updateVariant);

_buttonLayoutSub ??=
_settings!.buttonLayoutChanged.listen(updateButtonLayout);

final buttonLayout = _settings?.getButtonLayout();

final buttons = buttonLayout?.split(':');

_customTitleButtonLayout['left'] =
buttons?.firstOrNull?.split(',') ?? <String>[];
_customTitleButtonLayout['right'] =
buttons?.lastOrNull?.split(',') ?? [];
}
}
}

@override
void dispose() {
_themeNameSubscription?.cancel();
_accentColorSubScription?.cancel();
_themeNameSub?.cancel();
_accentColorSub?.cancel();
_buttonLayoutSub?.cancel();
_settings?.dispose();
super.dispose();
}

bool canDetectVariant() {
bool canDetectGnome() {
return !kIsWeb &&
widget._platform.isLinux &&
!widget._platform.environment.containsKey('FLUTTER_TEST');
Expand Down Expand Up @@ -221,7 +239,7 @@ class _YaruThemeState extends State<YaruTheme> {
};

void updateVariant([String? value]) {
assert(canDetectVariant());
assert(canDetectGnome());
final gtkThemeName = value ?? _settings?.getThemeName();
final accentColor = value ?? _settings?.getAccentColor();
setState(
Expand All @@ -230,6 +248,24 @@ class _YaruThemeState extends State<YaruTheme> {
);
}

void updateButtonLayout([String? value]) {
assert(canDetectGnome());
final buttonLayout = value ?? _settings?.getButtonLayout();

final buttons = buttonLayout?.split(':');

setState(() {
_customTitleButtonLayout.update(
'left',
(value) => buttons?.firstOrNull?.split(',') ?? <String>[],
);
_customTitleButtonLayout.update(
'right',
(value) => buttons?.lastOrNull?.split(',') ?? [],
);
});
}

ThemeMode resolveMode() {
final mode = widget.data.themeMode ?? ThemeMode.system;
if (mode == ThemeMode.system) {
Expand All @@ -246,6 +282,8 @@ class _YaruThemeState extends State<YaruTheme> {
highContrast:
widget.data.highContrast ?? MediaQuery.highContrastOf(context),
themeMode: resolveMode(),
customTitleButtonLayout:
widget.data.customTitleButtonLayout ?? _customTitleButtonLayout,
);
}

Expand All @@ -262,7 +300,7 @@ class _YaruThemeState extends State<YaruTheme> {

@override
Widget build(BuildContext context) {
if (_settings != null && _themeNameSubscription == null) {
if (_settings != null && _themeNameSub == null) {
return const SizedBox.shrink(); // #231
}
final data = resolveData();
Expand All @@ -287,11 +325,20 @@ class YaruThemeData with Diagnosticable {
this.pageTransitionsTheme,
this.useMaterial3,
this.visualDensity,
this.customTitleButtonLayout,
});

/// Specifies the theme variant.
final YaruVariant? variant;

final Map<String, List<String>?>? customTitleButtonLayout;

bool get hasLeftWindowControls =>
customTitleButtonLayout?['left']?.isNotEmpty ?? false;

bool get hasRightWindowControls =>
customTitleButtonLayout?['right']?.isNotEmpty ?? false;

/// Whether to use high contrast colors.
final bool? highContrast;

Expand Down Expand Up @@ -328,6 +375,7 @@ class YaruThemeData with Diagnosticable {
PageTransitionsTheme? pageTransitionsTheme,
bool? useMaterial3,
VisualDensity? visualDensity,
Map<String, List<String>?>? customTitleButtonLayout,
}) {
return YaruThemeData(
variant: variant ?? this.variant,
Expand All @@ -337,6 +385,8 @@ class YaruThemeData with Diagnosticable {
pageTransitionsTheme: pageTransitionsTheme ?? this.pageTransitionsTheme,
useMaterial3: useMaterial3 ?? this.useMaterial3,
visualDensity: visualDensity ?? this.visualDensity,
customTitleButtonLayout:
customTitleButtonLayout ?? this.customTitleButtonLayout,
);
}

Expand All @@ -351,6 +401,9 @@ class YaruThemeData with Diagnosticable {
.add(DiagnosticsProperty('pageTransitionsTheme', pageTransitionsTheme));
properties.add(DiagnosticsProperty('useMaterial3', useMaterial3));
properties.add(DiagnosticsProperty('visualDensity', visualDensity));
properties.add(
DiagnosticsProperty('customTitleButtonLayout', customTitleButtonLayout),
);
}

@override
Expand All @@ -364,7 +417,8 @@ class YaruThemeData with Diagnosticable {
iterableEquals(other.extensions, extensions) &&
other.pageTransitionsTheme == pageTransitionsTheme &&
other.useMaterial3 == useMaterial3 &&
other.visualDensity == visualDensity;
other.visualDensity == visualDensity &&
other.customTitleButtonLayout == customTitleButtonLayout;
}

@override
Expand All @@ -377,6 +431,7 @@ class YaruThemeData with Diagnosticable {
pageTransitionsTheme,
useMaterial3,
visualDensity,
customTitleButtonLayout,
);
}
}
Expand Down
30 changes: 26 additions & 4 deletions lib/src/settings/yaru_settings.dart
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,10 @@ abstract class YaruSettings {

String? getThemeName();
String? getAccentColor();
String? getButtonLayout();
Stream<String?> get themeNameChanged;
Stream<String?> get accentColorChanged;
Stream<String?> get buttonLayoutChanged;
void init();
Future<void> dispose();
}
Expand All @@ -27,7 +29,8 @@ class YaruGtkSettings extends YaruSettings {

final GtkSettings _gtkSettings;
final GSettingsService _gSettingsService;
GnomeSettings? _gSettings;
GnomeSettings? _interfaceSettings;
GnomeSettings? _wmPrefSettings;

@override
String? getThemeName() => _gtkSettings.getProperty(kGtkThemeName) as String?;
Expand All @@ -40,20 +43,39 @@ class YaruGtkSettings extends YaruSettings {
@override
Stream<String?> get accentColorChanged => _accentColorController.stream;

final _buttonLayoutController = StreamController<String?>.broadcast();
@override
Stream<String?> get buttonLayoutChanged => _buttonLayoutController.stream;

@override
void init() {
_gSettings ??= _gSettingsService.lookup(kSchemaInterface);
_gSettings?.addListener(
_interfaceSettings ??= _gSettingsService.lookup(kSchemaInterface);
_interfaceSettings?.addListener(
() => _accentColorController.add(getAccentColor()),
);
_wmPrefSettings ??= _gSettingsService.lookup(kSchemeWmPreferences);
_wmPrefSettings?.addListener(
() => _buttonLayoutController.add(getButtonLayout()),
);
}

@override
Future<void> dispose() async {
await _accentColorController.close();
await _buttonLayoutController.close();
await _gSettingsService.dispose();
}

@override
String? getAccentColor() => _gSettings?.stringValue(kAccentColorKey);
String? getAccentColor() => _interfaceSettings?.stringValue(kAccentColorKey);

@override
String? getButtonLayout() {
final layout = _wmPrefSettings?.stringValue(kButtonLayoutKey);
return (layout == null || layout == 'appmenu:close')
? _defaultLayout
: layout;
}
}

const _defaultLayout = ':minimize,maximize,close';
Loading

0 comments on commit b3a6f03

Please sign in to comment.