Skip to content

Commit

Permalink
core: add animatedTheme setting, editable by performance mode
Browse files Browse the repository at this point in the history
- with other smol perf boost
  • Loading branch information
MSOB7YY committed Sep 17, 2024
1 parent 3e28717 commit 25a229f
Show file tree
Hide file tree
Showing 11 changed files with 154 additions and 99 deletions.
5 changes: 5 additions & 0 deletions lib/controller/settings_controller.dart
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ class _SettingsController with SettingsFileWriter {
final themeMode = ThemeMode.system.obs;
final pitchBlack = false.obs;
final autoColor = true.obs;
final animatedTheme = true.obs;
final staticColor = kMainColorLight.value.obs;
final staticColorDark = kMainColorDark.value.obs;
final RxList<LibraryTab> libraryTabs = [
Expand Down Expand Up @@ -296,6 +297,7 @@ class _SettingsController with SettingsFileWriter {
themeMode.value = ThemeMode.values.getEnum(json['themeMode']) ?? themeMode.value;
pitchBlack.value = json['pitchBlack'] ?? pitchBlack.value;
autoColor.value = json['autoColor'] ?? autoColor.value;
animatedTheme.value = json['animatedTheme'] ?? animatedTheme.value;
staticColor.value = json['staticColor'] ?? staticColor.value;
staticColorDark.value = json['staticColorDark'] ?? staticColorDark.value;
final libraryListFromStorage = json['libraryTabs'];
Expand Down Expand Up @@ -496,6 +498,7 @@ class _SettingsController with SettingsFileWriter {
'themeMode': themeMode.value.name,
'pitchBlack': pitchBlack.value,
'autoColor': autoColor.value,
'animatedTheme': animatedTheme.value,
'staticColor': staticColor.value,
'staticColorDark': staticColorDark.value,
'libraryTabs': libraryTabs.mapped((element) => element.name),
Expand Down Expand Up @@ -650,6 +653,7 @@ class _SettingsController with SettingsFileWriter {
ThemeMode? themeMode,
bool? pitchBlack,
bool? autoColor,
bool? animatedTheme,
int? staticColor,
int? staticColorDark,
int? searchResultsPlayMode,
Expand Down Expand Up @@ -789,6 +793,7 @@ class _SettingsController with SettingsFileWriter {
if (themeMode != null) this.themeMode.value = themeMode;
if (pitchBlack != null) this.pitchBlack.value = pitchBlack;
if (autoColor != null) this.autoColor.value = autoColor;
if (animatedTheme != null) this.animatedTheme.value = animatedTheme;
if (staticColor != null) this.staticColor.value = staticColor;
if (staticColorDark != null) this.staticColorDark.value = staticColorDark;
if (libraryTabs != null) {
Expand Down
3 changes: 3 additions & 0 deletions lib/core/namida_converter_ext.dart
Original file line number Diff line number Diff line change
Expand Up @@ -554,6 +554,7 @@ extension PerformanceModeUtils on PerformanceMode {
enableMiniplayerParallaxEffect: false,
artworkCacheHeightMultiplier: 0.8,
autoColor: false,
animatedTheme: false,
);
case PerformanceMode.balanced:
settings.save(
Expand All @@ -563,6 +564,7 @@ extension PerformanceModeUtils on PerformanceMode {
enableMiniplayerParallaxEffect: true,
artworkCacheHeightMultiplier: 0.9,
autoColor: true,
animatedTheme: false,
);
case PerformanceMode.goodLooking:
settings.save(
Expand All @@ -572,6 +574,7 @@ extension PerformanceModeUtils on PerformanceMode {
enableMiniplayerParallaxEffect: true,
artworkCacheHeightMultiplier: 1.0,
autoColor: true,
animatedTheme: true,
);
case PerformanceMode.custom:
settings.save(
Expand Down
2 changes: 1 addition & 1 deletion lib/ui/dialogs/edit_tags_dialog.dart
Original file line number Diff line number Diff line change
Expand Up @@ -307,7 +307,7 @@ Future<void> _editSingleTrackTagsDialog(Track track, Color? colorScheme) async {
rx: color,
builder: (context, color) {
final theme = AppThemes.inst.getAppTheme(color, null, false);
return AnimatedTheme(
return AnimatedThemeOrTheme(
data: theme,
child: Form(
key: formKey,
Expand Down
2 changes: 1 addition & 1 deletion lib/ui/dialogs/general_popup_dialog.dart
Original file line number Diff line number Diff line change
Expand Up @@ -760,7 +760,7 @@ Future<void> showGeneralPopupDialog(
builder: (context, colorDelightened) {
final theme = AppThemes.inst.getAppTheme(colorDelightened, null, false);
final iconColor = Color.alphaBlend(colorDelightened.withAlpha(120), theme.textTheme.displayMedium!.color!);
return AnimatedTheme(
return AnimatedThemeOrTheme(
data: theme,
child: Dialog(
backgroundColor: theme.dialogBackgroundColor,
Expand Down
4 changes: 2 additions & 2 deletions lib/ui/dialogs/track_info_dialog.dart
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ Future<void> showTrackInfoDialog(
rx: color,
builder: (context, dialogColor) {
final theme = AppThemes.inst.getAppTheme(dialogColor, null, true);
return AnimatedTheme(
return AnimatedThemeOrTheme(
data: theme,
child: CustomBlurryDialog(
theme: theme,
Expand Down Expand Up @@ -175,7 +175,7 @@ Future<void> showTrackInfoDialog(
rx: color,
builder: (context, dialogColor) {
final theme = AppThemes.inst.getAppTheme(dialogColor, null, true);
return AnimatedTheme(
return AnimatedThemeOrTheme(
data: theme,
child: CustomBlurryDialog(
theme: theme,
Expand Down
2 changes: 1 addition & 1 deletion lib/ui/dialogs/track_listens_dialog.dart
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ void showListensDialog({
rx: color,
builder: (context, dialogColor) {
final theme = AppThemes.inst.getAppTheme(dialogColor, null, false);
return AnimatedTheme(
return AnimatedThemeOrTheme(
data: theme,
child: CustomBlurryDialog(
theme: theme,
Expand Down
2 changes: 1 addition & 1 deletion lib/ui/pages/equalizer_page.dart
Original file line number Diff line number Diff line change
Expand Up @@ -210,7 +210,7 @@ class EqualizerPageState extends State<EqualizerPage> {
Widget build(BuildContext context) {
const verticalInBetweenPaddingH = 18.0;
const verticalInBetweenPadding = SizedBox(height: verticalInBetweenPaddingH);
return AnimatedTheme(
return AnimatedThemeOrTheme(
duration: const Duration(milliseconds: kThemeAnimationDurationMS),
data: context.theme,
child: BackgroundWrapper(
Expand Down
199 changes: 109 additions & 90 deletions lib/ui/pages/main_page.dart
Original file line number Diff line number Diff line change
Expand Up @@ -35,81 +35,86 @@ class MainPage extends StatelessWidget {
const MainPage({super.key, required this.animation});

@override
Widget build(BuildContext context) {
final main = WillPopScope(
onWillPop: () async {
await NamidaNavigator.inst.popPage();
return false;
},
child: Navigator(
key: NamidaNavigator.inst.navKey,
restorationScopeId: 'namida',
requestFocus: false,
observers: [NamidaNavigator.inst.heroController],
onGenerateRoute: (settings) {
WidgetsBinding.instance.addPostFrameCallback((_) {
NamidaNavigator.inst.onFirstLoad();
});
return MaterialPageRoute(
builder: (_) => const SizedBox(),
);
Widget build(BuildContext _) {
final main = RepaintBoundary(
child: WillPopScope(
onWillPop: () async {
await NamidaNavigator.inst.popPage();
return false;
},
child: Navigator(
key: NamidaNavigator.inst.navKey,
restorationScopeId: 'namida',
requestFocus: false,
observers: [NamidaNavigator.inst.heroController],
onGenerateRoute: (settings) {
WidgetsBinding.instance.addPostFrameCallback((_) {
NamidaNavigator.inst.onFirstLoad();
});
return MaterialPageRoute(
builder: (_) => const SizedBox(),
);
},
),
),
);

final searchProgressColor = context.theme.colorScheme.onSecondaryContainer.withOpacity(0.4);
final searchProgressWidget = CircularProgressIndicator(
strokeWidth: 2.0,
strokeCap: StrokeCap.round,
color: searchProgressColor,
);

final fabChild = NamidaTooltip(
message: () => ScrollSearchController.inst.isGlobalSearchMenuShown.value ? lang.CLEAR : settings.floatingActionButton.value.toText(),
child: FloatingActionButton(
heroTag: 'main_page_fab_hero',
backgroundColor: Color.alphaBlend(CurrentColor.inst.currentColorScheme.withOpacity(0.6), context.theme.cardColor),
onPressed: () {
final fab = settings.floatingActionButton.value;
final isMenuOpened = ScrollSearchController.inst.isGlobalSearchMenuShown.value;
if (fab == FABType.search || isMenuOpened) {
final isOpen = ScrollSearchController.inst.searchBarKey.currentState?.isOpen ?? false;
if (isOpen && !isMenuOpened) {
SearchSortController.inst.prepareResources();
ScrollSearchController.inst.showSearchMenu();
ScrollSearchController.inst.searchBarKey.currentState?.focusNode.requestFocus();
} else {
isMenuOpened ? SearchSortController.inst.disposeResources() : SearchSortController.inst.prepareResources();
ScrollSearchController.inst.toggleSearchMenu();
ScrollSearchController.inst.searchBarKey.currentState?.openCloseSearchBar();
final searchProgressWidget = Builder(builder: (context) {
return CircularProgressIndicator(
strokeWidth: 2.0,
strokeCap: StrokeCap.round,
color: context.theme.colorScheme.onSecondaryContainer.withOpacity(0.4),
);
});

final fabChild = Builder(
builder: (context) => NamidaTooltip(
message: () => ScrollSearchController.inst.isGlobalSearchMenuShown.value ? lang.CLEAR : settings.floatingActionButton.value.toText(),
child: FloatingActionButton(
heroTag: 'main_page_fab_hero',
backgroundColor: Color.alphaBlend(CurrentColor.inst.currentColorScheme.withOpacity(0.6), context.theme.cardColor),
onPressed: () {
final fab = settings.floatingActionButton.value;
final isMenuOpened = ScrollSearchController.inst.isGlobalSearchMenuShown.value;
if (fab == FABType.search || isMenuOpened) {
final isOpen = ScrollSearchController.inst.searchBarKey.currentState?.isOpen ?? false;
if (isOpen && !isMenuOpened) {
SearchSortController.inst.prepareResources();
ScrollSearchController.inst.showSearchMenu();
ScrollSearchController.inst.searchBarKey.currentState?.focusNode.requestFocus();
} else {
isMenuOpened ? SearchSortController.inst.disposeResources() : SearchSortController.inst.prepareResources();
ScrollSearchController.inst.toggleSearchMenu();
ScrollSearchController.inst.searchBarKey.currentState?.openCloseSearchBar();
}
} else if (fab == FABType.shuffle || fab == FABType.play) {
Player.inst.playOrPause(0, SelectedTracksController.inst.getCurrentAllTracks(), QueueSource.allTracks, shuffle: fab == FABType.shuffle);
}
} else if (fab == FABType.shuffle || fab == FABType.play) {
Player.inst.playOrPause(0, SelectedTracksController.inst.getCurrentAllTracks(), QueueSource.allTracks, shuffle: fab == FABType.shuffle);
}
},
child: ObxO(
rx: ScrollSearchController.inst.isGlobalSearchMenuShown,
builder: (context, isGlobalSearchMenuShown) => isGlobalSearchMenuShown
? ObxO(
rx: SearchSortController.inst.runningSearches,
builder: (context, runningSearches) => Stack(
alignment: Alignment.center,
children: [
const Icon(
Broken.search_status_1,
color: Color.fromRGBO(255, 255, 255, 0.8),
),
if (runningSearches.values.any((running) => running)) searchProgressWidget,
],
),
)
: ObxO(
rx: settings.floatingActionButton,
builder: (context, fabButton) => Icon(
fabButton.toIcon(),
color: const Color.fromRGBO(255, 255, 255, 0.8),
},
child: ObxO(
rx: ScrollSearchController.inst.isGlobalSearchMenuShown,
builder: (context, isGlobalSearchMenuShown) => isGlobalSearchMenuShown
? ObxO(
rx: SearchSortController.inst.runningSearches,
builder: (context, runningSearches) => Stack(
alignment: Alignment.center,
children: [
const Icon(
Broken.search_status_1,
color: Color.fromRGBO(255, 255, 255, 0.8),
),
if (runningSearches.values.any((running) => running)) searchProgressWidget,
],
),
)
: ObxO(
rx: settings.floatingActionButton,
builder: (context, fabButton) => Icon(
fabButton.toIcon(),
color: const Color.fromRGBO(255, 255, 255, 0.8),
),
),
),
),
),
),
);
Expand Down Expand Up @@ -222,28 +227,42 @@ class MainPage extends StatelessWidget {
bottomNavigationBar: _CustomNavBar(animation: animation),
);

final theme = context.theme;
return ObxO(
rx: settings.animatedTheme,
builder: (context, animatedTheme) {
if (!animatedTheme) {
return Builder(
builder: (context) => Theme(
data: context.theme,
child: mainChild,
),
);
}

final animatedThemeWidget = RepaintBoundary(
child: _AnimatedTheme(
key: _animatedThemeGlobalKey,
duration: const Duration(milliseconds: kThemeAnimationDurationMS),
data: theme,
child: mainChild,
),
);
final animatedThemeState = _animatedThemeGlobalKey.currentState;
animatedThemeState?.setAnimated(animation.value < 1);

return AnimatedBuilder(
animation: animation,
builder: (context, _) {
final mainPlayerVisible = animation.value < 1;
animatedThemeState?.setAnimated(mainPlayerVisible);
return Visibility(
maintainState: true,
visible: mainPlayerVisible,
child: animatedThemeWidget,
final animatedThemeWidget = Builder(
builder: (context) => RepaintBoundary(
child: _AnimatedTheme(
key: _animatedThemeGlobalKey,
duration: const Duration(milliseconds: kThemeAnimationDurationMS),
data: context.theme,
child: mainChild,
),
),
);
final animatedThemeState = _animatedThemeGlobalKey.currentState;
animatedThemeState?.setAnimated(animation.value < 1);

return AnimatedBuilder(
animation: animation,
builder: (context, _) {
final mainPlayerVisible = animation.value < 1;
animatedThemeState?.setAnimated(mainPlayerVisible);
return Visibility(
maintainState: true,
visible: mainPlayerVisible,
child: animatedThemeWidget,
);
},
);
},
);
Expand Down
28 changes: 28 additions & 0 deletions lib/ui/widgets/custom_widgets.dart
Original file line number Diff line number Diff line change
Expand Up @@ -4514,3 +4514,31 @@ class NamidaClearDialogExpansionTile<T> extends StatelessWidget {
);
}
}

/// Returns [AnimatedTheme] or [Theme] based on [settings.animatedTheme].
class AnimatedThemeOrTheme extends StatelessWidget {
final ThemeData data;
final Widget child;
final Duration duration;

const AnimatedThemeOrTheme({
super.key,
required this.data,
required this.child,
this.duration = kThemeAnimationDuration,
});

@override
Widget build(BuildContext context) {
return settings.animatedTheme.value
? AnimatedTheme(
data: data,
duration: duration,
child: child,
)
: Theme(
data: data,
child: child,
);
}
}
4 changes: 2 additions & 2 deletions lib/youtube/pages/yt_playlist_subpage.dart
Original file line number Diff line number Diff line change
Expand Up @@ -161,7 +161,7 @@ class _YTNormalPlaylistSubpageState extends State<YTNormalPlaylistSubpage> {
rx: YoutubePlaylistController.inst.canReorderVideos,
builder: (context, canReorderVideos) => ThreeLineSmallContainers(enabled: canReorderVideos, color: threeCColor),
);
return AnimatedTheme(
return AnimatedThemeOrTheme(
duration: const Duration(milliseconds: 300),
data: AppThemes.inst.getAppTheme(bgColor, !context.isDarkMode),
child: BackgroundWrapper(
Expand Down Expand Up @@ -550,7 +550,7 @@ class _YTHostedPlaylistSubpageState extends State<YTHostedPlaylistSubpage> with
final plIdWrapper = PlaylistID(id: plId);
final firstID = playlist.items.firstOrNull?.id;
final hasMoreStreamsLeft = playlist.canFetchNext;
return AnimatedTheme(
return AnimatedThemeOrTheme(
duration: const Duration(milliseconds: 300),
data: AppThemes.inst.getAppTheme(bgColor, !context.isDarkMode),
child: BackgroundWrapper(
Expand Down
2 changes: 1 addition & 1 deletion pubspec.yaml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
name: namida
description: A Beautiful and Feature-rich Music Player, With YouTube & Video Support Built in Flutter
publish_to: "none"
version: 4.4.1-beta+240917209
version: 4.4.14-beta+240917213

environment:
sdk: ">=3.4.0 <4.0.0"
Expand Down

0 comments on commit 25a229f

Please sign in to comment.