#902 widget: outline color options according to device theme
This commit is contained in:
parent
ed250f9ccf
commit
3cef268138
9 changed files with 166 additions and 75 deletions
|
@ -7,6 +7,7 @@ All notable changes to this project will be documented in this file.
|
||||||
### Added
|
### Added
|
||||||
|
|
||||||
- Viewer: prompt to show newly edited item
|
- Viewer: prompt to show newly edited item
|
||||||
|
- Widget: outline color options according to device theme
|
||||||
- Catalan translation (thanks Marc Amorós)
|
- Catalan translation (thanks Marc Amorós)
|
||||||
|
|
||||||
## <a id="v1.10.4"></a>[v1.10.4] - 2024-02-07
|
## <a id="v1.10.4"></a>[v1.10.4] - 2024-02-07
|
||||||
|
|
|
@ -87,6 +87,8 @@ class HomeWidgetProvider : AppWidgetProvider() {
|
||||||
val (widthPx, heightPx) = getWidgetSizePx(context, widgetInfo)
|
val (widthPx, heightPx) = getWidgetSizePx(context, widgetInfo)
|
||||||
if (widthPx == 0 || heightPx == 0) return null
|
if (widthPx == 0 || heightPx == 0) return null
|
||||||
|
|
||||||
|
val isNightModeOn = (context.resources.configuration.uiMode and Configuration.UI_MODE_NIGHT_MASK) == Configuration.UI_MODE_NIGHT_YES
|
||||||
|
|
||||||
initFlutterEngine(context)
|
initFlutterEngine(context)
|
||||||
val messenger = flutterEngine!!.dartExecutor
|
val messenger = flutterEngine!!.dartExecutor
|
||||||
val channel = MethodChannel(messenger, WIDGET_DRAW_CHANNEL)
|
val channel = MethodChannel(messenger, WIDGET_DRAW_CHANNEL)
|
||||||
|
@ -101,6 +103,7 @@ class HomeWidgetProvider : AppWidgetProvider() {
|
||||||
"devicePixelRatio" to getDevicePixelRatio(),
|
"devicePixelRatio" to getDevicePixelRatio(),
|
||||||
"drawEntryImage" to drawEntryImage,
|
"drawEntryImage" to drawEntryImage,
|
||||||
"reuseEntry" to reuseEntry,
|
"reuseEntry" to reuseEntry,
|
||||||
|
"isSystemThemeDark" to isNightModeOn,
|
||||||
), object : MethodChannel.Result {
|
), object : MethodChannel.Result {
|
||||||
override fun success(result: Any?) {
|
override fun success(result: Any?) {
|
||||||
cont.resume(result)
|
cont.resume(result)
|
||||||
|
|
23
lib/model/settings/enums/widget_outline.dart
Normal file
23
lib/model/settings/enums/widget_outline.dart
Normal file
|
@ -0,0 +1,23 @@
|
||||||
|
import 'package:aves_model/aves_model.dart';
|
||||||
|
import 'package:dynamic_color/dynamic_color.dart';
|
||||||
|
import 'package:flutter/foundation.dart';
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
|
extension ExtraWidgetOutline on WidgetOutline {
|
||||||
|
Future<Color?> color(Brightness brightness) async {
|
||||||
|
switch (this) {
|
||||||
|
case WidgetOutline.none:
|
||||||
|
return SynchronousFuture(null);
|
||||||
|
case WidgetOutline.black:
|
||||||
|
return SynchronousFuture(Colors.black);
|
||||||
|
case WidgetOutline.white:
|
||||||
|
return SynchronousFuture(Colors.white);
|
||||||
|
case WidgetOutline.systemBlackAndWhite:
|
||||||
|
return SynchronousFuture(brightness == Brightness.dark ? Colors.black : Colors.white);
|
||||||
|
case WidgetOutline.systemDynamic:
|
||||||
|
final corePalette = await DynamicColorPlugin.getCorePalette();
|
||||||
|
final scheme = corePalette?.toColorScheme(brightness: brightness);
|
||||||
|
return scheme?.primary ?? await WidgetOutline.systemBlackAndWhite.color(brightness);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -274,12 +274,9 @@ class Settings with ChangeNotifier, SettingsAccess, AppSettings, DisplaySettings
|
||||||
|
|
||||||
// widget
|
// widget
|
||||||
|
|
||||||
Color? getWidgetOutline(int widgetId) {
|
WidgetOutline getWidgetOutline(int widgetId) => getEnumOrDefault('${SettingKeys.widgetOutlinePrefixKey}$widgetId', WidgetOutline.none, WidgetOutline.values);
|
||||||
final value = getInt('${SettingKeys.widgetOutlinePrefixKey}$widgetId');
|
|
||||||
return value != null ? Color(value) : null;
|
|
||||||
}
|
|
||||||
|
|
||||||
void setWidgetOutline(int widgetId, Color? newValue) => set('${SettingKeys.widgetOutlinePrefixKey}$widgetId', newValue?.value);
|
void setWidgetOutline(int widgetId, WidgetOutline newValue) => set('${SettingKeys.widgetOutlinePrefixKey}$widgetId', newValue.toString());
|
||||||
|
|
||||||
WidgetShape getWidgetShape(int widgetId) => getEnumOrDefault('${SettingKeys.widgetShapePrefixKey}$widgetId', SettingsDefaults.widgetShape, WidgetShape.values);
|
WidgetShape getWidgetShape(int widgetId) => getEnumOrDefault('${SettingKeys.widgetShapePrefixKey}$widgetId', SettingsDefaults.widgetShape, WidgetShape.values);
|
||||||
|
|
||||||
|
|
|
@ -3,6 +3,7 @@ import 'dart:async';
|
||||||
import 'package:aves/app_flavor.dart';
|
import 'package:aves/app_flavor.dart';
|
||||||
import 'package:aves/model/entry/entry.dart';
|
import 'package:aves/model/entry/entry.dart';
|
||||||
import 'package:aves/model/entry/sort.dart';
|
import 'package:aves/model/entry/sort.dart';
|
||||||
|
import 'package:aves/model/settings/enums/widget_outline.dart';
|
||||||
import 'package:aves/model/settings/settings.dart';
|
import 'package:aves/model/settings/settings.dart';
|
||||||
import 'package:aves/model/source/collection_lens.dart';
|
import 'package:aves/model/source/collection_lens.dart';
|
||||||
import 'package:aves/model/source/media_store_source.dart';
|
import 'package:aves/model/source/media_store_source.dart';
|
||||||
|
@ -20,6 +21,7 @@ void widgetMainCommon(AppFlavor flavor) async {
|
||||||
WidgetsFlutterBinding.ensureInitialized();
|
WidgetsFlutterBinding.ensureInitialized();
|
||||||
initPlatformServices();
|
initPlatformServices();
|
||||||
await settings.init(monitorPlatformSettings: false);
|
await settings.init(monitorPlatformSettings: false);
|
||||||
|
await reportService.init();
|
||||||
|
|
||||||
_widgetDrawChannel.setMethodCallHandler((call) async {
|
_widgetDrawChannel.setMethodCallHandler((call) async {
|
||||||
// widget settings may be modified in a different process after channel setup
|
// widget settings may be modified in a different process after channel setup
|
||||||
|
@ -41,6 +43,10 @@ Future<Map<String, dynamic>> _drawWidget(dynamic args) async {
|
||||||
final devicePixelRatio = args['devicePixelRatio'] as double;
|
final devicePixelRatio = args['devicePixelRatio'] as double;
|
||||||
final drawEntryImage = args['drawEntryImage'] as bool;
|
final drawEntryImage = args['drawEntryImage'] as bool;
|
||||||
final reuseEntry = args['reuseEntry'] as bool;
|
final reuseEntry = args['reuseEntry'] as bool;
|
||||||
|
final isSystemThemeDark = args['isSystemThemeDark'] as bool;
|
||||||
|
|
||||||
|
final brightness = isSystemThemeDark ? Brightness.dark : Brightness.light;
|
||||||
|
final outline = await settings.getWidgetOutline(widgetId).color(brightness);
|
||||||
|
|
||||||
final entry = drawEntryImage ? await _getWidgetEntry(widgetId, reuseEntry) : null;
|
final entry = drawEntryImage ? await _getWidgetEntry(widgetId, reuseEntry) : null;
|
||||||
final painter = HomeWidgetPainter(
|
final painter = HomeWidgetPainter(
|
||||||
|
@ -50,7 +56,7 @@ Future<Map<String, dynamic>> _drawWidget(dynamic args) async {
|
||||||
final bytes = await painter.drawWidget(
|
final bytes = await painter.drawWidget(
|
||||||
widthPx: widthPx,
|
widthPx: widthPx,
|
||||||
heightPx: heightPx,
|
heightPx: heightPx,
|
||||||
outline: settings.getWidgetOutline(widgetId),
|
outline: outline,
|
||||||
shape: settings.getWidgetShape(widgetId),
|
shape: settings.getWidgetShape(widgetId),
|
||||||
);
|
);
|
||||||
return {
|
return {
|
||||||
|
|
|
@ -3,6 +3,7 @@ import 'package:flutter/widgets.dart';
|
||||||
|
|
||||||
class ColorIndicator extends StatelessWidget {
|
class ColorIndicator extends StatelessWidget {
|
||||||
final Color? value;
|
final Color? value;
|
||||||
|
final Color? alternate;
|
||||||
final Widget? child;
|
final Widget? child;
|
||||||
|
|
||||||
static const double radius = 16;
|
static const double radius = 16;
|
||||||
|
@ -10,18 +11,33 @@ class ColorIndicator extends StatelessWidget {
|
||||||
const ColorIndicator({
|
const ColorIndicator({
|
||||||
super.key,
|
super.key,
|
||||||
required this.value,
|
required this.value,
|
||||||
|
this.alternate,
|
||||||
this.child,
|
this.child,
|
||||||
});
|
});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
const dimension = radius * 2;
|
const dimension = radius * 2;
|
||||||
|
|
||||||
|
Gradient? gradient;
|
||||||
|
final _value = value;
|
||||||
|
final _alternate = alternate;
|
||||||
|
if (_value != null && _alternate != null && _alternate != _value) {
|
||||||
|
gradient = LinearGradient(
|
||||||
|
begin: AlignmentDirectional.topStart,
|
||||||
|
end: AlignmentDirectional.bottomEnd,
|
||||||
|
colors: [_value, _value, _alternate, _alternate],
|
||||||
|
stops: const [0, .5, .5, 1],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
return Container(
|
return Container(
|
||||||
height: dimension,
|
height: dimension,
|
||||||
width: dimension,
|
width: dimension,
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
color: value,
|
color: _value,
|
||||||
border: AvesBorder.border(context),
|
border: AvesBorder.border(context),
|
||||||
|
gradient: gradient,
|
||||||
shape: BoxShape.circle,
|
shape: BoxShape.circle,
|
||||||
),
|
),
|
||||||
child: child,
|
child: child,
|
||||||
|
|
|
@ -14,9 +14,10 @@ class HomeWidgetPainter {
|
||||||
final AvesEntry? entry;
|
final AvesEntry? entry;
|
||||||
final double devicePixelRatio;
|
final double devicePixelRatio;
|
||||||
|
|
||||||
|
// do not use `AlignmentDirectional` as there is no `TextDirection` in context
|
||||||
static const backgroundGradient = LinearGradient(
|
static const backgroundGradient = LinearGradient(
|
||||||
begin: AlignmentDirectional.bottomStart,
|
begin: Alignment.bottomLeft,
|
||||||
end: AlignmentDirectional.topEnd,
|
end: Alignment.topRight,
|
||||||
colors: AColors.boraBoraGradient,
|
colors: AColors.boraBoraGradient,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,6 @@
|
||||||
|
import 'package:aves/model/device.dart';
|
||||||
import 'package:aves/model/filters/filters.dart';
|
import 'package:aves/model/filters/filters.dart';
|
||||||
|
import 'package:aves/model/settings/enums/widget_outline.dart';
|
||||||
import 'package:aves/model/settings/enums/widget_shape.dart';
|
import 'package:aves/model/settings/enums/widget_shape.dart';
|
||||||
import 'package:aves/model/settings/settings.dart';
|
import 'package:aves/model/settings/settings.dart';
|
||||||
import 'package:aves/services/widget_service.dart';
|
import 'package:aves/services/widget_service.dart';
|
||||||
|
@ -33,10 +35,11 @@ class HomeWidgetSettingsPage extends StatefulWidget {
|
||||||
|
|
||||||
class _HomeWidgetSettingsPageState extends State<HomeWidgetSettingsPage> {
|
class _HomeWidgetSettingsPageState extends State<HomeWidgetSettingsPage> {
|
||||||
late WidgetShape _shape;
|
late WidgetShape _shape;
|
||||||
late Color? _outline;
|
late WidgetOutline _outline;
|
||||||
late WidgetOpenPage _openPage;
|
late WidgetOpenPage _openPage;
|
||||||
late WidgetDisplayedItem _displayedItem;
|
late WidgetDisplayedItem _displayedItem;
|
||||||
late Set<CollectionFilter> _collectionFilters;
|
late Set<CollectionFilter> _collectionFilters;
|
||||||
|
Future<Map<Brightness, Map<WidgetOutline, Color?>>> _outlineColorsByBrightness = Future.value({});
|
||||||
|
|
||||||
int get widgetId => widget.widgetId;
|
int get widgetId => widget.widgetId;
|
||||||
|
|
||||||
|
@ -61,6 +64,24 @@ class _HomeWidgetSettingsPageState extends State<HomeWidgetSettingsPage> {
|
||||||
_openPage = settings.getWidgetOpenPage(widgetId);
|
_openPage = settings.getWidgetOpenPage(widgetId);
|
||||||
_displayedItem = settings.getWidgetDisplayedItem(widgetId);
|
_displayedItem = settings.getWidgetDisplayedItem(widgetId);
|
||||||
_collectionFilters = settings.getWidgetCollectionFilters(widgetId);
|
_collectionFilters = settings.getWidgetCollectionFilters(widgetId);
|
||||||
|
WidgetsBinding.instance.addPostFrameCallback((_) => _updateOutlineColors());
|
||||||
|
}
|
||||||
|
|
||||||
|
void _updateOutlineColors() {
|
||||||
|
_outlineColorsByBrightness = _loadOutlineColors();
|
||||||
|
setState(() {});
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<Map<Brightness, Map<WidgetOutline, Color?>>> _loadOutlineColors() async {
|
||||||
|
final byBrightness = <Brightness, Map<WidgetOutline, Color?>>{};
|
||||||
|
await Future.forEach(Brightness.values, (brightness) async {
|
||||||
|
final byOutline = <WidgetOutline, Color?>{};
|
||||||
|
await Future.forEach(WidgetOutline.values, (outline) async {
|
||||||
|
byOutline[outline] = await outline.color(brightness);
|
||||||
|
});
|
||||||
|
byBrightness[brightness] = byOutline;
|
||||||
|
});
|
||||||
|
return byBrightness;
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
|
@ -71,58 +92,70 @@ class _HomeWidgetSettingsPageState extends State<HomeWidgetSettingsPage> {
|
||||||
title: Text(l10n.settingsWidgetPageTitle),
|
title: Text(l10n.settingsWidgetPageTitle),
|
||||||
),
|
),
|
||||||
body: SafeArea(
|
body: SafeArea(
|
||||||
child: Column(
|
child: FutureBuilder<Map<Brightness, Map<WidgetOutline, Color?>>>(
|
||||||
children: [
|
future: _outlineColorsByBrightness,
|
||||||
Expanded(
|
builder: (context, snapshot) {
|
||||||
child: ListView(
|
final outlineColorsByBrightness = snapshot.data;
|
||||||
children: [
|
if (outlineColorsByBrightness == null) return const SizedBox();
|
||||||
_buildShapeSelector(),
|
|
||||||
ListTile(
|
final effectiveOutlineColors = outlineColorsByBrightness[Theme.of(context).brightness];
|
||||||
title: Text(l10n.settingsWidgetShowOutline),
|
if (effectiveOutlineColors == null) return const SizedBox();
|
||||||
trailing: HomeWidgetOutlineSelector(
|
|
||||||
getter: () => _outline,
|
return Column(
|
||||||
setter: (v) => setState(() => _outline = v),
|
children: [
|
||||||
),
|
Expanded(
|
||||||
|
child: ListView(
|
||||||
|
children: [
|
||||||
|
_buildShapeSelector(effectiveOutlineColors),
|
||||||
|
ListTile(
|
||||||
|
title: Text(l10n.settingsWidgetShowOutline),
|
||||||
|
trailing: HomeWidgetOutlineSelector(
|
||||||
|
getter: () => _outline,
|
||||||
|
setter: (v) => setState(() => _outline = v),
|
||||||
|
outlineColorsByBrightness: outlineColorsByBrightness,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
SettingsSelectionListTile<WidgetOpenPage>(
|
||||||
|
values: WidgetOpenPage.values,
|
||||||
|
getName: (context, v) => v.getName(context),
|
||||||
|
selector: (context, s) => _openPage,
|
||||||
|
onSelection: (v) => setState(() => _openPage = v),
|
||||||
|
tileTitle: l10n.settingsWidgetOpenPage,
|
||||||
|
),
|
||||||
|
SettingsSelectionListTile<WidgetDisplayedItem>(
|
||||||
|
values: WidgetDisplayedItem.values,
|
||||||
|
getName: (context, v) => v.getName(context),
|
||||||
|
selector: (context, s) => _displayedItem,
|
||||||
|
onSelection: (v) => setState(() => _displayedItem = v),
|
||||||
|
tileTitle: l10n.settingsWidgetDisplayedItem,
|
||||||
|
),
|
||||||
|
SettingsCollectionTile(
|
||||||
|
filters: _collectionFilters,
|
||||||
|
onSelection: (v) => setState(() => _collectionFilters = v),
|
||||||
|
),
|
||||||
|
],
|
||||||
),
|
),
|
||||||
SettingsSelectionListTile<WidgetOpenPage>(
|
),
|
||||||
values: WidgetOpenPage.values,
|
const Divider(height: 0),
|
||||||
getName: (context, v) => v.getName(context),
|
Padding(
|
||||||
selector: (context, s) => _openPage,
|
padding: const EdgeInsets.all(8),
|
||||||
onSelection: (v) => setState(() => _openPage = v),
|
child: AvesOutlinedButton(
|
||||||
tileTitle: l10n.settingsWidgetOpenPage,
|
label: l10n.saveTooltip,
|
||||||
|
onPressed: () {
|
||||||
|
_saveSettings();
|
||||||
|
WidgetService.configure();
|
||||||
|
},
|
||||||
),
|
),
|
||||||
SettingsSelectionListTile<WidgetDisplayedItem>(
|
),
|
||||||
values: WidgetDisplayedItem.values,
|
],
|
||||||
getName: (context, v) => v.getName(context),
|
);
|
||||||
selector: (context, s) => _displayedItem,
|
},
|
||||||
onSelection: (v) => setState(() => _displayedItem = v),
|
|
||||||
tileTitle: l10n.settingsWidgetDisplayedItem,
|
|
||||||
),
|
|
||||||
SettingsCollectionTile(
|
|
||||||
filters: _collectionFilters,
|
|
||||||
onSelection: (v) => setState(() => _collectionFilters = v),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
const Divider(height: 0),
|
|
||||||
Padding(
|
|
||||||
padding: const EdgeInsets.all(8),
|
|
||||||
child: AvesOutlinedButton(
|
|
||||||
label: l10n.saveTooltip,
|
|
||||||
onPressed: () {
|
|
||||||
_saveSettings();
|
|
||||||
WidgetService.configure();
|
|
||||||
},
|
|
||||||
),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
Widget _buildShapeSelector() {
|
Widget _buildShapeSelector(Map<WidgetOutline, Color?> outlineColors) {
|
||||||
return Padding(
|
return Padding(
|
||||||
padding: const EdgeInsets.symmetric(vertical: 8, horizontal: 8),
|
padding: const EdgeInsets.symmetric(vertical: 8, horizontal: 8),
|
||||||
child: Wrap(
|
child: Wrap(
|
||||||
|
@ -143,7 +176,7 @@ class _HomeWidgetSettingsPageState extends State<HomeWidgetSettingsPage> {
|
||||||
height: 124,
|
height: 124,
|
||||||
decoration: ShapeDecoration(
|
decoration: ShapeDecoration(
|
||||||
gradient: selected ? gradient : deselectedGradient,
|
gradient: selected ? gradient : deselectedGradient,
|
||||||
shape: _WidgetShapeBorder(_outline, shape),
|
shape: _WidgetShapeBorder(_outline, shape, outlineColors),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
@ -169,12 +202,13 @@ class _HomeWidgetSettingsPageState extends State<HomeWidgetSettingsPage> {
|
||||||
}
|
}
|
||||||
|
|
||||||
class _WidgetShapeBorder extends ShapeBorder {
|
class _WidgetShapeBorder extends ShapeBorder {
|
||||||
final Color? outline;
|
final WidgetOutline outline;
|
||||||
final WidgetShape shape;
|
final WidgetShape shape;
|
||||||
|
final Map<WidgetOutline, Color?> outlineColors;
|
||||||
|
|
||||||
static const _devicePixelRatio = 1.0;
|
static const _devicePixelRatio = 1.0;
|
||||||
|
|
||||||
const _WidgetShapeBorder(this.outline, this.shape);
|
const _WidgetShapeBorder(this.outline, this.shape, this.outlineColors);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
EdgeInsetsGeometry get dimensions => EdgeInsets.zero;
|
EdgeInsetsGeometry get dimensions => EdgeInsets.zero;
|
||||||
|
@ -191,10 +225,11 @@ class _WidgetShapeBorder extends ShapeBorder {
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void paint(Canvas canvas, Rect rect, {TextDirection? textDirection}) {
|
void paint(Canvas canvas, Rect rect, {TextDirection? textDirection}) {
|
||||||
if (outline != null) {
|
final outlineColor = outlineColors[outline];
|
||||||
|
if (outlineColor != null) {
|
||||||
final path = shape.path(rect.size, _devicePixelRatio);
|
final path = shape.path(rect.size, _devicePixelRatio);
|
||||||
canvas.clipPath(path);
|
canvas.clipPath(path);
|
||||||
HomeWidgetPainter.drawOutline(canvas, path, _devicePixelRatio, outline!);
|
HomeWidgetPainter.drawOutline(canvas, path, _devicePixelRatio, outlineColor);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -203,13 +238,15 @@ class _WidgetShapeBorder extends ShapeBorder {
|
||||||
}
|
}
|
||||||
|
|
||||||
class HomeWidgetOutlineSelector extends StatefulWidget {
|
class HomeWidgetOutlineSelector extends StatefulWidget {
|
||||||
final ValueGetter<Color?> getter;
|
final ValueGetter<WidgetOutline> getter;
|
||||||
final ValueSetter<Color?> setter;
|
final ValueSetter<WidgetOutline> setter;
|
||||||
|
final Map<Brightness, Map<WidgetOutline, Color?>> outlineColorsByBrightness;
|
||||||
|
|
||||||
const HomeWidgetOutlineSelector({
|
const HomeWidgetOutlineSelector({
|
||||||
super.key,
|
super.key,
|
||||||
required this.getter,
|
required this.getter,
|
||||||
required this.setter,
|
required this.setter,
|
||||||
|
required this.outlineColorsByBrightness,
|
||||||
});
|
});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
|
@ -217,35 +254,40 @@ class HomeWidgetOutlineSelector extends StatefulWidget {
|
||||||
}
|
}
|
||||||
|
|
||||||
class _HomeWidgetOutlineSelectorState extends State<HomeWidgetOutlineSelector> {
|
class _HomeWidgetOutlineSelectorState extends State<HomeWidgetOutlineSelector> {
|
||||||
static const List<Color?> options = [
|
|
||||||
null,
|
|
||||||
Colors.black,
|
|
||||||
Colors.white,
|
|
||||||
];
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return DropdownButtonHideUnderline(
|
return DropdownButtonHideUnderline(
|
||||||
child: DropdownButton<Color?>(
|
child: DropdownButton<WidgetOutline>(
|
||||||
items: _buildItems(context),
|
items: _buildItems(context),
|
||||||
value: widget.getter(),
|
value: widget.getter(),
|
||||||
onChanged: (selected) {
|
onChanged: (selected) {
|
||||||
widget.setter(selected);
|
widget.setter(selected ?? WidgetOutline.none);
|
||||||
setState(() {});
|
setState(() {});
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
List<DropdownMenuItem<Color?>> _buildItems(BuildContext context) {
|
List<DropdownMenuItem<WidgetOutline>> _buildItems(BuildContext context) {
|
||||||
return options.map((selected) {
|
return supportedWidgetOutlines.map((selected) {
|
||||||
return DropdownMenuItem<Color?>(
|
final lightColors = widget.outlineColorsByBrightness[Brightness.light];
|
||||||
|
final darkColors = widget.outlineColorsByBrightness[Brightness.dark];
|
||||||
|
return DropdownMenuItem<WidgetOutline>(
|
||||||
value: selected,
|
value: selected,
|
||||||
child: ColorIndicator(
|
child: ColorIndicator(
|
||||||
value: selected,
|
value: lightColors?[selected],
|
||||||
child: selected == null ? const Icon(AIcons.clear) : null,
|
alternate: darkColors?[selected],
|
||||||
|
child: lightColors?[selected] == null ? const Icon(AIcons.clear) : null,
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}).toList();
|
}).toList();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
List<WidgetOutline> get supportedWidgetOutlines => [
|
||||||
|
WidgetOutline.none,
|
||||||
|
WidgetOutline.black,
|
||||||
|
WidgetOutline.white,
|
||||||
|
WidgetOutline.systemBlackAndWhite,
|
||||||
|
if (device.isDynamicColorAvailable) WidgetOutline.systemDynamic,
|
||||||
|
];
|
||||||
}
|
}
|
||||||
|
|
|
@ -48,4 +48,6 @@ enum WidgetDisplayedItem { random, mostRecent }
|
||||||
|
|
||||||
enum WidgetOpenPage { home, collection, viewer, updateWidget }
|
enum WidgetOpenPage { home, collection, viewer, updateWidget }
|
||||||
|
|
||||||
|
enum WidgetOutline { none, black, white, systemBlackAndWhite, systemDynamic }
|
||||||
|
|
||||||
enum WidgetShape { rrect, circle, heart }
|
enum WidgetShape { rrect, circle, heart }
|
||||||
|
|
Loading…
Reference in a new issue