fix(automix): use themed transition effect picker

This commit is contained in:
zarzet committed 2026-10-04 04:42:05 +07:00
1 parent e6c7213067
commit ee8719cc5d
2 files changed
+133 -15

No files matched your search

+55 -15
View File
@@ -3,6 +3,7 @@ import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:spotiflac_android/l10n/l10n.dart';
import 'package:spotiflac_android/models/automix_options.dart';
import 'package:spotiflac_android/providers/settings_provider.dart';
import 'package:spotiflac_android/widgets/app_bottom_sheet.dart';
import 'package:spotiflac_android/widgets/settings_group.dart';
class AutoMixSettings extends ConsumerStatefulWidget {
@@ -17,6 +18,53 @@ class _AutoMixSettingsState extends ConsumerState<AutoMixSettings> {
double? _pitch;
double? _speed;
void _showEffectPicker(
BuildContext context,
AutoMixEffect current,
Map<AutoMixEffect, String> names,
) {
final notifier = ref.read(settingsProvider.notifier);
showAppBottomSheet<void>(
context: context,
useRootNavigator: true,
title: context.l10n.autoMixEffect,
maxHeightFactor: 0.85,
builder: (sheetContext) => SingleChildScrollView(
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
for (final effect in AutoMixEffect.values)
Semantics(
selected: effect == current,
child: AppSheetOption(
leading: Icon(switch (effect) {
AutoMixEffect.auto => Icons.auto_awesome,
AutoMixEffect.crossfade => Icons.compare_arrows,
AutoMixEffect.muffled => Icons.graphic_eq,
AutoMixEffect.echo => Icons.surround_sound,
AutoMixEffect.pitch => Icons.music_note,
AutoMixEffect.custom => Icons.tune,
}),
title: Text(names[effect]!),
trailing: effect == current
? Icon(
Icons.check,
color: Theme.of(sheetContext).colorScheme.primary,
)
: null,
onTap: () {
notifier.setAutoMixEffect(effect);
Navigator.pop(sheetContext);
},
),
),
const SizedBox(height: 8),
],
),
),
);
}
@override
Widget build(BuildContext context) {
final settings = ref.watch(settingsProvider);
@@ -83,21 +131,13 @@ class _AutoMixSettingsState extends ConsumerState<AutoMixSettings> {
setState(() => _duration = null);
},
),
Padding(
padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 8),
child: DropdownButtonFormField<AutoMixEffect>(
initialValue: settings.autoMixEffect,
decoration: InputDecoration(labelText: l10n.autoMixEffect),
items: [
for (final effect in AutoMixEffect.values)
DropdownMenuItem(value: effect, child: Text(names[effect]!)),
],
onChanged: enabled
? (value) {
if (value != null) notifier.setAutoMixEffect(value);
}
: null,
),
SettingsItem(
icon: Icons.tune,
title: l10n.autoMixEffect,
subtitle: names[settings.autoMixEffect],
onTap: enabled
? () => _showEffectPicker(context, settings.autoMixEffect, names)
: null,
),
if (settings.autoMixEffect == AutoMixEffect.pitch ||
settings.autoMixEffect == AutoMixEffect.custom)
+78
View File
@@ -5,8 +5,12 @@ import 'package:shared_preferences/shared_preferences.dart';
import 'package:spotiflac_android/l10n/l10n.dart';
import 'package:spotiflac_android/models/automix_options.dart';
import 'package:spotiflac_android/models/settings.dart';
import 'package:spotiflac_android/models/theme_settings.dart';
import 'package:spotiflac_android/providers/settings_provider.dart';
import 'package:spotiflac_android/widgets/automix_settings.dart';
import 'package:spotiflac_android/theme/app_theme.dart';
import 'package:spotiflac_android/theme/mornye_theme.dart';
import 'package:spotiflac_android/widgets/app_bottom_sheet.dart';
void main() {
testWidgets(
@@ -50,7 +54,81 @@ void main() {
for (final slider in tester.widgetList<Slider>(find.byType(Slider))) {
expect(slider.onChanged, isNull);
}
await tester.tap(find.text('Transition effect'));
await tester.pumpAndSettle();
expect(find.byType(BottomSheet), findsNothing);
expect(tester.takeException(), isNull);
},
);
for (final mornye in [false, true]) {
testWidgets(
'effect picker follows app theme and saves selection ($mornye)',
(tester) async {
SharedPreferences.setMockInitialValues({});
tester.view.physicalSize = const Size(350, 600);
tester.view.devicePixelRatio = 1;
addTearDown(tester.view.reset);
final container = ProviderContainer(
overrides: [
initialSettingsProvider.overrideWithValue(
const AppSettings(autoMix: true),
),
],
);
addTearDown(container.dispose);
await tester.pumpWidget(
UncontrolledProviderScope(
container: container,
child: MaterialApp(
theme: mornye
? MornyeTheme.build(
Brightness.dark,
accent: MornyeAccent.blue,
)
: AppTheme.light(seedColor: Colors.blue),
localizationsDelegates: AppLocalizations.localizationsDelegates,
supportedLocales: AppLocalizations.supportedLocales,
home: const MornyeSettingsTheme(
child: Scaffold(
body: SingleChildScrollView(child: AutoMixSettings()),
),
),
),
),
);
await tester.pumpAndSettle();
await tester.tap(find.text('Transition effect'));
await tester.pumpAndSettle();
expect(find.byType(AppBottomSheet), findsOneWidget);
expect(find.byType(AppSheetOption), findsNWidgets(6));
final context = tester.element(find.byType(AppBottomSheet));
expect(context.isMornye, mornye);
final selected = tester
.widgetList<AppSheetOption>(find.byType(AppSheetOption))
.singleWhere((option) => option.trailing != null);
expect((selected.title as Text).data, 'Auto');
expect(
(selected.trailing as Icon).color,
Theme.of(context).colorScheme.primary,
);
final custom = find.descendant(
of: find.byType(AppBottomSheet),
matching: find.text('Custom'),
);
await tester.ensureVisible(custom);
await tester.pumpAndSettle();
await tester.tap(custom);
await tester.pumpAndSettle();
expect(
container.read(settingsProvider).autoMixEffect,
AutoMixEffect.custom,
);
expect(find.byType(BottomSheet), findsNothing);
expect(find.text('Custom'), findsOneWidget);
expect(find.byType(Slider), findsNWidgets(2));
expect(tester.takeException(), isNull);
},
);
}
}