mirror of
https://github.com/zarzet/SpotiFLAC-Mobile.git
synced 2026-10-21 15:02:21 +02:00
The Material theme now draws its main surfaces with rounded Material Symbols: navigation, player, mini player, queue, settings, sheets, dialogs and shared controls. AppIcon maps legacy Icons to their symbol and keeps outlined glyphs unfilled. Mornye keeps its original icons. Icon buttons, text and filled buttons, dialog actions, sliders, the setup FAB and indeterminate spinners use the Material 3 Expressive components. Each wrapper falls back to the standard Flutter widget for Mornye, reduced motion and custom sizing, so existing layouts and hit areas stay intact.
101 lines
2.7 KiB
Dart
101 lines
2.7 KiB
Dart
import 'package:flutter/material.dart';
|
|
import 'package:spotiflac_android/theme/material_symbols.dart';
|
|
import 'package:spotiflac_android/theme/mornye_icons.dart';
|
|
import 'package:spotiflac_android/theme/mornye_theme.dart';
|
|
|
|
/// [widget] as an [AppIcon] when it is a plain [Icon], so shared components
|
|
/// can adopt Material Symbols without changing every caller.
|
|
Widget symbolIconWidget(Widget widget) {
|
|
if (widget case Icon(:final icon?)) {
|
|
return AppIcon(
|
|
icon,
|
|
key: widget.key,
|
|
size: widget.size,
|
|
color: widget.color,
|
|
fill: widget.fill,
|
|
semanticLabel: widget.semanticLabel,
|
|
shadows: widget.shadows,
|
|
textDirection: widget.textDirection,
|
|
);
|
|
}
|
|
return widget;
|
|
}
|
|
|
|
/// [Icon] that draws the Material theme with rounded Material Symbols.
|
|
///
|
|
/// Mornye keeps [icon] unchanged, or its Cupertino counterpart with
|
|
/// [AppIcon.adaptive]. Icons without a symbol fall back to [icon].
|
|
class AppIcon extends StatelessWidget {
|
|
const AppIcon(
|
|
this.icon, {
|
|
super.key,
|
|
this.size,
|
|
this.color,
|
|
this.fill,
|
|
this.semanticLabel,
|
|
this.shadows,
|
|
this.textDirection,
|
|
}) : _adaptive = false;
|
|
|
|
/// Uses [mornyeIconFor] when the Mornye theme is on.
|
|
const AppIcon.adaptive(
|
|
this.icon, {
|
|
super.key,
|
|
this.size,
|
|
this.color,
|
|
this.fill,
|
|
this.semanticLabel,
|
|
this.shadows,
|
|
this.textDirection,
|
|
}) : _adaptive = true;
|
|
|
|
final IconData? icon;
|
|
final double? size;
|
|
final Color? color;
|
|
|
|
/// Overrides the symbol fill; null keeps the legacy glyph's filled state.
|
|
final double? fill;
|
|
final String? semanticLabel;
|
|
final List<Shadow>? shadows;
|
|
final TextDirection? textDirection;
|
|
final bool _adaptive;
|
|
|
|
@override
|
|
Widget build(BuildContext context) {
|
|
final icon = this.icon;
|
|
if (context.isMornye) {
|
|
return Icon(
|
|
_adaptive && icon != null ? mornyeIconFor(icon) : icon,
|
|
size: size,
|
|
color: color,
|
|
semanticLabel: semanticLabel,
|
|
shadows: shadows,
|
|
textDirection: textDirection,
|
|
);
|
|
}
|
|
final symbol = materialSymbolFor(icon);
|
|
if (symbol == null) {
|
|
return Icon(
|
|
icon,
|
|
size: size,
|
|
color: color,
|
|
semanticLabel: semanticLabel,
|
|
shadows: shadows,
|
|
textDirection: textDirection,
|
|
);
|
|
}
|
|
final resolvedSize = size ?? IconTheme.of(context).size ?? 24;
|
|
return Icon(
|
|
symbol.icon,
|
|
size: size,
|
|
color: color,
|
|
fill: fill ?? (symbol.filled ? 1 : 0),
|
|
// Material Symbols adjust stroke detail for the drawn size.
|
|
opticalSize: resolvedSize.clamp(20, 48).toDouble(),
|
|
semanticLabel: semanticLabel,
|
|
shadows: shadows,
|
|
textDirection: textDirection,
|
|
);
|
|
}
|
|
}
|