From c7817909ce0920fac6d70706bc596e6fa3039a09 Mon Sep 17 00:00:00 2001 From: Amin <23167933+aminsaedi@users.noreply.github.com> Date: Sun, 29 Oct 2023 05:56:48 -0400 Subject: [PATCH 001/195] Updated README.md file (#847) --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 71589794..d82af783 100644 --- a/README.md +++ b/README.md @@ -108,7 +108,7 @@ This handy table lists all methods you can use to install Spotube: Debian/Ubuntu Download -

Then run: sudo apt install Spotube-linux-x86_64.deb

+

Then run: sudo apt install ./Spotube-linux-x86_64.deb

From ac0e2e74d803a902b0abef94f674f68ffcd81fd3 Mon Sep 17 00:00:00 2001 From: Kingkor Roy Tirtho Date: Wed, 8 Nov 2023 11:43:17 +0600 Subject: [PATCH 002/195] refactor: extract settings section to separate files --- lib/pages/home/genres.dart | 3 +- lib/pages/settings/sections/about.dart | 84 +++ lib/pages/settings/sections/appearance.dart | 109 ++++ lib/pages/settings/sections/desktop.dart | 54 ++ lib/pages/settings/sections/developers.dart | 27 + lib/pages/settings/sections/downloads.dart | 51 ++ .../settings/sections/language_region.dart | 74 +++ lib/pages/settings/sections/playback.dart | 218 +++++++ lib/pages/settings/settings.dart | 541 +----------------- lib/utils/persisted_state_notifier.dart | 36 +- pubspec.lock | 4 +- 11 files changed, 653 insertions(+), 548 deletions(-) create mode 100644 lib/pages/settings/sections/about.dart create mode 100644 lib/pages/settings/sections/appearance.dart create mode 100644 lib/pages/settings/sections/desktop.dart create mode 100644 lib/pages/settings/sections/developers.dart create mode 100644 lib/pages/settings/sections/downloads.dart create mode 100644 lib/pages/settings/sections/language_region.dart create mode 100644 lib/pages/settings/sections/playback.dart diff --git a/lib/pages/home/genres.dart b/lib/pages/home/genres.dart index b4e3c664..db1c58c5 100644 --- a/lib/pages/home/genres.dart +++ b/lib/pages/home/genres.dart @@ -74,7 +74,8 @@ class GenrePage extends HookConsumerWidget { searchController: searchController, searchFocus: searchFocus, ), - if (!categoriesQuery.hasPageData) + if (!categoriesQuery.hasPageData && + !categoriesQuery.isLoadingNextPage) const ShimmerCategories() else Expanded( diff --git a/lib/pages/settings/sections/about.dart b/lib/pages/settings/sections/about.dart new file mode 100644 index 00000000..0340b27c --- /dev/null +++ b/lib/pages/settings/sections/about.dart @@ -0,0 +1,84 @@ +import 'package:auto_size_text/auto_size_text.dart'; +import 'package:flutter/material.dart'; +import 'package:go_router/go_router.dart'; +import 'package:hooks_riverpod/hooks_riverpod.dart'; +import 'package:spotube/collections/env.dart'; +import 'package:spotube/collections/spotube_icons.dart'; +import 'package:spotube/components/settings/section_card_with_heading.dart'; +import 'package:spotube/components/shared/adaptive/adaptive_list_tile.dart'; +import 'package:spotube/extensions/context.dart'; +import 'package:spotube/provider/user_preferences_provider.dart'; +import 'package:url_launcher/url_launcher_string.dart'; + +class SettingsAboutSection extends HookConsumerWidget { + const SettingsAboutSection({Key? key}) : super(key: key); + + @override + Widget build(BuildContext context, ref) { + final preferences = ref.watch(userPreferencesProvider); + + return SectionCardWithHeading( + heading: context.l10n.about, + children: [ + AdaptiveListTile( + leading: const Icon( + SpotubeIcons.heart, + color: Colors.pink, + ), + title: SizedBox( + height: 50, + width: 200, + child: Align( + alignment: Alignment.centerLeft, + child: AutoSizeText( + context.l10n.u_love_spotube, + maxLines: 1, + style: const TextStyle( + color: Colors.pink, + fontWeight: FontWeight.bold, + ), + ), + ), + ), + trailing: (context, update) => FilledButton( + style: ButtonStyle( + backgroundColor: MaterialStatePropertyAll(Colors.red[100]), + foregroundColor: + const MaterialStatePropertyAll(Colors.pinkAccent), + padding: const MaterialStatePropertyAll(EdgeInsets.all(15)), + ), + onPressed: () { + launchUrlString( + "https://opencollective.com/spotube", + mode: LaunchMode.externalApplication, + ); + }, + child: Row( + mainAxisSize: MainAxisSize.min, + children: [ + const Icon(SpotubeIcons.heart), + const SizedBox(width: 5), + Text(context.l10n.please_sponsor), + ], + ), + ), + ), + if (Env.enableUpdateChecker) + SwitchListTile( + secondary: const Icon(SpotubeIcons.update), + title: Text(context.l10n.check_for_updates), + value: preferences.checkUpdate, + onChanged: (checked) => preferences.setCheckUpdate(checked), + ), + ListTile( + leading: const Icon(SpotubeIcons.info), + title: Text(context.l10n.about_spotube), + trailing: const Icon(SpotubeIcons.angleRight), + onTap: () { + GoRouter.of(context).push("/settings/about"); + }, + ) + ], + ); + } +} diff --git a/lib/pages/settings/sections/appearance.dart b/lib/pages/settings/sections/appearance.dart new file mode 100644 index 00000000..f4b097e8 --- /dev/null +++ b/lib/pages/settings/sections/appearance.dart @@ -0,0 +1,109 @@ +import 'package:flutter/foundation.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_hooks/flutter_hooks.dart'; +import 'package:hooks_riverpod/hooks_riverpod.dart'; +import 'package:spotube/collections/spotube_icons.dart'; +import 'package:spotube/components/settings/color_scheme_picker_dialog.dart'; +import 'package:spotube/components/settings/section_card_with_heading.dart'; +import 'package:spotube/components/shared/adaptive/adaptive_select_tile.dart'; +import 'package:spotube/extensions/context.dart'; +import 'package:spotube/provider/user_preferences_provider.dart'; + +class SettingsAppearanceSection extends HookConsumerWidget { + const SettingsAppearanceSection({Key? key}) : super(key: key); + + @override + Widget build(BuildContext context, ref) { + final preferences = ref.watch(userPreferencesProvider); + final pickColorScheme = useCallback(() { + return () => showDialog( + context: context, + builder: (context) { + return const ColorSchemePickerDialog(); + }); + }, []); + + return SectionCardWithHeading( + heading: context.l10n.appearance, + children: [ + AdaptiveSelectTile( + secondary: const Icon(SpotubeIcons.dashboard), + title: Text(context.l10n.layout_mode), + subtitle: Text(context.l10n.override_layout_settings), + value: preferences.layoutMode, + onChanged: (value) { + if (value != null) { + preferences.setLayoutMode(value); + } + }, + options: [ + DropdownMenuItem( + value: LayoutMode.adaptive, + child: Text(context.l10n.adaptive), + ), + DropdownMenuItem( + value: LayoutMode.compact, + child: Text(context.l10n.compact), + ), + DropdownMenuItem( + value: LayoutMode.extended, + child: Text(context.l10n.extended), + ), + ], + ), + AdaptiveSelectTile( + secondary: const Icon(SpotubeIcons.darkMode), + title: Text(context.l10n.theme), + value: preferences.themeMode, + options: [ + DropdownMenuItem( + value: ThemeMode.dark, + child: Text(context.l10n.dark), + ), + DropdownMenuItem( + value: ThemeMode.light, + child: Text(context.l10n.light), + ), + DropdownMenuItem( + value: ThemeMode.system, + child: Text(context.l10n.system), + ), + ], + onChanged: (value) { + if (value != null) { + preferences.setThemeMode(value); + } + }, + ), + SwitchListTile( + secondary: const Icon(SpotubeIcons.amoled), + title: Text(context.l10n.use_amoled_mode), + subtitle: Text(context.l10n.pitch_dark_theme), + value: preferences.amoledDarkTheme, + onChanged: preferences.setAmoledDarkTheme, + ), + ListTile( + leading: const Icon(SpotubeIcons.palette), + title: Text(context.l10n.accent_color), + contentPadding: const EdgeInsets.symmetric( + horizontal: 15, + vertical: 5, + ), + trailing: ColorTile.compact( + color: preferences.accentColorScheme, + onPressed: pickColorScheme(), + isActive: true, + ), + onTap: pickColorScheme(), + ), + SwitchListTile( + secondary: const Icon(SpotubeIcons.colorSync), + title: Text(context.l10n.sync_album_color), + subtitle: Text(context.l10n.sync_album_color_description), + value: preferences.albumColorSync, + onChanged: preferences.setAlbumColorSync, + ), + ], + ); + } +} diff --git a/lib/pages/settings/sections/desktop.dart b/lib/pages/settings/sections/desktop.dart new file mode 100644 index 00000000..d12bcb41 --- /dev/null +++ b/lib/pages/settings/sections/desktop.dart @@ -0,0 +1,54 @@ +import 'package:flutter/material.dart'; +import 'package:hooks_riverpod/hooks_riverpod.dart'; +import 'package:spotube/collections/spotube_icons.dart'; +import 'package:spotube/components/settings/section_card_with_heading.dart'; +import 'package:spotube/components/shared/adaptive/adaptive_select_tile.dart'; +import 'package:spotube/extensions/context.dart'; +import 'package:spotube/provider/user_preferences_provider.dart'; + +class SettingsDesktopSection extends HookConsumerWidget { + const SettingsDesktopSection({Key? key}) : super(key: key); + + @override + Widget build(BuildContext context, ref) { + final preferences = ref.watch(userPreferencesProvider); + + return SectionCardWithHeading( + heading: context.l10n.desktop, + children: [ + AdaptiveSelectTile( + secondary: const Icon(SpotubeIcons.close), + title: Text(context.l10n.close_behavior), + value: preferences.closeBehavior, + options: [ + DropdownMenuItem( + value: CloseBehavior.close, + child: Text(context.l10n.close), + ), + DropdownMenuItem( + value: CloseBehavior.minimizeToTray, + child: Text(context.l10n.minimize_to_tray), + ), + ], + onChanged: (value) { + if (value != null) { + preferences.setCloseBehavior(value); + } + }, + ), + SwitchListTile( + secondary: const Icon(SpotubeIcons.tray), + title: Text(context.l10n.show_tray_icon), + value: preferences.showSystemTrayIcon, + onChanged: preferences.setShowSystemTrayIcon, + ), + SwitchListTile( + secondary: const Icon(SpotubeIcons.window), + title: Text(context.l10n.use_system_title_bar), + value: preferences.systemTitleBar, + onChanged: preferences.setSystemTitleBar, + ), + ], + ); + } +} diff --git a/lib/pages/settings/sections/developers.dart b/lib/pages/settings/sections/developers.dart new file mode 100644 index 00000000..4b5f58a6 --- /dev/null +++ b/lib/pages/settings/sections/developers.dart @@ -0,0 +1,27 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_hooks/flutter_hooks.dart'; +import 'package:go_router/go_router.dart'; +import 'package:spotube/collections/spotube_icons.dart'; +import 'package:spotube/components/settings/section_card_with_heading.dart'; +import 'package:spotube/extensions/context.dart'; + +class SettingsDevelopersSection extends HookWidget { + const SettingsDevelopersSection({Key? key}) : super(key: key); + + @override + Widget build(BuildContext context) { + return SectionCardWithHeading( + heading: context.l10n.developers, + children: [ + ListTile( + leading: const Icon(SpotubeIcons.logs), + title: Text(context.l10n.logs), + trailing: const Icon(SpotubeIcons.angleRight), + onTap: () { + GoRouter.of(context).push("/settings/logs"); + }, + ) + ], + ); + } +} diff --git a/lib/pages/settings/sections/downloads.dart b/lib/pages/settings/sections/downloads.dart new file mode 100644 index 00000000..1f157037 --- /dev/null +++ b/lib/pages/settings/sections/downloads.dart @@ -0,0 +1,51 @@ +import 'package:file_picker/file_picker.dart'; +import 'package:file_selector/file_selector.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_desktop_tools/flutter_desktop_tools.dart'; +import 'package:flutter_hooks/flutter_hooks.dart'; +import 'package:hooks_riverpod/hooks_riverpod.dart'; +import 'package:spotube/collections/spotube_icons.dart'; +import 'package:spotube/components/settings/section_card_with_heading.dart'; +import 'package:spotube/extensions/context.dart'; +import 'package:spotube/provider/user_preferences_provider.dart'; + +class SettingsDownloadsSection extends HookConsumerWidget { + const SettingsDownloadsSection({Key? key}) : super(key: key); + + @override + Widget build(BuildContext context, ref) { + final preferences = ref.watch(userPreferencesProvider); + + final pickDownloadLocation = useCallback(() async { + if (DesktopTools.platform.isMobile) { + final dirStr = await FilePicker.platform.getDirectoryPath( + initialDirectory: preferences.downloadLocation, + ); + if (dirStr == null) return; + preferences.setDownloadLocation(dirStr); + } else { + String? dirStr = await getDirectoryPath( + initialDirectory: preferences.downloadLocation, + ); + if (dirStr == null) return; + preferences.setDownloadLocation(dirStr); + } + }, [preferences.downloadLocation]); + + return SectionCardWithHeading( + heading: context.l10n.downloads, + children: [ + ListTile( + leading: const Icon(SpotubeIcons.download), + title: Text(context.l10n.download_location), + subtitle: Text(preferences.downloadLocation), + trailing: FilledButton( + onPressed: pickDownloadLocation, + child: const Icon(SpotubeIcons.folder), + ), + onTap: pickDownloadLocation, + ), + ], + ); + } +} diff --git a/lib/pages/settings/sections/language_region.dart b/lib/pages/settings/sections/language_region.dart new file mode 100644 index 00000000..64c56224 --- /dev/null +++ b/lib/pages/settings/sections/language_region.dart @@ -0,0 +1,74 @@ +import 'package:flutter/material.dart'; +import 'package:hooks_riverpod/hooks_riverpod.dart'; +import 'package:spotify/spotify.dart'; +import 'package:spotube/collections/language_codes.dart'; +import 'package:spotube/collections/spotify_markets.dart'; +import 'package:spotube/collections/spotube_icons.dart'; +import 'package:spotube/components/settings/section_card_with_heading.dart'; +import 'package:spotube/components/shared/adaptive/adaptive_select_tile.dart'; +import 'package:spotube/extensions/constrains.dart'; +import 'package:spotube/extensions/context.dart'; +import 'package:spotube/l10n/l10n.dart'; +import 'package:spotube/provider/user_preferences_provider.dart'; + +class SettingsLanguageRegionSection extends HookConsumerWidget { + const SettingsLanguageRegionSection({Key? key}) : super(key: key); + + @override + Widget build(BuildContext context, ref) { + final preferences = ref.watch(userPreferencesProvider); + final mediaQuery = MediaQuery.of(context); + + return SectionCardWithHeading( + heading: context.l10n.language_region, + children: [ + AdaptiveSelectTile( + value: preferences.locale, + onChanged: (locale) { + if (locale == null) return; + preferences.setLocale(locale); + }, + title: Text(context.l10n.language), + secondary: const Icon(SpotubeIcons.language), + options: [ + DropdownMenuItem( + value: const Locale("system", "system"), + child: Text(context.l10n.system_default), + ), + for (final locale in L10n.all) + DropdownMenuItem( + value: locale, + child: Builder(builder: (context) { + final isoCodeName = LanguageLocals.getDisplayLanguage( + locale.languageCode, + ); + return Text( + "${isoCodeName.name} (${isoCodeName.nativeName})", + ); + }), + ), + ], + ), + AdaptiveSelectTile( + breakLayout: mediaQuery.lgAndUp, + secondary: const Icon(SpotubeIcons.shoppingBag), + title: Text(context.l10n.market_place_region), + subtitle: Text(context.l10n.recommendation_country), + value: preferences.recommendationMarket, + onChanged: (value) { + if (value == null) return; + preferences.setRecommendationMarket(value); + }, + options: spotifyMarkets + .map( + (country) => DropdownMenuItem( + value: country.$1, + child: Text(country.$2), + ), + ) + .toList(), + ), + ], + ); + } +} diff --git a/lib/pages/settings/sections/playback.dart b/lib/pages/settings/sections/playback.dart new file mode 100644 index 00000000..cf7e33e9 --- /dev/null +++ b/lib/pages/settings/sections/playback.dart @@ -0,0 +1,218 @@ +import 'package:collection/collection.dart'; +import 'package:flutter/material.dart'; +import 'package:go_router/go_router.dart'; +import 'package:google_fonts/google_fonts.dart'; +import 'package:hooks_riverpod/hooks_riverpod.dart'; +import 'package:piped_client/piped_client.dart'; +import 'package:spotube/collections/spotube_icons.dart'; +import 'package:spotube/components/settings/section_card_with_heading.dart'; +import 'package:spotube/components/shared/adaptive/adaptive_select_tile.dart'; +import 'package:spotube/extensions/context.dart'; +import 'package:spotube/models/matched_track.dart'; +import 'package:spotube/provider/piped_instances_provider.dart'; +import 'package:spotube/provider/user_preferences_provider.dart'; + +class SettingsPlaybackSection extends HookConsumerWidget { + const SettingsPlaybackSection({Key? key}) : super(key: key); + + @override + Widget build(BuildContext context, ref) { + final preferences = ref.watch(userPreferencesProvider); + final theme = Theme.of(context); + + return SectionCardWithHeading( + heading: context.l10n.playback, + children: [ + AdaptiveSelectTile( + secondary: const Icon(SpotubeIcons.audioQuality), + title: Text(context.l10n.audio_quality), + value: preferences.audioQuality, + options: [ + DropdownMenuItem( + value: AudioQuality.high, + child: Text(context.l10n.high), + ), + DropdownMenuItem( + value: AudioQuality.low, + child: Text(context.l10n.low), + ), + ], + onChanged: (value) { + if (value != null) { + preferences.setAudioQuality(value); + } + }, + ), + AdaptiveSelectTile( + secondary: const Icon(SpotubeIcons.api), + title: Text(context.l10n.youtube_api_type), + value: preferences.youtubeApiType, + options: YoutubeApiType.values + .map((e) => DropdownMenuItem( + value: e, + child: Text(e.label), + )) + .toList(), + onChanged: (value) { + if (value == null) return; + preferences.setYoutubeApiType(value); + }, + ), + AnimatedSwitcher( + duration: const Duration(milliseconds: 300), + child: preferences.youtubeApiType == YoutubeApiType.youtube + ? const SizedBox.shrink() + : Consumer(builder: (context, ref, child) { + final instanceList = ref.watch(pipedInstancesFutureProvider); + + return instanceList.when( + data: (data) { + return AdaptiveSelectTile( + secondary: const Icon(SpotubeIcons.piped), + title: Text(context.l10n.piped_instance), + subtitle: RichText( + text: TextSpan( + children: [ + TextSpan( + text: context.l10n.piped_description, + style: theme.textTheme.bodyMedium, + ), + const TextSpan(text: "\n"), + TextSpan( + text: context.l10n.piped_warning, + style: theme.textTheme.labelMedium, + ) + ], + ), + ), + value: preferences.pipedInstance, + showValueWhenUnfolded: false, + options: data + .sortedBy((e) => e.name) + .map( + (e) => DropdownMenuItem( + value: e.apiUrl, + child: RichText( + text: TextSpan( + children: [ + TextSpan( + text: "${e.name.trim()}\n", + style: theme.textTheme.labelLarge, + ), + TextSpan( + text: e.locations + .map(countryCodeToEmoji) + .join(""), + style: GoogleFonts.notoColorEmoji(), + ), + ], + ), + ), + ), + ) + .toList(), + onChanged: (value) { + if (value != null) { + preferences.setPipedInstance(value); + } + }, + ); + }, + loading: () => const Center( + child: CircularProgressIndicator(), + ), + error: (error, stackTrace) => Text(error.toString()), + ); + }), + ), + AnimatedSwitcher( + duration: const Duration(milliseconds: 300), + child: preferences.youtubeApiType == YoutubeApiType.youtube + ? const SizedBox.shrink() + : AdaptiveSelectTile( + secondary: const Icon(SpotubeIcons.search), + title: Text(context.l10n.search_mode), + value: preferences.searchMode, + options: SearchMode.values + .map((e) => DropdownMenuItem( + value: e, + child: Text(e.label), + )) + .toList(), + onChanged: (value) { + if (value == null) return; + preferences.setSearchMode(value); + }, + ), + ), + AnimatedSwitcher( + duration: const Duration(milliseconds: 300), + child: preferences.searchMode == SearchMode.youtubeMusic && + preferences.youtubeApiType == YoutubeApiType.piped + ? const SizedBox.shrink() + : SwitchListTile( + secondary: const Icon(SpotubeIcons.skip), + title: Text(context.l10n.skip_non_music), + value: preferences.skipNonMusic, + onChanged: (state) { + preferences.setSkipNonMusic(state); + }, + ), + ), + ListTile( + leading: const Icon(SpotubeIcons.playlistRemove), + title: Text(context.l10n.blacklist), + subtitle: Text(context.l10n.blacklist_description), + onTap: () { + GoRouter.of(context).push("/settings/blacklist"); + }, + trailing: const Icon(SpotubeIcons.angleRight), + ), + SwitchListTile( + secondary: const Icon(SpotubeIcons.normalize), + title: Text(context.l10n.normalize_audio), + value: preferences.normalizeAudio, + onChanged: preferences.setNormalizeAudio, + ), + AdaptiveSelectTile( + secondary: const Icon(SpotubeIcons.stream), + title: Text(context.l10n.streaming_music_codec), + value: preferences.streamMusicCodec, + showValueWhenUnfolded: false, + options: MusicCodec.values + .map((e) => DropdownMenuItem( + value: e, + child: Text( + e.label, + style: theme.textTheme.labelMedium, + ), + )) + .toList(), + onChanged: (value) { + if (value == null) return; + preferences.setStreamMusicCodec(value); + }, + ), + AdaptiveSelectTile( + secondary: const Icon(SpotubeIcons.file), + title: Text(context.l10n.download_music_codec), + value: preferences.downloadMusicCodec, + showValueWhenUnfolded: false, + options: MusicCodec.values + .map((e) => DropdownMenuItem( + value: e, + child: Text( + e.label, + style: theme.textTheme.labelMedium, + ), + )) + .toList(), + onChanged: (value) { + if (value == null) return; + preferences.setDownloadMusicCodec(value); + }, + ), + ], + ); + } +} diff --git a/lib/pages/settings/settings.dart b/lib/pages/settings/settings.dart index 5632a89a..5b377a1f 100644 --- a/lib/pages/settings/settings.dart +++ b/lib/pages/settings/settings.dart @@ -1,34 +1,19 @@ -import 'package:auto_size_text/auto_size_text.dart'; -import 'package:collection/collection.dart'; -import 'package:file_picker/file_picker.dart'; -import 'package:file_selector/file_selector.dart'; import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:flutter_desktop_tools/flutter_desktop_tools.dart'; -import 'package:flutter_hooks/flutter_hooks.dart'; -import 'package:go_router/go_router.dart'; -import 'package:google_fonts/google_fonts.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; -import 'package:piped_client/piped_client.dart'; -import 'package:spotify/spotify.dart'; -import 'package:spotube/collections/env.dart'; -import 'package:spotube/collections/language_codes.dart'; -import 'package:spotube/collections/spotube_icons.dart'; -import 'package:spotube/components/settings/color_scheme_picker_dialog.dart'; -import 'package:spotube/components/settings/section_card_with_heading.dart'; -import 'package:spotube/components/shared/adaptive/adaptive_list_tile.dart'; -import 'package:spotube/components/shared/adaptive/adaptive_select_tile.dart'; import 'package:spotube/components/shared/inter_scrollbar/inter_scrollbar.dart'; import 'package:spotube/components/shared/page_window_title_bar.dart'; -import 'package:spotube/collections/spotify_markets.dart'; -import 'package:spotube/extensions/constrains.dart'; import 'package:spotube/extensions/context.dart'; -import 'package:spotube/l10n/l10n.dart'; -import 'package:spotube/models/matched_track.dart'; +import 'package:spotube/pages/settings/sections/about.dart'; import 'package:spotube/pages/settings/sections/accounts.dart'; +import 'package:spotube/pages/settings/sections/appearance.dart'; +import 'package:spotube/pages/settings/sections/desktop.dart'; +import 'package:spotube/pages/settings/sections/developers.dart'; +import 'package:spotube/pages/settings/sections/downloads.dart'; +import 'package:spotube/pages/settings/sections/language_region.dart'; +import 'package:spotube/pages/settings/sections/playback.dart'; import 'package:spotube/provider/user_preferences_provider.dart'; -import 'package:spotube/provider/piped_instances_provider.dart'; -import 'package:url_launcher/url_launcher_string.dart'; class SettingsPage extends HookConsumerWidget { const SettingsPage({Key? key}) : super(key: key); @@ -36,32 +21,6 @@ class SettingsPage extends HookConsumerWidget { @override Widget build(BuildContext context, ref) { final preferences = ref.watch(userPreferencesProvider); - final theme = Theme.of(context); - final mediaQuery = MediaQuery.of(context); - - final pickColorScheme = useCallback(() { - return () => showDialog( - context: context, - builder: (context) { - return const ColorSchemePickerDialog(); - }); - }, []); - - final pickDownloadLocation = useCallback(() async { - if (DesktopTools.platform.isMobile) { - final dirStr = await FilePicker.platform.getDirectoryPath( - initialDirectory: preferences.downloadLocation, - ); - if (dirStr == null) return; - preferences.setDownloadLocation(dirStr); - } else { - String? dirStr = await getDirectoryPath( - initialDirectory: preferences.downloadLocation, - ); - if (dirStr == null) return; - preferences.setDownloadLocation(dirStr); - } - }, [preferences.downloadLocation]); return SafeArea( bottom: false, @@ -80,486 +39,14 @@ class SettingsPage extends HookConsumerWidget { child: ListView( children: [ const SettingsAccountSection(), - SectionCardWithHeading( - heading: context.l10n.language_region, - children: [ - AdaptiveSelectTile( - value: preferences.locale, - onChanged: (locale) { - if (locale == null) return; - preferences.setLocale(locale); - }, - title: Text(context.l10n.language), - secondary: const Icon(SpotubeIcons.language), - options: [ - DropdownMenuItem( - value: const Locale("system", "system"), - child: Text(context.l10n.system_default), - ), - for (final locale in L10n.all) - DropdownMenuItem( - value: locale, - child: Builder(builder: (context) { - final isoCodeName = - LanguageLocals.getDisplayLanguage( - locale.languageCode, - ); - return Text( - "${isoCodeName.name} (${isoCodeName.nativeName})", - ); - }), - ), - ], - ), - AdaptiveSelectTile( - breakLayout: mediaQuery.lgAndUp, - secondary: const Icon(SpotubeIcons.shoppingBag), - title: Text(context.l10n.market_place_region), - subtitle: Text(context.l10n.recommendation_country), - value: preferences.recommendationMarket, - onChanged: (value) { - if (value == null) return; - preferences.setRecommendationMarket(value); - }, - options: spotifyMarkets - .map( - (country) => DropdownMenuItem( - value: country.$1, - child: Text(country.$2), - ), - ) - .toList(), - ), - ], - ), - SectionCardWithHeading( - heading: context.l10n.appearance, - children: [ - AdaptiveSelectTile( - secondary: const Icon(SpotubeIcons.dashboard), - title: Text(context.l10n.layout_mode), - subtitle: - Text(context.l10n.override_layout_settings), - value: preferences.layoutMode, - onChanged: (value) { - if (value != null) { - preferences.setLayoutMode(value); - } - }, - options: [ - DropdownMenuItem( - value: LayoutMode.adaptive, - child: Text(context.l10n.adaptive), - ), - DropdownMenuItem( - value: LayoutMode.compact, - child: Text(context.l10n.compact), - ), - DropdownMenuItem( - value: LayoutMode.extended, - child: Text(context.l10n.extended), - ), - ], - ), - AdaptiveSelectTile( - secondary: const Icon(SpotubeIcons.darkMode), - title: Text(context.l10n.theme), - value: preferences.themeMode, - options: [ - DropdownMenuItem( - value: ThemeMode.dark, - child: Text(context.l10n.dark), - ), - DropdownMenuItem( - value: ThemeMode.light, - child: Text(context.l10n.light), - ), - DropdownMenuItem( - value: ThemeMode.system, - child: Text(context.l10n.system), - ), - ], - onChanged: (value) { - if (value != null) { - preferences.setThemeMode(value); - } - }, - ), - SwitchListTile( - secondary: const Icon(SpotubeIcons.amoled), - title: Text(context.l10n.use_amoled_mode), - subtitle: Text(context.l10n.pitch_dark_theme), - value: preferences.amoledDarkTheme, - onChanged: preferences.setAmoledDarkTheme, - ), - ListTile( - leading: const Icon(SpotubeIcons.palette), - title: Text(context.l10n.accent_color), - contentPadding: const EdgeInsets.symmetric( - horizontal: 15, - vertical: 5, - ), - trailing: ColorTile.compact( - color: preferences.accentColorScheme, - onPressed: pickColorScheme(), - isActive: true, - ), - onTap: pickColorScheme(), - ), - SwitchListTile( - secondary: const Icon(SpotubeIcons.colorSync), - title: Text(context.l10n.sync_album_color), - subtitle: - Text(context.l10n.sync_album_color_description), - value: preferences.albumColorSync, - onChanged: preferences.setAlbumColorSync, - ), - ], - ), - SectionCardWithHeading( - heading: context.l10n.playback, - children: [ - AdaptiveSelectTile( - secondary: const Icon(SpotubeIcons.audioQuality), - title: Text(context.l10n.audio_quality), - value: preferences.audioQuality, - options: [ - DropdownMenuItem( - value: AudioQuality.high, - child: Text(context.l10n.high), - ), - DropdownMenuItem( - value: AudioQuality.low, - child: Text(context.l10n.low), - ), - ], - onChanged: (value) { - if (value != null) { - preferences.setAudioQuality(value); - } - }, - ), - AdaptiveSelectTile( - secondary: const Icon(SpotubeIcons.api), - title: Text(context.l10n.youtube_api_type), - value: preferences.youtubeApiType, - options: YoutubeApiType.values - .map((e) => DropdownMenuItem( - value: e, - child: Text(e.label), - )) - .toList(), - onChanged: (value) { - if (value == null) return; - preferences.setYoutubeApiType(value); - }, - ), - AnimatedSwitcher( - duration: const Duration(milliseconds: 300), - child: preferences.youtubeApiType == - YoutubeApiType.youtube - ? const SizedBox.shrink() - : Consumer(builder: (context, ref, child) { - final instanceList = - ref.watch(pipedInstancesFutureProvider); - - return instanceList.when( - data: (data) { - return AdaptiveSelectTile( - secondary: - const Icon(SpotubeIcons.piped), - title: - Text(context.l10n.piped_instance), - subtitle: RichText( - text: TextSpan( - children: [ - TextSpan( - text: context - .l10n.piped_description, - style: theme - .textTheme.bodyMedium, - ), - const TextSpan(text: "\n"), - TextSpan( - text: context - .l10n.piped_warning, - style: theme - .textTheme.labelMedium, - ) - ], - ), - ), - value: preferences.pipedInstance, - showValueWhenUnfolded: false, - options: data - .sortedBy((e) => e.name) - .map( - (e) => DropdownMenuItem( - value: e.apiUrl, - child: RichText( - text: TextSpan( - children: [ - TextSpan( - text: - "${e.name.trim()}\n", - style: theme.textTheme - .labelLarge, - ), - TextSpan( - text: e.locations - .map( - countryCodeToEmoji) - .join(""), - style: GoogleFonts - .notoColorEmoji(), - ), - ], - ), - ), - ), - ) - .toList(), - onChanged: (value) { - if (value != null) { - preferences - .setPipedInstance(value); - } - }, - ); - }, - loading: () => const Center( - child: CircularProgressIndicator(), - ), - error: (error, stackTrace) => - Text(error.toString()), - ); - }), - ), - AnimatedSwitcher( - duration: const Duration(milliseconds: 300), - child: preferences.youtubeApiType == - YoutubeApiType.youtube - ? const SizedBox.shrink() - : AdaptiveSelectTile( - secondary: const Icon(SpotubeIcons.search), - title: Text(context.l10n.search_mode), - value: preferences.searchMode, - options: SearchMode.values - .map((e) => DropdownMenuItem( - value: e, - child: Text(e.label), - )) - .toList(), - onChanged: (value) { - if (value == null) return; - preferences.setSearchMode(value); - }, - ), - ), - AnimatedSwitcher( - duration: const Duration(milliseconds: 300), - child: preferences.searchMode == - SearchMode.youtubeMusic && - preferences.youtubeApiType == - YoutubeApiType.piped - ? const SizedBox.shrink() - : SwitchListTile( - secondary: const Icon(SpotubeIcons.skip), - title: Text(context.l10n.skip_non_music), - value: preferences.skipNonMusic, - onChanged: (state) { - preferences.setSkipNonMusic(state); - }, - ), - ), - ListTile( - leading: const Icon(SpotubeIcons.playlistRemove), - title: Text(context.l10n.blacklist), - subtitle: Text(context.l10n.blacklist_description), - onTap: () { - GoRouter.of(context).push("/settings/blacklist"); - }, - trailing: const Icon(SpotubeIcons.angleRight), - ), - SwitchListTile( - secondary: const Icon(SpotubeIcons.normalize), - title: Text(context.l10n.normalize_audio), - value: preferences.normalizeAudio, - onChanged: preferences.setNormalizeAudio, - ), - AdaptiveSelectTile( - secondary: const Icon(SpotubeIcons.stream), - title: Text(context.l10n.streaming_music_codec), - value: preferences.streamMusicCodec, - showValueWhenUnfolded: false, - options: MusicCodec.values - .map((e) => DropdownMenuItem( - value: e, - child: Text( - e.label, - style: theme.textTheme.labelMedium, - ), - )) - .toList(), - onChanged: (value) { - if (value == null) return; - preferences.setStreamMusicCodec(value); - }, - ), - AdaptiveSelectTile( - secondary: const Icon(SpotubeIcons.file), - title: Text(context.l10n.download_music_codec), - value: preferences.downloadMusicCodec, - showValueWhenUnfolded: false, - options: MusicCodec.values - .map((e) => DropdownMenuItem( - value: e, - child: Text( - e.label, - style: theme.textTheme.labelMedium, - ), - )) - .toList(), - onChanged: (value) { - if (value == null) return; - preferences.setDownloadMusicCodec(value); - }, - ), - ], - ), - SectionCardWithHeading( - heading: context.l10n.downloads, - children: [ - ListTile( - leading: const Icon(SpotubeIcons.download), - title: Text(context.l10n.download_location), - subtitle: Text(preferences.downloadLocation), - trailing: FilledButton( - onPressed: pickDownloadLocation, - child: const Icon(SpotubeIcons.folder), - ), - onTap: pickDownloadLocation, - ), - ], - ), + const SettingsLanguageRegionSection(), + const SettingsAppearanceSection(), + const SettingsPlaybackSection(), + const SettingsDownloadsSection(), if (DesktopTools.platform.isDesktop) - SectionCardWithHeading( - heading: context.l10n.desktop, - children: [ - AdaptiveSelectTile( - secondary: const Icon(SpotubeIcons.close), - title: Text(context.l10n.close_behavior), - value: preferences.closeBehavior, - options: [ - DropdownMenuItem( - value: CloseBehavior.close, - child: Text(context.l10n.close), - ), - DropdownMenuItem( - value: CloseBehavior.minimizeToTray, - child: Text(context.l10n.minimize_to_tray), - ), - ], - onChanged: (value) { - if (value != null) { - preferences.setCloseBehavior(value); - } - }, - ), - SwitchListTile( - secondary: const Icon(SpotubeIcons.tray), - title: Text(context.l10n.show_tray_icon), - value: preferences.showSystemTrayIcon, - onChanged: preferences.setShowSystemTrayIcon, - ), - SwitchListTile( - secondary: const Icon(SpotubeIcons.window), - title: Text(context.l10n.use_system_title_bar), - value: preferences.systemTitleBar, - onChanged: preferences.setSystemTitleBar, - ), - ], - ), - if (!kIsWeb) - SectionCardWithHeading( - heading: context.l10n.developers, - children: [ - ListTile( - leading: const Icon(SpotubeIcons.logs), - title: Text(context.l10n.logs), - trailing: const Icon(SpotubeIcons.angleRight), - onTap: () { - GoRouter.of(context).push("/settings/logs"); - }, - ) - ], - ), - SectionCardWithHeading( - heading: context.l10n.about, - children: [ - AdaptiveListTile( - leading: const Icon( - SpotubeIcons.heart, - color: Colors.pink, - ), - title: SizedBox( - height: 50, - width: 200, - child: Align( - alignment: Alignment.centerLeft, - child: AutoSizeText( - context.l10n.u_love_spotube, - maxLines: 1, - style: const TextStyle( - color: Colors.pink, - fontWeight: FontWeight.bold, - ), - ), - ), - ), - trailing: (context, update) => FilledButton( - style: ButtonStyle( - backgroundColor: - MaterialStatePropertyAll(Colors.red[100]), - foregroundColor: const MaterialStatePropertyAll( - Colors.pinkAccent), - padding: const MaterialStatePropertyAll( - EdgeInsets.all(15)), - ), - onPressed: () { - launchUrlString( - "https://opencollective.com/spotube", - mode: LaunchMode.externalApplication, - ); - }, - child: Row( - mainAxisSize: MainAxisSize.min, - children: [ - const Icon(SpotubeIcons.heart), - const SizedBox(width: 5), - Text(context.l10n.please_sponsor), - ], - ), - ), - ), - if (Env.enableUpdateChecker) - SwitchListTile( - secondary: const Icon(SpotubeIcons.update), - title: Text(context.l10n.check_for_updates), - value: preferences.checkUpdate, - onChanged: (checked) => - preferences.setCheckUpdate(checked), - ), - ListTile( - leading: const Icon(SpotubeIcons.info), - title: Text(context.l10n.about_spotube), - trailing: const Icon(SpotubeIcons.angleRight), - onTap: () { - GoRouter.of(context).push("/settings/about"); - }, - ) - ], - ), + const SettingsDesktopSection(), + if (!kIsWeb) const SettingsDevelopersSection(), + const SettingsAboutSection(), Center( child: FilledButton( onPressed: preferences.reset, diff --git a/lib/utils/persisted_state_notifier.dart b/lib/utils/persisted_state_notifier.dart index 2937bff9..218cd64a 100644 --- a/lib/utils/persisted_state_notifier.dart +++ b/lib/utils/persisted_state_notifier.dart @@ -59,32 +59,32 @@ abstract class PersistedStateNotifier extends StateNotifier { static Future read(String key) async { final localStorage = await SharedPreferences.getInstance(); - if (kIsMacOS || kIsIOS) { + if (kIsMacOS || kIsIOS || (kIsLinux && !kIsFlatpak)) { + return localStorage.getString(key); + } + + try { + await localStorage.setBool(kIsUsingEncryption, true); + return await secureStorage.read(key: key); + } catch (e) { + await localStorage.setBool(kIsUsingEncryption, false); return localStorage.getString(key); - } else { - try { - await localStorage.setBool(kIsUsingEncryption, true); - return await secureStorage.read(key: key); - } catch (e) { - await localStorage.setBool(kIsUsingEncryption, false); - return localStorage.getString(key); - } } } static Future write(String key, String value) async { final localStorage = await SharedPreferences.getInstance(); - if (kIsMacOS || kIsIOS) { + if (kIsMacOS || kIsIOS || (kIsLinux && !kIsFlatpak)) { await localStorage.setString(key, value); return; - } else { - try { - await localStorage.setBool(kIsUsingEncryption, true); - await secureStorage.write(key: key, value: value); - } catch (e) { - await localStorage.setBool(kIsUsingEncryption, false); - await localStorage.setString(key, value); - } + } + + try { + await localStorage.setBool(kIsUsingEncryption, true); + await secureStorage.write(key: key, value: value); + } catch (e) { + await localStorage.setBool(kIsUsingEncryption, false); + await localStorage.setString(key, value); } } diff --git a/pubspec.lock b/pubspec.lock index 15a50f41..9c0161c6 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -517,10 +517,10 @@ packages: dependency: "direct main" description: name: file_picker - sha256: "903dd4ba13eae7cef64acc480e91bf54c3ddd23b5b90b639c170f3911e489620" + sha256: "4e42aacde3b993c5947467ab640882c56947d9d27342a5b6f2895b23956954a6" url: "https://pub.dev" source: hosted - version: "6.0.0" + version: "6.1.1" file_selector: dependency: "direct main" description: From 574406dd5fc410914b27e7fce374323696845012 Mon Sep 17 00:00:00 2001 From: Kingkor Roy Tirtho Date: Wed, 8 Nov 2023 12:11:06 +0600 Subject: [PATCH 003/195] fix(playbutton_card): annoying animation --- lib/components/shared/playbutton_card.dart | 245 +++++++++--------- .../proxy_playlist/next_fetcher_mixin.dart | 1 - 2 files changed, 122 insertions(+), 124 deletions(-) diff --git a/lib/components/shared/playbutton_card.dart b/lib/components/shared/playbutton_card.dart index c9daa267..91c185c7 100644 --- a/lib/components/shared/playbutton_card.dart +++ b/lib/components/shared/playbutton_card.dart @@ -8,7 +8,6 @@ import 'package:spotube/components/shared/hover_builder.dart'; import 'package:spotube/components/shared/image/universal_image.dart'; import 'package:spotube/hooks/use_breakpoint_value.dart'; import 'package:spotube/hooks/use_brightness_value.dart'; -import 'package:spotube/utils/platform.dart'; final htmlTagRegexp = RegExp(r"<[^>]*>", caseSensitive: true); @@ -59,9 +58,9 @@ class PlaybuttonCard extends HookWidget { ); final end = useBreakpointValue( - xs: 15, - sm: 15, - others: 20, + xs: 10, + sm: 10, + others: 15, ); final textsHeight = useState( @@ -84,28 +83,29 @@ class PlaybuttonCard extends HookWidget { return null; }, [textsKey]); - return Stack( - children: [ - Container( - constraints: BoxConstraints(maxWidth: size), - margin: margin, - child: Material( - color: Color.lerp( - theme.colorScheme.surfaceVariant, - theme.colorScheme.surface, - useBrightnessValue(.9, .7), - ), - borderRadius: radius, - shadowColor: theme.colorScheme.background, - elevation: 3, - child: InkWell( - mouseCursor: SystemMouseCursors.click, - onTap: onTap, - borderRadius: radius, - splashFactory: theme.splashFactory, - child: Column( - mainAxisSize: MainAxisSize.min, - crossAxisAlignment: CrossAxisAlignment.start, + return Container( + constraints: BoxConstraints(maxWidth: size), + margin: margin, + child: Material( + color: Color.lerp( + theme.colorScheme.surfaceVariant, + theme.colorScheme.surface, + useBrightnessValue(.9, .7), + ), + borderRadius: radius, + shadowColor: theme.colorScheme.background, + elevation: 3, + child: InkWell( + mouseCursor: SystemMouseCursors.click, + onTap: onTap, + borderRadius: radius, + splashFactory: theme.splashFactory, + child: Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Stack( + clipBehavior: Clip.none, children: [ Padding( padding: const EdgeInsets.only( @@ -121,115 +121,114 @@ class PlaybuttonCard extends HookWidget { ), ), ), - Column( - key: textsKey, - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - const SizedBox(height: 15), - Padding( - padding: const EdgeInsets.symmetric(horizontal: 12.0), - child: AutoSizeText( - title, - maxLines: 1, - minFontSize: theme.textTheme.bodyMedium!.fontSize!, - overflow: TextOverflow.ellipsis, - ), - ), - if (cleanDescription != null) - Padding( - padding: const EdgeInsets.symmetric(horizontal: 12.0), - child: AutoSizeText( - cleanDescription, - maxLines: 2, - style: theme.textTheme.bodySmall?.copyWith( - color: - theme.colorScheme.onSurface.withOpacity(.5), + if (isOwner) + Positioned( + top: 15, + left: 15, + child: AnimatedSize( + duration: const Duration(milliseconds: 150), + alignment: Alignment.centerLeft, + curve: Curves.easeInExpo, + child: HoverBuilder(builder: (context, isHovered) { + return Container( + padding: const EdgeInsets.all(4), + decoration: BoxDecoration( + color: Colors.blueAccent, + borderRadius: BorderRadius.circular(20), ), - overflow: TextOverflow.ellipsis, + child: Row( + mainAxisSize: MainAxisSize.min, + children: [ + const Icon( + SpotubeIcons.user, + color: Colors.white, + size: 16, + ), + if (isHovered) + Text( + "Owned by you", + style: theme.textTheme.bodySmall?.copyWith( + color: Colors.white, + ), + ), + ], + ), + ); + }), + ), + ), + Positioned( + right: end, + bottom: -15, + child: Column( + mainAxisSize: MainAxisSize.min, + children: [ + if (!isPlaying) + IconButton( + style: IconButton.styleFrom( + backgroundColor: theme.colorScheme.background, + foregroundColor: theme.colorScheme.primary, + minimumSize: const Size.square(10), + ), + icon: const Icon(SpotubeIcons.queueAdd), + onPressed: isLoading ? null : onAddToQueuePressed, ), + const SizedBox(height: 5), + IconButton( + style: IconButton.styleFrom( + backgroundColor: theme.colorScheme.primaryContainer, + foregroundColor: theme.colorScheme.primary, + minimumSize: const Size.square(10), + ), + icon: isLoading + ? SizedBox.fromSize( + size: const Size.square(15), + child: const CircularProgressIndicator( + strokeWidth: 2), + ) + : isPlaying + ? const Icon(SpotubeIcons.pause) + : const Icon(SpotubeIcons.play), + onPressed: isLoading ? null : onPlaybuttonPressed, ), - const SizedBox(height: 10), - ], + ], + ), ), ], ), - ), - ), - ), - if (isOwner) - Positioned( - top: 15, - left: 25, - child: AnimatedSize( - duration: const Duration(milliseconds: 150), - alignment: Alignment.centerLeft, - curve: Curves.easeInExpo, - child: HoverBuilder(builder: (context, isHovered) { - return Container( - padding: const EdgeInsets.all(4), - decoration: BoxDecoration( - color: Colors.blueAccent, - borderRadius: BorderRadius.circular(20), + Column( + key: textsKey, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + const SizedBox(height: 15), + Padding( + padding: const EdgeInsets.symmetric(horizontal: 12.0), + child: AutoSizeText( + title, + maxLines: 1, + minFontSize: theme.textTheme.bodyMedium!.fontSize!, + overflow: TextOverflow.ellipsis, + ), ), - child: Row( - mainAxisSize: MainAxisSize.min, - children: [ - const Icon( - SpotubeIcons.user, - color: Colors.white, - size: 16, - ), - if (isHovered) - Text( - "Owned by you", - style: theme.textTheme.bodySmall?.copyWith( - color: Colors.white, - ), + if (cleanDescription != null) + Padding( + padding: const EdgeInsets.symmetric(horizontal: 12.0), + child: AutoSizeText( + cleanDescription, + maxLines: 2, + style: theme.textTheme.bodySmall?.copyWith( + color: theme.colorScheme.onSurface.withOpacity(.5), ), - ], - ), - ); - }), - ), - ), - AnimatedPositioned( - duration: const Duration(milliseconds: 300), - right: end, - bottom: textsHeight.value - (kIsMobile ? 5 : 10), - child: Column( - mainAxisSize: MainAxisSize.min, - children: [ - if (!isPlaying) - IconButton( - style: IconButton.styleFrom( - backgroundColor: theme.colorScheme.background, - foregroundColor: theme.colorScheme.primary, - minimumSize: const Size.square(10), - ), - icon: const Icon(SpotubeIcons.queueAdd), - onPressed: isLoading ? null : onAddToQueuePressed, - ), - const SizedBox(height: 5), - IconButton( - style: IconButton.styleFrom( - backgroundColor: theme.colorScheme.primaryContainer, - foregroundColor: theme.colorScheme.primary, - minimumSize: const Size.square(10), - ), - icon: isLoading - ? SizedBox.fromSize( - size: const Size.square(15), - child: const CircularProgressIndicator(strokeWidth: 2), - ) - : isPlaying - ? const Icon(SpotubeIcons.pause) - : const Icon(SpotubeIcons.play), - onPressed: isLoading ? null : onPlaybuttonPressed, + overflow: TextOverflow.ellipsis, + ), + ), + const SizedBox(height: 10), + ], ), ], ), ), - ], + ), ); } } diff --git a/lib/provider/proxy_playlist/next_fetcher_mixin.dart b/lib/provider/proxy_playlist/next_fetcher_mixin.dart index 61b86d8c..f6776234 100644 --- a/lib/provider/proxy_playlist/next_fetcher_mixin.dart +++ b/lib/provider/proxy_playlist/next_fetcher_mixin.dart @@ -1,5 +1,4 @@ import 'package:collection/collection.dart'; -import 'package:flutter/foundation.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:spotify/spotify.dart'; import 'package:spotube/models/local_track.dart'; From 1d77556157d158600f29cf2ea5f26c567607dec7 Mon Sep 17 00:00:00 2001 From: Kingkor Roy Tirtho Date: Wed, 8 Nov 2023 12:26:27 +0600 Subject: [PATCH 004/195] fix: check for unsynced lyrics and error handling for timed lyrics query --- lib/pages/lyrics/synced_lyrics.dart | 49 ++++++++++++++++++++++++++--- 1 file changed, 45 insertions(+), 4 deletions(-) diff --git a/lib/pages/lyrics/synced_lyrics.dart b/lib/pages/lyrics/synced_lyrics.dart index dab2103d..5f2afbc9 100644 --- a/lib/pages/lyrics/synced_lyrics.dart +++ b/lib/pages/lyrics/synced_lyrics.dart @@ -45,6 +45,11 @@ class SyncedLyrics extends HookConsumerWidget { final lyricValue = timedLyricsQuery.data; + final isUnSyncLyric = useMemoized( + () => lyricValue?.lyrics.every((l) => l.time == Duration.zero), + [lyricValue], + ); + final lyricsMap = useMemoized( () => lyricValue?.lyrics @@ -72,6 +77,9 @@ class SyncedLyrics extends HookConsumerWidget { : textTheme.headlineMedium?.copyWith(fontSize: 25)) ?.copyWith(color: palette.titleTextColor); + var bodyTextTheme = textTheme.bodyLarge?.copyWith( + color: palette.bodyTextColor, + ); return Stack( children: [ Column( @@ -93,7 +101,9 @@ class SyncedLyrics extends HookConsumerWidget { : textTheme.titleLarge, ), ), - if (lyricValue != null && lyricValue.lyrics.isNotEmpty) + if (lyricValue != null && + lyricValue.lyrics.isNotEmpty && + isUnSyncLyric == false) Expanded( child: ListView.builder( controller: controller, @@ -102,7 +112,7 @@ class SyncedLyrics extends HookConsumerWidget { final lyricSlice = lyricValue.lyrics[index]; final isActive = lyricSlice.time.inSeconds == currentTime; - if (isActive) { + if (isActive && isUnSyncLyric == true) { controller.scrollToIndex( index, preferPosition: AutoScrollPosition.middle, @@ -173,8 +183,39 @@ class SyncedLyrics extends HookConsumerWidget { ), ), if (playlist.activeTrack != null && - (lyricValue == null || lyricValue.lyrics.isEmpty == true)) - const Expanded(child: ShimmerLyrics()), + (timedLyricsQuery.isLoading || timedLyricsQuery.isRefreshing)) + const Expanded(child: ShimmerLyrics()) + else if (playlist.activeTrack != null && + (timedLyricsQuery.hasError)) + Text( + "Sorry, no Lyrics were found for `${playlist.activeTrack?.name}` :'(\n${timedLyricsQuery.error.toString()}", + style: bodyTextTheme, + ) + else if (isUnSyncLyric == true) + Expanded( + child: Center( + child: RichText( + textAlign: TextAlign.center, + text: TextSpan( + style: bodyTextTheme, + children: [ + const TextSpan( + text: + "Synced lyrics is not available for this song. Please use the", + ), + TextSpan( + text: " Plain Lyrics ", + style: textTheme.bodyLarge?.copyWith( + color: palette.bodyTextColor, + fontWeight: FontWeight.bold, + ), + ), + const TextSpan(text: "tab instead."), + ], + ), + ), + ), + ), ], ), Align( From 5633367397812148f6d712d06e97a4f84033f968 Mon Sep 17 00:00:00 2001 From: Kingkor Roy Tirtho Date: Wed, 8 Nov 2023 12:32:21 +0600 Subject: [PATCH 005/195] fix(album_card): show loading state during adding track to queue/play --- lib/components/album/album_card.dart | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/lib/components/album/album_card.dart b/lib/components/album/album_card.dart index d8f8d85b..93b4cefc 100644 --- a/lib/components/album/album_card.dart +++ b/lib/components/album/album_card.dart @@ -51,7 +51,8 @@ class AlbumCard extends HookConsumerWidget { ), margin: EdgeInsets.symmetric(horizontal: marginH.toDouble()), isPlaying: isPlaylistPlaying, - isLoading: isPlaylistPlaying && playlist.isFetching == true, + isLoading: (isPlaylistPlaying && playlist.isFetching == true) || + updating.value, title: album.name!, description: "${album.albumType?.formatted} • ${TypeConversionUtils.artists_X_String(album.artists ?? [])}", @@ -92,7 +93,7 @@ class AlbumCard extends HookConsumerWidget { "album-tracks/${album.id}", () { return spotify.albums - .getTracks(album.id!) + .tracks(album.id!) .all() .then((value) => value.toList()); }, From 487c2ed6bdc4af33006ba52532eb4eaaa261dceb Mon Sep 17 00:00:00 2001 From: Kingkor Roy Tirtho Date: Wed, 8 Nov 2023 14:41:15 +0600 Subject: [PATCH 006/195] fix: user_playlists layout, track tile index, --- lib/components/genre/category_card.dart | 69 ++++++++------ lib/components/library/user_playlists.dart | 94 ++++++++++--------- .../shared/track_table/track_tile.dart | 2 +- lib/pages/home/personalized.dart | 68 ++++++++------ 4 files changed, 133 insertions(+), 100 deletions(-) diff --git a/lib/components/genre/category_card.dart b/lib/components/genre/category_card.dart index 1aa33cd6..a8d67771 100644 --- a/lib/components/genre/category_card.dart +++ b/lib/components/genre/category_card.dart @@ -1,6 +1,7 @@ import 'dart:ui'; import 'package:flutter/material.dart' hide Page; +import 'package:flutter_desktop_tools/flutter_desktop_tools.dart'; import 'package:flutter_hooks/flutter_hooks.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; @@ -8,6 +9,7 @@ import 'package:spotify/spotify.dart'; import 'package:spotube/components/playlist/playlist_card.dart'; import 'package:spotube/components/shared/shimmers/shimmer_playbutton_card.dart'; import 'package:spotube/components/shared/waypoint.dart'; +import 'package:spotube/extensions/constrains.dart'; import 'package:spotube/models/logger.dart'; import 'package:spotube/services/queries/queries.dart'; @@ -28,16 +30,23 @@ class CategoryCard extends HookConsumerWidget { category.id!, ); + final playlists = useMemoized( + () => playlistQuery.pages.expand( + (page) { + return page.items?.where((i) => i != null) ?? const Iterable.empty(); + }, + ).toList(), + [playlistQuery.pages], + ); + if (playlistQuery.hasErrors && !playlistQuery.hasPageData && !playlistQuery.isLoadingNextPage) { return const SizedBox.shrink(); } - final playlists = playlistQuery.pages.expand( - (page) { - return page.items?.where((i) => i != null) ?? const Iterable.empty(); - }, - ).toList(); + + final mediaQuery = MediaQuery.of(context); + return Padding( padding: const EdgeInsets.all(8.0), child: Column( @@ -48,29 +57,35 @@ class CategoryCard extends HookConsumerWidget { category.name!, style: Theme.of(context).textTheme.titleMedium, ), - ScrollConfiguration( - behavior: ScrollConfiguration.of(context).copyWith( - dragDevices: { - PointerDeviceKind.touch, - PointerDeviceKind.mouse, - }, - ), - child: Waypoint( - controller: scrollController, - onTouchEdge: playlistQuery.fetchNext, - child: SingleChildScrollView( - scrollDirection: Axis.horizontal, - controller: scrollController, - padding: const EdgeInsets.symmetric(vertical: 8.0), - child: Row( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - ...playlists.map((playlist) => PlaylistCard(playlist)), - if (playlistQuery.hasNextPage) - const ShimmerPlaybuttonCard(count: 1), - ], - ), + SizedBox( + height: mediaQuery.smAndDown ? 226 : 266, + child: ScrollConfiguration( + behavior: ScrollConfiguration.of(context).copyWith( + dragDevices: { + PointerDeviceKind.touch, + PointerDeviceKind.mouse, + }, ), + child: ListView.builder( + controller: scrollController, + scrollDirection: Axis.horizontal, + padding: const EdgeInsets.symmetric(vertical: 8.0), + itemCount: playlists.length + 1, + itemBuilder: (context, index) { + if (index == playlists.length) { + if (!playlistQuery.hasNextPage) { + return const SizedBox.shrink(); + } + return Waypoint( + controller: scrollController, + onTouchEdge: playlistQuery.fetchNext, + isGrid: true, + child: const ShimmerPlaybuttonCard(), + ); + } + final playlist = playlists[index]; + return PlaylistCard(playlist); + }), ), ), ], diff --git a/lib/components/library/user_playlists.dart b/lib/components/library/user_playlists.dart index 8ed3e73d..ecf4fa12 100644 --- a/lib/components/library/user_playlists.dart +++ b/lib/components/library/user_playlists.dart @@ -1,4 +1,5 @@ import 'package:flutter/material.dart' hide Image; +import 'package:flutter_desktop_tools/flutter_desktop_tools.dart'; import 'package:flutter_hooks/flutter_hooks.dart'; import 'package:fuzzywuzzy/fuzzywuzzy.dart'; import 'package:collection/collection.dart'; @@ -8,7 +9,6 @@ import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:spotify/spotify.dart'; import 'package:spotube/collections/spotube_icons.dart'; import 'package:spotube/components/playlist/playlist_create_dialog.dart'; -import 'package:spotube/components/shared/inter_scrollbar/inter_scrollbar.dart'; import 'package:spotube/components/shared/shimmers/shimmer_playbutton_card.dart'; import 'package:spotube/components/shared/fallbacks/anonymous_fallback.dart'; import 'package:spotube/components/playlist/playlist_card.dart'; @@ -80,20 +80,13 @@ class UserPlaylists extends HookConsumerWidget { return RefreshIndicator( onRefresh: playlistsQuery.refresh, - child: InterScrollbar( - controller: controller, - child: SingleChildScrollView( + child: SafeArea( + child: CustomScrollView( controller: controller, - physics: const AlwaysScrollableScrollPhysics(), - child: Waypoint( - controller: controller, - onTouchEdge: () { - if (playlistsQuery.hasNextPage) { - playlistsQuery.fetchNext(); - } - }, - child: SafeArea( + slivers: [ + SliverToBoxAdapter( child: Column( + mainAxisSize: MainAxisSize.min, children: [ Padding( padding: const EdgeInsets.all(10), @@ -103,42 +96,53 @@ class UserPlaylists extends HookConsumerWidget { leading: const Icon(SpotubeIcons.filter), ), ), - AnimatedCrossFade( - duration: const Duration(milliseconds: 300), - crossFadeState: !playlistsQuery.hasPageData && - !playlistsQuery.hasPageError && - !playlistsQuery.isLoadingNextPage - ? CrossFadeState.showFirst - : CrossFadeState.showSecond, - firstChild: - const Center(child: ShimmerPlaybuttonCard(count: 7)), - secondChild: Wrap( - runSpacing: 10, - alignment: WrapAlignment.center, - children: [ - Row( - children: [ - const SizedBox(width: 10), - const PlaylistCreateDialogButton(), - const SizedBox(width: 10), - ElevatedButton.icon( - icon: const Icon(SpotubeIcons.magic), - label: Text(context.l10n.generate_playlist), - onPressed: () { - GoRouter.of(context).push("/library/generate"); - }, - ), - const SizedBox(width: 10), - ], - ), - ...playlists.map((playlist) => PlaylistCard(playlist)) - ], - ), + Row( + children: [ + const SizedBox(width: 10), + const PlaylistCreateDialogButton(), + const SizedBox(width: 10), + ElevatedButton.icon( + icon: const Icon(SpotubeIcons.magic), + label: Text(context.l10n.generate_playlist), + onPressed: () { + GoRouter.of(context).push("/library/generate"); + }, + ), + const SizedBox(width: 10), + ], ), ], ), ), - ), + const SliverToBoxAdapter( + child: SizedBox(height: 10), + ), + SliverGrid.builder( + itemCount: playlists.length + 1, + gridDelegate: SliverGridDelegateWithMaxCrossAxisExtent( + maxCrossAxisExtent: 200, + mainAxisExtent: DesktopTools.platform.isMobile ? 225 : 250, + crossAxisSpacing: 8, + mainAxisSpacing: 8, + ), + itemBuilder: (context, index) { + if (index == playlists.length) { + if (!playlistsQuery.hasNextPage) { + return const SizedBox.shrink(); + } + + return Waypoint( + controller: controller, + isGrid: true, + onTouchEdge: playlistsQuery.fetchNext, + child: const ShimmerPlaybuttonCard(count: 1), + ); + } + + return PlaylistCard(playlists[index]); + }, + ) + ], ), ), ); diff --git a/lib/components/shared/track_table/track_tile.dart b/lib/components/shared/track_table/track_tile.dart index ff1b314b..4980f96b 100644 --- a/lib/components/shared/track_table/track_tile.dart +++ b/lib/components/shared/track_table/track_tile.dart @@ -113,7 +113,7 @@ class TrackTile extends HookConsumerWidget { child: Padding( padding: const EdgeInsets.symmetric(horizontal: 6), child: Text( - '$index', + '${(index ?? 0) + 1}', maxLines: 1, style: theme.textTheme.bodySmall, textAlign: TextAlign.center, diff --git a/lib/pages/home/personalized.dart b/lib/pages/home/personalized.dart index f7e942be..4f0b655f 100644 --- a/lib/pages/home/personalized.dart +++ b/lib/pages/home/personalized.dart @@ -10,6 +10,7 @@ import 'package:spotube/components/shared/inter_scrollbar/inter_scrollbar.dart'; import 'package:spotube/components/shared/shimmers/shimmer_categories.dart'; import 'package:spotube/components/shared/shimmers/shimmer_playbutton_card.dart'; import 'package:spotube/components/shared/waypoint.dart'; +import 'package:spotube/extensions/constrains.dart'; import 'package:spotube/extensions/context.dart'; import 'package:spotube/models/logger.dart'; import 'package:spotube/provider/authentication_provider.dart'; @@ -38,6 +39,7 @@ class PersonalizedItemCard extends HookWidget { @override Widget build(BuildContext context) { final scrollController = useScrollController(); + final mediaQuery = MediaQuery.of(context); return Padding( padding: const EdgeInsets.all(8.0), @@ -52,36 +54,48 @@ class PersonalizedItemCard extends HookWidget { style: Theme.of(context).textTheme.titleLarge, ), ), - ScrollConfiguration( - behavior: ScrollConfiguration.of(context).copyWith( - dragDevices: { - PointerDeviceKind.touch, - PointerDeviceKind.mouse, - }, - ), - child: Scrollbar( - controller: scrollController, - interactive: false, - child: Waypoint( + SizedBox( + height: mediaQuery.smAndDown ? 226 : 266, + child: ScrollConfiguration( + behavior: ScrollConfiguration.of(context).copyWith( + dragDevices: { + PointerDeviceKind.touch, + PointerDeviceKind.mouse, + }, + ), + child: Scrollbar( controller: scrollController, - onTouchEdge: hasNextPage ? onFetchMore : null, - child: SingleChildScrollView( - scrollDirection: Axis.horizontal, - controller: scrollController, - physics: const AlwaysScrollableScrollPhysics(), + interactive: false, + child: ListView.builder( + itemCount: (playlists?.length ?? albums?.length)! + 1, padding: const EdgeInsets.symmetric(vertical: 8.0), - child: Row( - mainAxisSize: MainAxisSize.min, - children: [ - ...?playlists?.map((playlist) => PlaylistCard(playlist)), - ...?albums?.map( - (album) => AlbumCard( - TypeConversionUtils.simpleAlbum_X_Album(album), + scrollDirection: Axis.horizontal, + itemBuilder: (context, index) { + if (index == (playlists?.length ?? albums?.length)!) { + if (!hasNextPage) return const SizedBox.shrink(); + + return Waypoint( + controller: scrollController, + onTouchEdge: onFetchMore, + isGrid: true, + child: const ShimmerPlaybuttonCard(count: 1), + ); + } + + final item = playlists == null + ? albums!.elementAt(index) + : playlists!.elementAt(index); + + if (playlists == null) { + return AlbumCard( + TypeConversionUtils.simpleAlbum_X_Album( + item as AlbumSimple, ), - ), - if (hasNextPage) const ShimmerPlaybuttonCard(count: 1), - ], - ), + ); + } + + return PlaylistCard(item as PlaylistSimple); + }, ), ), ), From 6b8ae88db4105039c6cbd40bc032a45febab7f63 Mon Sep 17 00:00:00 2001 From: Kingkor Roy Tirtho Date: Wed, 8 Nov 2023 17:07:20 +0600 Subject: [PATCH 007/195] refactor: horizontal playbutton layout to use ListView and breakdown search page into sections --- lib/components/album/album_card.dart | 10 +- lib/components/artist/artist_album_list.dart | 49 +-- lib/components/genre/category_card.dart | 63 +--- .../horizontal_playbutton_card_view.dart | 96 ++++++ lib/pages/artist/artist.dart | 7 - lib/pages/home/genres.dart | 18 +- lib/pages/home/personalized.dart | 125 +------ lib/pages/search/search.dart | 308 ++---------------- lib/pages/search/sections/albums.dart | 39 +++ lib/pages/search/sections/artists.dart | 37 +++ lib/pages/search/sections/playlists.dart | 35 ++ lib/pages/search/sections/tracks.dart | 98 ++++++ 12 files changed, 374 insertions(+), 511 deletions(-) create mode 100644 lib/components/shared/horizontal_playbutton_card_view/horizontal_playbutton_card_view.dart create mode 100644 lib/pages/search/sections/albums.dart create mode 100644 lib/pages/search/sections/artists.dart create mode 100644 lib/pages/search/sections/playlists.dart create mode 100644 lib/pages/search/sections/tracks.dart diff --git a/lib/components/album/album_card.dart b/lib/components/album/album_card.dart index 93b4cefc..945f8ecf 100644 --- a/lib/components/album/album_card.dart +++ b/lib/components/album/album_card.dart @@ -4,7 +4,6 @@ import 'package:flutter_hooks/flutter_hooks.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:spotify/spotify.dart'; import 'package:spotube/components/shared/playbutton_card.dart'; -import 'package:spotube/hooks/use_breakpoint_value.dart'; import 'package:spotube/provider/proxy_playlist/proxy_playlist_provider.dart'; import 'package:spotube/provider/spotify_provider.dart'; import 'package:spotube/services/audio_player/audio_player.dart'; @@ -34,13 +33,6 @@ class AlbumCard extends HookConsumerWidget { [playlist, album.id], ); - final marginH = useBreakpointValue( - xs: 10, - sm: 10, - md: 15, - others: 20, - ); - final updating = useState(false); final spotify = ref.watch(spotifyProvider); @@ -49,7 +41,7 @@ class AlbumCard extends HookConsumerWidget { album.images, placeholder: ImagePlaceholder.collection, ), - margin: EdgeInsets.symmetric(horizontal: marginH.toDouble()), + margin: const EdgeInsets.symmetric(horizontal: 10), isPlaying: isPlaylistPlaying, isLoading: (isPlaylistPlaying && playlist.isFetching == true) || updating.value, diff --git a/lib/components/artist/artist_album_list.dart b/lib/components/artist/artist_album_list.dart index 8fa9be87..e075cd60 100644 --- a/lib/components/artist/artist_album_list.dart +++ b/lib/components/artist/artist_album_list.dart @@ -1,11 +1,9 @@ -import 'package:flutter/gestures.dart'; import 'package:flutter/material.dart' hide Page; import 'package:flutter_hooks/flutter_hooks.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:spotify/spotify.dart'; -import 'package:spotube/components/album/album_card.dart'; -import 'package:spotube/components/shared/shimmers/shimmer_playbutton_card.dart'; -import 'package:spotube/components/shared/waypoint.dart'; +import 'package:spotube/components/shared/horizontal_playbutton_card_view/horizontal_playbutton_card_view.dart'; +import 'package:spotube/extensions/context.dart'; import 'package:spotube/models/logger.dart'; import 'package:spotube/services/queries/queries.dart'; @@ -20,7 +18,6 @@ class ArtistAlbumList extends HookConsumerWidget { @override Widget build(BuildContext context, ref) { - final scrollController = useScrollController(); final albumsQuery = useQueries.artist.albumsOf(ref, artistId); final albums = useMemoized(() { @@ -29,40 +26,16 @@ class ArtistAlbumList extends HookConsumerWidget { .toList(); }, [albumsQuery.pages]); - final hasNextPage = albumsQuery.pages.isEmpty - ? false - : (albumsQuery.pages.last.items?.length ?? 0) == 5; + final theme = Theme.of(context); - return Column( - children: [ - ScrollConfiguration( - behavior: ScrollConfiguration.of(context).copyWith( - dragDevices: { - PointerDeviceKind.touch, - PointerDeviceKind.mouse, - }, - ), - child: Scrollbar( - interactive: false, - controller: scrollController, - child: Waypoint( - controller: scrollController, - onTouchEdge: albumsQuery.fetchNext, - child: SingleChildScrollView( - controller: scrollController, - scrollDirection: Axis.horizontal, - child: Row( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - ...albums.map((album) => AlbumCard(album)), - if (hasNextPage) const ShimmerPlaybuttonCard(count: 1), - ], - ), - ), - ), - ), - ), - ], + return HorizontalPlaybuttonCardView( + hasNextPage: albumsQuery.hasNextPage, + items: albums, + onFetchMore: albumsQuery.fetchNext, + title: Text( + context.l10n.albums, + style: theme.textTheme.headlineSmall, + ), ); } } diff --git a/lib/components/genre/category_card.dart b/lib/components/genre/category_card.dart index a8d67771..d5809b5d 100644 --- a/lib/components/genre/category_card.dart +++ b/lib/components/genre/category_card.dart @@ -1,15 +1,10 @@ -import 'dart:ui'; - +import 'package:collection/collection.dart'; import 'package:flutter/material.dart' hide Page; -import 'package:flutter_desktop_tools/flutter_desktop_tools.dart'; import 'package:flutter_hooks/flutter_hooks.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:spotify/spotify.dart'; -import 'package:spotube/components/playlist/playlist_card.dart'; -import 'package:spotube/components/shared/shimmers/shimmer_playbutton_card.dart'; -import 'package:spotube/components/shared/waypoint.dart'; -import 'package:spotube/extensions/constrains.dart'; +import 'package:spotube/components/shared/horizontal_playbutton_card_view/horizontal_playbutton_card_view.dart'; import 'package:spotube/models/logger.dart'; import 'package:spotube/services/queries/queries.dart'; @@ -24,7 +19,6 @@ class CategoryCard extends HookConsumerWidget { @override Widget build(BuildContext context, ref) { - final scrollController = useScrollController(); final playlistQuery = useQueries.category.playlistsOf( ref, category.id!, @@ -33,7 +27,8 @@ class CategoryCard extends HookConsumerWidget { final playlists = useMemoized( () => playlistQuery.pages.expand( (page) { - return page.items?.where((i) => i != null) ?? const Iterable.empty(); + return page.items?.whereNotNull() ?? + const Iterable.empty(); }, ).toList(), [playlistQuery.pages], @@ -45,51 +40,11 @@ class CategoryCard extends HookConsumerWidget { return const SizedBox.shrink(); } - final mediaQuery = MediaQuery.of(context); - - return Padding( - padding: const EdgeInsets.all(8.0), - child: Column( - mainAxisSize: MainAxisSize.min, - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text( - category.name!, - style: Theme.of(context).textTheme.titleMedium, - ), - SizedBox( - height: mediaQuery.smAndDown ? 226 : 266, - child: ScrollConfiguration( - behavior: ScrollConfiguration.of(context).copyWith( - dragDevices: { - PointerDeviceKind.touch, - PointerDeviceKind.mouse, - }, - ), - child: ListView.builder( - controller: scrollController, - scrollDirection: Axis.horizontal, - padding: const EdgeInsets.symmetric(vertical: 8.0), - itemCount: playlists.length + 1, - itemBuilder: (context, index) { - if (index == playlists.length) { - if (!playlistQuery.hasNextPage) { - return const SizedBox.shrink(); - } - return Waypoint( - controller: scrollController, - onTouchEdge: playlistQuery.fetchNext, - isGrid: true, - child: const ShimmerPlaybuttonCard(), - ); - } - final playlist = playlists[index]; - return PlaylistCard(playlist); - }), - ), - ), - ], - ), + return HorizontalPlaybuttonCardView( + title: Text(category.name!), + hasNextPage: playlistQuery.hasNextPage, + items: playlists, + onFetchMore: playlistQuery.fetchNext, ); } } diff --git a/lib/components/shared/horizontal_playbutton_card_view/horizontal_playbutton_card_view.dart b/lib/components/shared/horizontal_playbutton_card_view/horizontal_playbutton_card_view.dart new file mode 100644 index 00000000..a415d721 --- /dev/null +++ b/lib/components/shared/horizontal_playbutton_card_view/horizontal_playbutton_card_view.dart @@ -0,0 +1,96 @@ +import 'dart:ui'; + +import 'package:flutter/material.dart'; +import 'package:flutter_hooks/flutter_hooks.dart'; +import 'package:spotify/spotify.dart'; +import 'package:spotube/components/album/album_card.dart'; +import 'package:spotube/components/artist/artist_card.dart'; +import 'package:spotube/components/playlist/playlist_card.dart'; +import 'package:spotube/components/shared/shimmers/shimmer_playbutton_card.dart'; +import 'package:spotube/components/shared/waypoint.dart'; +import 'package:spotube/hooks/use_breakpoint_value.dart'; + +class HorizontalPlaybuttonCardView extends HookWidget { + final Widget title; + final List items; + final VoidCallback onFetchMore; + final bool hasNextPage; + const HorizontalPlaybuttonCardView({ + required this.title, + required this.items, + required this.hasNextPage, + required this.onFetchMore, + Key? key, + }) : assert( + items is List || + items is List || + items is List, + ), + super(key: key); + + @override + Widget build(BuildContext context) { + final ThemeData(:textTheme) = Theme.of(context); + final scrollController = useScrollController(); + final height = useBreakpointValue( + xs: 226, + sm: 226, + md: 236, + others: 266, + ); + + return Padding( + padding: const EdgeInsets.all(8.0), + child: Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + DefaultTextStyle( + style: textTheme.titleMedium!, + child: title, + ), + SizedBox( + height: height, + child: ScrollConfiguration( + behavior: ScrollConfiguration.of(context).copyWith( + dragDevices: { + PointerDeviceKind.touch, + PointerDeviceKind.mouse, + }, + ), + child: ListView.builder( + controller: scrollController, + scrollDirection: Axis.horizontal, + padding: const EdgeInsets.symmetric(vertical: 8.0), + itemCount: items.length + 1, + itemBuilder: (context, index) { + if (index == items.length) { + if (!hasNextPage) { + return const SizedBox.shrink(); + } + return Waypoint( + controller: scrollController, + onTouchEdge: onFetchMore, + isGrid: true, + child: const ShimmerPlaybuttonCard(), + ); + } + final item = items[index]; + + return switch (item.runtimeType) { + PlaylistSimple => PlaylistCard(item as PlaylistSimple), + Album => AlbumCard(item as Album), + Artist => Padding( + padding: const EdgeInsets.symmetric(horizontal: 12.0), + child: ArtistCard(item as Artist), + ), + _ => const SizedBox.shrink(), + }; + }), + ), + ), + ], + ), + ); + } +} diff --git a/lib/pages/artist/artist.dart b/lib/pages/artist/artist.dart index 67a99d86..2f169583 100644 --- a/lib/pages/artist/artist.dart +++ b/lib/pages/artist/artist.dart @@ -410,13 +410,6 @@ class ArtistPage extends HookConsumerWidget { }, ), const SizedBox(height: 50), - Padding( - padding: const EdgeInsets.all(8.0), - child: Text( - context.l10n.albums, - style: theme.textTheme.headlineSmall, - ), - ), ArtistAlbumList(artistId), const SizedBox(height: 20), Padding( diff --git a/lib/pages/home/genres.dart b/lib/pages/home/genres.dart index db1c58c5..076305f2 100644 --- a/lib/pages/home/genres.dart +++ b/lib/pages/home/genres.dart @@ -85,15 +85,19 @@ class GenrePage extends HookConsumerWidget { controller: scrollController, itemCount: categories.length, itemBuilder: (context, index) { - return AnimatedCrossFade( - crossFadeState: searchController.text.isEmpty && + return AnimatedSwitcher( + transitionBuilder: (child, animation) { + return FadeTransition( + opacity: animation, + child: child, + ); + }, + duration: const Duration(milliseconds: 300), + child: searchController.text.isEmpty && index == categories.length - 1 && categoriesQuery.hasNextPage - ? CrossFadeState.showFirst - : CrossFadeState.showSecond, - duration: const Duration(milliseconds: 300), - firstChild: const ShimmerCategories(), - secondChild: CategoryCard(categories[index]), + ? const ShimmerCategories() + : CategoryCard(categories[index]), ); }, ), diff --git a/lib/pages/home/personalized.dart b/lib/pages/home/personalized.dart index 4f0b655f..bbffbc11 100644 --- a/lib/pages/home/personalized.dart +++ b/lib/pages/home/personalized.dart @@ -1,111 +1,16 @@ -import 'package:flutter/gestures.dart'; import 'package:flutter/material.dart' hide Page; import 'package:flutter_hooks/flutter_hooks.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:spotify/spotify.dart'; -import 'package:spotube/components/album/album_card.dart'; -import 'package:spotube/components/playlist/playlist_card.dart'; +import 'package:spotube/components/shared/horizontal_playbutton_card_view/horizontal_playbutton_card_view.dart'; import 'package:spotube/components/shared/inter_scrollbar/inter_scrollbar.dart'; import 'package:spotube/components/shared/shimmers/shimmer_categories.dart'; -import 'package:spotube/components/shared/shimmers/shimmer_playbutton_card.dart'; -import 'package:spotube/components/shared/waypoint.dart'; -import 'package:spotube/extensions/constrains.dart'; import 'package:spotube/extensions/context.dart'; -import 'package:spotube/models/logger.dart'; import 'package:spotube/provider/authentication_provider.dart'; import 'package:spotube/services/queries/queries.dart'; import 'package:spotube/utils/type_conversion_utils.dart'; -class PersonalizedItemCard extends HookWidget { - final Iterable? playlists; - final Iterable? albums; - final String title; - final bool hasNextPage; - final void Function() onFetchMore; - - PersonalizedItemCard({ - this.playlists, - this.albums, - required this.title, - required this.hasNextPage, - required this.onFetchMore, - Key? key, - }) : assert(playlists == null || albums == null), - super(key: key); - - final logger = getLogger(PersonalizedItemCard); - - @override - Widget build(BuildContext context) { - final scrollController = useScrollController(); - final mediaQuery = MediaQuery.of(context); - - return Padding( - padding: const EdgeInsets.all(8.0), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - mainAxisSize: MainAxisSize.min, - children: [ - Padding( - padding: const EdgeInsets.all(8.0), - child: Text( - title, - style: Theme.of(context).textTheme.titleLarge, - ), - ), - SizedBox( - height: mediaQuery.smAndDown ? 226 : 266, - child: ScrollConfiguration( - behavior: ScrollConfiguration.of(context).copyWith( - dragDevices: { - PointerDeviceKind.touch, - PointerDeviceKind.mouse, - }, - ), - child: Scrollbar( - controller: scrollController, - interactive: false, - child: ListView.builder( - itemCount: (playlists?.length ?? albums?.length)! + 1, - padding: const EdgeInsets.symmetric(vertical: 8.0), - scrollDirection: Axis.horizontal, - itemBuilder: (context, index) { - if (index == (playlists?.length ?? albums?.length)!) { - if (!hasNextPage) return const SizedBox.shrink(); - - return Waypoint( - controller: scrollController, - onTouchEdge: onFetchMore, - isGrid: true, - child: const ShimmerPlaybuttonCard(count: 1), - ); - } - - final item = playlists == null - ? albums!.elementAt(index) - : playlists!.elementAt(index); - - if (playlists == null) { - return AlbumCard( - TypeConversionUtils.simpleAlbum_X_Album( - item as AlbumSimple, - ), - ); - } - - return PlaylistCard(item as PlaylistSimple); - }, - ), - ), - ), - ), - ], - ), - ); - } -} - class PersonalizedPage extends HookConsumerWidget { const PersonalizedPage({Key? key}) : super(key: key); @@ -133,10 +38,12 @@ class PersonalizedPage extends HookConsumerWidget { .whereType>() .expand((page) => page.items ?? const []) .where((album) { - return album.artists - ?.any((artist) => userArtists.contains(artist.id!)) == - true; - }), + return album.artists + ?.any((artist) => userArtists.contains(artist.id!)) == + true; + }) + .map((album) => TypeConversionUtils.simpleAlbum_X_Album(album)) + .toList(), [newReleases.pages], ); @@ -149,18 +56,18 @@ class PersonalizedPage extends HookConsumerWidget { !featuredPlaylistsQuery.isLoadingNextPage) const ShimmerCategories() else - PersonalizedItemCard( - playlists: playlists, - title: context.l10n.featured, + HorizontalPlaybuttonCardView( + items: playlists.toList(), + title: Text(context.l10n.featured), hasNextPage: featuredPlaylistsQuery.hasNextPage, onFetchMore: featuredPlaylistsQuery.fetchNext, ), if (auth != null && newReleases.hasPageData && userArtistsQuery.hasData) - PersonalizedItemCard( - albums: albums, - title: context.l10n.new_releases, + HorizontalPlaybuttonCardView( + items: albums, + title: Text(context.l10n.new_releases), hasNextPage: newReleases.hasNextPage, onFetchMore: newReleases.fetchNext, ), @@ -172,9 +79,9 @@ class PersonalizedPage extends HookConsumerWidget { .cast() ?? []; if (playlists.isEmpty) return const SizedBox.shrink(); - return PersonalizedItemCard( - playlists: playlists, - title: item["name"] ?? "", + return HorizontalPlaybuttonCardView( + items: playlists, + title: Text(item["name"] ?? ""), hasNextPage: false, onFetchMore: () {}, ); diff --git a/lib/pages/search/search.dart b/lib/pages/search/search.dart index c192eb7b..d659e8e3 100644 --- a/lib/pages/search/search.dart +++ b/lib/pages/search/search.dart @@ -1,30 +1,24 @@ import 'dart:async'; -import 'package:flutter/gestures.dart'; import 'package:flutter/material.dart' hide Page; import 'package:flutter_hooks/flutter_hooks.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:spotify/spotify.dart'; import 'package:spotube/collections/spotube_icons.dart'; -import 'package:spotube/components/album/album_card.dart'; -import 'package:spotube/components/shared/dialogs/prompt_dialog.dart'; import 'package:spotube/components/shared/inter_scrollbar/inter_scrollbar.dart'; -import 'package:spotube/components/shared/shimmers/shimmer_playbutton_card.dart'; import 'package:spotube/components/shared/fallbacks/anonymous_fallback.dart'; import 'package:spotube/components/shared/page_window_title_bar.dart'; -import 'package:spotube/components/shared/track_table/track_tile.dart'; -import 'package:spotube/components/shared/waypoint.dart'; -import 'package:spotube/components/artist/artist_card.dart'; -import 'package:spotube/components/playlist/playlist_card.dart'; import 'package:spotube/extensions/constrains.dart'; import 'package:spotube/extensions/context.dart'; +import 'package:spotube/pages/search/sections/albums.dart'; +import 'package:spotube/pages/search/sections/artists.dart'; +import 'package:spotube/pages/search/sections/playlists.dart'; +import 'package:spotube/pages/search/sections/tracks.dart'; import 'package:spotube/provider/authentication_provider.dart'; -import 'package:spotube/provider/proxy_playlist/proxy_playlist_provider.dart'; import 'package:spotube/services/queries/queries.dart'; import 'package:spotube/utils/platform.dart'; -import 'package:spotube/utils/type_conversion_utils.dart'; import 'package:collection/collection.dart'; final searchTermStateProvider = StateProvider((ref) => ""); @@ -38,9 +32,6 @@ class SearchPage extends HookConsumerWidget { ref.watch(AuthenticationNotifier.provider); final authenticationNotifier = ref.watch(AuthenticationNotifier.provider.notifier); - final albumController = useScrollController(); - final playlistController = useScrollController(); - final artistController = useScrollController(); final mediaQuery = MediaQuery.of(context); final searchTerm = ref.watch(searchTermStateProvider); @@ -80,283 +71,26 @@ class SearchPage extends HookConsumerWidget { searchTerm.isNotEmpty; final resultWidget = HookBuilder( - builder: (context) { - final playlist = ref.watch(ProxyPlaylistNotifier.provider); - final playlistNotifier = ref.watch(ProxyPlaylistNotifier.notifier); - List albums = []; - List artists = []; - List tracks = []; - List playlists = []; - final pages = [ - ...searchTrack.pages, - ...searchAlbum.pages, - ...searchPlaylist.pages, - ...searchArtist.pages, - ].expand((page) => page).toList(); - for (MapEntry page in pages.asMap().entries) { - for (var item in page.value.items ?? []) { - if (item is AlbumSimple) { - albums.add(item); - } else if (item is PlaylistSimple) { - playlists.add(item); - } else if (item is Artist) { - artists.add(item); - } else if (item is Track) { - tracks.add(item); - } - } - } - - return InterScrollbar( - child: SingleChildScrollView( - child: Padding( - padding: const EdgeInsets.symmetric(vertical: 8), - child: SafeArea( - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - if (tracks.isNotEmpty) - Padding( - padding: const EdgeInsets.symmetric(horizontal: 8), - child: Text( - context.l10n.songs, - style: theme.textTheme.titleLarge!, - ), - ), - if (!searchTrack.hasPageData && - !searchTrack.hasPageError && - !searchTrack.isLoadingNextPage) - const CircularProgressIndicator() - else if (searchTrack.hasPageError) - Text( - searchTrack.errors.lastOrNull?.toString() ?? "", - ) - else - ...tracks.mapIndexed((i, track) { - return TrackTile( - index: i, - track: track, - onTap: () async { - final isTrackPlaying = - playlist.activeTrack?.id == track.id; - if (!isTrackPlaying && context.mounted) { - final shouldPlay = (playlist.tracks.length) > 20 - ? await showPromptDialog( - context: context, - title: context.l10n.playing_track( - track.name!, - ), - message: context.l10n.queue_clear_alert( - playlist.tracks.length, - ), - ) - : true; - - if (shouldPlay) { - await playlistNotifier.load( - [track], - autoPlay: true, - ); - } - } - }, - ); - }), - if (searchTrack.hasNextPage && tracks.isNotEmpty) - Center( - child: TextButton( - onPressed: searchTrack.isLoadingNextPage - ? null - : () => searchTrack.fetchNext(), - child: searchTrack.isLoadingNextPage - ? const CircularProgressIndicator() - : Text(context.l10n.load_more), - ), - ), - if (playlists.isNotEmpty) - Padding( - padding: const EdgeInsets.symmetric(horizontal: 8), - child: Text( - context.l10n.playlists, - style: theme.textTheme.titleLarge!, - ), - ), - const SizedBox(height: 10), - ScrollConfiguration( - behavior: ScrollConfiguration.of(context).copyWith( - dragDevices: { - PointerDeviceKind.touch, - PointerDeviceKind.mouse, - }, - ), - child: Scrollbar( - scrollbarOrientation: mediaQuery.lgAndUp - ? ScrollbarOrientation.bottom - : ScrollbarOrientation.top, - controller: playlistController, - child: Waypoint( - onTouchEdge: () { - searchPlaylist.fetchNext(); - }, - controller: playlistController, - child: SingleChildScrollView( - scrollDirection: Axis.horizontal, - controller: playlistController, - padding: const EdgeInsets.symmetric(vertical: 4), - child: Row( - children: [ - ...playlists.mapIndexed( - (i, playlist) { - if (i == playlists.length - 1 && - searchPlaylist.hasNextPage) { - return const ShimmerPlaybuttonCard( - count: 1); - } - return PlaylistCard(playlist); - }, - ), - ], - ), - ), - ), - ), - ), - if (!searchPlaylist.hasPageData && - !searchPlaylist.hasPageError && - !searchPlaylist.isLoadingNextPage) - const CircularProgressIndicator(), - if (searchPlaylist.hasPageError) - Padding( - padding: const EdgeInsets.symmetric(horizontal: 8), - child: Text( - searchPlaylist.errors.lastOrNull?.toString() ?? "", - ), - ), - const SizedBox(height: 20), - if (artists.isNotEmpty) - Padding( - padding: const EdgeInsets.symmetric(horizontal: 8), - child: Text( - context.l10n.artists, - style: theme.textTheme.titleLarge!, - ), - ), - const SizedBox(height: 10), - ScrollConfiguration( - behavior: ScrollConfiguration.of(context).copyWith( - dragDevices: { - PointerDeviceKind.touch, - PointerDeviceKind.mouse, - }, - ), - child: Scrollbar( - controller: artistController, - child: Waypoint( - controller: artistController, - onTouchEdge: () { - searchArtist.fetchNext(); - }, - child: SingleChildScrollView( - scrollDirection: Axis.horizontal, - controller: artistController, - child: Row( - children: [ - ...artists.mapIndexed( - (i, artist) { - if (i == artists.length - 1 && - searchArtist.hasNextPage) { - return const ShimmerPlaybuttonCard( - count: 1); - } - return Container( - margin: const EdgeInsets.symmetric( - horizontal: 15), - child: ArtistCard(artist), - ); - }, - ), - ], - ), - ), - ), - ), - ), - if (!searchArtist.hasPageData && - !searchArtist.hasPageError && - !searchArtist.isLoadingNextPage) - const CircularProgressIndicator(), - if (searchArtist.hasPageError) - Padding( - padding: const EdgeInsets.symmetric(horizontal: 8), - child: Text( - searchArtist.errors.lastOrNull?.toString() ?? "", - ), - ), - const SizedBox(height: 20), - if (albums.isNotEmpty) - Padding( - padding: const EdgeInsets.symmetric(horizontal: 8), - child: Text( - context.l10n.albums, - style: theme.textTheme.titleLarge!, - ), - ), - const SizedBox(height: 10), - ScrollConfiguration( - behavior: ScrollConfiguration.of(context).copyWith( - dragDevices: { - PointerDeviceKind.touch, - PointerDeviceKind.mouse, - }, - ), - child: Scrollbar( - controller: albumController, - child: Waypoint( - controller: albumController, - onTouchEdge: () { - searchAlbum.fetchNext(); - }, - child: SingleChildScrollView( - scrollDirection: Axis.horizontal, - controller: albumController, - child: Row( - children: [ - ...albums.mapIndexed((i, album) { - if (i == albums.length - 1 && - searchAlbum.hasNextPage) { - return const ShimmerPlaybuttonCard( - count: 1); - } - return AlbumCard( - TypeConversionUtils.simpleAlbum_X_Album( - album, - ), - ); - }), - ], - ), - ), - ), - ), - ), - if (!searchAlbum.hasPageData && - !searchAlbum.hasPageError && - !searchAlbum.isLoadingNextPage) - const CircularProgressIndicator(), - if (searchAlbum.hasPageError) - Padding( - padding: const EdgeInsets.symmetric(horizontal: 8), - child: Text( - searchAlbum.errors.lastOrNull?.toString() ?? "", - ), - ), - ], - ), + builder: (context) => InterScrollbar( + child: SingleChildScrollView( + child: Padding( + padding: const EdgeInsets.symmetric(vertical: 8), + child: SafeArea( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + SearchTracksSection(query: searchTrack), + SearchPlaylistsSection(query: searchPlaylist), + const SizedBox(height: 20), + SearchArtistsSection(query: searchArtist), + const SizedBox(height: 20), + SearchAlbumsSection(query: searchAlbum), + ], ), ), ), - ); - }, + ), + ), ); return SafeArea( diff --git a/lib/pages/search/sections/albums.dart b/lib/pages/search/sections/albums.dart new file mode 100644 index 00000000..787a1924 --- /dev/null +++ b/lib/pages/search/sections/albums.dart @@ -0,0 +1,39 @@ +import 'package:fl_query/fl_query.dart'; + +import 'package:flutter/material.dart' hide Page; +import 'package:flutter_hooks/flutter_hooks.dart'; +import 'package:hooks_riverpod/hooks_riverpod.dart'; + +import 'package:spotify/spotify.dart'; +import 'package:spotube/components/shared/horizontal_playbutton_card_view/horizontal_playbutton_card_view.dart'; +import 'package:spotube/extensions/context.dart'; +import 'package:spotube/utils/type_conversion_utils.dart'; + +class SearchAlbumsSection extends HookConsumerWidget { + final InfiniteQuery>, dynamic, int> query; + const SearchAlbumsSection({ + required this.query, + Key? key, + }) : super(key: key); + + @override + Widget build(BuildContext context, ref) { + final albums = useMemoized( + () => query.pages + .expand( + (page) => page.map((p) => p.items!).expand((element) => element), + ) + .whereType() + .map((e) => TypeConversionUtils.simpleAlbum_X_Album(e)) + .toList(), + [query.pages], + ); + + return HorizontalPlaybuttonCardView( + hasNextPage: query.hasNextPage, + items: albums, + onFetchMore: query.fetchNext, + title: Text(context.l10n.albums), + ); + } +} diff --git a/lib/pages/search/sections/artists.dart b/lib/pages/search/sections/artists.dart new file mode 100644 index 00000000..7abd5250 --- /dev/null +++ b/lib/pages/search/sections/artists.dart @@ -0,0 +1,37 @@ +import 'package:fl_query/fl_query.dart'; +import 'package:flutter/material.dart' hide Page; +import 'package:flutter_hooks/flutter_hooks.dart'; +import 'package:hooks_riverpod/hooks_riverpod.dart'; + +import 'package:spotify/spotify.dart'; +import 'package:spotube/components/shared/horizontal_playbutton_card_view/horizontal_playbutton_card_view.dart'; +import 'package:spotube/extensions/context.dart'; + +class SearchArtistsSection extends HookConsumerWidget { + final InfiniteQuery>, dynamic, int> query; + + const SearchArtistsSection({ + Key? key, + required this.query, + }) : super(key: key); + + @override + Widget build(BuildContext context, ref) { + final artists = useMemoized( + () => query.pages + .expand( + (page) => page.map((p) => p.items!).expand((element) => element), + ) + .whereType() + .toList(), + [query.pages], + ); + + return HorizontalPlaybuttonCardView( + hasNextPage: query.hasNextPage, + items: artists, + onFetchMore: query.fetchNext, + title: Text(context.l10n.albums), + ); + } +} diff --git a/lib/pages/search/sections/playlists.dart b/lib/pages/search/sections/playlists.dart new file mode 100644 index 00000000..620e914b --- /dev/null +++ b/lib/pages/search/sections/playlists.dart @@ -0,0 +1,35 @@ +import 'package:fl_query/fl_query.dart'; +import 'package:flutter/material.dart' hide Page; +import 'package:flutter_hooks/flutter_hooks.dart'; +import 'package:hooks_riverpod/hooks_riverpod.dart'; +import 'package:spotify/spotify.dart'; +import 'package:spotube/components/shared/horizontal_playbutton_card_view/horizontal_playbutton_card_view.dart'; +import 'package:spotube/extensions/context.dart'; + +class SearchPlaylistsSection extends HookConsumerWidget { + final InfiniteQuery>, dynamic, int> query; + const SearchPlaylistsSection({ + required this.query, + Key? key, + }) : super(key: key); + + @override + Widget build(BuildContext context, ref) { + final playlists = useMemoized( + () => query.pages + .expand( + (page) => page.map((p) => p.items!).expand((element) => element), + ) + .whereType() + .toList(), + [query.pages], + ); + + return HorizontalPlaybuttonCardView( + hasNextPage: query.hasNextPage, + items: playlists, + onFetchMore: query.fetchNext, + title: Text(context.l10n.playlists), + ); + } +} diff --git a/lib/pages/search/sections/tracks.dart b/lib/pages/search/sections/tracks.dart new file mode 100644 index 00000000..59c6a4e1 --- /dev/null +++ b/lib/pages/search/sections/tracks.dart @@ -0,0 +1,98 @@ +import 'package:collection/collection.dart'; +import 'package:fl_query/fl_query.dart'; +import 'package:flutter/material.dart' hide Page; +import 'package:flutter_hooks/flutter_hooks.dart'; +import 'package:hooks_riverpod/hooks_riverpod.dart'; +import 'package:spotify/spotify.dart'; +import 'package:spotube/components/shared/dialogs/prompt_dialog.dart'; +import 'package:spotube/components/shared/track_table/track_tile.dart'; +import 'package:spotube/extensions/context.dart'; +import 'package:spotube/provider/proxy_playlist/proxy_playlist_provider.dart'; + +class SearchTracksSection extends HookConsumerWidget { + final InfiniteQuery>, dynamic, int> query; + const SearchTracksSection({ + Key? key, + required this.query, + }) : super(key: key); + + @override + Widget build(BuildContext context, ref) { + final searchTrack = query; + final tracks = useMemoized( + () => searchTrack.pages + .expand( + (page) => page.map((p) => p.items!).expand((element) => element), + ) + .whereType(), + [searchTrack.pages], + ); + final playlistNotifier = ref.watch(ProxyPlaylistNotifier.provider.notifier); + final playlist = ref.watch(ProxyPlaylistNotifier.provider); + final theme = Theme.of(context); + + return Column( + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisSize: MainAxisSize.min, + children: [ + if (tracks.isNotEmpty) + Padding( + padding: const EdgeInsets.symmetric(horizontal: 8), + child: Text( + context.l10n.songs, + style: theme.textTheme.titleLarge!, + ), + ), + if (!searchTrack.hasPageData && + !searchTrack.hasPageError && + !searchTrack.isLoadingNextPage) + const CircularProgressIndicator() + else if (searchTrack.hasPageError) + Text( + searchTrack.errors.lastOrNull?.toString() ?? "", + ) + else + ...tracks.mapIndexed((i, track) { + return TrackTile( + index: i, + track: track, + onTap: () async { + final isTrackPlaying = playlist.activeTrack?.id == track.id; + if (!isTrackPlaying && context.mounted) { + final shouldPlay = (playlist.tracks.length) > 20 + ? await showPromptDialog( + context: context, + title: context.l10n.playing_track( + track.name!, + ), + message: context.l10n.queue_clear_alert( + playlist.tracks.length, + ), + ) + : true; + + if (shouldPlay) { + await playlistNotifier.load( + [track], + autoPlay: true, + ); + } + } + }, + ); + }), + if (searchTrack.hasNextPage && tracks.isNotEmpty) + Center( + child: TextButton( + onPressed: searchTrack.isLoadingNextPage + ? null + : () => searchTrack.fetchNext(), + child: searchTrack.isLoadingNextPage + ? const CircularProgressIndicator() + : Text(context.l10n.load_more), + ), + ) + ], + ); + } +} From da04f068f9b7effff8d50cb5714d93ea80c22b7f Mon Sep 17 00:00:00 2001 From: Kingkor Roy Tirtho Date: Wed, 8 Nov 2023 17:48:59 +0600 Subject: [PATCH 008/195] fix: Navigating to settings, redirects to home page #812 --- lib/components/root/sidebar.dart | 18 +++++++++++------- .../root/spotube_navigation_bar.dart | 8 +++++--- lib/pages/root/root_app.dart | 4 ++-- 3 files changed, 18 insertions(+), 12 deletions(-) diff --git a/lib/components/root/sidebar.dart b/lib/components/root/sidebar.dart index 0dc8b5b4..7fb1b95f 100644 --- a/lib/components/root/sidebar.dart +++ b/lib/components/root/sidebar.dart @@ -22,7 +22,7 @@ import 'package:spotube/utils/platform.dart'; import 'package:spotube/utils/type_conversion_utils.dart'; class Sidebar extends HookConsumerWidget { - final int selectedIndex; + final int? selectedIndex; final void Function(int) onSelectedIndexChanged; final Widget child; @@ -57,7 +57,7 @@ class Sidebar extends HookConsumerWidget { ref.watch(userPreferencesProvider.select((s) => s.layoutMode)); final controller = useSidebarXController( - selectedIndex: selectedIndex, + selectedIndex: selectedIndex ?? 0, extended: mediaQuery.lgAndUp, ); @@ -75,17 +75,21 @@ class Sidebar extends HookConsumerWidget { ); useEffect(() { - if (controller.selectedIndex != selectedIndex) { - controller.selectIndex(selectedIndex); + if (controller.selectedIndex != selectedIndex && selectedIndex != null) { + controller.selectIndex(selectedIndex!); } return null; }, [selectedIndex]); useEffect(() { - controller.addListener(() { + void listener() { onSelectedIndexChanged(controller.selectedIndex); - }); - return null; + } + + controller.addListener(listener); + return () { + controller.removeListener(listener); + }; }, [controller]); useEffect(() { diff --git a/lib/components/root/spotube_navigation_bar.dart b/lib/components/root/spotube_navigation_bar.dart index 9cea5603..b62d19d1 100644 --- a/lib/components/root/spotube_navigation_bar.dart +++ b/lib/components/root/spotube_navigation_bar.dart @@ -16,7 +16,7 @@ import 'package:spotube/provider/user_preferences_provider.dart'; final navigationPanelHeight = StateProvider((ref) => 50); class SpotubeNavigationBar extends HookConsumerWidget { - final int selectedIndex; + final int? selectedIndex; final void Function(int) onSelectedIndexChanged; const SpotubeNavigationBar({ @@ -33,7 +33,7 @@ class SpotubeNavigationBar extends HookConsumerWidget { final layoutMode = ref.watch(userPreferencesProvider.select((s) => s.layoutMode)); - final insideSelectedIndex = useState(selectedIndex); + final insideSelectedIndex = useState(selectedIndex ?? 0); final buttonColor = useBrightnessValue( theme.colorScheme.inversePrimary, @@ -46,7 +46,9 @@ class SpotubeNavigationBar extends HookConsumerWidget { final panelHeight = ref.watch(navigationPanelHeight); useEffect(() { - insideSelectedIndex.value = selectedIndex; + if (selectedIndex != null) { + insideSelectedIndex.value = selectedIndex!; + } return null; }, [selectedIndex]); diff --git a/lib/pages/root/root_app.dart b/lib/pages/root/root_app.dart index b2bd4620..bdbc1c75 100644 --- a/lib/pages/root/root_app.dart +++ b/lib/pages/root/root_app.dart @@ -159,7 +159,7 @@ class RootApp extends HookConsumerWidget { return Scaffold( body: Sidebar( - selectedIndex: rootPaths[location] ?? 0, + selectedIndex: rootPaths[location], onSelectedIndexChanged: onSelectIndexChanged, child: child, ), @@ -169,7 +169,7 @@ class RootApp extends HookConsumerWidget { children: [ BottomPlayer(), SpotubeNavigationBar( - selectedIndex: rootPaths[location] ?? 0, + selectedIndex: rootPaths[location], onSelectedIndexChanged: onSelectIndexChanged, ), ], From a1cc44759b63e731a7f73e24fd9ff29636e9bb77 Mon Sep 17 00:00:00 2001 From: Kingkor Roy Tirtho Date: Wed, 8 Nov 2023 18:51:19 +0600 Subject: [PATCH 009/195] refactor: show queue from side in desktop --- lib/components/player/player_actions.dart | 22 +- lib/components/player/player_queue.dart | 338 +++++++++--------- .../player/sibling_tracks_sheet.dart | 274 +++++++------- lib/pages/root/root_app.dart | 18 + 4 files changed, 333 insertions(+), 319 deletions(-) diff --git a/lib/components/player/player_actions.dart b/lib/components/player/player_actions.dart index b3a1e340..7a248aa5 100644 --- a/lib/components/player/player_actions.dart +++ b/lib/components/player/player_actions.dart @@ -5,10 +5,10 @@ import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:spotify/spotify.dart' hide Offset; import 'package:spotube/collections/spotube_icons.dart'; -import 'package:spotube/components/player/player_queue.dart'; import 'package:spotube/components/player/sibling_tracks_sheet.dart'; import 'package:spotube/components/shared/adaptive/adaptive_pop_sheet_list.dart'; import 'package:spotube/components/shared/heart_button.dart'; +import 'package:spotube/extensions/constrains.dart'; import 'package:spotube/extensions/context.dart'; import 'package:spotube/extensions/duration.dart'; import 'package:spotube/models/local_track.dart'; @@ -35,6 +35,7 @@ class PlayerActions extends HookConsumerWidget { @override Widget build(BuildContext context, ref) { + final mediaQuery = MediaQuery.of(context); final playlist = ref.watch(ProxyPlaylistNotifier.provider); final isLocalTrack = playlist.activeTrack is LocalTrack; ref.watch(downloadManagerProvider); @@ -86,23 +87,7 @@ class PlayerActions extends HookConsumerWidget { tooltip: context.l10n.queue, onPressed: playlist.activeTrack != null ? () { - showModalBottomSheet( - context: context, - isDismissible: true, - enableDrag: true, - isScrollControlled: true, - backgroundColor: Colors.black12, - barrierColor: Colors.black12, - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(10), - ), - constraints: BoxConstraints( - maxHeight: MediaQuery.of(context).size.height * .7, - ), - builder: (context) { - return PlayerQueue(floating: floatingQueue); - }, - ); + Scaffold.of(context).openEndDrawer(); } : null, ), @@ -119,6 +104,7 @@ class PlayerActions extends HookConsumerWidget { isScrollControlled: true, backgroundColor: Colors.black12, barrierColor: Colors.black12, + elevation: 0, shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(10), ), diff --git a/lib/components/player/player_queue.dart b/lib/components/player/player_queue.dart index 725af22b..2d8ba329 100644 --- a/lib/components/player/player_queue.dart +++ b/lib/components/player/player_queue.dart @@ -36,7 +36,9 @@ class PlayerQueue extends HookConsumerWidget { final tracks = playlist.tracks; final borderRadius = floating - ? BorderRadius.circular(10) + ? const BorderRadius.only( + topLeft: Radius.circular(10), + ) : const BorderRadius.only( topLeft: Radius.circular(10), topRight: Radius.circular(10), @@ -80,140 +82,177 @@ class PlayerQueue extends HookConsumerWidget { return const NotFound(vertical: true); } - return BackdropFilter( - filter: ImageFilter.blur( - sigmaX: 12.0, - sigmaY: 12.0, - ), - child: Container( - margin: EdgeInsets.all(floating ? 8.0 : 0), - padding: const EdgeInsets.only( - top: 5.0, + return ClipRRect( + borderRadius: borderRadius, + clipBehavior: Clip.hardEdge, + child: BackdropFilter( + filter: ImageFilter.blur( + sigmaX: 15, + sigmaY: 15, ), - decoration: BoxDecoration( - color: theme.scaffoldBackgroundColor.withOpacity(0.5), - borderRadius: borderRadius, - ), - child: CallbackShortcuts( - bindings: { - LogicalKeySet(LogicalKeyboardKey.escape): () { - if (!isSearching.value) { - Navigator.of(context).pop(); + child: Container( + padding: const EdgeInsets.only( + top: 5.0, + ), + decoration: BoxDecoration( + color: theme.colorScheme.surfaceVariant.withOpacity(0.5), + borderRadius: borderRadius, + ), + child: CallbackShortcuts( + bindings: { + LogicalKeySet(LogicalKeyboardKey.escape): () { + if (!isSearching.value) { + Navigator.of(context).pop(); + } + isSearching.value = false; + searchText.value = ''; } - isSearching.value = false; - searchText.value = ''; - } - }, - child: LayoutBuilder(builder: (context, constraints) { - return Column( - children: [ - Container( - height: 5, - width: 100, - margin: const EdgeInsets.only(bottom: 5, top: 2), - decoration: BoxDecoration( - color: headlineColor, - borderRadius: BorderRadius.circular(20), - ), - ), - Row( - crossAxisAlignment: CrossAxisAlignment.center, - mainAxisAlignment: MainAxisAlignment.center, - children: [ - if (constraints.mdAndUp || !isSearching.value) ...[ - const SizedBox(width: 10), - Text( - context.l10n.tracks_in_queue(tracks.length), - style: TextStyle( - color: headlineColor, - fontWeight: FontWeight.bold, - fontSize: 18, - ), + }, + child: LayoutBuilder(builder: (context, constraints) { + return Column( + children: [ + if (!floating) + Container( + height: 5, + width: 100, + margin: const EdgeInsets.only(bottom: 5, top: 2), + decoration: BoxDecoration( + color: headlineColor, + borderRadius: BorderRadius.circular(20), ), - const Spacer(), - ], - if (constraints.mdAndUp || isSearching.value) - TextField( - onChanged: (value) { - searchText.value = value; - }, - decoration: InputDecoration( - hintText: context.l10n.search, - isDense: true, - prefixIcon: constraints.smAndDown - ? IconButton( - icon: const Icon( - Icons.arrow_back_ios_new_outlined, - ), - onPressed: () { - isSearching.value = false; - searchText.value = ''; - }, - style: IconButton.styleFrom( - padding: EdgeInsets.zero, - minimumSize: const Size.square(20), - ), - ) - : const Icon(SpotubeIcons.filter), - constraints: BoxConstraints( - maxHeight: 40, - maxWidth: constraints.smAndDown - ? constraints.maxWidth - 20 - : 300, + ), + Row( + crossAxisAlignment: CrossAxisAlignment.center, + mainAxisAlignment: MainAxisAlignment.center, + children: [ + if (constraints.mdAndUp || !isSearching.value) ...[ + const SizedBox(width: 10), + Text( + context.l10n.tracks_in_queue(tracks.length), + style: TextStyle( + color: headlineColor, + fontWeight: FontWeight.bold, + fontSize: 18, ), ), - ) - else - IconButton.filledTonal( - icon: const Icon(SpotubeIcons.filter), - onPressed: () { - isSearching.value = !isSearching.value; - }, - ), - if (constraints.mdAndUp || !isSearching.value) ...[ - const SizedBox(width: 10), - FilledButton( - style: FilledButton.styleFrom( - backgroundColor: - theme.scaffoldBackgroundColor.withOpacity(0.5), - foregroundColor: theme.textTheme.headlineSmall?.color, + const Spacer(), + ], + if (constraints.mdAndUp || isSearching.value) + TextField( + onChanged: (value) { + searchText.value = value; + }, + decoration: InputDecoration( + hintText: context.l10n.search, + isDense: true, + prefixIcon: constraints.smAndDown + ? IconButton( + icon: const Icon( + Icons.arrow_back_ios_new_outlined, + ), + onPressed: () { + isSearching.value = false; + searchText.value = ''; + }, + style: IconButton.styleFrom( + padding: EdgeInsets.zero, + minimumSize: const Size.square(20), + ), + ) + : const Icon(SpotubeIcons.filter), + constraints: BoxConstraints( + maxHeight: 40, + maxWidth: constraints.smAndDown + ? constraints.maxWidth - 20 + : 300, + ), + ), + ) + else + IconButton.filledTonal( + icon: const Icon(SpotubeIcons.filter), + onPressed: () { + isSearching.value = !isSearching.value; + }, ), - child: Row( - children: [ - const Icon(SpotubeIcons.playlistRemove), - const SizedBox(width: 5), - Text(context.l10n.clear_all), - ], + if (constraints.mdAndUp || !isSearching.value) ...[ + const SizedBox(width: 10), + FilledButton( + style: FilledButton.styleFrom( + backgroundColor: + theme.scaffoldBackgroundColor.withOpacity(0.5), + foregroundColor: + theme.textTheme.headlineSmall?.color, + ), + child: Row( + children: [ + const Icon(SpotubeIcons.playlistRemove), + const SizedBox(width: 5), + Text(context.l10n.clear_all), + ], + ), + onPressed: () { + playlistNotifier.stop(); + Navigator.of(context).pop(); + }, ), - onPressed: () { - playlistNotifier.stop(); - Navigator.of(context).pop(); - }, - ), - const SizedBox(width: 10), + const SizedBox(width: 10), + ], ], - ], - ), - const SizedBox(height: 10), - if (!isSearching.value && searchText.value.isEmpty) - Flexible( - child: InterScrollbar( - controller: controller, - child: ReorderableListView.builder( - onReorder: (oldIndex, newIndex) { - playlistNotifier.moveTrack(oldIndex, newIndex); - }, - scrollController: controller, - itemCount: tracks.length, - shrinkWrap: true, - buildDefaultDragHandles: false, - itemBuilder: (context, i) { - final track = tracks.elementAt(i); - return AutoScrollTag( - key: ValueKey(i), - controller: controller, - index: i, - child: Padding( + ), + const SizedBox(height: 10), + if (!isSearching.value && searchText.value.isEmpty) + Flexible( + child: InterScrollbar( + controller: controller, + child: ReorderableListView.builder( + onReorder: (oldIndex, newIndex) { + playlistNotifier.moveTrack(oldIndex, newIndex); + }, + scrollController: controller, + itemCount: tracks.length, + shrinkWrap: true, + buildDefaultDragHandles: false, + itemBuilder: (context, i) { + final track = tracks.elementAt(i); + return AutoScrollTag( + key: ValueKey(i), + controller: controller, + index: i, + child: Padding( + padding: + const EdgeInsets.symmetric(horizontal: 8.0), + child: TrackTile( + index: i, + track: track, + onTap: () async { + if (playlist.activeTrack?.id == track.id) { + return; + } + await playlistNotifier.jumpToTrack(track); + }, + leadingActions: [ + ReorderableDragStartListener( + index: i, + child: + const Icon(SpotubeIcons.dragHandle), + ), + ], + ), + ), + ); + }, + ), + ), + ) + else + Flexible( + child: InterScrollbar( + child: ListView.builder( + itemCount: filteredTracks.length, + itemBuilder: (context, i) { + final track = filteredTracks.elementAt(i); + return Padding( padding: const EdgeInsets.symmetric(horizontal: 8.0), child: TrackTile( @@ -225,47 +264,16 @@ class PlayerQueue extends HookConsumerWidget { } await playlistNotifier.jumpToTrack(track); }, - leadingActions: [ - ReorderableDragStartListener( - index: i, - child: const Icon(SpotubeIcons.dragHandle), - ), - ], ), - ), - ); - }, + ); + }, + ), ), ), - ) - else - Flexible( - child: InterScrollbar( - child: ListView.builder( - itemCount: filteredTracks.length, - itemBuilder: (context, i) { - final track = filteredTracks.elementAt(i); - return Padding( - padding: - const EdgeInsets.symmetric(horizontal: 8.0), - child: TrackTile( - index: i, - track: track, - onTap: () async { - if (playlist.activeTrack?.id == track.id) { - return; - } - await playlistNotifier.jumpToTrack(track); - }, - ), - ); - }, - ), - ), - ), - ], - ); - }), + ], + ); + }), + ), ), ), ); diff --git a/lib/components/player/sibling_tracks_sheet.dart b/lib/components/player/sibling_tracks_sheet.dart index 6587b8b3..14c042b8 100644 --- a/lib/components/player/sibling_tracks_sheet.dart +++ b/lib/components/player/sibling_tracks_sheet.dart @@ -86,151 +86,153 @@ class SiblingTracksSheet extends HookConsumerWidget { return null; }, [playlist.activeTrack]); - final itemBuilder = useCallback((YoutubeVideoInfo video) { - return ListTile( - title: Text(video.title), - leading: Padding( - padding: const EdgeInsets.all(8.0), - child: UniversalImage( - path: video.thumbnailUrl, - height: 60, - width: 60, + final itemBuilder = useCallback( + (YoutubeVideoInfo video) { + return ListTile( + title: Text(video.title), + leading: Padding( + padding: const EdgeInsets.all(8.0), + child: UniversalImage( + path: video.thumbnailUrl, + height: 60, + width: 60, + ), ), - ), - shape: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(5), - ), - trailing: Text(video.duration.toHumanReadableString()), - subtitle: Text(video.channelName), - enabled: playlist.isFetching != true, - selected: playlist.isFetching != true && - video.id == (playlist.activeTrack as SpotubeTrack).ytTrack.id, - selectedTileColor: theme.popupMenuTheme.color, - onTap: () { - if (playlist.isFetching == false && - video.id != (playlist.activeTrack as SpotubeTrack).ytTrack.id) { - playlistNotifier.swapSibling(video); - Navigator.of(context).pop(); - } - }, - ); - }, [ - playlist.isFetching, - playlist.activeTrack, - siblings, - ]); + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(5), + ), + trailing: Text(video.duration.toHumanReadableString()), + subtitle: Text(video.channelName), + enabled: playlist.isFetching != true, + selected: playlist.isFetching != true && + video.id == (playlist.activeTrack as SpotubeTrack).ytTrack.id, + selectedTileColor: theme.popupMenuTheme.color, + onTap: () { + if (playlist.isFetching == false && + video.id != (playlist.activeTrack as SpotubeTrack).ytTrack.id) { + playlistNotifier.swapSibling(video); + Navigator.of(context).pop(); + } + }, + ); + }, + [playlist.isFetching, playlist.activeTrack, siblings], + ); var mediaQuery = MediaQuery.of(context); return SafeArea( - child: BackdropFilter( - filter: ImageFilter.blur( - sigmaX: 12.0, - sigmaY: 12.0, - ), - child: AnimatedSize( - duration: const Duration(milliseconds: 300), - child: Container( - height: isSearching.value && mediaQuery.smAndDown - ? mediaQuery.size.height - : mediaQuery.size.height * .6, - margin: const EdgeInsets.all(8.0), - decoration: BoxDecoration( - borderRadius: borderRadius, - color: theme.scaffoldBackgroundColor.withOpacity(.3), - ), - child: Scaffold( - backgroundColor: Colors.transparent, - appBar: AppBar( - centerTitle: true, - title: AnimatedSwitcher( - duration: const Duration(milliseconds: 300), - child: !isSearching.value - ? Text( - context.l10n.alternative_track_sources, - style: theme.textTheme.headlineSmall, - ) - : TextField( - autofocus: true, - controller: searchController, - decoration: InputDecoration( - hintText: context.l10n.search, - hintStyle: theme.textTheme.headlineSmall, - border: InputBorder.none, - ), - style: theme.textTheme.headlineSmall, - ), - ), - automaticallyImplyLeading: false, + child: ClipRRect( + borderRadius: borderRadius, + clipBehavior: Clip.hardEdge, + child: BackdropFilter( + filter: ImageFilter.blur( + sigmaX: 12.0, + sigmaY: 12.0, + ), + child: AnimatedSize( + duration: const Duration(milliseconds: 300), + child: Container( + height: isSearching.value && mediaQuery.smAndDown + ? mediaQuery.size.height - mediaQuery.padding.top + : mediaQuery.size.height * .6, + decoration: BoxDecoration( + borderRadius: borderRadius, + color: theme.colorScheme.surfaceVariant.withOpacity(.5), + ), + child: Scaffold( backgroundColor: Colors.transparent, - actions: [ - if (!isSearching.value) - IconButton( - icon: const Icon(SpotubeIcons.search, size: 18), - onPressed: () { - isSearching.value = true; - }, - ) - else ...[ - if (preferences.youtubeApiType == YoutubeApiType.piped) - PopupMenuButton( - icon: const Icon(SpotubeIcons.filter, size: 18), - onSelected: (SearchMode mode) { - searchMode.value = mode; + appBar: AppBar( + centerTitle: true, + title: AnimatedSwitcher( + duration: const Duration(milliseconds: 300), + child: !isSearching.value + ? Text( + context.l10n.alternative_track_sources, + style: theme.textTheme.headlineSmall, + ) + : TextField( + autofocus: true, + controller: searchController, + decoration: InputDecoration( + hintText: context.l10n.search, + hintStyle: theme.textTheme.headlineSmall, + border: InputBorder.none, + ), + style: theme.textTheme.headlineSmall, + ), + ), + automaticallyImplyLeading: false, + backgroundColor: Colors.transparent, + actions: [ + if (!isSearching.value) + IconButton( + icon: const Icon(SpotubeIcons.search, size: 18), + onPressed: () { + isSearching.value = true; + }, + ) + else ...[ + if (preferences.youtubeApiType == YoutubeApiType.piped) + PopupMenuButton( + icon: const Icon(SpotubeIcons.filter, size: 18), + onSelected: (SearchMode mode) { + searchMode.value = mode; + }, + initialValue: searchMode.value, + itemBuilder: (context) => SearchMode.values + .map( + (e) => PopupMenuItem( + value: e, + child: Text(e.label), + ), + ) + .toList(), + ), + IconButton( + icon: const Icon(SpotubeIcons.close, size: 18), + onPressed: () { + isSearching.value = false; }, - initialValue: searchMode.value, - itemBuilder: (context) => SearchMode.values - .map( - (e) => PopupMenuItem( - value: e, - child: Text(e.label), - ), - ) - .toList(), ), - IconButton( - icon: const Icon(SpotubeIcons.close, size: 18), - onPressed: () { - isSearching.value = false; + ] + ], + ), + body: Padding( + padding: const EdgeInsets.all(8.0), + child: AnimatedSwitcher( + duration: const Duration(milliseconds: 300), + transitionBuilder: (child, animation) => + FadeTransition(opacity: animation, child: child), + child: InterScrollbar( + child: switch (isSearching.value) { + false => ListView.builder( + itemCount: siblings.length, + itemBuilder: (context, index) => + itemBuilder(siblings[index]), + ), + true => FutureBuilder( + future: searchRequest, + builder: (context, snapshot) { + if (snapshot.hasError) { + return Center( + child: Text(snapshot.error.toString()), + ); + } else if (!snapshot.hasData) { + return const Center( + child: CircularProgressIndicator()); + } + + return InterScrollbar( + child: ListView.builder( + itemCount: snapshot.data!.length, + itemBuilder: (context, index) => + itemBuilder(snapshot.data![index]), + ), + ); + }, + ), }, ), - ] - ], - ), - body: Padding( - padding: const EdgeInsets.all(8.0), - child: AnimatedSwitcher( - duration: const Duration(milliseconds: 300), - transitionBuilder: (child, animation) => - FadeTransition(opacity: animation, child: child), - child: InterScrollbar( - child: switch (isSearching.value) { - false => ListView.builder( - itemCount: siblings.length, - itemBuilder: (context, index) => - itemBuilder(siblings[index]), - ), - true => FutureBuilder( - future: searchRequest, - builder: (context, snapshot) { - if (snapshot.hasError) { - return Center( - child: Text(snapshot.error.toString()), - ); - } else if (!snapshot.hasData) { - return const Center( - child: CircularProgressIndicator()); - } - - return InterScrollbar( - child: ListView.builder( - itemCount: snapshot.data!.length, - itemBuilder: (context, index) => - itemBuilder(snapshot.data![index]), - ), - ); - }, - ), - }, ), ), ), diff --git a/lib/pages/root/root_app.dart b/lib/pages/root/root_app.dart index bdbc1c75..5797b63f 100644 --- a/lib/pages/root/root_app.dart +++ b/lib/pages/root/root_app.dart @@ -3,11 +3,13 @@ import 'dart:async'; import 'package:fl_query/fl_query.dart'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; +import 'package:flutter_desktop_tools/flutter_desktop_tools.dart'; import 'package:flutter_hooks/flutter_hooks.dart'; import 'package:go_router/go_router.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:shared_preferences/shared_preferences.dart'; import 'package:spotube/collections/spotube_icons.dart'; +import 'package:spotube/components/player/player_queue.dart'; import 'package:spotube/components/shared/dialogs/replace_downloaded_dialog.dart'; import 'package:spotube/components/root/bottom_player.dart'; import 'package:spotube/components/root/sidebar.dart'; @@ -164,6 +166,22 @@ class RootApp extends HookConsumerWidget { child: child, ), extendBody: true, + drawerScrimColor: Colors.transparent, + endDrawer: DesktopTools.platform.isDesktop + ? Container( + constraints: const BoxConstraints(maxWidth: 800), + decoration: BoxDecoration( + boxShadow: theme.brightness == Brightness.light + ? null + : kElevationToShadow[8], + ), + margin: const EdgeInsets.only( + top: 40, + bottom: 100, + ), + child: const PlayerQueue(floating: true), + ) + : null, bottomNavigationBar: Column( mainAxisSize: MainAxisSize.min, children: [ From 0c22469503f32dbbf1a5d31419c1b76c699fa966 Mon Sep 17 00:00:00 2001 From: Kingkor Roy Tirtho Date: Sun, 12 Nov 2023 09:22:26 +0600 Subject: [PATCH 010/195] feat(translations): add Turkish translations --- lib/collections/language_codes.dart | 8 +- lib/l10n/app_tr.arb | 283 ++++++++++++++++++++++++++++ lib/l10n/l10n.dart | 10 +- 3 files changed, 293 insertions(+), 8 deletions(-) create mode 100644 lib/l10n/app_tr.arb diff --git a/lib/collections/language_codes.dart b/lib/collections/language_codes.dart index 58328b75..0518363e 100644 --- a/lib/collections/language_codes.dart +++ b/lib/collections/language_codes.dart @@ -660,10 +660,10 @@ abstract class LanguageLocals { // name: "Tonga (Tonga Islands)", // nativeName: "faka Tonga", // ), - // "tr": const ISOLanguageName( - // name: "Turkish", - // nativeName: "Türkçe", - // ), + "tr": const ISOLanguageName( + name: "Turkish", + nativeName: "Türkçe", + ), // "ts": const ISOLanguageName( // name: "Tsonga", // nativeName: "Xitsonga", diff --git a/lib/l10n/app_tr.arb b/lib/l10n/app_tr.arb new file mode 100644 index 00000000..1d72ec85 --- /dev/null +++ b/lib/l10n/app_tr.arb @@ -0,0 +1,283 @@ +{ + "guest": "Misafir", + "browse": "Gözat", + "search": "Ara", + "library": "Kütüphane", + "lyrics": "Sözler", + "settings": "Ayarlar", + "genre_categories_filter": "Kategorileri veya türleri filtreleyin...", + "genre": "Tür", + "personalized": "Kişiselleştirilmiş", + "featured": "Öne Çıkanlar", + "new_releases": "Yeni Çıkanlar", + "songs": "Şarkılar", + "playing_track": "Oynatılıyor {track}", + "queue_clear_alert": "Bu, mevcut kuyruğu temizleyecektir. {track_length} parçaları kaldırılacaktır\nDevam etmek istiyor musunuz?", + "load_more": "Daha fazlasını yükle", + "playlists": "Çalma Listeleri", + "artists": "Sanatçılar", + "albums": "Albümler", + "tracks": "Parçalar", + "downloads": "İndirmeler", + "filter_playlists": "Çalma listelerinizi filtreleyin...", + "liked_tracks": "Beğenilen Parçalar", + "liked_tracks_description": "Beğendiğiniz tüm parçalar", + "create_playlist": "Çalma Listesi Oluştur", + "create_a_playlist": "Bir çalma listesi oluştur", + "update_playlist": "Çalma listesini güncelle", + "create": "Oluştur", + "cancel": "İptal", + "update": "Güncelle", + "playlist_name": "Çalma Listesi Adı", + "name_of_playlist": "Çalma listesi adı", + "description": "Açıklama", + "public": "Halka açık", + "collaborative": "İşbirliği", + "search_local_tracks": "Yerel parçaları arayın...", + "play": "Oynat", + "delete": "Sil", + "none": "Hiçbiri", + "sort_a_z": "A'dan Z'ye sırala", + "sort_z_a": "Z'dan A'ye sırala", + "sort_artist": "Sanatçıya Göre Sırala", + "sort_album": "Albüme Göre Sırala", + "sort_tracks": "Parçaları Sırala", + "currently_downloading": "Şu Anda İndiriliyor ({tracks_length})", + "cancel_all": "Tümünü İptal Et", + "filter_artist": "Sanatçıları filtrele...", + "followers": "{followers} Takipçiler", + "add_artist_to_blacklist": "Sanatçıyı kara listeye ekle", + "top_tracks": "En İyi Parçalar", + "fans_also_like": "Hayranlar ayrıca şunları beğendi", + "loading": "Yükleniyor...", + "artist": "Sanatçı", + "blacklisted": "Kara Listede", + "following": "Takip Ediliyor", + "follow": "Takip Et", + "artist_url_copied": "Sanatçı bağlantısı panoya kopyalandı", + "added_to_queue": "Kuyruğa {tracks} parçaları eklendi", + "filter_albums": "Albümleri filtrele...", + "synced": "Eşitlendi", + "plain": "Sade", + "shuffle": "Karıştır", + "search_tracks": "Parça ara...", + "released": "Yayınlandı", + "error": "Hata {error}", + "title": "Başlık", + "time": "Zaman", + "more_actions": "Daha fazla işlem", + "download_count": "İndir ({count})", + "add_count_to_playlist": "Çalma Listesine ({count}) Ekle", + "add_count_to_queue": "Sıraya ({count}) ekle", + "play_count_next": "Oynat ({count}) sonraki", + "album": "Albüm", + "copied_to_clipboard": "Panoya {data} kopyalandı", + "add_to_following_playlists": "Aşağıdaki Çalma Listelerine {track} ekle", + "add": "Ekle", + "added_track_to_queue": "Sıraya {track} eklendi", + "add_to_queue": "Kuyruğa ekle", + "track_will_play_next": "{track} sonraki çalacak", + "play_next": "Sıradaki", + "removed_track_from_queue": "Sıradan {track} kaldırıldı", + "remove_from_queue": "Kuyruktan çıkar", + "remove_from_favorites": "Favorilerden kaldır", + "save_as_favorite": "Favori olarak kaydet", + "add_to_playlist": "Çalma listesine ekle", + "remove_from_playlist": "Çalma listesinden kaldır", + "add_to_blacklist": "Kara listeye ekle", + "remove_from_blacklist": "Kara listeden çıkar", + "share": "Paylaş", + "mini_player": "Mini Oynatıcı", + "slide_to_seek": "İleri veya geri arama yapmak için kaydırın", + "shuffle_playlist": "Çalma listesini karıştır", + "unshuffle_playlist": "Karışık çalma listesi", + "previous_track": "Önceki parça", + "next_track": "Sonraki parça", + "pause_playback": "Çalmayı Duraklat", + "resume_playback": "Çalmaya Devam Et", + "loop_track": "Döngü parçası", + "repeat_playlist": "Çalma listesini tekrarla", + "queue": "Sıra", + "alternative_track_sources": "Alternatif parça kaynakları", + "download_track": "Parçayı indir", + "tracks_in_queue": "{tracks} sıradaki parçalar", + "clear_all": "Tümünü temizle", + "show_hide_ui_on_hover": "Üzerine gelindiğinde kullanıcı arayüzünü göster/gizle", + "always_on_top": "Her zaman en üstte", + "exit_mini_player": "Mini oynatıcıdan çık", + "download_location": "İndirme konumu", + "account": "Hesap", + "login_with_spotify": "Spotify hesabınız ile giriş yapın", + "connect_with_spotify": "Spotify ile bağlantı kurun", + "logout": "Çıkış Yap", + "logout_of_this_account": "Bu hesaptan çıkış yap", + "language_region": "Dil & Bölge", + "language": "Dil", + "system_default": "Sistem Varsayılanı", + "market_place_region": "Mevcut Bölge", + "recommendation_country": "Tavsiye Edilen Ülke", + "appearance": "Görünüm", + "layout_mode": "Düzen Modu", + "override_layout_settings": "Duyarlı düzen modu ayarlarını geçersiz kıl", + "adaptive": "Uyarlanabilir", + "compact": "Sıkıştırılmış", + "extended": "Genişletilmiş", + "theme": "Tema", + "dark": "Karanlık", + "light": "Aydınlık", + "system": "Sistem", + "accent_color": "Vurgu Rengi", + "sync_album_color": "Albüm rengini eşitle", + "sync_album_color_description": "Albüm resminin baskın rengini vurgu rengi olarak kullanır", + "playback": "Çalma", + "audio_quality": "Ses Kalitesi", + "high": "Yüksek", + "low": "Düşük", + "pre_download_play": "Önceden indir ve oynat", + "pre_download_play_description": "Ses akışı yerine, baytları indirin ve oynatın (Daha yüksek bant genişliği kullanıcıları için önerilir)", + "skip_non_music": "Müzik olmayan bölümleri atla (SponsorBlock)", + "blacklist_description": "Kara listeye alınan parçalar ve sanatçılar", + "wait_for_download_to_finish": "Lütfen mevcut indirme işleminin bitmesini bekleyin", + "desktop": "Masaüstü", + "close_behavior": "Yakın Davranış", + "close": "Kapat", + "minimize_to_tray": "Tepsiye küçült", + "show_tray_icon": "Sistem tepsisi simgesini göster", + "about": "Hakkında", + "u_love_spotube": "Spotube'u sevdiğinizi biliyoruz", + "check_for_updates": "Güncellemeleri kontrol et", + "about_spotube": "Spotube Hakkında", + "blacklist": "Kara Liste", + "please_sponsor": "Lütfen Sponsor Olun/Bağış Yapın", + "spotube_description": "Spotube, hafif, platformlar arası, herkesin kullanabileceği ücretsiz bir Spotify istemcisidir.", + "version": "Sürüm", + "build_number": "Derleme Numarası", + "founder": "Kurucu", + "repository": "Depo", + "bug_issues": "Hata + Sorunlar", + "made_with": "❤️ ile Bangladesh🇧🇩 adresinde yapılmıştır.", + "kingkor_roy_tirtho": "Kingkor Roy Tirtho", + "copyright": "© 2021-{current_year} Kingkor Roy Tirtho", + "license": "Lisans", + "add_spotify_credentials": "Başlamak için spotify bilgilerinizi ekleyin", + "credentials_will_not_be_shared_disclaimer": "Endişelenmeyin, bilgileriniz toplanmayacak veya kimseyle paylaşılmayacak", + "know_how_to_login": "Nasıl yapılacağını bilmiyor musunuz?", + "follow_step_by_step_guide": "Adım Adım kılavuzu takip edin", + "spotify_cookie": "Spotify {name} Çerez", + "cookie_name_cookie": "{name} Çerez", + "fill_in_all_fields": "Lütfen tüm alanları doldurun", + "submit": "Gönder", + "exit": "Çık", + "previous": "Önceki", + "next": "Sonraki", + "done": "Bitti", + "step_1": "1. Adım", + "first_go_to": "İlk önce şu adrese gidin", + "login_if_not_logged_in": "ve oturum açmadıysanız Giriş Yapın/Kaydolun", + "step_2": "2. Adım", + "step_2_steps": "1. Giriş yaptıktan sonra, Tarayıcı devtools.\n2'yi açmak için F12'ye basın veya Fare Sağ Tıklaması > İncele'ye basın. Ardından \"Uygulama\" Sekmesine (Chrome, Edge, Brave vb.) veya \"Depolama\" Sekmesine (Firefox, Palemoon vb.) gidin\n3. \"Çerezler\" bölümüne ve ardından \"https://accounts.spotify.com\" alt bölümüne gidin", + "step_3": "3. Adım", + "step_3_steps": "\"sp_dc\" ve \"sp_key\" (veya sp_gaid) Çerezlerinin değerlerini kopyalayın", + "success_emoji": "Başarılı🥳", + "success_message": "Şimdi Spotify hesabınızla başarılı bir şekilde oturum açtınız. İyi iş, dostum!", + "step_4": "4. Adım", + "step_4_steps": "Kopyalanan \"sp_dc\" ve \"sp_key\" (veya sp_gaid) değerlerini ilgili alanlara yapıştırın", + "something_went_wrong": "Bir şeyler ters gitti", + "piped_instance": "Piped Sunucu Örneği", + "piped_description": "Parça eşleştirme için kullanılacak Piped sunucu örneği", + "piped_warning": "Bazıları iyi çalışmayabilir. Bu yüzden riski size ait olmak üzere kullanın", + "generate_playlist": "Çalma Listesi Oluştur", + "track_exists": "Track {track} zaten mevcut", + "replace_downloaded_tracks": "İndirilen tüm parçaları değiştir", + "skip_download_tracks": "İndirilen tüm parçaları indirmeyi atla", + "do_you_want_to_replace": "Mevcut parçayı değiştirmek mi istiyorsunuz?", + "replace": "Değiştir", + "skip": "Atla", + "select_up_to_count_type": "En fazla {count} {type} seçin", + "select_genres": "Tür Seç", + "add_genres": "Tür Ekle", + "country": "Ülke", + "number_of_tracks_generate": "Oluşturulacak parça sayısı", + "acousticness": "Akustiklik", + "danceability": "Dansedilebilirlik", + "energy": "Enerji", + "instrumentalness": "Enstrümansallık", + "liveness": "Canlılık", + "loudness": "Yükseklik", + "speechiness": "Konuşkanlık", + "valence": "Değerlilik", + "popularity": "Popülerlik", + "key": "Anahtar", + "duration": "Süre (sn)", + "tempo": "Tempo (BPM)", + "mode": "Mod", + "time_signature": "Zaman İmzası", + "short": "Kısa", + "medium": "Orta", + "long": "Uzun", + "min": "Min", + "max": "Maks", + "target": "Hedef", + "moderate": "Orta", + "deselect_all": "Tüm Seçimleri Kaldır", + "select_all": "Tümünü Seç", + "are_you_sure": "Emin misiniz?", + "generating_playlist": "Özel çalma listenizi oluşturun...", + "selected_count_tracks": "Seçilen {count} parçalar", + "download_warning": "Tüm Parçaları toplu olarak indirirseniz, açıkça Müzik korsanlığı yapmış ve yaratıcı Müzik toplumuna zarar vermiş olursunuz. Umarım bunun farkındasınızdır. Her zaman, Sanatçıların sıkı çalışmalarına saygı duymayı ve desteklemeyi deneyin", + "download_ip_ban_warning": "Bu arada, normalden fazla indirme isteği nedeniyle IP adresiniz YouTube'da engellenebilir. IP engeli, o IP cihazından en az 2-3 ay boyunca YouTube'u (giriş yapmış olsanız bile) kullanamayacağınız anlamına gelir. Ve Spotube böyle bir durumda herhangi bir sorumluluk kabul etmez", + "by_clicking_accept_terms": "'Kabul et' seçeneğine tıklayarak aşağıdaki şartları kabul etmiş olursunuz:", + "download_agreement_1": "Müzik korsanlığı yaptığımı biliyorum. Ben malım.", + "download_agreement_2": "Sanatçıları elimden geldiğince destekleyeceğim ve bunu sadece sanatlarını satın alacak param olmadığı için yapıyorum", + "download_agreement_3": "IP adresimin YouTube'da engellenebileceğinin tamamen farkındayım ve mevcut eylemimin neden olduğu herhangi bir kazadan Spotube'u veya sahiplerini/dağıtıcılarını sorumlu tutmuyorum", + "decline": "Reddet", + "accept": "Kabul et", + "details": "Detaylar", + "youtube": "YouTube", + "channel": "Kanal", + "likes": "Beğeniler", + "dislikes": "Beğenmemeler", + "views": "İzlenmeler", + "streamUrl": "Yayın Bağlantısı", + "stop": "Dur", + "sort_newest": "En yeni eklenene göre sırala", + "sort_oldest": "En eski eklenene göre sırala", + "sleep_timer": "Uyku Zamanlayıcısı", + "mins": "{minutes} Dakikalar", + "hours": "{hours} Saat", + "hour": "{hours} Saatler", + "custom_hours": "Özel Saatler", + "logs": "Günlükler", + "developers": "Geliştiriciler", + "not_logged_in": "Giriş yapmadınız", + "search_mode": "Arama Modu", + "youtube_api_type": "API Türü", + "ok": "Tamam", + "failed_to_encrypt": "Şifreleme başarısız oldu", + "encryption_failed_warning": "Spotube, verilerinizi güvenli bir şekilde depolamak için şifreleme kullanır. Ancak bunu başaramadı. Bu nedenle güvensiz bir depolamaya geri dönecektir. Linux kullanıyorsanız, lütfen gnome-keyring, kde-wallet, keepassxc vb. gibi bir güvenlik hizmetinizin kurulu olduğundan emin olun.", + "querying_info": "Bilgi sorgulanıyor...", + "piped_api_down": "Piped API kapalı", + "piped_down_error_instructions": "Piped örneği {pipedInstance} şu anda kapalı\n\nYa örneği değiştirin ya da 'API türünü' resmi YouTube API'si olarak değiştirin\n\nDeğişiklikten sonra uygulamayı yeniden başlattığınızdan emin olun", + "you_are_offline": "Şu anda çevrimdışısınız", + "connection_restored": "İnternet bağlantınız yeniden kuruldu", + "use_system_title_bar": "Sistem başlık çubuğunu kullan", + "crunching_results": "Sonuçlar kırılıyor...", + "search_to_get_results": "Sonuç almak için arama yap", + "use_amoled_mode": "AMOLED modunu kullan", + "pitch_dark_theme": "Zifiri siyah dart teması", + "normalize_audio": "Sesi normalleştir", + "change_cover": "Kapağı değiştir", + "add_cover": "Kapak ekle", + "restore_defaults": "Varsayılanları geri yükle", + "download_music_codec": "Müzik codec bileşenini indirin", + "streaming_music_codec": "Müzik akışı codec bileşeni", + "login_with_lastfm": "Last.fm ile giriş yap", + "connect": "Bağlan", + "disconnect_lastfm": "Last.fm bağlantısını kes", + "disconnect": "Bağlantıyı Kes", + "username": "Kullanıcı Adı", + "password": "Şifre", + "login": "Giriş Yap", + "login_with_your_lastfm": "Last.fm hesabınız ile giriş yapın", + "scrobble_to_lastfm": "Last.fm için Scrobble" +} \ No newline at end of file diff --git a/lib/l10n/l10n.dart b/lib/l10n/l10n.dart index 13cf0e24..61a6d097 100644 --- a/lib/l10n/l10n.dart +++ b/lib/l10n/l10n.dart @@ -6,24 +6,26 @@ /// iceyear@github => Simplified Chinese /// TexturedPolak@github => Polish /// yuri-val@github => Ukrainian +/// mdksec@github => Turkish import 'package:flutter/material.dart'; class L10n { static final all = [ const Locale('en'), + const Locale('ar', 'SA'), const Locale('bn', 'BD'), - const Locale('de', 'GE'), const Locale('ca', 'AD'), + const Locale('de', 'GE'), const Locale('es', 'ES'), const Locale("fa", "IR"), const Locale('fr', 'FR'), const Locale('hi', 'IN'), const Locale('ja', 'JP'), - const Locale('zh', 'CN'), const Locale('pl', 'PL'), - const Locale('ru', 'RU'), const Locale('pt', 'PT'), + const Locale('ru', 'RU'), const Locale('uk', 'UA'), - const Locale('ar', 'SA'), + const Locale('tr', 'TR'), + const Locale('zh', 'CN'), ]; } From 5928185599f3739845391476c0ae47b9efa2cd36 Mon Sep 17 00:00:00 2001 From: Kingkor Roy Tirtho Date: Sun, 12 Nov 2023 19:01:14 +0600 Subject: [PATCH 011/195] fix: new releases section flickering on scroll glitch --- lib/pages/home/personalized.dart | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/pages/home/personalized.dart b/lib/pages/home/personalized.dart index bbffbc11..8a18fd0b 100644 --- a/lib/pages/home/personalized.dart +++ b/lib/pages/home/personalized.dart @@ -64,7 +64,8 @@ class PersonalizedPage extends HookConsumerWidget { ), if (auth != null && newReleases.hasPageData && - userArtistsQuery.hasData) + userArtistsQuery.hasData && + !newReleases.isLoadingNextPage) HorizontalPlaybuttonCardView( items: albums, title: Text(context.l10n.new_releases), From ee94b7cbb24e0f0bc22a6d49c830d4055aa02895 Mon Sep 17 00:00:00 2001 From: Kingkor Roy Tirtho Date: Sun, 12 Nov 2023 19:03:27 +0600 Subject: [PATCH 012/195] fix: new releases section flickering on scroll glitch --- lib/pages/home/personalized.dart | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/lib/pages/home/personalized.dart b/lib/pages/home/personalized.dart index 8a18fd0b..30115889 100644 --- a/lib/pages/home/personalized.dart +++ b/lib/pages/home/personalized.dart @@ -71,7 +71,9 @@ class PersonalizedPage extends HookConsumerWidget { title: Text(context.l10n.new_releases), hasNextPage: newReleases.hasNextPage, onFetchMore: newReleases.fetchNext, - ), + ) + else + const ShimmerCategories(), ...?madeForUser.data?["content"]?["items"]?.map((item) { final playlists = item["content"]?["items"] ?.where((itemL2) => itemL2["type"] == "playlist") From 694ddf07a310ec3909cdb6a2617100054c3b3b9e Mon Sep 17 00:00:00 2001 From: Kingkor Roy Tirtho Date: Sun, 12 Nov 2023 19:04:20 +0600 Subject: [PATCH 013/195] chore: revert --- lib/pages/home/personalized.dart | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/lib/pages/home/personalized.dart b/lib/pages/home/personalized.dart index 30115889..8a18fd0b 100644 --- a/lib/pages/home/personalized.dart +++ b/lib/pages/home/personalized.dart @@ -71,9 +71,7 @@ class PersonalizedPage extends HookConsumerWidget { title: Text(context.l10n.new_releases), hasNextPage: newReleases.hasNextPage, onFetchMore: newReleases.fetchNext, - ) - else - const ShimmerCategories(), + ), ...?madeForUser.data?["content"]?["items"]?.map((item) { final playlists = item["content"]?["items"] ?.where((itemL2) => itemL2["type"] == "playlist") From e29a38dfa43ddf7a38046d1d40424f01dbe62261 Mon Sep 17 00:00:00 2001 From: Kingkor Roy Tirtho Date: Mon, 13 Nov 2023 20:59:54 +0600 Subject: [PATCH 014/195] fix: changed settings are not persisting after force stop #821 --- .../settings/color_scheme_picker_dialog.dart | 3 +- lib/pages/settings/sections/about.dart | 3 +- lib/pages/settings/sections/appearance.dart | 9 +- lib/pages/settings/sections/desktop.dart | 7 +- lib/pages/settings/sections/downloads.dart | 5 +- .../settings/sections/language_region.dart | 5 +- lib/pages/settings/sections/playback.dart | 17 +- lib/pages/settings/settings.dart | 4 +- lib/provider/user_preferences_provider.dart | 539 +++++++++--------- 9 files changed, 287 insertions(+), 305 deletions(-) diff --git a/lib/components/settings/color_scheme_picker_dialog.dart b/lib/components/settings/color_scheme_picker_dialog.dart index 170bae94..f06a9d84 100644 --- a/lib/components/settings/color_scheme_picker_dialog.dart +++ b/lib/components/settings/color_scheme_picker_dialog.dart @@ -49,6 +49,7 @@ class ColorSchemePickerDialog extends HookConsumerWidget { @override Widget build(BuildContext context, ref) { final preferences = ref.watch(userPreferencesProvider); + final preferencesNotifier = ref.watch(userPreferencesProvider.notifier); final scheme = preferences.accentColorScheme; final active = useState(colorsMap.firstWhere( (element) { @@ -57,7 +58,7 @@ class ColorSchemePickerDialog extends HookConsumerWidget { ).name); onOk() { - preferences.setAccentColorScheme( + preferencesNotifier.setAccentColorScheme( colorsMap.firstWhere( (element) { return element.name == active.value; diff --git a/lib/pages/settings/sections/about.dart b/lib/pages/settings/sections/about.dart index 0340b27c..85181355 100644 --- a/lib/pages/settings/sections/about.dart +++ b/lib/pages/settings/sections/about.dart @@ -16,6 +16,7 @@ class SettingsAboutSection extends HookConsumerWidget { @override Widget build(BuildContext context, ref) { final preferences = ref.watch(userPreferencesProvider); + final preferencesNotifier = ref.watch(userPreferencesProvider.notifier); return SectionCardWithHeading( heading: context.l10n.about, @@ -68,7 +69,7 @@ class SettingsAboutSection extends HookConsumerWidget { secondary: const Icon(SpotubeIcons.update), title: Text(context.l10n.check_for_updates), value: preferences.checkUpdate, - onChanged: (checked) => preferences.setCheckUpdate(checked), + onChanged: (checked) => preferencesNotifier.setCheckUpdate(checked), ), ListTile( leading: const Icon(SpotubeIcons.info), diff --git a/lib/pages/settings/sections/appearance.dart b/lib/pages/settings/sections/appearance.dart index f4b097e8..5e1ffa50 100644 --- a/lib/pages/settings/sections/appearance.dart +++ b/lib/pages/settings/sections/appearance.dart @@ -15,6 +15,7 @@ class SettingsAppearanceSection extends HookConsumerWidget { @override Widget build(BuildContext context, ref) { final preferences = ref.watch(userPreferencesProvider); + final preferencesNotifier = ref.watch(userPreferencesProvider.notifier); final pickColorScheme = useCallback(() { return () => showDialog( context: context, @@ -33,7 +34,7 @@ class SettingsAppearanceSection extends HookConsumerWidget { value: preferences.layoutMode, onChanged: (value) { if (value != null) { - preferences.setLayoutMode(value); + preferencesNotifier.setLayoutMode(value); } }, options: [ @@ -71,7 +72,7 @@ class SettingsAppearanceSection extends HookConsumerWidget { ], onChanged: (value) { if (value != null) { - preferences.setThemeMode(value); + preferencesNotifier.setThemeMode(value); } }, ), @@ -80,7 +81,7 @@ class SettingsAppearanceSection extends HookConsumerWidget { title: Text(context.l10n.use_amoled_mode), subtitle: Text(context.l10n.pitch_dark_theme), value: preferences.amoledDarkTheme, - onChanged: preferences.setAmoledDarkTheme, + onChanged: preferencesNotifier.setAmoledDarkTheme, ), ListTile( leading: const Icon(SpotubeIcons.palette), @@ -101,7 +102,7 @@ class SettingsAppearanceSection extends HookConsumerWidget { title: Text(context.l10n.sync_album_color), subtitle: Text(context.l10n.sync_album_color_description), value: preferences.albumColorSync, - onChanged: preferences.setAlbumColorSync, + onChanged: preferencesNotifier.setAlbumColorSync, ), ], ); diff --git a/lib/pages/settings/sections/desktop.dart b/lib/pages/settings/sections/desktop.dart index d12bcb41..1cc2c5c8 100644 --- a/lib/pages/settings/sections/desktop.dart +++ b/lib/pages/settings/sections/desktop.dart @@ -12,6 +12,7 @@ class SettingsDesktopSection extends HookConsumerWidget { @override Widget build(BuildContext context, ref) { final preferences = ref.watch(userPreferencesProvider); + final preferencesNotifier = ref.watch(userPreferencesProvider.notifier); return SectionCardWithHeading( heading: context.l10n.desktop, @@ -32,7 +33,7 @@ class SettingsDesktopSection extends HookConsumerWidget { ], onChanged: (value) { if (value != null) { - preferences.setCloseBehavior(value); + preferencesNotifier.setCloseBehavior(value); } }, ), @@ -40,13 +41,13 @@ class SettingsDesktopSection extends HookConsumerWidget { secondary: const Icon(SpotubeIcons.tray), title: Text(context.l10n.show_tray_icon), value: preferences.showSystemTrayIcon, - onChanged: preferences.setShowSystemTrayIcon, + onChanged: preferencesNotifier.setShowSystemTrayIcon, ), SwitchListTile( secondary: const Icon(SpotubeIcons.window), title: Text(context.l10n.use_system_title_bar), value: preferences.systemTitleBar, - onChanged: preferences.setSystemTitleBar, + onChanged: preferencesNotifier.setSystemTitleBar, ), ], ); diff --git a/lib/pages/settings/sections/downloads.dart b/lib/pages/settings/sections/downloads.dart index 1f157037..ff64cdea 100644 --- a/lib/pages/settings/sections/downloads.dart +++ b/lib/pages/settings/sections/downloads.dart @@ -14,6 +14,7 @@ class SettingsDownloadsSection extends HookConsumerWidget { @override Widget build(BuildContext context, ref) { + final preferencesNotifier = ref.watch(userPreferencesProvider.notifier); final preferences = ref.watch(userPreferencesProvider); final pickDownloadLocation = useCallback(() async { @@ -22,13 +23,13 @@ class SettingsDownloadsSection extends HookConsumerWidget { initialDirectory: preferences.downloadLocation, ); if (dirStr == null) return; - preferences.setDownloadLocation(dirStr); + preferencesNotifier.setDownloadLocation(dirStr); } else { String? dirStr = await getDirectoryPath( initialDirectory: preferences.downloadLocation, ); if (dirStr == null) return; - preferences.setDownloadLocation(dirStr); + preferencesNotifier.setDownloadLocation(dirStr); } }, [preferences.downloadLocation]); diff --git a/lib/pages/settings/sections/language_region.dart b/lib/pages/settings/sections/language_region.dart index 64c56224..ece28455 100644 --- a/lib/pages/settings/sections/language_region.dart +++ b/lib/pages/settings/sections/language_region.dart @@ -17,6 +17,7 @@ class SettingsLanguageRegionSection extends HookConsumerWidget { @override Widget build(BuildContext context, ref) { final preferences = ref.watch(userPreferencesProvider); + final preferencesNotifier = ref.watch(userPreferencesProvider.notifier); final mediaQuery = MediaQuery.of(context); return SectionCardWithHeading( @@ -26,7 +27,7 @@ class SettingsLanguageRegionSection extends HookConsumerWidget { value: preferences.locale, onChanged: (locale) { if (locale == null) return; - preferences.setLocale(locale); + preferencesNotifier.setLocale(locale); }, title: Text(context.l10n.language), secondary: const Icon(SpotubeIcons.language), @@ -57,7 +58,7 @@ class SettingsLanguageRegionSection extends HookConsumerWidget { value: preferences.recommendationMarket, onChanged: (value) { if (value == null) return; - preferences.setRecommendationMarket(value); + preferencesNotifier.setRecommendationMarket(value); }, options: spotifyMarkets .map( diff --git a/lib/pages/settings/sections/playback.dart b/lib/pages/settings/sections/playback.dart index cf7e33e9..39d9b7c2 100644 --- a/lib/pages/settings/sections/playback.dart +++ b/lib/pages/settings/sections/playback.dart @@ -18,6 +18,7 @@ class SettingsPlaybackSection extends HookConsumerWidget { @override Widget build(BuildContext context, ref) { final preferences = ref.watch(userPreferencesProvider); + final preferencesNotifier = ref.watch(userPreferencesProvider.notifier); final theme = Theme.of(context); return SectionCardWithHeading( @@ -39,7 +40,7 @@ class SettingsPlaybackSection extends HookConsumerWidget { ], onChanged: (value) { if (value != null) { - preferences.setAudioQuality(value); + preferencesNotifier.setAudioQuality(value); } }, ), @@ -55,7 +56,7 @@ class SettingsPlaybackSection extends HookConsumerWidget { .toList(), onChanged: (value) { if (value == null) return; - preferences.setYoutubeApiType(value); + preferencesNotifier.setYoutubeApiType(value); }, ), AnimatedSwitcher( @@ -113,7 +114,7 @@ class SettingsPlaybackSection extends HookConsumerWidget { .toList(), onChanged: (value) { if (value != null) { - preferences.setPipedInstance(value); + preferencesNotifier.setPipedInstance(value); } }, ); @@ -141,7 +142,7 @@ class SettingsPlaybackSection extends HookConsumerWidget { .toList(), onChanged: (value) { if (value == null) return; - preferences.setSearchMode(value); + preferencesNotifier.setSearchMode(value); }, ), ), @@ -155,7 +156,7 @@ class SettingsPlaybackSection extends HookConsumerWidget { title: Text(context.l10n.skip_non_music), value: preferences.skipNonMusic, onChanged: (state) { - preferences.setSkipNonMusic(state); + preferencesNotifier.setSkipNonMusic(state); }, ), ), @@ -172,7 +173,7 @@ class SettingsPlaybackSection extends HookConsumerWidget { secondary: const Icon(SpotubeIcons.normalize), title: Text(context.l10n.normalize_audio), value: preferences.normalizeAudio, - onChanged: preferences.setNormalizeAudio, + onChanged: preferencesNotifier.setNormalizeAudio, ), AdaptiveSelectTile( secondary: const Icon(SpotubeIcons.stream), @@ -190,7 +191,7 @@ class SettingsPlaybackSection extends HookConsumerWidget { .toList(), onChanged: (value) { if (value == null) return; - preferences.setStreamMusicCodec(value); + preferencesNotifier.setStreamMusicCodec(value); }, ), AdaptiveSelectTile( @@ -209,7 +210,7 @@ class SettingsPlaybackSection extends HookConsumerWidget { .toList(), onChanged: (value) { if (value == null) return; - preferences.setDownloadMusicCodec(value); + preferencesNotifier.setDownloadMusicCodec(value); }, ), ], diff --git a/lib/pages/settings/settings.dart b/lib/pages/settings/settings.dart index 5b377a1f..baf245b4 100644 --- a/lib/pages/settings/settings.dart +++ b/lib/pages/settings/settings.dart @@ -20,7 +20,7 @@ class SettingsPage extends HookConsumerWidget { @override Widget build(BuildContext context, ref) { - final preferences = ref.watch(userPreferencesProvider); + final preferencesNotifier = ref.watch(userPreferencesProvider.notifier); return SafeArea( bottom: false, @@ -49,7 +49,7 @@ class SettingsPage extends HookConsumerWidget { const SettingsAboutSection(), Center( child: FilledButton( - onPressed: preferences.reset, + onPressed: preferencesNotifier.reset, child: Text(context.l10n.restore_defaults), ), ), diff --git a/lib/provider/user_preferences_provider.dart b/lib/provider/user_preferences_provider.dart index 3355adb0..80c71de9 100644 --- a/lib/provider/user_preferences_provider.dart +++ b/lib/provider/user_preferences_provider.dart @@ -1,7 +1,6 @@ import 'dart:async'; import 'dart:convert'; -import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:flutter_desktop_tools/flutter_desktop_tools.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; @@ -13,7 +12,7 @@ import 'package:spotube/provider/palette_provider.dart'; import 'package:spotube/provider/proxy_playlist/proxy_playlist_provider.dart'; import 'package:spotube/services/audio_player/audio_player.dart'; -import 'package:spotube/utils/persisted_change_notifier.dart'; +import 'package:spotube/utils/persisted_state_notifier.dart'; import 'package:spotube/utils/platform.dart'; import 'package:path/path.dart' as path; @@ -48,220 +47,103 @@ enum MusicCodec { const MusicCodec._(this.label); } -class UserPreferences extends PersistedChangeNotifier { - AudioQuality audioQuality; - bool albumColorSync; - bool amoledDarkTheme; - bool checkUpdate; - bool normalizeAudio; - bool showSystemTrayIcon; - bool skipNonMusic; - bool systemTitleBar; - CloseBehavior closeBehavior; - late SpotubeColor accentColorScheme; - LayoutMode layoutMode; - Locale locale; - Market recommendationMarket; - SearchMode searchMode; +class UserPreferences { + final AudioQuality audioQuality; + final bool albumColorSync; + final bool amoledDarkTheme; + final bool checkUpdate; + final bool normalizeAudio; + final bool showSystemTrayIcon; + final bool skipNonMusic; + final bool systemTitleBar; + final CloseBehavior closeBehavior; + final SpotubeColor accentColorScheme; + final LayoutMode layoutMode; + final Locale locale; + final Market recommendationMarket; + final SearchMode searchMode; String downloadLocation; - String pipedInstance; - ThemeMode themeMode; - YoutubeApiType youtubeApiType; - MusicCodec streamMusicCodec; - MusicCodec downloadMusicCodec; + final String pipedInstance; + final ThemeMode themeMode; + final YoutubeApiType youtubeApiType; + final MusicCodec streamMusicCodec; + final MusicCodec downloadMusicCodec; - final Ref ref; - - UserPreferences( - this.ref, { - this.recommendationMarket = Market.US, - this.themeMode = ThemeMode.system, - this.layoutMode = LayoutMode.adaptive, - this.albumColorSync = true, - this.checkUpdate = true, - this.audioQuality = AudioQuality.high, - this.downloadLocation = "", - this.closeBehavior = CloseBehavior.close, - this.showSystemTrayIcon = true, - this.locale = const Locale("system", "system"), - this.pipedInstance = "https://pipedapi.kavin.rocks", - this.searchMode = SearchMode.youtube, - this.skipNonMusic = true, - this.youtubeApiType = YoutubeApiType.youtube, - this.systemTitleBar = false, - this.amoledDarkTheme = false, - this.normalizeAudio = true, - this.streamMusicCodec = MusicCodec.weba, - this.downloadMusicCodec = MusicCodec.m4a, - SpotubeColor? accentColorScheme, - }) : super() { - this.accentColorScheme = - accentColorScheme ?? SpotubeColor(Colors.blue.value, name: "Blue"); - if (downloadLocation.isEmpty && !kIsWeb) { + UserPreferences({ + required AudioQuality? audioQuality, + required bool? albumColorSync, + required bool? amoledDarkTheme, + required bool? checkUpdate, + required bool? normalizeAudio, + required bool? showSystemTrayIcon, + required bool? skipNonMusic, + required bool? systemTitleBar, + required CloseBehavior? closeBehavior, + required SpotubeColor? accentColorScheme, + required LayoutMode? layoutMode, + required Locale? locale, + required Market? recommendationMarket, + required SearchMode? searchMode, + required String? downloadLocation, + required String? pipedInstance, + required ThemeMode? themeMode, + required YoutubeApiType? youtubeApiType, + required MusicCodec? streamMusicCodec, + required MusicCodec? downloadMusicCodec, + }) : accentColorScheme = + accentColorScheme ?? const SpotubeColor(0xFF2196F3, name: "Blue"), + albumColorSync = albumColorSync ?? true, + amoledDarkTheme = amoledDarkTheme ?? false, + audioQuality = audioQuality ?? AudioQuality.high, + checkUpdate = checkUpdate ?? true, + closeBehavior = closeBehavior ?? CloseBehavior.close, + downloadLocation = downloadLocation ?? "", + downloadMusicCodec = downloadMusicCodec ?? MusicCodec.m4a, + layoutMode = layoutMode ?? LayoutMode.adaptive, + locale = locale ?? const Locale("system", "system"), + normalizeAudio = normalizeAudio ?? true, + pipedInstance = pipedInstance ?? "https://pipedapi.kavin.rocks", + recommendationMarket = recommendationMarket ?? Market.US, + searchMode = searchMode ?? SearchMode.youtube, + showSystemTrayIcon = showSystemTrayIcon ?? true, + skipNonMusic = skipNonMusic ?? true, + streamMusicCodec = streamMusicCodec ?? MusicCodec.weba, + systemTitleBar = systemTitleBar ?? false, + themeMode = themeMode ?? ThemeMode.system, + youtubeApiType = youtubeApiType ?? YoutubeApiType.youtube { + if (downloadLocation == null) { _getDefaultDownloadDirectory().then( - (value) { - downloadLocation = value; - }, + (value) => this.downloadLocation = value, ); } } - void reset() { - setRecommendationMarket(Market.US); - setThemeMode(ThemeMode.system); - setLayoutMode(LayoutMode.adaptive); - setAlbumColorSync(true); - setCheckUpdate(true); - setAudioQuality(AudioQuality.high); - setDownloadLocation(""); - setCloseBehavior(CloseBehavior.close); - setShowSystemTrayIcon(true); - setLocale(const Locale("system", "system")); - setPipedInstance("https://pipedapi.kavin.rocks"); - setSearchMode(SearchMode.youtube); - setSkipNonMusic(true); - setYoutubeApiType(YoutubeApiType.youtube); - setSystemTitleBar(false); - setAmoledDarkTheme(false); - setNormalizeAudio(true); - setAccentColorScheme(SpotubeColor(Colors.blue.value, name: "Blue")); - setStreamMusicCodec(MusicCodec.weba); - setDownloadMusicCodec(MusicCodec.m4a); + factory UserPreferences.withDefaults() { + return UserPreferences( + audioQuality: null, + albumColorSync: null, + amoledDarkTheme: null, + checkUpdate: null, + normalizeAudio: null, + showSystemTrayIcon: null, + skipNonMusic: null, + systemTitleBar: null, + closeBehavior: null, + accentColorScheme: null, + layoutMode: null, + locale: null, + recommendationMarket: null, + searchMode: null, + downloadLocation: null, + pipedInstance: null, + themeMode: null, + youtubeApiType: null, + streamMusicCodec: null, + downloadMusicCodec: null, + ); } - void setStreamMusicCodec(MusicCodec codec) { - streamMusicCodec = codec; - notifyListeners(); - updatePersistence(); - } - - void setDownloadMusicCodec(MusicCodec codec) { - downloadMusicCodec = codec; - notifyListeners(); - updatePersistence(); - } - - void setThemeMode(ThemeMode mode) { - themeMode = mode; - notifyListeners(); - updatePersistence(); - } - - void setRecommendationMarket(Market country) { - recommendationMarket = country; - notifyListeners(); - updatePersistence(); - } - - void setAccentColorScheme(SpotubeColor color) { - accentColorScheme = color; - notifyListeners(); - updatePersistence(); - } - - void setAlbumColorSync(bool sync) { - albumColorSync = sync; - if (!sync) { - ref.read(paletteProvider.notifier).state = null; - } else { - ref.read(ProxyPlaylistNotifier.notifier).updatePalette(); - } - notifyListeners(); - updatePersistence(); - } - - void setCheckUpdate(bool check) { - checkUpdate = check; - notifyListeners(); - updatePersistence(); - } - - void setAudioQuality(AudioQuality quality) { - audioQuality = quality; - notifyListeners(); - updatePersistence(); - } - - void setDownloadLocation(String downloadDir) { - if (downloadDir.isEmpty) return; - downloadLocation = downloadDir; - notifyListeners(); - updatePersistence(); - } - - void setLayoutMode(LayoutMode mode) { - layoutMode = mode; - notifyListeners(); - updatePersistence(); - } - - void setCloseBehavior(CloseBehavior behavior) { - closeBehavior = behavior; - notifyListeners(); - updatePersistence(); - } - - void setShowSystemTrayIcon(bool show) { - showSystemTrayIcon = show; - notifyListeners(); - updatePersistence(); - } - - void setLocale(Locale locale) { - this.locale = locale; - notifyListeners(); - updatePersistence(); - } - - void setPipedInstance(String instance) { - pipedInstance = instance; - notifyListeners(); - updatePersistence(); - } - - void setSearchMode(SearchMode mode) { - searchMode = mode; - notifyListeners(); - updatePersistence(); - } - - void setSkipNonMusic(bool skip) { - skipNonMusic = skip; - notifyListeners(); - updatePersistence(); - } - - void setYoutubeApiType(YoutubeApiType type) { - youtubeApiType = type; - notifyListeners(); - updatePersistence(); - } - - void setSystemTitleBar(bool isSystemTitleBar) { - systemTitleBar = isSystemTitleBar; - if (DesktopTools.platform.isDesktop) { - DesktopTools.window.setTitleBarStyle( - systemTitleBar ? TitleBarStyle.normal : TitleBarStyle.hidden, - ); - } - notifyListeners(); - updatePersistence(); - } - - void setAmoledDarkTheme(bool isAmoled) { - amoledDarkTheme = isAmoled; - notifyListeners(); - updatePersistence(); - } - - void setNormalizeAudio(bool normalize) { - normalizeAudio = normalize; - audioPlayer.setAudioNormalization(normalize); - notifyListeners(); - updatePersistence(); - } - - Future _getDefaultDownloadDirectory() async { + static Future _getDefaultDownloadDirectory() async { if (kIsAndroid) return "/storage/emulated/0/Download/Spotube"; if (kIsMacOS) { @@ -273,102 +155,71 @@ class UserPreferences extends PersistedChangeNotifier { }); } - @override - FutureOr loadFromLocal(Map map) async { - recommendationMarket = Market.values.firstWhere( - (market) => - market.name == (map["recommendationMarket"] ?? recommendationMarket), - orElse: () => Market.US, - ); - checkUpdate = map["checkUpdate"] ?? checkUpdate; + static Future fromJson(Map json) async { + final localeMap = + json["locale"] != null ? jsonDecode(json["locale"]) : null; - themeMode = ThemeMode.values[map["themeMode"] ?? 0]; - accentColorScheme = map["accentColorScheme"] != null - ? SpotubeColor.fromString(map["accentColorScheme"]) - : accentColorScheme; - albumColorSync = map["albumColorSync"] ?? albumColorSync; - audioQuality = map["audioQuality"] != null - ? AudioQuality.values[map["audioQuality"]] - : audioQuality; - - if (!kIsWeb) { - downloadLocation = - map["downloadLocation"] ?? await _getDefaultDownloadDirectory(); + final systemTitleBar = json["systemTitleBar"] ?? false; + if (DesktopTools.platform.isDesktop) { + await DesktopTools.window.setTitleBarStyle( + systemTitleBar ? TitleBarStyle.normal : TitleBarStyle.hidden, + ); } - layoutMode = LayoutMode.values.firstWhere( - (mode) => mode.name == map["layoutMode"], - orElse: () => kIsDesktop ? LayoutMode.extended : LayoutMode.compact, - ); - - closeBehavior = map["closeBehavior"] != null - ? CloseBehavior.values[map["closeBehavior"]] - : closeBehavior; - - showSystemTrayIcon = map["showSystemTrayIcon"] ?? showSystemTrayIcon; - - final localeMap = map["locale"] != null ? jsonDecode(map["locale"]) : null; - locale = - localeMap != null ? Locale(localeMap?["lc"], localeMap?["cc"]) : locale; - - pipedInstance = map["pipedInstance"] ?? pipedInstance; - - searchMode = SearchMode.values.firstWhere( - (mode) => mode.name == map["searchMode"], - orElse: () => SearchMode.youtube, - ); - - skipNonMusic = map["skipNonMusic"] ?? skipNonMusic; - - youtubeApiType = YoutubeApiType.values.firstWhere( - (type) => type.name == map["youtubeApiType"], - orElse: () => YoutubeApiType.youtube, - ); - - systemTitleBar = map["systemTitleBar"] ?? systemTitleBar; - // updates the title bar - setSystemTitleBar(systemTitleBar); - - amoledDarkTheme = map["amoledDarkTheme"] ?? amoledDarkTheme; - - normalizeAudio = map["normalizeAudio"] ?? normalizeAudio; + final normalizeAudio = json["normalizeAudio"] ?? true; audioPlayer.setAudioNormalization(normalizeAudio); - streamMusicCodec = MusicCodec.values.firstWhere( - (codec) => codec.name == map["streamMusicCodec"], - orElse: () => MusicCodec.weba, - ); - - downloadMusicCodec = MusicCodec.values.firstWhere( - (codec) => codec.name == map["downloadMusicCodec"], - orElse: () => MusicCodec.m4a, + return UserPreferences( + accentColorScheme: json["accentColorScheme"] == null + ? null + : SpotubeColor.fromString(json["accentColorScheme"]), + albumColorSync: json["albumColorSync"], + amoledDarkTheme: json["amoledDarkTheme"], + audioQuality: AudioQuality.values[json["audioQuality"]], + checkUpdate: json["checkUpdate"], + closeBehavior: CloseBehavior.values[json["closeBehavior"]], + downloadLocation: + json["downloadLocation"] ?? await _getDefaultDownloadDirectory(), + downloadMusicCodec: MusicCodec.values[json["downloadMusicCodec"]], + layoutMode: LayoutMode.values[json["layoutMode"]], + locale: + localeMap == null ? null : Locale(localeMap?["lc"], localeMap?["cc"]), + normalizeAudio: json["normalizeAudio"], + pipedInstance: json["pipedInstance"], + recommendationMarket: Market.values[json["recommendationMarket"]], + searchMode: SearchMode.values[json["searchMode"]], + showSystemTrayIcon: json["showSystemTrayIcon"], + skipNonMusic: json["skipNonMusic"], + streamMusicCodec: MusicCodec.values[json["streamMusicCodec"]], + systemTitleBar: json["systemTitleBar"], + themeMode: ThemeMode.values[json["themeMode"]], + youtubeApiType: YoutubeApiType.values[json["youtubeApiType"]], ); } - @override - FutureOr> toMap() { + Map toJson() { return { - "recommendationMarket": recommendationMarket.name, + "recommendationMarket": recommendationMarket.index, "themeMode": themeMode.index, "accentColorScheme": accentColorScheme.toString(), "albumColorSync": albumColorSync, "checkUpdate": checkUpdate, "audioQuality": audioQuality.index, "downloadLocation": downloadLocation, - "layoutMode": layoutMode.name, + "layoutMode": layoutMode.index, "closeBehavior": closeBehavior.index, "showSystemTrayIcon": showSystemTrayIcon, "locale": jsonEncode({"lc": locale.languageCode, "cc": locale.countryCode}), "pipedInstance": pipedInstance, - "searchMode": searchMode.name, + "searchMode": searchMode.index, "skipNonMusic": skipNonMusic, - "youtubeApiType": youtubeApiType.name, + "youtubeApiType": youtubeApiType.index, 'systemTitleBar': systemTitleBar, "amoledDarkTheme": amoledDarkTheme, "normalizeAudio": normalizeAudio, - "streamMusicCodec": streamMusicCodec.name, - "downloadMusicCodec": downloadMusicCodec.name, + "streamMusicCodec": streamMusicCodec.index, + "downloadMusicCodec": downloadMusicCodec.index, }; } @@ -389,9 +240,13 @@ class UserPreferences extends PersistedChangeNotifier { YoutubeApiType? youtubeApiType, Market? recommendationMarket, bool? saveTrackLyrics, + bool? amoledDarkTheme, + bool? normalizeAudio, + MusicCodec? downloadMusicCodec, + MusicCodec? streamMusicCodec, + bool? systemTitleBar, }) { return UserPreferences( - ref, themeMode: themeMode ?? this.themeMode, accentColorScheme: accentColorScheme ?? this.accentColorScheme, albumColorSync: albumColorSync ?? this.albumColorSync, @@ -407,10 +262,130 @@ class UserPreferences extends PersistedChangeNotifier { skipNonMusic: skipNonMusic ?? this.skipNonMusic, youtubeApiType: youtubeApiType ?? this.youtubeApiType, recommendationMarket: recommendationMarket ?? this.recommendationMarket, + amoledDarkTheme: amoledDarkTheme ?? this.amoledDarkTheme, + downloadMusicCodec: downloadMusicCodec ?? this.downloadMusicCodec, + normalizeAudio: normalizeAudio ?? this.normalizeAudio, + streamMusicCodec: streamMusicCodec ?? this.streamMusicCodec, + systemTitleBar: systemTitleBar ?? this.systemTitleBar, ); } } -final userPreferencesProvider = ChangeNotifierProvider( - (ref) => UserPreferences(ref), +class UserPreferencesNotifier extends PersistedStateNotifier { + final Ref ref; + + UserPreferencesNotifier(this.ref) + : super(UserPreferences.withDefaults(), "preferences"); + + void reset() { + state = UserPreferences.withDefaults(); + } + + void setStreamMusicCodec(MusicCodec codec) { + state = state.copyWith(streamMusicCodec: codec); + } + + void setDownloadMusicCodec(MusicCodec codec) { + state = state.copyWith(downloadMusicCodec: codec); + } + + void setThemeMode(ThemeMode mode) { + state = state.copyWith(themeMode: mode); + } + + void setRecommendationMarket(Market country) { + state = state.copyWith(recommendationMarket: country); + } + + void setAccentColorScheme(SpotubeColor color) { + state = state.copyWith(accentColorScheme: color); + } + + void setAlbumColorSync(bool sync) { + state = state.copyWith(albumColorSync: sync); + + if (!sync) { + ref.read(paletteProvider.notifier).state = null; + } else { + ref.read(ProxyPlaylistNotifier.notifier).updatePalette(); + } + } + + void setCheckUpdate(bool check) { + state = state.copyWith(checkUpdate: check); + } + + void setAudioQuality(AudioQuality quality) { + state = state.copyWith(audioQuality: quality); + } + + void setDownloadLocation(String downloadDir) { + if (downloadDir.isEmpty) return; + state = state.copyWith(downloadLocation: downloadDir); + } + + void setLayoutMode(LayoutMode mode) { + state = state.copyWith(layoutMode: mode); + } + + void setCloseBehavior(CloseBehavior behavior) { + state = state.copyWith(closeBehavior: behavior); + } + + void setShowSystemTrayIcon(bool show) { + state = state.copyWith(showSystemTrayIcon: show); + } + + void setLocale(Locale locale) { + state = state.copyWith(locale: locale); + } + + void setPipedInstance(String instance) { + state = state.copyWith(pipedInstance: instance); + } + + void setSearchMode(SearchMode mode) { + state = state.copyWith(searchMode: mode); + } + + void setSkipNonMusic(bool skip) { + state = state.copyWith(skipNonMusic: skip); + } + + void setYoutubeApiType(YoutubeApiType type) { + state = state.copyWith(youtubeApiType: type); + } + + void setSystemTitleBar(bool isSystemTitleBar) { + state = state.copyWith(systemTitleBar: isSystemTitleBar); + if (DesktopTools.platform.isDesktop) { + DesktopTools.window.setTitleBarStyle( + isSystemTitleBar ? TitleBarStyle.normal : TitleBarStyle.hidden, + ); + } + } + + void setAmoledDarkTheme(bool isAmoled) { + state = state.copyWith(amoledDarkTheme: isAmoled); + } + + void setNormalizeAudio(bool normalize) { + state = state.copyWith(normalizeAudio: normalize); + audioPlayer.setAudioNormalization(normalize); + } + + @override + FutureOr fromJson(Map json) { + return UserPreferences.fromJson(json); + } + + @override + Map toJson() { + return state.toJson(); + } +} + +final userPreferencesProvider = + StateNotifierProvider( + (ref) => UserPreferencesNotifier(ref), ); From 0a6b54da367345b73fe6e954f1d9368d9f9ead71 Mon Sep 17 00:00:00 2001 From: Kingkor Roy Tirtho Date: Mon, 13 Nov 2023 21:46:33 +0600 Subject: [PATCH 015/195] fix: scrobbling not working for first track or single track --- .../proxy_playlist_provider.dart | 38 ++++++++++--------- 1 file changed, 20 insertions(+), 18 deletions(-) diff --git a/lib/provider/proxy_playlist/proxy_playlist_provider.dart b/lib/provider/proxy_playlist/proxy_playlist_provider.dart index 685a9942..bf7293ce 100644 --- a/lib/provider/proxy_playlist/proxy_playlist_provider.dart +++ b/lib/provider/proxy_playlist/proxy_playlist_provider.dart @@ -213,6 +213,26 @@ class ProxyPlaylistNotifier extends PersistedStateNotifier Catcher2.reportCheckedError(e, stackTrace); } }); + + String? lastScrobbled; + audioPlayer.positionStream.listen((position) { + try { + final uid = state.activeTrack is LocalTrack + ? (state.activeTrack as LocalTrack).path + : state.activeTrack?.id; + + if (state.activeTrack == null || + lastScrobbled == uid || + position.inSeconds < 30) { + return; + } + + scrobbler.scrobble(state.activeTrack!); + lastScrobbled = uid; + } catch (e, stack) { + Catcher2.reportCheckedError(e, stack); + } + }); }(); } @@ -609,30 +629,12 @@ class ProxyPlaylistNotifier extends PersistedStateNotifier @override set state(state) { - final hasActiveTrackChanged = super.state.activeTrack is SpotubeTrack - ? state.activeTrack?.id != super.state.activeTrack?.id - : super.state.activeTrack is LocalTrack && - state.activeTrack is LocalTrack - ? (super.state.activeTrack as LocalTrack).path != - (state.activeTrack as LocalTrack).path - : super.state.activeTrack?.id != state.activeTrack?.id; - - final oldTrack = super.state.activeTrack; - super.state = state; if (state.tracks.isEmpty && ref.read(paletteProvider) != null) { ref.read(paletteProvider.notifier).state = null; } else { updatePalette(); } - audioPlayer.position.then((position) { - final isMoreThan30secs = position != null && - (position == Duration.zero || position.inSeconds > 30); - - if (hasActiveTrackChanged && oldTrack != null && isMoreThan30secs) { - scrobbler.scrobble(oldTrack); - } - }); } @override From 2e2c44f0afef69bf9bc485db97d45127a0847c8e Mon Sep 17 00:00:00 2001 From: Kingkor Roy Tirtho Date: Mon, 13 Nov 2023 23:17:16 +0600 Subject: [PATCH 016/195] feat(android): better quick scroll/drag to scroll implementation --- lib/components/library/user_local_tracks.dart | 4 + lib/components/library/user_playlists.dart | 116 +++---- lib/components/player/player_queue.dart | 308 +++++++++--------- .../player/sibling_tracks_sheet.dart | 6 + .../inter_scrollbar/inter_scrollbar.dart | 54 +-- lib/pages/home/genres.dart | 39 +-- lib/pages/home/personalized.dart | 80 +++-- lib/pages/search/search.dart | 40 ++- lib/pages/settings/blacklist.dart | 3 + lib/pages/settings/logs.dart | 3 + lib/pages/settings/settings.dart | 4 + pubspec.lock | 9 + pubspec.yaml | 4 + 13 files changed, 330 insertions(+), 340 deletions(-) diff --git a/lib/components/library/user_local_tracks.dart b/lib/components/library/user_local_tracks.dart index c7cd0682..0546c2a7 100644 --- a/lib/components/library/user_local_tracks.dart +++ b/lib/components/library/user_local_tracks.dart @@ -163,6 +163,8 @@ class UserLocalTracks extends HookConsumerWidget { final searchFocus = useFocusNode(); final isFiltering = useState(false); + final controller = useScrollController(); + return Column( children: [ Padding( @@ -256,7 +258,9 @@ class UserLocalTracks extends HookConsumerWidget { ref.refresh(localTracksProvider); }, child: InterScrollbar( + controller: controller, child: ListView.builder( + controller: controller, physics: const AlwaysScrollableScrollPhysics(), itemCount: filteredTracks.length, itemBuilder: (context, index) { diff --git a/lib/components/library/user_playlists.dart b/lib/components/library/user_playlists.dart index ecf4fa12..0102a3c7 100644 --- a/lib/components/library/user_playlists.dart +++ b/lib/components/library/user_playlists.dart @@ -9,6 +9,7 @@ import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:spotify/spotify.dart'; import 'package:spotube/collections/spotube_icons.dart'; import 'package:spotube/components/playlist/playlist_create_dialog.dart'; +import 'package:spotube/components/shared/inter_scrollbar/inter_scrollbar.dart'; import 'package:spotube/components/shared/shimmers/shimmer_playbutton_card.dart'; import 'package:spotube/components/shared/fallbacks/anonymous_fallback.dart'; import 'package:spotube/components/playlist/playlist_card.dart'; @@ -81,68 +82,71 @@ class UserPlaylists extends HookConsumerWidget { return RefreshIndicator( onRefresh: playlistsQuery.refresh, child: SafeArea( - child: CustomScrollView( + child: InterScrollbar( controller: controller, - slivers: [ - SliverToBoxAdapter( - child: Column( - mainAxisSize: MainAxisSize.min, - children: [ - Padding( - padding: const EdgeInsets.all(10), - child: SearchBar( - onChanged: (value) => searchText.value = value, - hintText: context.l10n.filter_playlists, - leading: const Icon(SpotubeIcons.filter), - ), - ), - Row( - children: [ - const SizedBox(width: 10), - const PlaylistCreateDialogButton(), - const SizedBox(width: 10), - ElevatedButton.icon( - icon: const Icon(SpotubeIcons.magic), - label: Text(context.l10n.generate_playlist), - onPressed: () { - GoRouter.of(context).push("/library/generate"); - }, + child: CustomScrollView( + controller: controller, + slivers: [ + SliverToBoxAdapter( + child: Column( + mainAxisSize: MainAxisSize.min, + children: [ + Padding( + padding: const EdgeInsets.all(10), + child: SearchBar( + onChanged: (value) => searchText.value = value, + hintText: context.l10n.filter_playlists, + leading: const Icon(SpotubeIcons.filter), ), - const SizedBox(width: 10), - ], - ), - ], + ), + Row( + children: [ + const SizedBox(width: 10), + const PlaylistCreateDialogButton(), + const SizedBox(width: 10), + ElevatedButton.icon( + icon: const Icon(SpotubeIcons.magic), + label: Text(context.l10n.generate_playlist), + onPressed: () { + GoRouter.of(context).push("/library/generate"); + }, + ), + const SizedBox(width: 10), + ], + ), + ], + ), ), - ), - const SliverToBoxAdapter( - child: SizedBox(height: 10), - ), - SliverGrid.builder( - itemCount: playlists.length + 1, - gridDelegate: SliverGridDelegateWithMaxCrossAxisExtent( - maxCrossAxisExtent: 200, - mainAxisExtent: DesktopTools.platform.isMobile ? 225 : 250, - crossAxisSpacing: 8, - mainAxisSpacing: 8, + const SliverToBoxAdapter( + child: SizedBox(height: 10), ), - itemBuilder: (context, index) { - if (index == playlists.length) { - if (!playlistsQuery.hasNextPage) { - return const SizedBox.shrink(); + SliverGrid.builder( + itemCount: playlists.length + 1, + gridDelegate: SliverGridDelegateWithMaxCrossAxisExtent( + maxCrossAxisExtent: 200, + mainAxisExtent: DesktopTools.platform.isMobile ? 225 : 250, + crossAxisSpacing: 8, + mainAxisSpacing: 8, + ), + itemBuilder: (context, index) { + if (index == playlists.length) { + if (!playlistsQuery.hasNextPage) { + return const SizedBox.shrink(); + } + + return Waypoint( + controller: controller, + isGrid: true, + onTouchEdge: playlistsQuery.fetchNext, + child: const ShimmerPlaybuttonCard(count: 1), + ); } - return Waypoint( - controller: controller, - isGrid: true, - onTouchEdge: playlistsQuery.fetchNext, - child: const ShimmerPlaybuttonCard(count: 1), - ); - } - - return PlaylistCard(playlists[index]); - }, - ) - ], + return PlaylistCard(playlists[index]); + }, + ) + ], + ), ), ), ); diff --git a/lib/components/player/player_queue.dart b/lib/components/player/player_queue.dart index 2d8ba329..9e303cb8 100644 --- a/lib/components/player/player_queue.dart +++ b/lib/components/player/player_queue.dart @@ -44,6 +44,7 @@ class PlayerQueue extends HookConsumerWidget { topRight: Radius.circular(10), ); final theme = Theme.of(context); + final mediaQuery = MediaQuery.of(context); final headlineColor = theme.textTheme.headlineSmall?.color; final filteredTracks = useMemoized( @@ -108,171 +109,166 @@ class PlayerQueue extends HookConsumerWidget { searchText.value = ''; } }, - child: LayoutBuilder(builder: (context, constraints) { - return Column( - children: [ - if (!floating) - Container( - height: 5, - width: 100, - margin: const EdgeInsets.only(bottom: 5, top: 2), - decoration: BoxDecoration( - color: headlineColor, - borderRadius: BorderRadius.circular(20), - ), + child: Column( + children: [ + if (!floating) + Container( + height: 5, + width: 100, + margin: const EdgeInsets.only(bottom: 5, top: 2), + decoration: BoxDecoration( + color: headlineColor, + borderRadius: BorderRadius.circular(20), ), - Row( - crossAxisAlignment: CrossAxisAlignment.center, - mainAxisAlignment: MainAxisAlignment.center, - children: [ - if (constraints.mdAndUp || !isSearching.value) ...[ - const SizedBox(width: 10), - Text( - context.l10n.tracks_in_queue(tracks.length), - style: TextStyle( - color: headlineColor, - fontWeight: FontWeight.bold, - fontSize: 18, + ), + Row( + crossAxisAlignment: CrossAxisAlignment.center, + mainAxisAlignment: MainAxisAlignment.center, + children: [ + if (mediaQuery.mdAndUp || !isSearching.value) ...[ + const SizedBox(width: 10), + Text( + context.l10n.tracks_in_queue(tracks.length), + style: TextStyle( + color: headlineColor, + fontWeight: FontWeight.bold, + fontSize: 18, + ), + ), + const Spacer(), + ], + if (mediaQuery.mdAndUp || isSearching.value) + TextField( + onChanged: (value) { + searchText.value = value; + }, + decoration: InputDecoration( + hintText: context.l10n.search, + isDense: true, + prefixIcon: mediaQuery.smAndDown + ? IconButton( + icon: const Icon( + Icons.arrow_back_ios_new_outlined, + ), + onPressed: () { + isSearching.value = false; + searchText.value = ''; + }, + style: IconButton.styleFrom( + padding: EdgeInsets.zero, + minimumSize: const Size.square(20), + ), + ) + : const Icon(SpotubeIcons.filter), + constraints: BoxConstraints( + maxHeight: 40, + maxWidth: mediaQuery.smAndDown + ? mediaQuery.size.width - 40 + : 300, ), ), - const Spacer(), - ], - if (constraints.mdAndUp || isSearching.value) - TextField( - onChanged: (value) { - searchText.value = value; - }, - decoration: InputDecoration( - hintText: context.l10n.search, - isDense: true, - prefixIcon: constraints.smAndDown - ? IconButton( - icon: const Icon( - Icons.arrow_back_ios_new_outlined, - ), - onPressed: () { - isSearching.value = false; - searchText.value = ''; - }, - style: IconButton.styleFrom( - padding: EdgeInsets.zero, - minimumSize: const Size.square(20), - ), - ) - : const Icon(SpotubeIcons.filter), - constraints: BoxConstraints( - maxHeight: 40, - maxWidth: constraints.smAndDown - ? constraints.maxWidth - 20 - : 300, + ) + else + IconButton.filledTonal( + icon: const Icon(SpotubeIcons.filter), + onPressed: () { + isSearching.value = !isSearching.value; + }, + ), + if (mediaQuery.mdAndUp || !isSearching.value) ...[ + const SizedBox(width: 10), + FilledButton( + style: FilledButton.styleFrom( + backgroundColor: + theme.scaffoldBackgroundColor.withOpacity(0.5), + foregroundColor: theme.textTheme.headlineSmall?.color, + ), + child: Row( + children: [ + const Icon(SpotubeIcons.playlistRemove), + const SizedBox(width: 5), + Text(context.l10n.clear_all), + ], + ), + onPressed: () { + playlistNotifier.stop(); + Navigator.of(context).pop(); + }, + ), + const SizedBox(width: 10), + ], + ], + ), + const SizedBox(height: 10), + if (!isSearching.value && searchText.value.isEmpty) + Flexible( + child: ReorderableListView.builder( + onReorder: (oldIndex, newIndex) { + playlistNotifier.moveTrack(oldIndex, newIndex); + }, + scrollController: controller, + itemCount: tracks.length, + shrinkWrap: true, + buildDefaultDragHandles: false, + itemBuilder: (context, i) { + final track = tracks.elementAt(i); + return AutoScrollTag( + key: ValueKey(i), + controller: controller, + index: i, + child: Padding( + padding: + const EdgeInsets.symmetric(horizontal: 8.0), + child: TrackTile( + index: i, + track: track, + onTap: () async { + if (playlist.activeTrack?.id == track.id) { + return; + } + await playlistNotifier.jumpToTrack(track); + }, + leadingActions: [ + ReorderableDragStartListener( + index: i, + child: const Icon(SpotubeIcons.dragHandle), + ), + ], ), ), - ) - else - IconButton.filledTonal( - icon: const Icon(SpotubeIcons.filter), - onPressed: () { - isSearching.value = !isSearching.value; - }, - ), - if (constraints.mdAndUp || !isSearching.value) ...[ - const SizedBox(width: 10), - FilledButton( - style: FilledButton.styleFrom( - backgroundColor: - theme.scaffoldBackgroundColor.withOpacity(0.5), - foregroundColor: - theme.textTheme.headlineSmall?.color, - ), - child: Row( - children: [ - const Icon(SpotubeIcons.playlistRemove), - const SizedBox(width: 5), - Text(context.l10n.clear_all), - ], - ), - onPressed: () { - playlistNotifier.stop(); - Navigator.of(context).pop(); - }, - ), - const SizedBox(width: 10), - ], - ], - ), - const SizedBox(height: 10), - if (!isSearching.value && searchText.value.isEmpty) - Flexible( - child: InterScrollbar( + ); + }, + ), + ) + else + Flexible( + child: InterScrollbar( + controller: controller, + child: ListView.builder( controller: controller, - child: ReorderableListView.builder( - onReorder: (oldIndex, newIndex) { - playlistNotifier.moveTrack(oldIndex, newIndex); - }, - scrollController: controller, - itemCount: tracks.length, - shrinkWrap: true, - buildDefaultDragHandles: false, - itemBuilder: (context, i) { - final track = tracks.elementAt(i); - return AutoScrollTag( - key: ValueKey(i), - controller: controller, + itemCount: filteredTracks.length, + itemBuilder: (context, i) { + final track = filteredTracks.elementAt(i); + return Padding( + padding: + const EdgeInsets.symmetric(horizontal: 8.0), + child: TrackTile( index: i, - child: Padding( - padding: - const EdgeInsets.symmetric(horizontal: 8.0), - child: TrackTile( - index: i, - track: track, - onTap: () async { - if (playlist.activeTrack?.id == track.id) { - return; - } - await playlistNotifier.jumpToTrack(track); - }, - leadingActions: [ - ReorderableDragStartListener( - index: i, - child: - const Icon(SpotubeIcons.dragHandle), - ), - ], - ), - ), - ); - }, - ), - ), - ) - else - Flexible( - child: InterScrollbar( - child: ListView.builder( - itemCount: filteredTracks.length, - itemBuilder: (context, i) { - final track = filteredTracks.elementAt(i); - return Padding( - padding: - const EdgeInsets.symmetric(horizontal: 8.0), - child: TrackTile( - index: i, - track: track, - onTap: () async { - if (playlist.activeTrack?.id == track.id) { - return; - } - await playlistNotifier.jumpToTrack(track); - }, - ), - ); - }, - ), + track: track, + onTap: () async { + if (playlist.activeTrack?.id == track.id) { + return; + } + await playlistNotifier.jumpToTrack(track); + }, + ), + ); + }, ), ), - ], - ); - }), + ), + ], + ), ), ), ), diff --git a/lib/components/player/sibling_tracks_sheet.dart b/lib/components/player/sibling_tracks_sheet.dart index 14c042b8..8dc41026 100644 --- a/lib/components/player/sibling_tracks_sheet.dart +++ b/lib/components/player/sibling_tracks_sheet.dart @@ -56,6 +56,8 @@ class SiblingTracksSheet extends HookConsumerWidget { useValueListenable(searchController).text, ); + final controller = useScrollController(); + final searchRequest = useMemoized(() async { if (searchTerm.trim().isEmpty) { return []; @@ -204,8 +206,10 @@ class SiblingTracksSheet extends HookConsumerWidget { transitionBuilder: (child, animation) => FadeTransition(opacity: animation, child: child), child: InterScrollbar( + controller: controller, child: switch (isSearching.value) { false => ListView.builder( + controller: controller, itemCount: siblings.length, itemBuilder: (context, index) => itemBuilder(siblings[index]), @@ -223,7 +227,9 @@ class SiblingTracksSheet extends HookConsumerWidget { } return InterScrollbar( + controller: controller, child: ListView.builder( + controller: controller, itemCount: snapshot.data!.length, itemBuilder: (context, index) => itemBuilder(snapshot.data![index]), diff --git a/lib/components/shared/inter_scrollbar/inter_scrollbar.dart b/lib/components/shared/inter_scrollbar/inter_scrollbar.dart index 05eb174a..11f75829 100644 --- a/lib/components/shared/inter_scrollbar/inter_scrollbar.dart +++ b/lib/components/shared/inter_scrollbar/inter_scrollbar.dart @@ -1,29 +1,16 @@ +import 'package:draggable_scrollbar/draggable_scrollbar.dart'; import 'package:flutter/material.dart'; import 'package:flutter_desktop_tools/flutter_desktop_tools.dart'; import 'package:flutter_hooks/flutter_hooks.dart'; class InterScrollbar extends HookWidget { final Widget child; - final ScrollController? controller; - final bool? thumbVisibility; - final bool? trackVisibility; - final double? thickness; - final Radius? radius; - final bool Function(ScrollNotification)? notificationPredicate; - final bool? interactive; - final ScrollbarOrientation? scrollbarOrientation; + final ScrollController controller; const InterScrollbar({ super.key, required this.child, - this.controller, - this.thumbVisibility, - this.trackVisibility, - this.thickness, - this.radius, - this.notificationPredicate, - this.interactive, - this.scrollbarOrientation, + required this.controller, }); @override @@ -32,38 +19,9 @@ class InterScrollbar extends HookWidget { if (DesktopTools.platform.isDesktop) return child; - return ScrollbarTheme( - data: theme.scrollbarTheme.copyWith( - crossAxisMargin: 10, - minThumbLength: 80, - thickness: MaterialStateProperty.resolveWith((states) { - if (states.contains(MaterialState.hovered) || - states.contains(MaterialState.dragged) || - states.contains(MaterialState.pressed)) { - return 40; - } - return 20; - }), - radius: const Radius.circular(20), - thumbColor: MaterialStateProperty.resolveWith((states) { - if (states.contains(MaterialState.hovered) || - states.contains(MaterialState.dragged)) { - return theme.colorScheme.onSurface.withOpacity(0.5); - } - return theme.colorScheme.onSurface.withOpacity(0.3); - }), - ), - child: Scrollbar( - controller: controller, - thumbVisibility: thumbVisibility, - trackVisibility: trackVisibility, - thickness: thickness, - radius: radius, - notificationPredicate: notificationPredicate, - interactive: interactive ?? true, - scrollbarOrientation: scrollbarOrientation, - child: child, - ), + return DraggableScrollbar.semicircle( + controller: controller, + child: child, ); } } diff --git a/lib/pages/home/genres.dart b/lib/pages/home/genres.dart index 076305f2..6861853d 100644 --- a/lib/pages/home/genres.dart +++ b/lib/pages/home/genres.dart @@ -79,28 +79,25 @@ class GenrePage extends HookConsumerWidget { const ShimmerCategories() else Expanded( - child: InterScrollbar( + child: ListView.builder( controller: scrollController, - child: ListView.builder( - controller: scrollController, - itemCount: categories.length, - itemBuilder: (context, index) { - return AnimatedSwitcher( - transitionBuilder: (child, animation) { - return FadeTransition( - opacity: animation, - child: child, - ); - }, - duration: const Duration(milliseconds: 300), - child: searchController.text.isEmpty && - index == categories.length - 1 && - categoriesQuery.hasNextPage - ? const ShimmerCategories() - : CategoryCard(categories[index]), - ); - }, - ), + itemCount: categories.length, + itemBuilder: (context, index) { + return AnimatedSwitcher( + transitionBuilder: (child, animation) { + return FadeTransition( + opacity: animation, + child: child, + ); + }, + duration: const Duration(milliseconds: 300), + child: searchController.text.isEmpty && + index == categories.length - 1 && + categoriesQuery.hasNextPage + ? const ShimmerCategories() + : CategoryCard(categories[index]), + ); + }, ), ), ], diff --git a/lib/pages/home/personalized.dart b/lib/pages/home/personalized.dart index 8a18fd0b..b596a820 100644 --- a/lib/pages/home/personalized.dart +++ b/lib/pages/home/personalized.dart @@ -4,7 +4,6 @@ import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:spotify/spotify.dart'; import 'package:spotube/components/shared/horizontal_playbutton_card_view/horizontal_playbutton_card_view.dart'; -import 'package:spotube/components/shared/inter_scrollbar/inter_scrollbar.dart'; import 'package:spotube/components/shared/shimmers/shimmer_categories.dart'; import 'package:spotube/extensions/context.dart'; import 'package:spotube/provider/authentication_provider.dart'; @@ -47,48 +46,45 @@ class PersonalizedPage extends HookConsumerWidget { [newReleases.pages], ); - return InterScrollbar( + return ListView( controller: controller, - child: ListView( - controller: controller, - children: [ - if (!featuredPlaylistsQuery.hasPageData && - !featuredPlaylistsQuery.isLoadingNextPage) - const ShimmerCategories() - else - HorizontalPlaybuttonCardView( - items: playlists.toList(), - title: Text(context.l10n.featured), - hasNextPage: featuredPlaylistsQuery.hasNextPage, - onFetchMore: featuredPlaylistsQuery.fetchNext, - ), - if (auth != null && - newReleases.hasPageData && - userArtistsQuery.hasData && - !newReleases.isLoadingNextPage) - HorizontalPlaybuttonCardView( - items: albums, - title: Text(context.l10n.new_releases), - hasNextPage: newReleases.hasNextPage, - onFetchMore: newReleases.fetchNext, - ), - ...?madeForUser.data?["content"]?["items"]?.map((item) { - final playlists = item["content"]?["items"] - ?.where((itemL2) => itemL2["type"] == "playlist") - .map((itemL2) => PlaylistSimple.fromJson(itemL2)) - .toList() - .cast() ?? - []; - if (playlists.isEmpty) return const SizedBox.shrink(); - return HorizontalPlaybuttonCardView( - items: playlists, - title: Text(item["name"] ?? ""), - hasNextPage: false, - onFetchMore: () {}, - ); - }) - ], - ), + children: [ + if (!featuredPlaylistsQuery.hasPageData && + !featuredPlaylistsQuery.isLoadingNextPage) + const ShimmerCategories() + else + HorizontalPlaybuttonCardView( + items: playlists.toList(), + title: Text(context.l10n.featured), + hasNextPage: featuredPlaylistsQuery.hasNextPage, + onFetchMore: featuredPlaylistsQuery.fetchNext, + ), + if (auth != null && + newReleases.hasPageData && + userArtistsQuery.hasData && + !newReleases.isLoadingNextPage) + HorizontalPlaybuttonCardView( + items: albums, + title: Text(context.l10n.new_releases), + hasNextPage: newReleases.hasNextPage, + onFetchMore: newReleases.fetchNext, + ), + ...?madeForUser.data?["content"]?["items"]?.map((item) { + final playlists = item["content"]?["items"] + ?.where((itemL2) => itemL2["type"] == "playlist") + .map((itemL2) => PlaylistSimple.fromJson(itemL2)) + .toList() + .cast() ?? + []; + if (playlists.isEmpty) return const SizedBox.shrink(); + return HorizontalPlaybuttonCardView( + items: playlists, + title: Text(item["name"] ?? ""), + hasNextPage: false, + onFetchMore: () {}, + ); + }) + ], ); } } diff --git a/lib/pages/search/search.dart b/lib/pages/search/search.dart index d659e8e3..b19162fa 100644 --- a/lib/pages/search/search.dart +++ b/lib/pages/search/search.dart @@ -71,26 +71,32 @@ class SearchPage extends HookConsumerWidget { searchTerm.isNotEmpty; final resultWidget = HookBuilder( - builder: (context) => InterScrollbar( - child: SingleChildScrollView( - child: Padding( - padding: const EdgeInsets.symmetric(vertical: 8), - child: SafeArea( - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - SearchTracksSection(query: searchTrack), - SearchPlaylistsSection(query: searchPlaylist), - const SizedBox(height: 20), - SearchArtistsSection(query: searchArtist), - const SizedBox(height: 20), - SearchAlbumsSection(query: searchAlbum), - ], + builder: (context) { + final controller = useScrollController(); + + return InterScrollbar( + controller: controller, + child: SingleChildScrollView( + controller: controller, + child: Padding( + padding: const EdgeInsets.symmetric(vertical: 8), + child: SafeArea( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + SearchTracksSection(query: searchTrack), + SearchPlaylistsSection(query: searchPlaylist), + const SizedBox(height: 20), + SearchArtistsSection(query: searchArtist), + const SizedBox(height: 20), + SearchAlbumsSection(query: searchAlbum), + ], + ), ), ), ), - ), - ), + ); + }, ); return SafeArea( diff --git a/lib/pages/settings/blacklist.dart b/lib/pages/settings/blacklist.dart index 69800633..b4ce5044 100644 --- a/lib/pages/settings/blacklist.dart +++ b/lib/pages/settings/blacklist.dart @@ -15,6 +15,7 @@ class BlackListPage extends HookConsumerWidget { @override Widget build(BuildContext context, ref) { + final controller = useScrollController(); final blacklist = ref.watch(BlackListNotifier.provider); final searchText = useState(""); @@ -58,7 +59,9 @@ class BlackListPage extends HookConsumerWidget { ), ), InterScrollbar( + controller: controller, child: ListView.builder( + controller: controller, shrinkWrap: true, itemCount: filteredBlacklist.length, itemBuilder: (context, index) { diff --git a/lib/pages/settings/logs.dart b/lib/pages/settings/logs.dart index 91d87fbb..cfb28d18 100644 --- a/lib/pages/settings/logs.dart +++ b/lib/pages/settings/logs.dart @@ -52,6 +52,7 @@ class LogsPage extends HookWidget { @override Widget build(BuildContext context) { + final controller = useScrollController(); final logs = useState>([]); final rawLogs = useRef(""); final path = useRef(null); @@ -93,7 +94,9 @@ class LogsPage extends HookWidget { ), body: SafeArea( child: InterScrollbar( + controller: controller, child: ListView.builder( + controller: controller, itemCount: logs.value.length, itemBuilder: (context, index) { final log = logs.value[index]; diff --git a/lib/pages/settings/settings.dart b/lib/pages/settings/settings.dart index baf245b4..84b51d4d 100644 --- a/lib/pages/settings/settings.dart +++ b/lib/pages/settings/settings.dart @@ -1,6 +1,7 @@ import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:flutter_desktop_tools/flutter_desktop_tools.dart'; +import 'package:flutter_hooks/flutter_hooks.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:spotube/components/shared/inter_scrollbar/inter_scrollbar.dart'; import 'package:spotube/components/shared/page_window_title_bar.dart'; @@ -20,6 +21,7 @@ class SettingsPage extends HookConsumerWidget { @override Widget build(BuildContext context, ref) { + final controller = useScrollController(); final preferencesNotifier = ref.watch(userPreferencesProvider.notifier); return SafeArea( @@ -36,7 +38,9 @@ class SettingsPage extends HookConsumerWidget { child: Container( constraints: const BoxConstraints(maxWidth: 1366), child: InterScrollbar( + controller: controller, child: ListView( + controller: controller, children: [ const SettingsAccountSection(), const SettingsLanguageRegionSection(), diff --git a/pubspec.lock b/pubspec.lock index 9c0161c6..3d072e09 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -465,6 +465,15 @@ packages: url: "https://pub.dev" source: hosted version: "2.1.2" + draggable_scrollbar: + dependency: "direct main" + description: + path: "." + ref: cfd570035bf393de541d32e9b28808b5d7e602df + resolved-ref: cfd570035bf393de541d32e9b28808b5d7e602df + url: "https://github.com/thielepaul/flutter-draggable-scrollbar.git" + source: git + version: "0.1.0" duration: dependency: "direct main" description: diff --git a/pubspec.yaml b/pubspec.yaml index 64b2b6a3..f9c1155f 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -106,6 +106,10 @@ dependencies: simple_icons: ^7.10.0 audio_service_mpris: ^0.1.0 file_picker: ^6.0.0 + draggable_scrollbar: + git: + url: https://github.com/thielepaul/flutter-draggable-scrollbar.git + ref: cfd570035bf393de541d32e9b28808b5d7e602df dev_dependencies: build_runner: ^2.3.2 From 7b72a90bc65b541cbe2e24ef2234524b522ad71d Mon Sep 17 00:00:00 2001 From: Kingkor Roy Tirtho Date: Tue, 14 Nov 2023 19:04:59 +0600 Subject: [PATCH 017/195] fix: alternative track source safearea overflow #876 --- lib/components/player/sibling_tracks_sheet.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/components/player/sibling_tracks_sheet.dart b/lib/components/player/sibling_tracks_sheet.dart index 8dc41026..c4100b9a 100644 --- a/lib/components/player/sibling_tracks_sheet.dart +++ b/lib/components/player/sibling_tracks_sheet.dart @@ -135,7 +135,7 @@ class SiblingTracksSheet extends HookConsumerWidget { duration: const Duration(milliseconds: 300), child: Container( height: isSearching.value && mediaQuery.smAndDown - ? mediaQuery.size.height - mediaQuery.padding.top + ? mediaQuery.size.height - 50 : mediaQuery.size.height * .6, decoration: BoxDecoration( borderRadius: borderRadius, From fed36ecdd81e8a0f8358693eff0a6233dea32e5d Mon Sep 17 00:00:00 2001 From: Kingkor Roy Tirtho Date: Tue, 14 Nov 2023 19:36:07 +0600 Subject: [PATCH 018/195] fix: Add to Playlist Dialog memory leak #817 --- .../dialogs/playlist_add_track_dialog.dart | 36 +++++++------------ lib/services/queries/playlist.dart | 23 ++++++++++++ 2 files changed, 35 insertions(+), 24 deletions(-) diff --git a/lib/components/shared/dialogs/playlist_add_track_dialog.dart b/lib/components/shared/dialogs/playlist_add_track_dialog.dart index 29f64268..aadcd9d6 100644 --- a/lib/components/shared/dialogs/playlist_add_track_dialog.dart +++ b/lib/components/shared/dialogs/playlist_add_track_dialog.dart @@ -1,4 +1,3 @@ -import 'package:async/async.dart'; import 'package:fl_query_hooks/fl_query_hooks.dart'; import 'package:flutter/material.dart'; import 'package:flutter_hooks/flutter_hooks.dart'; @@ -21,32 +20,21 @@ class PlaylistAddTrackDialog extends HookConsumerWidget { @override Widget build(BuildContext context, ref) { final spotify = ref.watch(spotifyProvider); - final userPlaylists = useQueries.playlist.ofMine(ref); - - useEffect(() { - final op = CancelableOperation.fromFuture( - () async { - while (userPlaylists.hasNextPage) { - await userPlaylists.fetchNext(); - } - }(), - ); - - return () { - op.cancel(); - }; - }, [userPlaylists.hasNextPage]); + final userPlaylists = useQueries.playlist.ofMineAll(ref); final me = useQueries.user.me(ref); final filteredPlaylists = useMemoized( - () => userPlaylists.pages - .expand((page) => page.items?.toList() ?? []) - .where( - (playlist) => - playlist.owner?.id != null && playlist.owner!.id == me.data?.id, - ), - [userPlaylists.pages, me.data?.id], + () => + userPlaylists.data + ?.where( + (playlist) => + playlist.owner?.id != null && + playlist.owner!.id == me.data?.id, + ) + .toList() ?? + [], + [userPlaylists.data, me.data?.id], ); final playlistsCheck = useState({}); @@ -93,7 +81,7 @@ class PlaylistAddTrackDialog extends HookConsumerWidget { content: SizedBox( height: 300, width: 300, - child: userPlaylists.hasNextPage + child: userPlaylists.isLoading ? const Center(child: CircularProgressIndicator()) : ListView.builder( shrinkWrap: true, diff --git a/lib/services/queries/playlist.dart b/lib/services/queries/playlist.dart index ac8dc73f..c0434a6e 100644 --- a/lib/services/queries/playlist.dart +++ b/lib/services/queries/playlist.dart @@ -143,6 +143,29 @@ class PlaylistQueries { ); } + Query, dynamic> ofMineAll(WidgetRef ref) { + return useSpotifyQuery, dynamic>( + "current-user-all-playlists", + (spotify) async { + var page = await spotify.playlists.me.getPage(50); + final playlists = []; + + if (page.isLast == true) { + return page.items?.toList() ?? []; + } + + playlists.addAll(page.items ?? []); + while (!page.isLast) { + page = await spotify.playlists.me.getPage(50, page.nextOffset); + playlists.addAll(page.items ?? []); + } + + return playlists; + }, + ref: ref, + ); + } + Future> likedTracks( SpotifyApi spotify, WidgetRef ref, From 0e075067168f817ca2de0e25cd47d81fa86184c8 Mon Sep 17 00:00:00 2001 From: Kingkor Roy Tirtho Date: Tue, 14 Nov 2023 19:46:54 +0600 Subject: [PATCH 019/195] refactor: organize hooks --- lib/collections/env.dart | 4 +++- lib/components/artist/artist_card.dart | 4 ++-- .../lyrics}/use_synced_lyrics.dart | 0 lib/components/player/player.dart | 4 ++-- lib/components/player/player_controls.dart | 2 +- lib/components/player/player_overlay.dart | 2 +- lib/components/player/player_queue.dart | 2 +- .../player/sibling_tracks_sheet.dart | 2 +- .../player}/use_progress.dart | 0 lib/components/root/bottom_player.dart | 2 +- lib/components/root/sidebar.dart | 4 ++-- .../root/spotube_navigation_bar.dart | 2 +- .../horizontal_playbutton_card_view.dart | 2 +- lib/components/shared/playbutton_card.dart | 4 ++-- .../shimmers/shimmer_artist_profile.dart | 2 +- .../shared/shimmers/shimmer_categories.dart | 2 +- .../shimmers/shimmer_playbutton_card.dart | 2 +- .../shared/themed_button_tab_bar.dart | 4 ++-- .../track_collection_view.dart | 6 +++--- .../use_disable_battery_optimizations.dart | 2 +- .../use_get_storage_perms.dart | 2 +- .../{ => configurators}/use_init_sys_tray.dart | 0 .../use_update_checker.dart | 2 +- .../use_auto_scroll_controller.dart | 0 .../{ => controllers}/use_package_info.dart | 0 .../use_sidebarx_controller.dart | 0 .../use_spotify_infinite_query.dart | 0 .../{ => spotify}/use_spotify_mutation.dart | 0 lib/hooks/{ => spotify}/use_spotify_query.dart | 0 lib/hooks/use_is_current_route.dart | 18 ------------------ lib/hooks/use_shared_preferences.dart | 9 --------- lib/hooks/{ => utils}/use_async_effect.dart | 0 .../{ => utils}/use_breakpoint_value.dart | 0 .../{ => utils}/use_brightness_value.dart | 0 .../use_custom_status_bar_color.dart | 0 lib/hooks/{ => utils}/use_debounce.dart | 0 lib/hooks/{ => utils}/use_force_update.dart | 0 lib/hooks/{ => utils}/use_palette_color.dart | 0 lib/main.dart | 6 +++--- lib/pages/artist/artist.dart | 2 +- lib/pages/lyrics/lyrics.dart | 4 ++-- lib/pages/lyrics/mini_lyrics.dart | 2 +- lib/pages/lyrics/synced_lyrics.dart | 4 ++-- lib/pages/root/root_app.dart | 2 +- lib/pages/settings/about.dart | 2 +- lib/services/mutations/album.dart | 2 +- lib/services/mutations/playlist.dart | 2 +- lib/services/mutations/track.dart | 2 +- lib/services/queries/album.dart | 4 ++-- lib/services/queries/artist.dart | 4 ++-- lib/services/queries/category.dart | 2 +- lib/services/queries/lyrics.dart | 2 +- lib/services/queries/playlist.dart | 4 ++-- lib/services/queries/search.dart | 2 +- lib/services/queries/user.dart | 2 +- 55 files changed, 53 insertions(+), 78 deletions(-) rename lib/{hooks => components/lyrics}/use_synced_lyrics.dart (100%) rename lib/{hooks => components/player}/use_progress.dart (100%) rename lib/hooks/{ => configurators}/use_disable_battery_optimizations.dart (96%) rename lib/hooks/{ => configurators}/use_get_storage_perms.dart (95%) rename lib/hooks/{ => configurators}/use_init_sys_tray.dart (100%) rename lib/hooks/{ => configurators}/use_update_checker.dart (98%) rename lib/hooks/{ => controllers}/use_auto_scroll_controller.dart (100%) rename lib/hooks/{ => controllers}/use_package_info.dart (100%) rename lib/hooks/{ => controllers}/use_sidebarx_controller.dart (100%) rename lib/hooks/{ => spotify}/use_spotify_infinite_query.dart (100%) rename lib/hooks/{ => spotify}/use_spotify_mutation.dart (100%) rename lib/hooks/{ => spotify}/use_spotify_query.dart (100%) delete mode 100644 lib/hooks/use_is_current_route.dart delete mode 100644 lib/hooks/use_shared_preferences.dart rename lib/hooks/{ => utils}/use_async_effect.dart (100%) rename lib/hooks/{ => utils}/use_breakpoint_value.dart (100%) rename lib/hooks/{ => utils}/use_brightness_value.dart (100%) rename lib/hooks/{ => utils}/use_custom_status_bar_color.dart (100%) rename lib/hooks/{ => utils}/use_debounce.dart (100%) rename lib/hooks/{ => utils}/use_force_update.dart (100%) rename lib/hooks/{ => utils}/use_palette_color.dart (100%) diff --git a/lib/collections/env.dart b/lib/collections/env.dart index 1b9de3de..8086ada7 100644 --- a/lib/collections/env.dart +++ b/lib/collections/env.dart @@ -1,4 +1,5 @@ import 'package:envied/envied.dart'; +import 'package:flutter_desktop_tools/flutter_desktop_tools.dart'; part 'env.g.dart'; @@ -30,5 +31,6 @@ abstract class Env { @EnviedField(varName: 'ENABLE_UPDATE_CHECK', defaultValue: "1") static final String _enableUpdateChecker = _Env._enableUpdateChecker; - static bool get enableUpdateChecker => _enableUpdateChecker == "1"; + static bool get enableUpdateChecker => + DesktopTools.platform.isFlatpak || _enableUpdateChecker == "1"; } diff --git a/lib/components/artist/artist_card.dart b/lib/components/artist/artist_card.dart index 993e9f6a..434b90ad 100644 --- a/lib/components/artist/artist_card.dart +++ b/lib/components/artist/artist_card.dart @@ -5,8 +5,8 @@ import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:spotify/spotify.dart'; import 'package:spotube/components/shared/image/universal_image.dart'; import 'package:spotube/extensions/context.dart'; -import 'package:spotube/hooks/use_breakpoint_value.dart'; -import 'package:spotube/hooks/use_brightness_value.dart'; +import 'package:spotube/hooks/utils/use_breakpoint_value.dart'; +import 'package:spotube/hooks/utils/use_brightness_value.dart'; import 'package:spotube/provider/blacklist_provider.dart'; import 'package:spotube/utils/service_utils.dart'; import 'package:spotube/utils/type_conversion_utils.dart'; diff --git a/lib/hooks/use_synced_lyrics.dart b/lib/components/lyrics/use_synced_lyrics.dart similarity index 100% rename from lib/hooks/use_synced_lyrics.dart rename to lib/components/lyrics/use_synced_lyrics.dart diff --git a/lib/components/player/player.dart b/lib/components/player/player.dart index 811d24c5..889b7c5c 100644 --- a/lib/components/player/player.dart +++ b/lib/components/player/player.dart @@ -18,8 +18,8 @@ import 'package:spotube/components/shared/image/universal_image.dart'; import 'package:spotube/components/shared/panels/sliding_up_panel.dart'; import 'package:spotube/extensions/constrains.dart'; import 'package:spotube/extensions/context.dart'; -import 'package:spotube/hooks/use_custom_status_bar_color.dart'; -import 'package:spotube/hooks/use_palette_color.dart'; +import 'package:spotube/hooks/utils/use_custom_status_bar_color.dart'; +import 'package:spotube/hooks/utils/use_palette_color.dart'; import 'package:spotube/models/local_track.dart'; import 'package:spotube/pages/lyrics/lyrics.dart'; import 'package:spotube/provider/authentication_provider.dart'; diff --git a/lib/components/player/player_controls.dart b/lib/components/player/player_controls.dart index 07a6b7ba..1000af18 100644 --- a/lib/components/player/player_controls.dart +++ b/lib/components/player/player_controls.dart @@ -8,7 +8,7 @@ import 'package:spotube/collections/spotube_icons.dart'; import 'package:spotube/collections/intents.dart'; import 'package:spotube/extensions/context.dart'; import 'package:spotube/extensions/duration.dart'; -import 'package:spotube/hooks/use_progress.dart'; +import 'package:spotube/components/player/use_progress.dart'; import 'package:spotube/models/logger.dart'; import 'package:spotube/provider/proxy_playlist/proxy_playlist_provider.dart'; import 'package:spotube/services/audio_player/audio_player.dart'; diff --git a/lib/components/player/player_overlay.dart b/lib/components/player/player_overlay.dart index 354d1a36..4869a0fa 100644 --- a/lib/components/player/player_overlay.dart +++ b/lib/components/player/player_overlay.dart @@ -9,7 +9,7 @@ import 'package:spotube/components/root/spotube_navigation_bar.dart'; import 'package:spotube/components/shared/panels/sliding_up_panel.dart'; import 'package:spotube/collections/spotube_icons.dart'; import 'package:spotube/collections/intents.dart'; -import 'package:spotube/hooks/use_progress.dart'; +import 'package:spotube/components/player/use_progress.dart'; import 'package:spotube/components/player/player.dart'; import 'package:spotube/provider/proxy_playlist/proxy_playlist_provider.dart'; import 'package:spotube/services/audio_player/audio_player.dart'; diff --git a/lib/components/player/player_queue.dart b/lib/components/player/player_queue.dart index 9e303cb8..a6f69925 100644 --- a/lib/components/player/player_queue.dart +++ b/lib/components/player/player_queue.dart @@ -14,7 +14,7 @@ import 'package:spotube/components/shared/inter_scrollbar/inter_scrollbar.dart'; import 'package:spotube/components/shared/track_table/track_tile.dart'; import 'package:spotube/extensions/constrains.dart'; import 'package:spotube/extensions/context.dart'; -import 'package:spotube/hooks/use_auto_scroll_controller.dart'; +import 'package:spotube/hooks/controllers/use_auto_scroll_controller.dart'; import 'package:spotube/provider/proxy_playlist/proxy_playlist_provider.dart'; import 'package:spotube/utils/type_conversion_utils.dart'; diff --git a/lib/components/player/sibling_tracks_sheet.dart b/lib/components/player/sibling_tracks_sheet.dart index c4100b9a..f6702e0c 100644 --- a/lib/components/player/sibling_tracks_sheet.dart +++ b/lib/components/player/sibling_tracks_sheet.dart @@ -11,7 +11,7 @@ import 'package:spotube/components/shared/inter_scrollbar/inter_scrollbar.dart'; import 'package:spotube/extensions/constrains.dart'; import 'package:spotube/extensions/context.dart'; import 'package:spotube/extensions/duration.dart'; -import 'package:spotube/hooks/use_debounce.dart'; +import 'package:spotube/hooks/utils/use_debounce.dart'; import 'package:spotube/models/matched_track.dart'; import 'package:spotube/models/spotube_track.dart'; import 'package:spotube/provider/proxy_playlist/proxy_playlist_provider.dart'; diff --git a/lib/hooks/use_progress.dart b/lib/components/player/use_progress.dart similarity index 100% rename from lib/hooks/use_progress.dart rename to lib/components/player/use_progress.dart diff --git a/lib/components/root/bottom_player.dart b/lib/components/root/bottom_player.dart index 6d2e8319..4bc08fc0 100644 --- a/lib/components/root/bottom_player.dart +++ b/lib/components/root/bottom_player.dart @@ -14,7 +14,7 @@ import 'package:spotube/components/player/player_controls.dart'; import 'package:spotube/components/player/volume_slider.dart'; import 'package:spotube/extensions/constrains.dart'; import 'package:spotube/extensions/context.dart'; -import 'package:spotube/hooks/use_brightness_value.dart'; +import 'package:spotube/hooks/utils/use_brightness_value.dart'; import 'package:spotube/models/logger.dart'; import 'package:flutter/material.dart'; import 'package:spotube/provider/authentication_provider.dart'; diff --git a/lib/components/root/sidebar.dart b/lib/components/root/sidebar.dart index 7fb1b95f..f7cdcac3 100644 --- a/lib/components/root/sidebar.dart +++ b/lib/components/root/sidebar.dart @@ -11,8 +11,8 @@ import 'package:spotube/collections/spotube_icons.dart'; import 'package:spotube/components/shared/image/universal_image.dart'; import 'package:spotube/extensions/constrains.dart'; import 'package:spotube/extensions/context.dart'; -import 'package:spotube/hooks/use_brightness_value.dart'; -import 'package:spotube/hooks/use_sidebarx_controller.dart'; +import 'package:spotube/hooks/utils/use_brightness_value.dart'; +import 'package:spotube/hooks/controllers/use_sidebarx_controller.dart'; import 'package:spotube/provider/download_manager_provider.dart'; import 'package:spotube/provider/authentication_provider.dart'; diff --git a/lib/components/root/spotube_navigation_bar.dart b/lib/components/root/spotube_navigation_bar.dart index b62d19d1..d602f390 100644 --- a/lib/components/root/spotube_navigation_bar.dart +++ b/lib/components/root/spotube_navigation_bar.dart @@ -9,7 +9,7 @@ import 'package:spotube/collections/side_bar_tiles.dart'; import 'package:spotube/components/root/sidebar.dart'; import 'package:spotube/extensions/constrains.dart'; import 'package:spotube/extensions/context.dart'; -import 'package:spotube/hooks/use_brightness_value.dart'; +import 'package:spotube/hooks/utils/use_brightness_value.dart'; import 'package:spotube/provider/download_manager_provider.dart'; import 'package:spotube/provider/user_preferences_provider.dart'; diff --git a/lib/components/shared/horizontal_playbutton_card_view/horizontal_playbutton_card_view.dart b/lib/components/shared/horizontal_playbutton_card_view/horizontal_playbutton_card_view.dart index a415d721..f17a9714 100644 --- a/lib/components/shared/horizontal_playbutton_card_view/horizontal_playbutton_card_view.dart +++ b/lib/components/shared/horizontal_playbutton_card_view/horizontal_playbutton_card_view.dart @@ -8,7 +8,7 @@ import 'package:spotube/components/artist/artist_card.dart'; import 'package:spotube/components/playlist/playlist_card.dart'; import 'package:spotube/components/shared/shimmers/shimmer_playbutton_card.dart'; import 'package:spotube/components/shared/waypoint.dart'; -import 'package:spotube/hooks/use_breakpoint_value.dart'; +import 'package:spotube/hooks/utils/use_breakpoint_value.dart'; class HorizontalPlaybuttonCardView extends HookWidget { final Widget title; diff --git a/lib/components/shared/playbutton_card.dart b/lib/components/shared/playbutton_card.dart index 91c185c7..4fef72c0 100644 --- a/lib/components/shared/playbutton_card.dart +++ b/lib/components/shared/playbutton_card.dart @@ -6,8 +6,8 @@ import 'package:spotube/collections/assets.gen.dart'; import 'package:spotube/collections/spotube_icons.dart'; import 'package:spotube/components/shared/hover_builder.dart'; import 'package:spotube/components/shared/image/universal_image.dart'; -import 'package:spotube/hooks/use_breakpoint_value.dart'; -import 'package:spotube/hooks/use_brightness_value.dart'; +import 'package:spotube/hooks/utils/use_breakpoint_value.dart'; +import 'package:spotube/hooks/utils/use_brightness_value.dart'; final htmlTagRegexp = RegExp(r"<[^>]*>", caseSensitive: true); diff --git a/lib/components/shared/shimmers/shimmer_artist_profile.dart b/lib/components/shared/shimmers/shimmer_artist_profile.dart index 940c4e81..d0b0288f 100644 --- a/lib/components/shared/shimmers/shimmer_artist_profile.dart +++ b/lib/components/shared/shimmers/shimmer_artist_profile.dart @@ -4,7 +4,7 @@ import 'package:flutter_hooks/flutter_hooks.dart'; import 'package:skeleton_text/skeleton_text.dart'; import 'package:spotube/components/shared/shimmers/shimmer_track_tile.dart'; import 'package:spotube/extensions/theme.dart'; -import 'package:spotube/hooks/use_breakpoint_value.dart'; +import 'package:spotube/hooks/utils/use_breakpoint_value.dart'; class ShimmerArtistProfile extends HookWidget { const ShimmerArtistProfile({Key? key}) : super(key: key); diff --git a/lib/components/shared/shimmers/shimmer_categories.dart b/lib/components/shared/shimmers/shimmer_categories.dart index e9f442d4..9bc773da 100644 --- a/lib/components/shared/shimmers/shimmer_categories.dart +++ b/lib/components/shared/shimmers/shimmer_categories.dart @@ -3,7 +3,7 @@ import 'package:flutter_hooks/flutter_hooks.dart'; import 'package:spotube/components/shared/shimmers/shimmer_playbutton_card.dart'; import 'package:spotube/extensions/theme.dart'; -import 'package:spotube/hooks/use_breakpoint_value.dart'; +import 'package:spotube/hooks/utils/use_breakpoint_value.dart'; class ShimmerCategories extends HookWidget { const ShimmerCategories({Key? key}) : super(key: key); diff --git a/lib/components/shared/shimmers/shimmer_playbutton_card.dart b/lib/components/shared/shimmers/shimmer_playbutton_card.dart index 82da5bd9..2259c9b0 100644 --- a/lib/components/shared/shimmers/shimmer_playbutton_card.dart +++ b/lib/components/shared/shimmers/shimmer_playbutton_card.dart @@ -1,7 +1,7 @@ import 'package:flutter/material.dart'; import 'package:flutter_hooks/flutter_hooks.dart'; -import 'package:spotube/hooks/use_breakpoint_value.dart'; +import 'package:spotube/hooks/utils/use_breakpoint_value.dart'; class ShimmerPlaybuttonCardPainter extends CustomPainter { final Color background; diff --git a/lib/components/shared/themed_button_tab_bar.dart b/lib/components/shared/themed_button_tab_bar.dart index d38c3a19..079a4e8a 100644 --- a/lib/components/shared/themed_button_tab_bar.dart +++ b/lib/components/shared/themed_button_tab_bar.dart @@ -1,8 +1,8 @@ import 'package:buttons_tabbar/buttons_tabbar.dart'; import 'package:flutter/material.dart'; import 'package:flutter_hooks/flutter_hooks.dart'; -import 'package:spotube/hooks/use_breakpoint_value.dart'; -import 'package:spotube/hooks/use_brightness_value.dart'; +import 'package:spotube/hooks/utils/use_breakpoint_value.dart'; +import 'package:spotube/hooks/utils/use_brightness_value.dart'; import 'package:spotube/utils/platform.dart'; class ThemedButtonsTabBar extends HookWidget implements PreferredSizeWidget { diff --git a/lib/components/shared/track_table/track_collection_view/track_collection_view.dart b/lib/components/shared/track_table/track_collection_view/track_collection_view.dart index dcf01dd2..f211a521 100644 --- a/lib/components/shared/track_table/track_collection_view/track_collection_view.dart +++ b/lib/components/shared/track_table/track_collection_view/track_collection_view.dart @@ -13,8 +13,8 @@ import 'package:spotube/components/shared/page_window_title_bar.dart'; import 'package:spotube/components/shared/track_table/track_collection_view/track_collection_heading.dart'; import 'package:spotube/components/shared/track_table/tracks_table_view.dart'; import 'package:spotube/extensions/context.dart'; -import 'package:spotube/hooks/use_custom_status_bar_color.dart'; -import 'package:spotube/hooks/use_palette_color.dart'; +import 'package:spotube/hooks/utils/use_custom_status_bar_color.dart'; +import 'package:spotube/hooks/utils/use_palette_color.dart'; import 'package:spotube/models/logger.dart'; import 'package:flutter/material.dart'; import 'package:spotify/spotify.dart'; @@ -237,7 +237,7 @@ class TrackCollectionView extends HookConsumerWidget { ), ); } - + return TracksTableView( (tracksSnapshot.data ?? []).map( (track) { diff --git a/lib/hooks/use_disable_battery_optimizations.dart b/lib/hooks/configurators/use_disable_battery_optimizations.dart similarity index 96% rename from lib/hooks/use_disable_battery_optimizations.dart rename to lib/hooks/configurators/use_disable_battery_optimizations.dart index 267655b6..c1155d19 100644 --- a/lib/hooks/use_disable_battery_optimizations.dart +++ b/lib/hooks/configurators/use_disable_battery_optimizations.dart @@ -1,7 +1,7 @@ import 'package:disable_battery_optimization/disable_battery_optimization.dart'; import 'package:flutter_desktop_tools/flutter_desktop_tools.dart'; import 'package:shared_preferences/shared_preferences.dart'; -import 'package:spotube/hooks/use_async_effect.dart'; +import 'package:spotube/hooks/utils/use_async_effect.dart'; bool _asked = false; void useDisableBatteryOptimizations() { diff --git a/lib/hooks/use_get_storage_perms.dart b/lib/hooks/configurators/use_get_storage_perms.dart similarity index 95% rename from lib/hooks/use_get_storage_perms.dart rename to lib/hooks/configurators/use_get_storage_perms.dart index d83c60f6..3fcb369b 100644 --- a/lib/hooks/use_get_storage_perms.dart +++ b/lib/hooks/configurators/use_get_storage_perms.dart @@ -4,7 +4,7 @@ import 'package:flutter_hooks/flutter_hooks.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:permission_handler/permission_handler.dart'; import 'package:spotube/components/library/user_local_tracks.dart'; -import 'package:spotube/hooks/use_async_effect.dart'; +import 'package:spotube/hooks/utils/use_async_effect.dart'; void useGetStoragePermissions(WidgetRef ref) { final isMounted = useIsMounted(); diff --git a/lib/hooks/use_init_sys_tray.dart b/lib/hooks/configurators/use_init_sys_tray.dart similarity index 100% rename from lib/hooks/use_init_sys_tray.dart rename to lib/hooks/configurators/use_init_sys_tray.dart diff --git a/lib/hooks/use_update_checker.dart b/lib/hooks/configurators/use_update_checker.dart similarity index 98% rename from lib/hooks/use_update_checker.dart rename to lib/hooks/configurators/use_update_checker.dart index 33df5397..515d6701 100644 --- a/lib/hooks/use_update_checker.dart +++ b/lib/hooks/configurators/use_update_checker.dart @@ -8,7 +8,7 @@ import 'package:http/http.dart' as http; import 'package:spotube/collections/env.dart'; import 'package:spotube/components/shared/links/anchor_button.dart'; -import 'package:spotube/hooks/use_package_info.dart'; +import 'package:spotube/hooks/controllers/use_package_info.dart'; import 'package:spotube/provider/user_preferences_provider.dart'; import 'package:url_launcher/url_launcher_string.dart'; import 'package:version/version.dart'; diff --git a/lib/hooks/use_auto_scroll_controller.dart b/lib/hooks/controllers/use_auto_scroll_controller.dart similarity index 100% rename from lib/hooks/use_auto_scroll_controller.dart rename to lib/hooks/controllers/use_auto_scroll_controller.dart diff --git a/lib/hooks/use_package_info.dart b/lib/hooks/controllers/use_package_info.dart similarity index 100% rename from lib/hooks/use_package_info.dart rename to lib/hooks/controllers/use_package_info.dart diff --git a/lib/hooks/use_sidebarx_controller.dart b/lib/hooks/controllers/use_sidebarx_controller.dart similarity index 100% rename from lib/hooks/use_sidebarx_controller.dart rename to lib/hooks/controllers/use_sidebarx_controller.dart diff --git a/lib/hooks/use_spotify_infinite_query.dart b/lib/hooks/spotify/use_spotify_infinite_query.dart similarity index 100% rename from lib/hooks/use_spotify_infinite_query.dart rename to lib/hooks/spotify/use_spotify_infinite_query.dart diff --git a/lib/hooks/use_spotify_mutation.dart b/lib/hooks/spotify/use_spotify_mutation.dart similarity index 100% rename from lib/hooks/use_spotify_mutation.dart rename to lib/hooks/spotify/use_spotify_mutation.dart diff --git a/lib/hooks/use_spotify_query.dart b/lib/hooks/spotify/use_spotify_query.dart similarity index 100% rename from lib/hooks/use_spotify_query.dart rename to lib/hooks/spotify/use_spotify_query.dart diff --git a/lib/hooks/use_is_current_route.dart b/lib/hooks/use_is_current_route.dart deleted file mode 100644 index b7b6490a..00000000 --- a/lib/hooks/use_is_current_route.dart +++ /dev/null @@ -1,18 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:flutter_hooks/flutter_hooks.dart'; -import 'package:go_router/go_router.dart'; - -bool? useIsCurrentRoute([String matcher = "/"]) { - final isCurrentRoute = useState(null); - final context = useContext(); - useEffect(() { - WidgetsBinding.instance.addPostFrameCallback((timer) { - final isCurrent = GoRouterState.of(context).matchedLocation == matcher; - if (isCurrent != isCurrentRoute.value) { - isCurrentRoute.value = isCurrent; - } - }); - return null; - }); - return isCurrentRoute.value; -} diff --git a/lib/hooks/use_shared_preferences.dart b/lib/hooks/use_shared_preferences.dart deleted file mode 100644 index 922beaa6..00000000 --- a/lib/hooks/use_shared_preferences.dart +++ /dev/null @@ -1,9 +0,0 @@ -import 'package:flutter_hooks/flutter_hooks.dart'; -import 'package:shared_preferences/shared_preferences.dart'; - -SharedPreferences? useSharedPreferences() { - final future = useMemoized(SharedPreferences.getInstance); - final snapshot = useFuture(future, initialData: null); - - return snapshot.data; -} diff --git a/lib/hooks/use_async_effect.dart b/lib/hooks/utils/use_async_effect.dart similarity index 100% rename from lib/hooks/use_async_effect.dart rename to lib/hooks/utils/use_async_effect.dart diff --git a/lib/hooks/use_breakpoint_value.dart b/lib/hooks/utils/use_breakpoint_value.dart similarity index 100% rename from lib/hooks/use_breakpoint_value.dart rename to lib/hooks/utils/use_breakpoint_value.dart diff --git a/lib/hooks/use_brightness_value.dart b/lib/hooks/utils/use_brightness_value.dart similarity index 100% rename from lib/hooks/use_brightness_value.dart rename to lib/hooks/utils/use_brightness_value.dart diff --git a/lib/hooks/use_custom_status_bar_color.dart b/lib/hooks/utils/use_custom_status_bar_color.dart similarity index 100% rename from lib/hooks/use_custom_status_bar_color.dart rename to lib/hooks/utils/use_custom_status_bar_color.dart diff --git a/lib/hooks/use_debounce.dart b/lib/hooks/utils/use_debounce.dart similarity index 100% rename from lib/hooks/use_debounce.dart rename to lib/hooks/utils/use_debounce.dart diff --git a/lib/hooks/use_force_update.dart b/lib/hooks/utils/use_force_update.dart similarity index 100% rename from lib/hooks/use_force_update.dart rename to lib/hooks/utils/use_force_update.dart diff --git a/lib/hooks/use_palette_color.dart b/lib/hooks/utils/use_palette_color.dart similarity index 100% rename from lib/hooks/use_palette_color.dart rename to lib/hooks/utils/use_palette_color.dart diff --git a/lib/main.dart b/lib/main.dart index b92dfaf1..e1f0bd53 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -14,8 +14,8 @@ import 'package:metadata_god/metadata_god.dart'; import 'package:shared_preferences/shared_preferences.dart'; import 'package:spotube/collections/routes.dart'; import 'package:spotube/collections/intents.dart'; -import 'package:spotube/hooks/use_disable_battery_optimizations.dart'; -import 'package:spotube/hooks/use_get_storage_perms.dart'; +import 'package:spotube/hooks/configurators/use_disable_battery_optimizations.dart'; +import 'package:spotube/hooks/configurators/use_get_storage_perms.dart'; import 'package:spotube/l10n/l10n.dart'; import 'package:spotube/models/logger.dart'; import 'package:spotube/models/matched_track.dart'; @@ -29,7 +29,7 @@ import 'package:spotube/themes/theme.dart'; import 'package:spotube/utils/persisted_state_notifier.dart'; import 'package:system_theme/system_theme.dart'; import 'package:path_provider/path_provider.dart'; -import 'package:spotube/hooks/use_init_sys_tray.dart'; +import 'package:spotube/hooks/configurators/use_init_sys_tray.dart'; import 'package:flutter_gen/gen_l10n/app_localizations.dart'; import 'package:flutter_native_splash/flutter_native_splash.dart'; import 'package:flutter_displaymode/flutter_displaymode.dart'; diff --git a/lib/pages/artist/artist.dart b/lib/pages/artist/artist.dart index 2f169583..299bf9f5 100644 --- a/lib/pages/artist/artist.dart +++ b/lib/pages/artist/artist.dart @@ -16,7 +16,7 @@ import 'package:spotube/components/artist/artist_album_list.dart'; import 'package:spotube/components/artist/artist_card.dart'; import 'package:spotube/extensions/constrains.dart'; import 'package:spotube/extensions/context.dart'; -import 'package:spotube/hooks/use_breakpoint_value.dart'; +import 'package:spotube/hooks/utils/use_breakpoint_value.dart'; import 'package:spotube/models/logger.dart'; import 'package:spotube/provider/authentication_provider.dart'; import 'package:spotube/provider/blacklist_provider.dart'; diff --git a/lib/pages/lyrics/lyrics.dart b/lib/pages/lyrics/lyrics.dart index c97649d7..ac4b61e7 100644 --- a/lib/pages/lyrics/lyrics.dart +++ b/lib/pages/lyrics/lyrics.dart @@ -11,8 +11,8 @@ import 'package:spotube/components/shared/image/universal_image.dart'; import 'package:spotube/components/shared/themed_button_tab_bar.dart'; import 'package:spotube/extensions/constrains.dart'; import 'package:spotube/extensions/context.dart'; -import 'package:spotube/hooks/use_custom_status_bar_color.dart'; -import 'package:spotube/hooks/use_palette_color.dart'; +import 'package:spotube/hooks/utils/use_custom_status_bar_color.dart'; +import 'package:spotube/hooks/utils/use_palette_color.dart'; import 'package:spotube/pages/lyrics/plain_lyrics.dart'; import 'package:spotube/pages/lyrics/synced_lyrics.dart'; import 'package:spotube/provider/authentication_provider.dart'; diff --git a/lib/pages/lyrics/mini_lyrics.dart b/lib/pages/lyrics/mini_lyrics.dart index ad3a13ef..be32dbc9 100644 --- a/lib/pages/lyrics/mini_lyrics.dart +++ b/lib/pages/lyrics/mini_lyrics.dart @@ -11,7 +11,7 @@ import 'package:spotube/components/root/sidebar.dart'; import 'package:spotube/components/shared/fallbacks/anonymous_fallback.dart'; import 'package:spotube/components/shared/page_window_title_bar.dart'; import 'package:spotube/extensions/context.dart'; -import 'package:spotube/hooks/use_force_update.dart'; +import 'package:spotube/hooks/utils/use_force_update.dart'; import 'package:spotube/pages/lyrics/plain_lyrics.dart'; import 'package:spotube/pages/lyrics/synced_lyrics.dart'; import 'package:spotube/provider/authentication_provider.dart'; diff --git a/lib/pages/lyrics/synced_lyrics.dart b/lib/pages/lyrics/synced_lyrics.dart index 5f2afbc9..8147915f 100644 --- a/lib/pages/lyrics/synced_lyrics.dart +++ b/lib/pages/lyrics/synced_lyrics.dart @@ -7,8 +7,8 @@ import 'package:spotube/collections/spotube_icons.dart'; import 'package:spotube/components/lyrics/zoom_controls.dart'; import 'package:spotube/components/shared/shimmers/shimmer_lyrics.dart'; import 'package:spotube/extensions/constrains.dart'; -import 'package:spotube/hooks/use_auto_scroll_controller.dart'; -import 'package:spotube/hooks/use_synced_lyrics.dart'; +import 'package:spotube/hooks/controllers/use_auto_scroll_controller.dart'; +import 'package:spotube/components/lyrics/use_synced_lyrics.dart'; import 'package:scroll_to_index/scroll_to_index.dart'; import 'package:spotube/provider/proxy_playlist/proxy_playlist_provider.dart'; import 'package:spotube/services/audio_player/audio_player.dart'; diff --git a/lib/pages/root/root_app.dart b/lib/pages/root/root_app.dart index 5797b63f..87be587c 100644 --- a/lib/pages/root/root_app.dart +++ b/lib/pages/root/root_app.dart @@ -15,7 +15,7 @@ import 'package:spotube/components/root/bottom_player.dart'; import 'package:spotube/components/root/sidebar.dart'; import 'package:spotube/components/root/spotube_navigation_bar.dart'; import 'package:spotube/extensions/context.dart'; -import 'package:spotube/hooks/use_update_checker.dart'; +import 'package:spotube/hooks/configurators/use_update_checker.dart'; import 'package:spotube/provider/download_manager_provider.dart'; import 'package:spotube/utils/persisted_state_notifier.dart'; diff --git a/lib/pages/settings/about.dart b/lib/pages/settings/about.dart index 97a0aae9..00263680 100644 --- a/lib/pages/settings/about.dart +++ b/lib/pages/settings/about.dart @@ -5,7 +5,7 @@ import 'package:spotube/components/shared/image/universal_image.dart'; import 'package:spotube/components/shared/links/hyper_link.dart'; import 'package:spotube/components/shared/page_window_title_bar.dart'; import 'package:spotube/extensions/context.dart'; -import 'package:spotube/hooks/use_package_info.dart'; +import 'package:spotube/hooks/controllers/use_package_info.dart'; import 'package:flutter_svg/flutter_svg.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; diff --git a/lib/services/mutations/album.dart b/lib/services/mutations/album.dart index dfc72fcc..144b6a8f 100644 --- a/lib/services/mutations/album.dart +++ b/lib/services/mutations/album.dart @@ -1,6 +1,6 @@ import 'package:fl_query/fl_query.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; -import 'package:spotube/hooks/use_spotify_mutation.dart'; +import 'package:spotube/hooks/spotify/use_spotify_mutation.dart'; class AlbumMutations { const AlbumMutations(); diff --git a/lib/services/mutations/playlist.dart b/lib/services/mutations/playlist.dart index 176b5cd8..a88e8512 100644 --- a/lib/services/mutations/playlist.dart +++ b/lib/services/mutations/playlist.dart @@ -2,7 +2,7 @@ import 'package:fl_query/fl_query.dart'; import 'package:flutter/material.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:spotify/spotify.dart'; -import 'package:spotube/hooks/use_spotify_mutation.dart'; +import 'package:spotube/hooks/spotify/use_spotify_mutation.dart'; import 'package:spotube/services/queries/queries.dart'; typedef PlaylistCRUDVariables = ({ diff --git a/lib/services/mutations/track.dart b/lib/services/mutations/track.dart index 2245c497..f8208b5e 100644 --- a/lib/services/mutations/track.dart +++ b/lib/services/mutations/track.dart @@ -1,6 +1,6 @@ import 'package:fl_query/fl_query.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; -import 'package:spotube/hooks/use_spotify_mutation.dart'; +import 'package:spotube/hooks/spotify/use_spotify_mutation.dart'; class TrackMutations { const TrackMutations(); diff --git a/lib/services/queries/album.dart b/lib/services/queries/album.dart index 53fcaf86..2e2e8f14 100644 --- a/lib/services/queries/album.dart +++ b/lib/services/queries/album.dart @@ -2,8 +2,8 @@ import 'package:catcher_2/catcher_2.dart'; import 'package:fl_query/fl_query.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:spotify/spotify.dart'; -import 'package:spotube/hooks/use_spotify_infinite_query.dart'; -import 'package:spotube/hooks/use_spotify_query.dart'; +import 'package:spotube/hooks/spotify/use_spotify_infinite_query.dart'; +import 'package:spotube/hooks/spotify/use_spotify_query.dart'; import 'package:spotube/provider/user_preferences_provider.dart'; class AlbumQueries { diff --git a/lib/services/queries/artist.dart b/lib/services/queries/artist.dart index 6dad2718..7501d619 100644 --- a/lib/services/queries/artist.dart +++ b/lib/services/queries/artist.dart @@ -1,8 +1,8 @@ import 'package:fl_query/fl_query.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:spotify/spotify.dart'; -import 'package:spotube/hooks/use_spotify_infinite_query.dart'; -import 'package:spotube/hooks/use_spotify_query.dart'; +import 'package:spotube/hooks/spotify/use_spotify_infinite_query.dart'; +import 'package:spotube/hooks/spotify/use_spotify_query.dart'; class ArtistQueries { const ArtistQueries(); diff --git a/lib/services/queries/category.dart b/lib/services/queries/category.dart index 33668d82..dbdd2a11 100644 --- a/lib/services/queries/category.dart +++ b/lib/services/queries/category.dart @@ -4,7 +4,7 @@ import 'package:flutter_hooks/flutter_hooks.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:spotify/spotify.dart'; import 'package:spotube/extensions/context.dart'; -import 'package:spotube/hooks/use_spotify_infinite_query.dart'; +import 'package:spotube/hooks/spotify/use_spotify_infinite_query.dart'; import 'package:spotube/provider/custom_spotify_endpoint_provider.dart'; import 'package:spotube/provider/user_preferences_provider.dart'; diff --git a/lib/services/queries/lyrics.dart b/lib/services/queries/lyrics.dart index 989a2e97..b51016b4 100644 --- a/lib/services/queries/lyrics.dart +++ b/lib/services/queries/lyrics.dart @@ -6,7 +6,7 @@ import 'package:fl_query_hooks/fl_query_hooks.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:spotify/spotify.dart'; import 'package:spotube/extensions/map.dart'; -import 'package:spotube/hooks/use_spotify_query.dart'; +import 'package:spotube/hooks/spotify/use_spotify_query.dart'; import 'package:spotube/models/lyrics.dart'; import 'package:spotube/models/spotube_track.dart'; import 'package:spotube/utils/service_utils.dart'; diff --git a/lib/services/queries/playlist.dart b/lib/services/queries/playlist.dart index c0434a6e..c4532aa8 100644 --- a/lib/services/queries/playlist.dart +++ b/lib/services/queries/playlist.dart @@ -7,8 +7,8 @@ import 'package:spotify/spotify.dart'; import 'package:spotube/components/library/playlist_generate/recommendation_attribute_dials.dart'; import 'package:spotube/extensions/map.dart'; import 'package:spotube/extensions/track.dart'; -import 'package:spotube/hooks/use_spotify_infinite_query.dart'; -import 'package:spotube/hooks/use_spotify_query.dart'; +import 'package:spotube/hooks/spotify/use_spotify_infinite_query.dart'; +import 'package:spotube/hooks/spotify/use_spotify_query.dart'; import 'package:spotube/pages/library/playlist_generate/playlist_generate.dart'; import 'package:spotube/provider/custom_spotify_endpoint_provider.dart'; import 'package:spotube/provider/user_preferences_provider.dart'; diff --git a/lib/services/queries/search.dart b/lib/services/queries/search.dart index eaf9c1b7..f11f4399 100644 --- a/lib/services/queries/search.dart +++ b/lib/services/queries/search.dart @@ -1,7 +1,7 @@ import 'package:fl_query/fl_query.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:spotify/spotify.dart'; -import 'package:spotube/hooks/use_spotify_infinite_query.dart'; +import 'package:spotube/hooks/spotify/use_spotify_infinite_query.dart'; class SearchQueries { const SearchQueries(); diff --git a/lib/services/queries/user.dart b/lib/services/queries/user.dart index 89792592..40799c1e 100644 --- a/lib/services/queries/user.dart +++ b/lib/services/queries/user.dart @@ -2,7 +2,7 @@ import 'package:fl_query/fl_query.dart'; import 'package:flutter_hooks/flutter_hooks.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:spotify/spotify.dart'; -import 'package:spotube/hooks/use_spotify_query.dart'; +import 'package:spotube/hooks/spotify/use_spotify_query.dart'; import 'package:spotube/provider/authentication_provider.dart'; import 'package:spotube/utils/type_conversion_utils.dart'; From dc980b024edad3132e72cbb2f0087297a4b76469 Mon Sep 17 00:00:00 2001 From: Kingkor Roy Tirtho Date: Tue, 14 Nov 2023 20:58:16 +0600 Subject: [PATCH 020/195] fix(genres): lag while scrolling --- lib/components/artist/artist_album_list.dart | 1 + lib/components/genre/category_card.dart | 1 + .../horizontal_playbutton_card_view.dart | 28 ++++++------- lib/pages/home/genres.dart | 25 ++++-------- lib/pages/home/personalized.dart | 3 ++ lib/pages/search/sections/albums.dart | 1 + lib/pages/search/sections/artists.dart | 1 + lib/pages/search/sections/playlists.dart | 1 + lib/pages/settings/settings.dart | 40 +++++++++---------- pubspec.lock | 8 ++++ pubspec.yaml | 1 + 11 files changed, 56 insertions(+), 54 deletions(-) diff --git a/lib/components/artist/artist_album_list.dart b/lib/components/artist/artist_album_list.dart index e075cd60..5114170c 100644 --- a/lib/components/artist/artist_album_list.dart +++ b/lib/components/artist/artist_album_list.dart @@ -29,6 +29,7 @@ class ArtistAlbumList extends HookConsumerWidget { final theme = Theme.of(context); return HorizontalPlaybuttonCardView( + isLoadingNextPage: albumsQuery.isLoadingNextPage, hasNextPage: albumsQuery.hasNextPage, items: albums, onFetchMore: albumsQuery.fetchNext, diff --git a/lib/components/genre/category_card.dart b/lib/components/genre/category_card.dart index d5809b5d..7f580157 100644 --- a/lib/components/genre/category_card.dart +++ b/lib/components/genre/category_card.dart @@ -42,6 +42,7 @@ class CategoryCard extends HookConsumerWidget { return HorizontalPlaybuttonCardView( title: Text(category.name!), + isLoadingNextPage: playlistQuery.isLoadingNextPage, hasNextPage: playlistQuery.hasNextPage, items: playlists, onFetchMore: playlistQuery.fetchNext, diff --git a/lib/components/shared/horizontal_playbutton_card_view/horizontal_playbutton_card_view.dart b/lib/components/shared/horizontal_playbutton_card_view/horizontal_playbutton_card_view.dart index f17a9714..dca77233 100644 --- a/lib/components/shared/horizontal_playbutton_card_view/horizontal_playbutton_card_view.dart +++ b/lib/components/shared/horizontal_playbutton_card_view/horizontal_playbutton_card_view.dart @@ -7,19 +7,22 @@ import 'package:spotube/components/album/album_card.dart'; import 'package:spotube/components/artist/artist_card.dart'; import 'package:spotube/components/playlist/playlist_card.dart'; import 'package:spotube/components/shared/shimmers/shimmer_playbutton_card.dart'; -import 'package:spotube/components/shared/waypoint.dart'; import 'package:spotube/hooks/utils/use_breakpoint_value.dart'; +import 'package:very_good_infinite_list/very_good_infinite_list.dart'; class HorizontalPlaybuttonCardView extends HookWidget { final Widget title; final List items; final VoidCallback onFetchMore; + final bool isLoadingNextPage; final bool hasNextPage; + const HorizontalPlaybuttonCardView({ required this.title, required this.items, required this.hasNextPage, required this.onFetchMore, + required this.isLoadingNextPage, Key? key, }) : assert( items is List || @@ -58,23 +61,18 @@ class HorizontalPlaybuttonCardView extends HookWidget { PointerDeviceKind.mouse, }, ), - child: ListView.builder( - controller: scrollController, + child: InfiniteList( + scrollController: scrollController, scrollDirection: Axis.horizontal, padding: const EdgeInsets.symmetric(vertical: 8.0), - itemCount: items.length + 1, + itemCount: items.length, + onFetchData: onFetchMore, + loadingBuilder: (context) => const ShimmerPlaybuttonCard(), + emptyBuilder: (context) => + const ShimmerPlaybuttonCard(count: 5), + isLoading: isLoadingNextPage, + hasReachedMax: !hasNextPage, itemBuilder: (context, index) { - if (index == items.length) { - if (!hasNextPage) { - return const SizedBox.shrink(); - } - return Waypoint( - controller: scrollController, - onTouchEdge: onFetchMore, - isGrid: true, - child: const ShimmerPlaybuttonCard(), - ); - } final item = items[index]; return switch (item.runtimeType) { diff --git a/lib/pages/home/genres.dart b/lib/pages/home/genres.dart index 6861853d..84082811 100644 --- a/lib/pages/home/genres.dart +++ b/lib/pages/home/genres.dart @@ -7,12 +7,12 @@ import 'package:spotify/spotify.dart'; import 'package:spotube/collections/spotube_icons.dart'; import 'package:spotube/components/genre/category_card.dart'; import 'package:spotube/components/shared/expandable_search/expandable_search.dart'; -import 'package:spotube/components/shared/inter_scrollbar/inter_scrollbar.dart'; import 'package:spotube/components/shared/shimmers/shimmer_categories.dart'; import 'package:spotube/components/shared/waypoint.dart'; import 'package:spotube/provider/user_preferences_provider.dart'; import 'package:spotube/services/queries/queries.dart'; +import 'package:very_good_infinite_list/very_good_infinite_list.dart'; class GenrePage extends HookConsumerWidget { const GenrePage({Key? key}) : super(key: key); @@ -79,24 +79,15 @@ class GenrePage extends HookConsumerWidget { const ShimmerCategories() else Expanded( - child: ListView.builder( - controller: scrollController, + child: InfiniteList( + scrollController: scrollController, itemCount: categories.length, + onFetchData: categoriesQuery.fetchNext, + isLoading: categoriesQuery.isLoadingNextPage, + hasReachedMax: !categoriesQuery.hasNextPage, + loadingBuilder: (context) => const ShimmerCategories(), itemBuilder: (context, index) { - return AnimatedSwitcher( - transitionBuilder: (child, animation) { - return FadeTransition( - opacity: animation, - child: child, - ); - }, - duration: const Duration(milliseconds: 300), - child: searchController.text.isEmpty && - index == categories.length - 1 && - categoriesQuery.hasNextPage - ? const ShimmerCategories() - : CategoryCard(categories[index]), - ); + return CategoryCard(categories[index]); }, ), ), diff --git a/lib/pages/home/personalized.dart b/lib/pages/home/personalized.dart index b596a820..16cfc3a8 100644 --- a/lib/pages/home/personalized.dart +++ b/lib/pages/home/personalized.dart @@ -56,6 +56,7 @@ class PersonalizedPage extends HookConsumerWidget { HorizontalPlaybuttonCardView( items: playlists.toList(), title: Text(context.l10n.featured), + isLoadingNextPage: featuredPlaylistsQuery.isLoadingNextPage, hasNextPage: featuredPlaylistsQuery.hasNextPage, onFetchMore: featuredPlaylistsQuery.fetchNext, ), @@ -66,6 +67,7 @@ class PersonalizedPage extends HookConsumerWidget { HorizontalPlaybuttonCardView( items: albums, title: Text(context.l10n.new_releases), + isLoadingNextPage: newReleases.isLoadingNextPage, hasNextPage: newReleases.hasNextPage, onFetchMore: newReleases.fetchNext, ), @@ -81,6 +83,7 @@ class PersonalizedPage extends HookConsumerWidget { items: playlists, title: Text(item["name"] ?? ""), hasNextPage: false, + isLoadingNextPage: false, onFetchMore: () {}, ); }) diff --git a/lib/pages/search/sections/albums.dart b/lib/pages/search/sections/albums.dart index 787a1924..8aa33feb 100644 --- a/lib/pages/search/sections/albums.dart +++ b/lib/pages/search/sections/albums.dart @@ -30,6 +30,7 @@ class SearchAlbumsSection extends HookConsumerWidget { ); return HorizontalPlaybuttonCardView( + isLoadingNextPage: query.isLoadingNextPage, hasNextPage: query.hasNextPage, items: albums, onFetchMore: query.fetchNext, diff --git a/lib/pages/search/sections/artists.dart b/lib/pages/search/sections/artists.dart index 7abd5250..b736bf13 100644 --- a/lib/pages/search/sections/artists.dart +++ b/lib/pages/search/sections/artists.dart @@ -28,6 +28,7 @@ class SearchArtistsSection extends HookConsumerWidget { ); return HorizontalPlaybuttonCardView( + isLoadingNextPage: query.isLoadingNextPage, hasNextPage: query.hasNextPage, items: artists, onFetchMore: query.fetchNext, diff --git a/lib/pages/search/sections/playlists.dart b/lib/pages/search/sections/playlists.dart index 620e914b..47614a70 100644 --- a/lib/pages/search/sections/playlists.dart +++ b/lib/pages/search/sections/playlists.dart @@ -26,6 +26,7 @@ class SearchPlaylistsSection extends HookConsumerWidget { ); return HorizontalPlaybuttonCardView( + isLoadingNextPage: query.isLoadingNextPage, hasNextPage: query.hasNextPage, items: playlists, onFetchMore: query.fetchNext, diff --git a/lib/pages/settings/settings.dart b/lib/pages/settings/settings.dart index 84b51d4d..f14fb453 100644 --- a/lib/pages/settings/settings.dart +++ b/lib/pages/settings/settings.dart @@ -3,7 +3,6 @@ import 'package:flutter/material.dart'; import 'package:flutter_desktop_tools/flutter_desktop_tools.dart'; import 'package:flutter_hooks/flutter_hooks.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; -import 'package:spotube/components/shared/inter_scrollbar/inter_scrollbar.dart'; import 'package:spotube/components/shared/page_window_title_bar.dart'; import 'package:spotube/extensions/context.dart'; import 'package:spotube/pages/settings/sections/about.dart'; @@ -37,29 +36,26 @@ class SettingsPage extends HookConsumerWidget { Flexible( child: Container( constraints: const BoxConstraints(maxWidth: 1366), - child: InterScrollbar( + child: ListView( controller: controller, - child: ListView( - controller: controller, - children: [ - const SettingsAccountSection(), - const SettingsLanguageRegionSection(), - const SettingsAppearanceSection(), - const SettingsPlaybackSection(), - const SettingsDownloadsSection(), - if (DesktopTools.platform.isDesktop) - const SettingsDesktopSection(), - if (!kIsWeb) const SettingsDevelopersSection(), - const SettingsAboutSection(), - Center( - child: FilledButton( - onPressed: preferencesNotifier.reset, - child: Text(context.l10n.restore_defaults), - ), + children: [ + const SettingsAccountSection(), + const SettingsLanguageRegionSection(), + const SettingsAppearanceSection(), + const SettingsPlaybackSection(), + const SettingsDownloadsSection(), + if (DesktopTools.platform.isDesktop) + const SettingsDesktopSection(), + if (!kIsWeb) const SettingsDevelopersSection(), + const SettingsAboutSection(), + Center( + child: FilledButton( + onPressed: preferencesNotifier.reset, + child: Text(context.l10n.restore_defaults), ), - const SizedBox(height: 10), - ], - ), + ), + const SizedBox(height: 10), + ], ), ), ), diff --git a/pubspec.lock b/pubspec.lock index 3d072e09..39e92028 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -2180,6 +2180,14 @@ packages: url: "https://pub.dev" source: hosted version: "3.0.2" + very_good_infinite_list: + dependency: "direct main" + description: + name: very_good_infinite_list + sha256: "6f5ad429edbce6084e1c600e56b26b1de8c6b138e8e8fc2de41b686166029aa5" + url: "https://pub.dev" + source: hosted + version: "0.7.1" visibility_detector: dependency: "direct main" description: diff --git a/pubspec.yaml b/pubspec.yaml index f9c1155f..590aaae4 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -110,6 +110,7 @@ dependencies: git: url: https://github.com/thielepaul/flutter-draggable-scrollbar.git ref: cfd570035bf393de541d32e9b28808b5d7e602df + very_good_infinite_list: ^0.7.1 dev_dependencies: build_runner: ^2.3.2 From 57c03ad045e9b9a4ceb13ac8b061d79396990949 Mon Sep 17 00:00:00 2001 From: Kingkor Roy Tirtho Date: Tue, 14 Nov 2023 22:48:02 +0600 Subject: [PATCH 021/195] refactor: use json serializer for preferences --- lib/components/library/user_local_tracks.dart | 2 +- .../player/sibling_tracks_sheet.dart | 3 +- lib/components/root/bottom_player.dart | 3 +- lib/components/root/sidebar.dart | 3 +- .../root/spotube_navigation_bar.dart | 3 +- .../settings/color_scheme_picker_dialog.dart | 2 +- .../shared/dialogs/piped_down_dialog.dart | 2 +- .../shared/page_window_title_bar.dart | 3 +- .../shared/track_table/tracks_table_view.dart | 3 +- .../configurators/use_init_sys_tray.dart | 2 +- .../configurators/use_update_checker.dart | 2 +- lib/main.dart | 2 +- lib/models/spotube_track.dart | 2 +- lib/pages/home/genres.dart | 2 +- .../playlist_generate/playlist_generate.dart | 2 +- lib/pages/settings/sections/about.dart | 2 +- lib/pages/settings/sections/appearance.dart | 4 +- lib/pages/settings/sections/desktop.dart | 3 +- lib/pages/settings/sections/downloads.dart | 2 +- .../settings/sections/language_region.dart | 2 +- lib/pages/settings/sections/playback.dart | 3 +- lib/pages/settings/settings.dart | 2 +- lib/provider/download_manager_provider.dart | 3 +- .../proxy_playlist/next_fetcher_mixin.dart | 2 +- .../proxy_playlist_provider.dart | 3 +- .../user_preferences_provider.dart | 165 ++++++++ .../user_preferences_state.dart | 273 ++++++++++++ .../user_preferences_state.g.dart | 381 +++++++++++++++++ lib/provider/user_preferences_provider.dart | 391 ------------------ lib/provider/youtube_provider.dart | 2 +- lib/services/queries/album.dart | 2 +- lib/services/queries/category.dart | 2 +- lib/services/queries/playlist.dart | 2 +- lib/services/queries/views.dart | 2 +- lib/services/youtube/youtube.dart | 2 +- 35 files changed, 861 insertions(+), 423 deletions(-) create mode 100644 lib/provider/user_preferences/user_preferences_provider.dart create mode 100644 lib/provider/user_preferences/user_preferences_state.dart create mode 100644 lib/provider/user_preferences/user_preferences_state.g.dart delete mode 100644 lib/provider/user_preferences_provider.dart diff --git a/lib/components/library/user_local_tracks.dart b/lib/components/library/user_local_tracks.dart index 0546c2a7..354d9fe6 100644 --- a/lib/components/library/user_local_tracks.dart +++ b/lib/components/library/user_local_tracks.dart @@ -22,7 +22,7 @@ import 'package:spotube/components/shared/track_table/track_tile.dart'; import 'package:spotube/extensions/context.dart'; import 'package:spotube/models/local_track.dart'; import 'package:spotube/provider/proxy_playlist/proxy_playlist_provider.dart'; -import 'package:spotube/provider/user_preferences_provider.dart'; +import 'package:spotube/provider/user_preferences/user_preferences_provider.dart'; import 'package:spotube/utils/service_utils.dart'; import 'package:spotube/utils/type_conversion_utils.dart'; import 'package:flutter_rust_bridge/flutter_rust_bridge.dart' show FfiException; diff --git a/lib/components/player/sibling_tracks_sheet.dart b/lib/components/player/sibling_tracks_sheet.dart index f6702e0c..ee8d9719 100644 --- a/lib/components/player/sibling_tracks_sheet.dart +++ b/lib/components/player/sibling_tracks_sheet.dart @@ -15,7 +15,8 @@ import 'package:spotube/hooks/utils/use_debounce.dart'; import 'package:spotube/models/matched_track.dart'; import 'package:spotube/models/spotube_track.dart'; import 'package:spotube/provider/proxy_playlist/proxy_playlist_provider.dart'; -import 'package:spotube/provider/user_preferences_provider.dart'; +import 'package:spotube/provider/user_preferences/user_preferences_provider.dart'; +import 'package:spotube/provider/user_preferences/user_preferences_state.dart'; import 'package:spotube/provider/youtube_provider.dart'; import 'package:spotube/services/youtube/youtube.dart'; import 'package:spotube/utils/service_utils.dart'; diff --git a/lib/components/root/bottom_player.dart b/lib/components/root/bottom_player.dart index 4bc08fc0..617e760b 100644 --- a/lib/components/root/bottom_player.dart +++ b/lib/components/root/bottom_player.dart @@ -19,7 +19,8 @@ import 'package:spotube/models/logger.dart'; import 'package:flutter/material.dart'; import 'package:spotube/provider/authentication_provider.dart'; import 'package:spotube/provider/proxy_playlist/proxy_playlist_provider.dart'; -import 'package:spotube/provider/user_preferences_provider.dart'; +import 'package:spotube/provider/user_preferences/user_preferences_provider.dart'; +import 'package:spotube/provider/user_preferences/user_preferences_state.dart'; import 'package:spotube/utils/platform.dart'; import 'package:spotube/utils/type_conversion_utils.dart'; diff --git a/lib/components/root/sidebar.dart b/lib/components/root/sidebar.dart index f7cdcac3..ac5233ed 100644 --- a/lib/components/root/sidebar.dart +++ b/lib/components/root/sidebar.dart @@ -16,7 +16,8 @@ import 'package:spotube/hooks/controllers/use_sidebarx_controller.dart'; import 'package:spotube/provider/download_manager_provider.dart'; import 'package:spotube/provider/authentication_provider.dart'; -import 'package:spotube/provider/user_preferences_provider.dart'; +import 'package:spotube/provider/user_preferences/user_preferences_provider.dart'; +import 'package:spotube/provider/user_preferences/user_preferences_state.dart'; import 'package:spotube/services/queries/queries.dart'; import 'package:spotube/utils/platform.dart'; import 'package:spotube/utils/type_conversion_utils.dart'; diff --git a/lib/components/root/spotube_navigation_bar.dart b/lib/components/root/spotube_navigation_bar.dart index d602f390..0853c60c 100644 --- a/lib/components/root/spotube_navigation_bar.dart +++ b/lib/components/root/spotube_navigation_bar.dart @@ -11,7 +11,8 @@ import 'package:spotube/extensions/constrains.dart'; import 'package:spotube/extensions/context.dart'; import 'package:spotube/hooks/utils/use_brightness_value.dart'; import 'package:spotube/provider/download_manager_provider.dart'; -import 'package:spotube/provider/user_preferences_provider.dart'; +import 'package:spotube/provider/user_preferences/user_preferences_provider.dart'; +import 'package:spotube/provider/user_preferences/user_preferences_state.dart'; final navigationPanelHeight = StateProvider((ref) => 50); diff --git a/lib/components/settings/color_scheme_picker_dialog.dart b/lib/components/settings/color_scheme_picker_dialog.dart index f06a9d84..e0c3d618 100644 --- a/lib/components/settings/color_scheme_picker_dialog.dart +++ b/lib/components/settings/color_scheme_picker_dialog.dart @@ -2,7 +2,7 @@ import 'package:flutter/material.dart'; import 'package:flutter_hooks/flutter_hooks.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; -import 'package:spotube/provider/user_preferences_provider.dart'; +import 'package:spotube/provider/user_preferences/user_preferences_provider.dart'; import 'package:system_theme/system_theme.dart'; class SpotubeColor extends Color { diff --git a/lib/components/shared/dialogs/piped_down_dialog.dart b/lib/components/shared/dialogs/piped_down_dialog.dart index 03362ed4..6220adeb 100644 --- a/lib/components/shared/dialogs/piped_down_dialog.dart +++ b/lib/components/shared/dialogs/piped_down_dialog.dart @@ -2,7 +2,7 @@ import 'package:flutter/material.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:spotube/collections/spotube_icons.dart'; import 'package:spotube/extensions/context.dart'; -import 'package:spotube/provider/user_preferences_provider.dart'; +import 'package:spotube/provider/user_preferences/user_preferences_provider.dart'; class PipedDownDialog extends HookConsumerWidget { const PipedDownDialog({Key? key}) : super(key: key); diff --git a/lib/components/shared/page_window_title_bar.dart b/lib/components/shared/page_window_title_bar.dart index 50d468aa..43435f7d 100644 --- a/lib/components/shared/page_window_title_bar.dart +++ b/lib/components/shared/page_window_title_bar.dart @@ -1,7 +1,8 @@ import 'package:flutter/material.dart'; import 'package:flutter_hooks/flutter_hooks.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; -import 'package:spotube/provider/user_preferences_provider.dart'; +import 'package:spotube/provider/user_preferences/user_preferences_provider.dart'; +import 'package:spotube/provider/user_preferences/user_preferences_state.dart'; import 'package:spotube/utils/platform.dart'; import 'package:titlebar_buttons/titlebar_buttons.dart'; import 'dart:math'; diff --git a/lib/components/shared/track_table/tracks_table_view.dart b/lib/components/shared/track_table/tracks_table_view.dart index d03e92d7..14a4f1a9 100644 --- a/lib/components/shared/track_table/tracks_table_view.dart +++ b/lib/components/shared/track_table/tracks_table_view.dart @@ -22,7 +22,8 @@ import 'package:spotube/extensions/context.dart'; import 'package:spotube/provider/download_manager_provider.dart'; import 'package:spotube/provider/blacklist_provider.dart'; import 'package:spotube/provider/proxy_playlist/proxy_playlist_provider.dart'; -import 'package:spotube/provider/user_preferences_provider.dart'; +import 'package:spotube/provider/user_preferences/user_preferences_provider.dart'; +import 'package:spotube/provider/user_preferences/user_preferences_state.dart'; import 'package:spotube/utils/service_utils.dart'; final trackCollectionSortState = diff --git a/lib/hooks/configurators/use_init_sys_tray.dart b/lib/hooks/configurators/use_init_sys_tray.dart index f342c24a..db4964ce 100644 --- a/lib/hooks/configurators/use_init_sys_tray.dart +++ b/lib/hooks/configurators/use_init_sys_tray.dart @@ -7,7 +7,7 @@ import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:spotube/collections/intents.dart'; import 'package:spotube/provider/proxy_playlist/proxy_playlist.dart'; import 'package:spotube/provider/proxy_playlist/proxy_playlist_provider.dart'; -import 'package:spotube/provider/user_preferences_provider.dart'; +import 'package:spotube/provider/user_preferences/user_preferences_provider.dart'; void useInitSysTray(WidgetRef ref) { final context = useContext(); diff --git a/lib/hooks/configurators/use_update_checker.dart b/lib/hooks/configurators/use_update_checker.dart index 515d6701..1a6a5be5 100644 --- a/lib/hooks/configurators/use_update_checker.dart +++ b/lib/hooks/configurators/use_update_checker.dart @@ -9,7 +9,7 @@ import 'package:spotube/collections/env.dart'; import 'package:spotube/components/shared/links/anchor_button.dart'; import 'package:spotube/hooks/controllers/use_package_info.dart'; -import 'package:spotube/provider/user_preferences_provider.dart'; +import 'package:spotube/provider/user_preferences/user_preferences_provider.dart'; import 'package:url_launcher/url_launcher_string.dart'; import 'package:version/version.dart'; diff --git a/lib/main.dart b/lib/main.dart index e1f0bd53..f46f02c1 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -21,7 +21,7 @@ import 'package:spotube/models/logger.dart'; import 'package:spotube/models/matched_track.dart'; import 'package:spotube/models/skip_segment.dart'; import 'package:spotube/provider/palette_provider.dart'; -import 'package:spotube/provider/user_preferences_provider.dart'; +import 'package:spotube/provider/user_preferences/user_preferences_provider.dart'; import 'package:spotube/services/audio_player/audio_player.dart'; import 'package:spotube/services/cli/cli.dart'; import 'package:spotube/services/connectivity_adapter.dart'; diff --git a/lib/models/spotube_track.dart b/lib/models/spotube_track.dart index 68641010..67b09ad8 100644 --- a/lib/models/spotube_track.dart +++ b/lib/models/spotube_track.dart @@ -3,7 +3,7 @@ import 'dart:async'; import 'package:spotify/spotify.dart'; import 'package:spotube/extensions/track.dart'; import 'package:spotube/models/matched_track.dart'; -import 'package:spotube/provider/user_preferences_provider.dart'; +import 'package:spotube/provider/user_preferences/user_preferences_state.dart'; import 'package:spotube/services/youtube/youtube.dart'; import 'package:spotube/utils/service_utils.dart'; import 'package:collection/collection.dart'; diff --git a/lib/pages/home/genres.dart b/lib/pages/home/genres.dart index 84082811..b3904e2e 100644 --- a/lib/pages/home/genres.dart +++ b/lib/pages/home/genres.dart @@ -10,7 +10,7 @@ import 'package:spotube/components/shared/expandable_search/expandable_search.da import 'package:spotube/components/shared/shimmers/shimmer_categories.dart'; import 'package:spotube/components/shared/waypoint.dart'; -import 'package:spotube/provider/user_preferences_provider.dart'; +import 'package:spotube/provider/user_preferences/user_preferences_provider.dart'; import 'package:spotube/services/queries/queries.dart'; import 'package:very_good_infinite_list/very_good_infinite_list.dart'; diff --git a/lib/pages/library/playlist_generate/playlist_generate.dart b/lib/pages/library/playlist_generate/playlist_generate.dart index 33e244b0..4b8dddaf 100644 --- a/lib/pages/library/playlist_generate/playlist_generate.dart +++ b/lib/pages/library/playlist_generate/playlist_generate.dart @@ -17,7 +17,7 @@ import 'package:spotube/extensions/constrains.dart'; import 'package:spotube/extensions/context.dart'; import 'package:spotube/pages/library/playlist_generate/playlist_generate_result.dart'; import 'package:spotube/provider/spotify_provider.dart'; -import 'package:spotube/provider/user_preferences_provider.dart'; +import 'package:spotube/provider/user_preferences/user_preferences_provider.dart'; import 'package:spotube/services/queries/queries.dart'; import 'package:spotube/utils/type_conversion_utils.dart'; diff --git a/lib/pages/settings/sections/about.dart b/lib/pages/settings/sections/about.dart index 85181355..9fe59662 100644 --- a/lib/pages/settings/sections/about.dart +++ b/lib/pages/settings/sections/about.dart @@ -7,7 +7,7 @@ import 'package:spotube/collections/spotube_icons.dart'; import 'package:spotube/components/settings/section_card_with_heading.dart'; import 'package:spotube/components/shared/adaptive/adaptive_list_tile.dart'; import 'package:spotube/extensions/context.dart'; -import 'package:spotube/provider/user_preferences_provider.dart'; +import 'package:spotube/provider/user_preferences/user_preferences_provider.dart'; import 'package:url_launcher/url_launcher_string.dart'; class SettingsAboutSection extends HookConsumerWidget { diff --git a/lib/pages/settings/sections/appearance.dart b/lib/pages/settings/sections/appearance.dart index 5e1ffa50..5de36c63 100644 --- a/lib/pages/settings/sections/appearance.dart +++ b/lib/pages/settings/sections/appearance.dart @@ -1,4 +1,3 @@ -import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:flutter_hooks/flutter_hooks.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; @@ -7,7 +6,8 @@ import 'package:spotube/components/settings/color_scheme_picker_dialog.dart'; import 'package:spotube/components/settings/section_card_with_heading.dart'; import 'package:spotube/components/shared/adaptive/adaptive_select_tile.dart'; import 'package:spotube/extensions/context.dart'; -import 'package:spotube/provider/user_preferences_provider.dart'; +import 'package:spotube/provider/user_preferences/user_preferences_provider.dart'; +import 'package:spotube/provider/user_preferences/user_preferences_state.dart'; class SettingsAppearanceSection extends HookConsumerWidget { const SettingsAppearanceSection({Key? key}) : super(key: key); diff --git a/lib/pages/settings/sections/desktop.dart b/lib/pages/settings/sections/desktop.dart index 1cc2c5c8..41d6d61e 100644 --- a/lib/pages/settings/sections/desktop.dart +++ b/lib/pages/settings/sections/desktop.dart @@ -4,7 +4,8 @@ import 'package:spotube/collections/spotube_icons.dart'; import 'package:spotube/components/settings/section_card_with_heading.dart'; import 'package:spotube/components/shared/adaptive/adaptive_select_tile.dart'; import 'package:spotube/extensions/context.dart'; -import 'package:spotube/provider/user_preferences_provider.dart'; +import 'package:spotube/provider/user_preferences/user_preferences_provider.dart'; +import 'package:spotube/provider/user_preferences/user_preferences_state.dart'; class SettingsDesktopSection extends HookConsumerWidget { const SettingsDesktopSection({Key? key}) : super(key: key); diff --git a/lib/pages/settings/sections/downloads.dart b/lib/pages/settings/sections/downloads.dart index ff64cdea..12026909 100644 --- a/lib/pages/settings/sections/downloads.dart +++ b/lib/pages/settings/sections/downloads.dart @@ -7,7 +7,7 @@ import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:spotube/collections/spotube_icons.dart'; import 'package:spotube/components/settings/section_card_with_heading.dart'; import 'package:spotube/extensions/context.dart'; -import 'package:spotube/provider/user_preferences_provider.dart'; +import 'package:spotube/provider/user_preferences/user_preferences_provider.dart'; class SettingsDownloadsSection extends HookConsumerWidget { const SettingsDownloadsSection({Key? key}) : super(key: key); diff --git a/lib/pages/settings/sections/language_region.dart b/lib/pages/settings/sections/language_region.dart index ece28455..9465feb3 100644 --- a/lib/pages/settings/sections/language_region.dart +++ b/lib/pages/settings/sections/language_region.dart @@ -9,7 +9,7 @@ import 'package:spotube/components/shared/adaptive/adaptive_select_tile.dart'; import 'package:spotube/extensions/constrains.dart'; import 'package:spotube/extensions/context.dart'; import 'package:spotube/l10n/l10n.dart'; -import 'package:spotube/provider/user_preferences_provider.dart'; +import 'package:spotube/provider/user_preferences/user_preferences_provider.dart'; class SettingsLanguageRegionSection extends HookConsumerWidget { const SettingsLanguageRegionSection({Key? key}) : super(key: key); diff --git a/lib/pages/settings/sections/playback.dart b/lib/pages/settings/sections/playback.dart index 39d9b7c2..5e000231 100644 --- a/lib/pages/settings/sections/playback.dart +++ b/lib/pages/settings/sections/playback.dart @@ -10,7 +10,8 @@ import 'package:spotube/components/shared/adaptive/adaptive_select_tile.dart'; import 'package:spotube/extensions/context.dart'; import 'package:spotube/models/matched_track.dart'; import 'package:spotube/provider/piped_instances_provider.dart'; -import 'package:spotube/provider/user_preferences_provider.dart'; +import 'package:spotube/provider/user_preferences/user_preferences_provider.dart'; +import 'package:spotube/provider/user_preferences/user_preferences_state.dart'; class SettingsPlaybackSection extends HookConsumerWidget { const SettingsPlaybackSection({Key? key}) : super(key: key); diff --git a/lib/pages/settings/settings.dart b/lib/pages/settings/settings.dart index f14fb453..842d5240 100644 --- a/lib/pages/settings/settings.dart +++ b/lib/pages/settings/settings.dart @@ -13,7 +13,7 @@ import 'package:spotube/pages/settings/sections/developers.dart'; import 'package:spotube/pages/settings/sections/downloads.dart'; import 'package:spotube/pages/settings/sections/language_region.dart'; import 'package:spotube/pages/settings/sections/playback.dart'; -import 'package:spotube/provider/user_preferences_provider.dart'; +import 'package:spotube/provider/user_preferences/user_preferences_provider.dart'; class SettingsPage extends HookConsumerWidget { const SettingsPage({Key? key}) : super(key: key); diff --git a/lib/provider/download_manager_provider.dart b/lib/provider/download_manager_provider.dart index 46c7ee7e..889641f4 100644 --- a/lib/provider/download_manager_provider.dart +++ b/lib/provider/download_manager_provider.dart @@ -10,7 +10,8 @@ import 'package:metadata_god/metadata_god.dart'; import 'package:path/path.dart'; import 'package:spotify/spotify.dart'; import 'package:spotube/models/spotube_track.dart'; -import 'package:spotube/provider/user_preferences_provider.dart'; +import 'package:spotube/provider/user_preferences/user_preferences_provider.dart'; +import 'package:spotube/provider/user_preferences/user_preferences_state.dart'; import 'package:spotube/provider/youtube_provider.dart'; import 'package:spotube/services/download_manager/download_manager.dart'; import 'package:spotube/services/youtube/youtube.dart'; diff --git a/lib/provider/proxy_playlist/next_fetcher_mixin.dart b/lib/provider/proxy_playlist/next_fetcher_mixin.dart index f6776234..b447f1ef 100644 --- a/lib/provider/proxy_playlist/next_fetcher_mixin.dart +++ b/lib/provider/proxy_playlist/next_fetcher_mixin.dart @@ -6,7 +6,7 @@ import 'package:spotube/models/logger.dart'; import 'package:spotube/models/matched_track.dart'; import 'package:spotube/models/spotube_track.dart'; import 'package:spotube/provider/proxy_playlist/proxy_playlist.dart'; -import 'package:spotube/provider/user_preferences_provider.dart'; +import 'package:spotube/provider/user_preferences/user_preferences_state.dart'; import 'package:spotube/services/supabase.dart'; import 'package:spotube/services/youtube/youtube.dart'; diff --git a/lib/provider/proxy_playlist/proxy_playlist_provider.dart b/lib/provider/proxy_playlist/proxy_playlist_provider.dart index bf7293ce..50024661 100644 --- a/lib/provider/proxy_playlist/proxy_playlist_provider.dart +++ b/lib/provider/proxy_playlist/proxy_playlist_provider.dart @@ -20,7 +20,8 @@ import 'package:spotube/provider/palette_provider.dart'; import 'package:spotube/provider/proxy_playlist/next_fetcher_mixin.dart'; import 'package:spotube/provider/proxy_playlist/proxy_playlist.dart'; import 'package:spotube/provider/scrobbler_provider.dart'; -import 'package:spotube/provider/user_preferences_provider.dart'; +import 'package:spotube/provider/user_preferences/user_preferences_provider.dart'; +import 'package:spotube/provider/user_preferences/user_preferences_state.dart'; import 'package:spotube/provider/youtube_provider.dart'; import 'package:spotube/services/audio_player/audio_player.dart'; import 'package:spotube/services/audio_services/audio_services.dart'; diff --git a/lib/provider/user_preferences/user_preferences_provider.dart b/lib/provider/user_preferences/user_preferences_provider.dart new file mode 100644 index 00000000..db4b73dc --- /dev/null +++ b/lib/provider/user_preferences/user_preferences_provider.dart @@ -0,0 +1,165 @@ +import 'dart:async'; + +import 'package:flutter/material.dart'; +import 'package:flutter_desktop_tools/flutter_desktop_tools.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; +import 'package:path_provider/path_provider.dart'; +import 'package:spotify/spotify.dart'; +import 'package:spotube/components/settings/color_scheme_picker_dialog.dart'; +import 'package:spotube/models/matched_track.dart'; +import 'package:spotube/provider/palette_provider.dart'; +import 'package:spotube/provider/proxy_playlist/proxy_playlist_provider.dart'; +import 'package:spotube/provider/user_preferences/user_preferences_state.dart'; +import 'package:spotube/services/audio_player/audio_player.dart'; + +import 'package:spotube/utils/persisted_state_notifier.dart'; +import 'package:spotube/utils/platform.dart'; +import 'package:path/path.dart' as path; + +class UserPreferencesNotifier extends PersistedStateNotifier { + final Ref ref; + + UserPreferencesNotifier(this.ref) + : super(UserPreferences.withDefaults(), "preferences"); + + void reset() { + state = UserPreferences.withDefaults(); + } + + void setStreamMusicCodec(MusicCodec codec) { + state = state.copyWith(streamMusicCodec: codec); + } + + void setDownloadMusicCodec(MusicCodec codec) { + state = state.copyWith(downloadMusicCodec: codec); + } + + void setThemeMode(ThemeMode mode) { + state = state.copyWith(themeMode: mode); + } + + void setRecommendationMarket(Market country) { + state = state.copyWith(recommendationMarket: country); + } + + void setAccentColorScheme(SpotubeColor color) { + state = state.copyWith(accentColorScheme: color); + } + + void setAlbumColorSync(bool sync) { + state = state.copyWith(albumColorSync: sync); + + if (!sync) { + ref.read(paletteProvider.notifier).state = null; + } else { + ref.read(ProxyPlaylistNotifier.notifier).updatePalette(); + } + } + + void setCheckUpdate(bool check) { + state = state.copyWith(checkUpdate: check); + } + + void setAudioQuality(AudioQuality quality) { + state = state.copyWith(audioQuality: quality); + } + + void setDownloadLocation(String downloadDir) { + if (downloadDir.isEmpty) return; + state = state.copyWith(downloadLocation: downloadDir); + } + + void setLayoutMode(LayoutMode mode) { + state = state.copyWith(layoutMode: mode); + } + + void setCloseBehavior(CloseBehavior behavior) { + state = state.copyWith(closeBehavior: behavior); + } + + void setShowSystemTrayIcon(bool show) { + state = state.copyWith(showSystemTrayIcon: show); + } + + void setLocale(Locale locale) { + state = state.copyWith(locale: locale); + } + + void setPipedInstance(String instance) { + state = state.copyWith(pipedInstance: instance); + } + + void setSearchMode(SearchMode mode) { + state = state.copyWith(searchMode: mode); + } + + void setSkipNonMusic(bool skip) { + state = state.copyWith(skipNonMusic: skip); + } + + void setYoutubeApiType(YoutubeApiType type) { + state = state.copyWith(youtubeApiType: type); + } + + void setSystemTitleBar(bool isSystemTitleBar) { + state = state.copyWith(systemTitleBar: isSystemTitleBar); + if (DesktopTools.platform.isDesktop) { + DesktopTools.window.setTitleBarStyle( + isSystemTitleBar ? TitleBarStyle.normal : TitleBarStyle.hidden, + ); + } + } + + void setAmoledDarkTheme(bool isAmoled) { + state = state.copyWith(amoledDarkTheme: isAmoled); + } + + void setNormalizeAudio(bool normalize) { + state = state.copyWith(normalizeAudio: normalize); + audioPlayer.setAudioNormalization(normalize); + } + + Future _getDefaultDownloadDirectory() async { + if (kIsAndroid) return "/storage/emulated/0/Download/Spotube"; + + if (kIsMacOS) { + return path.join((await getLibraryDirectory()).path, "Caches"); + } + + return getDownloadsDirectory().then((dir) { + return path.join(dir!.path, "Spotube"); + }); + } + + @override + FutureOr onInit() async { + if (state.downloadLocation.isEmpty) { + state = state.copyWith( + downloadLocation: await _getDefaultDownloadDirectory(), + ); + } + + if (DesktopTools.platform.isDesktop) { + await DesktopTools.window.setTitleBarStyle( + state.systemTitleBar ? TitleBarStyle.normal : TitleBarStyle.hidden, + ); + } + + await audioPlayer.setAudioNormalization(state.normalizeAudio); + } + + @override + FutureOr fromJson(Map json) { + return UserPreferences.fromJson(json); + } + + @override + Map toJson() { + return state.toJson(); + } +} + +final userPreferencesProvider = + StateNotifierProvider( + (ref) => UserPreferencesNotifier(ref), +); diff --git a/lib/provider/user_preferences/user_preferences_state.dart b/lib/provider/user_preferences/user_preferences_state.dart new file mode 100644 index 00000000..ff98fa8e --- /dev/null +++ b/lib/provider/user_preferences/user_preferences_state.dart @@ -0,0 +1,273 @@ +import 'dart:convert'; + +import 'package:flutter/material.dart'; +import 'package:json_annotation/json_annotation.dart'; +import 'package:spotify/spotify.dart'; +import 'package:spotube/components/settings/color_scheme_picker_dialog.dart'; +import 'package:spotube/models/matched_track.dart'; + +part 'user_preferences_state.g.dart'; + +@JsonEnum() +enum LayoutMode { + compact, + extended, + adaptive, +} + +@JsonEnum() +enum AudioQuality { + high, + low, +} + +@JsonEnum() +enum CloseBehavior { + minimizeToTray, + close, +} + +@JsonEnum() +enum YoutubeApiType { + youtube, + piped; + + String get label => name[0].toUpperCase() + name.substring(1); +} + +@JsonEnum() +enum MusicCodec { + m4a._("M4a (Best for downloaded music)"), + weba._("WebA (Best for streamed music)\nDoesn't support audio metadata"); + + final String label; + const MusicCodec._(this.label); +} + +@JsonSerializable() +final class UserPreferences { + @JsonKey( + defaultValue: AudioQuality.high, + unknownEnumValue: AudioQuality.high, + ) + final AudioQuality audioQuality; + + @JsonKey(defaultValue: true) + final bool albumColorSync; + + @JsonKey(defaultValue: false) + final bool amoledDarkTheme; + + @JsonKey(defaultValue: true) + final bool checkUpdate; + + @JsonKey(defaultValue: false) + final bool normalizeAudio; + + @JsonKey(defaultValue: true) + final bool showSystemTrayIcon; + + @JsonKey(defaultValue: true) + final bool skipNonMusic; + + @JsonKey(defaultValue: false) + final bool systemTitleBar; + + @JsonKey( + defaultValue: CloseBehavior.minimizeToTray, + unknownEnumValue: CloseBehavior.minimizeToTray, + ) + final CloseBehavior closeBehavior; + + static SpotubeColor _accentColorSchemeFromJson(Map json) { + return SpotubeColor.fromString(json["color"]); + } + + static Map? _accentColorSchemeReadValue( + Map json, String key) { + if (json[key] is String) { + return {"color": json[key]}; + } + + return json[key] as Map?; + } + + static Map _accentColorSchemeToJson(SpotubeColor color) { + return {"color": color.toString()}; + } + + static SpotubeColor _defaultAccentColorScheme() => + const SpotubeColor(0xFF2196F3, name: "Blue"); + + @JsonKey( + defaultValue: UserPreferences._defaultAccentColorScheme, + fromJson: UserPreferences._accentColorSchemeFromJson, + toJson: UserPreferences._accentColorSchemeToJson, + readValue: UserPreferences._accentColorSchemeReadValue, + ) + final SpotubeColor accentColorScheme; + + @JsonKey( + defaultValue: LayoutMode.adaptive, + unknownEnumValue: LayoutMode.adaptive, + ) + final LayoutMode layoutMode; + + static Locale _localeFromJson(Map json) { + return Locale(json["languageCode"], json["countryCode"]); + } + + static Map _localeToJson(Locale locale) { + return { + "languageCode": locale.languageCode, + "countryCode": locale.countryCode, + }; + } + + static Map? _localeReadValue( + Map json, String key) { + if (json[key] is String) { + final map = jsonDecode(json[key]); + return { + "languageCode": map["lc"], + "countryCode": map["cc"], + }; + } + + return json[key] as Map?; + } + + static Locale _defaultLocaleValue() => const Locale("system", "system"); + + @JsonKey( + defaultValue: UserPreferences._defaultLocaleValue, + toJson: UserPreferences._localeToJson, + fromJson: UserPreferences._localeFromJson, + readValue: UserPreferences._localeReadValue, + ) + final Locale locale; + + @JsonKey( + defaultValue: Market.US, + unknownEnumValue: Market.US, + ) + final Market recommendationMarket; + + @JsonKey( + defaultValue: SearchMode.youtube, + unknownEnumValue: SearchMode.youtube, + ) + final SearchMode searchMode; + + @JsonKey(defaultValue: "") + final String downloadLocation; + + @JsonKey(defaultValue: "https://pipedapi.kavin.rocks") + final String pipedInstance; + + @JsonKey( + defaultValue: ThemeMode.system, + unknownEnumValue: ThemeMode.system, + ) + final ThemeMode themeMode; + + @JsonKey( + defaultValue: YoutubeApiType.youtube, + unknownEnumValue: YoutubeApiType.youtube, + ) + final YoutubeApiType youtubeApiType; + + @JsonKey( + defaultValue: MusicCodec.weba, + unknownEnumValue: MusicCodec.weba, + ) + final MusicCodec streamMusicCodec; + + @JsonKey( + defaultValue: MusicCodec.m4a, + unknownEnumValue: MusicCodec.m4a, + ) + final MusicCodec downloadMusicCodec; + + UserPreferences({ + required this.audioQuality, + required this.albumColorSync, + required this.amoledDarkTheme, + required this.checkUpdate, + required this.normalizeAudio, + required this.showSystemTrayIcon, + required this.skipNonMusic, + required this.systemTitleBar, + required this.closeBehavior, + required this.accentColorScheme, + required this.layoutMode, + required this.locale, + required this.recommendationMarket, + required this.searchMode, + required this.downloadLocation, + required this.pipedInstance, + required this.themeMode, + required this.youtubeApiType, + required this.streamMusicCodec, + required this.downloadMusicCodec, + }); + + factory UserPreferences.withDefaults() { + return UserPreferences.fromJson({}); + } + + factory UserPreferences.fromJson(Map json) { + return _$UserPreferencesFromJson(json); + } + + Map toJson() { + return _$UserPreferencesToJson(this); + } + + UserPreferences copyWith({ + ThemeMode? themeMode, + SpotubeColor? accentColorScheme, + bool? albumColorSync, + bool? checkUpdate, + AudioQuality? audioQuality, + String? downloadLocation, + LayoutMode? layoutMode, + CloseBehavior? closeBehavior, + bool? showSystemTrayIcon, + Locale? locale, + String? pipedInstance, + SearchMode? searchMode, + bool? skipNonMusic, + YoutubeApiType? youtubeApiType, + Market? recommendationMarket, + bool? saveTrackLyrics, + bool? amoledDarkTheme, + bool? normalizeAudio, + MusicCodec? downloadMusicCodec, + MusicCodec? streamMusicCodec, + bool? systemTitleBar, + }) { + return UserPreferences( + themeMode: themeMode ?? this.themeMode, + accentColorScheme: accentColorScheme ?? this.accentColorScheme, + albumColorSync: albumColorSync ?? this.albumColorSync, + checkUpdate: checkUpdate ?? this.checkUpdate, + audioQuality: audioQuality ?? this.audioQuality, + downloadLocation: downloadLocation ?? this.downloadLocation, + layoutMode: layoutMode ?? this.layoutMode, + closeBehavior: closeBehavior ?? this.closeBehavior, + showSystemTrayIcon: showSystemTrayIcon ?? this.showSystemTrayIcon, + locale: locale ?? this.locale, + pipedInstance: pipedInstance ?? this.pipedInstance, + searchMode: searchMode ?? this.searchMode, + skipNonMusic: skipNonMusic ?? this.skipNonMusic, + youtubeApiType: youtubeApiType ?? this.youtubeApiType, + recommendationMarket: recommendationMarket ?? this.recommendationMarket, + amoledDarkTheme: amoledDarkTheme ?? this.amoledDarkTheme, + downloadMusicCodec: downloadMusicCodec ?? this.downloadMusicCodec, + normalizeAudio: normalizeAudio ?? this.normalizeAudio, + streamMusicCodec: streamMusicCodec ?? this.streamMusicCodec, + systemTitleBar: systemTitleBar ?? this.systemTitleBar, + ); + } +} diff --git a/lib/provider/user_preferences/user_preferences_state.g.dart b/lib/provider/user_preferences/user_preferences_state.g.dart new file mode 100644 index 00000000..9e3eeee9 --- /dev/null +++ b/lib/provider/user_preferences/user_preferences_state.g.dart @@ -0,0 +1,381 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +part of 'user_preferences_state.dart'; + +// ************************************************************************** +// JsonSerializableGenerator +// ************************************************************************** + +UserPreferences _$UserPreferencesFromJson(Map json) => + UserPreferences( + audioQuality: $enumDecodeNullable( + _$AudioQualityEnumMap, json['audioQuality'], + unknownValue: AudioQuality.high) ?? + AudioQuality.high, + albumColorSync: json['albumColorSync'] as bool? ?? true, + amoledDarkTheme: json['amoledDarkTheme'] as bool? ?? false, + checkUpdate: json['checkUpdate'] as bool? ?? true, + normalizeAudio: json['normalizeAudio'] as bool? ?? false, + showSystemTrayIcon: json['showSystemTrayIcon'] as bool? ?? true, + skipNonMusic: json['skipNonMusic'] as bool? ?? true, + systemTitleBar: json['systemTitleBar'] as bool? ?? false, + closeBehavior: $enumDecodeNullable( + _$CloseBehaviorEnumMap, json['closeBehavior'], + unknownValue: CloseBehavior.minimizeToTray) ?? + CloseBehavior.minimizeToTray, + accentColorScheme: UserPreferences._accentColorSchemeReadValue( + json, 'accentColorScheme') == + null + ? UserPreferences._defaultAccentColorScheme() + : UserPreferences._accentColorSchemeFromJson( + UserPreferences._accentColorSchemeReadValue( + json, 'accentColorScheme') as Map), + layoutMode: $enumDecodeNullable(_$LayoutModeEnumMap, json['layoutMode'], + unknownValue: LayoutMode.adaptive) ?? + LayoutMode.adaptive, + locale: UserPreferences._localeReadValue(json, 'locale') == null + ? UserPreferences._defaultLocaleValue() + : UserPreferences._localeFromJson( + UserPreferences._localeReadValue(json, 'locale') + as Map), + recommendationMarket: $enumDecodeNullable( + _$MarketEnumMap, json['recommendationMarket'], + unknownValue: Market.US) ?? + Market.US, + searchMode: $enumDecodeNullable(_$SearchModeEnumMap, json['searchMode'], + unknownValue: SearchMode.youtube) ?? + SearchMode.youtube, + downloadLocation: json['downloadLocation'] as String? ?? '', + pipedInstance: + json['pipedInstance'] as String? ?? 'https://pipedapi.kavin.rocks', + themeMode: $enumDecodeNullable(_$ThemeModeEnumMap, json['themeMode'], + unknownValue: ThemeMode.system) ?? + ThemeMode.system, + youtubeApiType: $enumDecodeNullable( + _$YoutubeApiTypeEnumMap, json['youtubeApiType'], + unknownValue: YoutubeApiType.youtube) ?? + YoutubeApiType.youtube, + streamMusicCodec: $enumDecodeNullable( + _$MusicCodecEnumMap, json['streamMusicCodec'], + unknownValue: MusicCodec.weba) ?? + MusicCodec.weba, + downloadMusicCodec: $enumDecodeNullable( + _$MusicCodecEnumMap, json['downloadMusicCodec'], + unknownValue: MusicCodec.m4a) ?? + MusicCodec.m4a, + ); + +Map _$UserPreferencesToJson(UserPreferences instance) => + { + 'audioQuality': _$AudioQualityEnumMap[instance.audioQuality]!, + 'albumColorSync': instance.albumColorSync, + 'amoledDarkTheme': instance.amoledDarkTheme, + 'checkUpdate': instance.checkUpdate, + 'normalizeAudio': instance.normalizeAudio, + 'showSystemTrayIcon': instance.showSystemTrayIcon, + 'skipNonMusic': instance.skipNonMusic, + 'systemTitleBar': instance.systemTitleBar, + 'closeBehavior': _$CloseBehaviorEnumMap[instance.closeBehavior]!, + 'accentColorScheme': + UserPreferences._accentColorSchemeToJson(instance.accentColorScheme), + 'layoutMode': _$LayoutModeEnumMap[instance.layoutMode]!, + 'locale': UserPreferences._localeToJson(instance.locale), + 'recommendationMarket': _$MarketEnumMap[instance.recommendationMarket]!, + 'searchMode': _$SearchModeEnumMap[instance.searchMode]!, + 'downloadLocation': instance.downloadLocation, + 'pipedInstance': instance.pipedInstance, + 'themeMode': _$ThemeModeEnumMap[instance.themeMode]!, + 'youtubeApiType': _$YoutubeApiTypeEnumMap[instance.youtubeApiType]!, + 'streamMusicCodec': _$MusicCodecEnumMap[instance.streamMusicCodec]!, + 'downloadMusicCodec': _$MusicCodecEnumMap[instance.downloadMusicCodec]!, + }; + +const _$AudioQualityEnumMap = { + AudioQuality.high: 'high', + AudioQuality.low: 'low', +}; + +const _$CloseBehaviorEnumMap = { + CloseBehavior.minimizeToTray: 'minimizeToTray', + CloseBehavior.close: 'close', +}; + +const _$LayoutModeEnumMap = { + LayoutMode.compact: 'compact', + LayoutMode.extended: 'extended', + LayoutMode.adaptive: 'adaptive', +}; + +const _$MarketEnumMap = { + Market.AD: 'AD', + Market.AE: 'AE', + Market.AF: 'AF', + Market.AG: 'AG', + Market.AI: 'AI', + Market.AL: 'AL', + Market.AM: 'AM', + Market.AO: 'AO', + Market.AQ: 'AQ', + Market.AR: 'AR', + Market.AS: 'AS', + Market.AT: 'AT', + Market.AU: 'AU', + Market.AW: 'AW', + Market.AX: 'AX', + Market.AZ: 'AZ', + Market.BA: 'BA', + Market.BB: 'BB', + Market.BD: 'BD', + Market.BE: 'BE', + Market.BF: 'BF', + Market.BG: 'BG', + Market.BH: 'BH', + Market.BI: 'BI', + Market.BJ: 'BJ', + Market.BL: 'BL', + Market.BM: 'BM', + Market.BN: 'BN', + Market.BO: 'BO', + Market.BQ: 'BQ', + Market.BR: 'BR', + Market.BS: 'BS', + Market.BT: 'BT', + Market.BV: 'BV', + Market.BW: 'BW', + Market.BY: 'BY', + Market.BZ: 'BZ', + Market.CA: 'CA', + Market.CC: 'CC', + Market.CD: 'CD', + Market.CF: 'CF', + Market.CG: 'CG', + Market.CH: 'CH', + Market.CI: 'CI', + Market.CK: 'CK', + Market.CL: 'CL', + Market.CM: 'CM', + Market.CN: 'CN', + Market.CO: 'CO', + Market.CR: 'CR', + Market.CU: 'CU', + Market.CV: 'CV', + Market.CW: 'CW', + Market.CX: 'CX', + Market.CY: 'CY', + Market.CZ: 'CZ', + Market.DE: 'DE', + Market.DJ: 'DJ', + Market.DK: 'DK', + Market.DM: 'DM', + Market.DO: 'DO', + Market.DZ: 'DZ', + Market.EC: 'EC', + Market.EE: 'EE', + Market.EG: 'EG', + Market.EH: 'EH', + Market.ER: 'ER', + Market.ES: 'ES', + Market.ET: 'ET', + Market.FI: 'FI', + Market.FJ: 'FJ', + Market.FK: 'FK', + Market.FM: 'FM', + Market.FO: 'FO', + Market.FR: 'FR', + Market.GA: 'GA', + Market.GB: 'GB', + Market.GD: 'GD', + Market.GE: 'GE', + Market.GF: 'GF', + Market.GG: 'GG', + Market.GH: 'GH', + Market.GI: 'GI', + Market.GL: 'GL', + Market.GM: 'GM', + Market.GN: 'GN', + Market.GP: 'GP', + Market.GQ: 'GQ', + Market.GR: 'GR', + Market.GS: 'GS', + Market.GT: 'GT', + Market.GU: 'GU', + Market.GW: 'GW', + Market.GY: 'GY', + Market.HK: 'HK', + Market.HM: 'HM', + Market.HN: 'HN', + Market.HR: 'HR', + Market.HT: 'HT', + Market.HU: 'HU', + Market.ID: 'ID', + Market.IE: 'IE', + Market.IL: 'IL', + Market.IM: 'IM', + Market.IN: 'IN', + Market.IO: 'IO', + Market.IQ: 'IQ', + Market.IR: 'IR', + Market.IS: 'IS', + Market.IT: 'IT', + Market.JE: 'JE', + Market.JM: 'JM', + Market.JO: 'JO', + Market.JP: 'JP', + Market.KE: 'KE', + Market.KG: 'KG', + Market.KH: 'KH', + Market.KI: 'KI', + Market.KM: 'KM', + Market.KN: 'KN', + Market.KP: 'KP', + Market.KR: 'KR', + Market.KW: 'KW', + Market.KY: 'KY', + Market.KZ: 'KZ', + Market.LA: 'LA', + Market.LB: 'LB', + Market.LC: 'LC', + Market.LI: 'LI', + Market.LK: 'LK', + Market.LR: 'LR', + Market.LS: 'LS', + Market.LT: 'LT', + Market.LU: 'LU', + Market.LV: 'LV', + Market.LY: 'LY', + Market.MA: 'MA', + Market.MC: 'MC', + Market.MD: 'MD', + Market.ME: 'ME', + Market.MF: 'MF', + Market.MG: 'MG', + Market.MH: 'MH', + Market.MK: 'MK', + Market.ML: 'ML', + Market.MM: 'MM', + Market.MN: 'MN', + Market.MO: 'MO', + Market.MP: 'MP', + Market.MQ: 'MQ', + Market.MR: 'MR', + Market.MS: 'MS', + Market.MT: 'MT', + Market.MU: 'MU', + Market.MV: 'MV', + Market.MW: 'MW', + Market.MX: 'MX', + Market.MY: 'MY', + Market.MZ: 'MZ', + Market.NA: 'NA', + Market.NC: 'NC', + Market.NE: 'NE', + Market.NF: 'NF', + Market.NG: 'NG', + Market.NI: 'NI', + Market.NL: 'NL', + Market.NO: 'NO', + Market.NP: 'NP', + Market.NR: 'NR', + Market.NU: 'NU', + Market.NZ: 'NZ', + Market.OM: 'OM', + Market.PA: 'PA', + Market.PE: 'PE', + Market.PF: 'PF', + Market.PG: 'PG', + Market.PH: 'PH', + Market.PK: 'PK', + Market.PL: 'PL', + Market.PM: 'PM', + Market.PN: 'PN', + Market.PR: 'PR', + Market.PS: 'PS', + Market.PT: 'PT', + Market.PW: 'PW', + Market.PY: 'PY', + Market.QA: 'QA', + Market.RE: 'RE', + Market.RO: 'RO', + Market.RS: 'RS', + Market.RU: 'RU', + Market.RW: 'RW', + Market.SA: 'SA', + Market.SB: 'SB', + Market.SC: 'SC', + Market.SD: 'SD', + Market.SE: 'SE', + Market.SG: 'SG', + Market.SH: 'SH', + Market.SI: 'SI', + Market.SJ: 'SJ', + Market.SK: 'SK', + Market.SL: 'SL', + Market.SM: 'SM', + Market.SN: 'SN', + Market.SO: 'SO', + Market.SR: 'SR', + Market.SS: 'SS', + Market.ST: 'ST', + Market.SV: 'SV', + Market.SX: 'SX', + Market.SY: 'SY', + Market.SZ: 'SZ', + Market.TC: 'TC', + Market.TD: 'TD', + Market.TF: 'TF', + Market.TG: 'TG', + Market.TH: 'TH', + Market.TJ: 'TJ', + Market.TK: 'TK', + Market.TL: 'TL', + Market.TM: 'TM', + Market.TN: 'TN', + Market.TO: 'TO', + Market.TR: 'TR', + Market.TT: 'TT', + Market.TV: 'TV', + Market.TW: 'TW', + Market.TZ: 'TZ', + Market.UA: 'UA', + Market.UG: 'UG', + Market.UM: 'UM', + Market.US: 'US', + Market.UY: 'UY', + Market.UZ: 'UZ', + Market.VA: 'VA', + Market.VC: 'VC', + Market.VE: 'VE', + Market.VG: 'VG', + Market.VI: 'VI', + Market.VN: 'VN', + Market.VU: 'VU', + Market.WF: 'WF', + Market.WS: 'WS', + Market.XK: 'XK', + Market.YE: 'YE', + Market.YT: 'YT', + Market.ZA: 'ZA', + Market.ZM: 'ZM', + Market.ZW: 'ZW', +}; + +const _$SearchModeEnumMap = { + SearchMode.youtube: 'youtube', + SearchMode.youtubeMusic: 'youtubeMusic', +}; + +const _$ThemeModeEnumMap = { + ThemeMode.system: 'system', + ThemeMode.light: 'light', + ThemeMode.dark: 'dark', +}; + +const _$YoutubeApiTypeEnumMap = { + YoutubeApiType.youtube: 'youtube', + YoutubeApiType.piped: 'piped', +}; + +const _$MusicCodecEnumMap = { + MusicCodec.m4a: 'm4a', + MusicCodec.weba: 'weba', +}; diff --git a/lib/provider/user_preferences_provider.dart b/lib/provider/user_preferences_provider.dart deleted file mode 100644 index 80c71de9..00000000 --- a/lib/provider/user_preferences_provider.dart +++ /dev/null @@ -1,391 +0,0 @@ -import 'dart:async'; -import 'dart:convert'; - -import 'package:flutter/material.dart'; -import 'package:flutter_desktop_tools/flutter_desktop_tools.dart'; -import 'package:flutter_riverpod/flutter_riverpod.dart'; -import 'package:path_provider/path_provider.dart'; -import 'package:spotify/spotify.dart'; -import 'package:spotube/components/settings/color_scheme_picker_dialog.dart'; -import 'package:spotube/models/matched_track.dart'; -import 'package:spotube/provider/palette_provider.dart'; -import 'package:spotube/provider/proxy_playlist/proxy_playlist_provider.dart'; -import 'package:spotube/services/audio_player/audio_player.dart'; - -import 'package:spotube/utils/persisted_state_notifier.dart'; -import 'package:spotube/utils/platform.dart'; -import 'package:path/path.dart' as path; - -enum LayoutMode { - compact, - extended, - adaptive, -} - -enum AudioQuality { - high, - low, -} - -enum CloseBehavior { - minimizeToTray, - close, -} - -enum YoutubeApiType { - youtube, - piped; - - String get label => name[0].toUpperCase() + name.substring(1); -} - -enum MusicCodec { - m4a._("M4a (Best for downloaded music)"), - weba._("WebA (Best for streamed music)\nDoesn't support audio metadata"); - - final String label; - const MusicCodec._(this.label); -} - -class UserPreferences { - final AudioQuality audioQuality; - final bool albumColorSync; - final bool amoledDarkTheme; - final bool checkUpdate; - final bool normalizeAudio; - final bool showSystemTrayIcon; - final bool skipNonMusic; - final bool systemTitleBar; - final CloseBehavior closeBehavior; - final SpotubeColor accentColorScheme; - final LayoutMode layoutMode; - final Locale locale; - final Market recommendationMarket; - final SearchMode searchMode; - String downloadLocation; - final String pipedInstance; - final ThemeMode themeMode; - final YoutubeApiType youtubeApiType; - final MusicCodec streamMusicCodec; - final MusicCodec downloadMusicCodec; - - UserPreferences({ - required AudioQuality? audioQuality, - required bool? albumColorSync, - required bool? amoledDarkTheme, - required bool? checkUpdate, - required bool? normalizeAudio, - required bool? showSystemTrayIcon, - required bool? skipNonMusic, - required bool? systemTitleBar, - required CloseBehavior? closeBehavior, - required SpotubeColor? accentColorScheme, - required LayoutMode? layoutMode, - required Locale? locale, - required Market? recommendationMarket, - required SearchMode? searchMode, - required String? downloadLocation, - required String? pipedInstance, - required ThemeMode? themeMode, - required YoutubeApiType? youtubeApiType, - required MusicCodec? streamMusicCodec, - required MusicCodec? downloadMusicCodec, - }) : accentColorScheme = - accentColorScheme ?? const SpotubeColor(0xFF2196F3, name: "Blue"), - albumColorSync = albumColorSync ?? true, - amoledDarkTheme = amoledDarkTheme ?? false, - audioQuality = audioQuality ?? AudioQuality.high, - checkUpdate = checkUpdate ?? true, - closeBehavior = closeBehavior ?? CloseBehavior.close, - downloadLocation = downloadLocation ?? "", - downloadMusicCodec = downloadMusicCodec ?? MusicCodec.m4a, - layoutMode = layoutMode ?? LayoutMode.adaptive, - locale = locale ?? const Locale("system", "system"), - normalizeAudio = normalizeAudio ?? true, - pipedInstance = pipedInstance ?? "https://pipedapi.kavin.rocks", - recommendationMarket = recommendationMarket ?? Market.US, - searchMode = searchMode ?? SearchMode.youtube, - showSystemTrayIcon = showSystemTrayIcon ?? true, - skipNonMusic = skipNonMusic ?? true, - streamMusicCodec = streamMusicCodec ?? MusicCodec.weba, - systemTitleBar = systemTitleBar ?? false, - themeMode = themeMode ?? ThemeMode.system, - youtubeApiType = youtubeApiType ?? YoutubeApiType.youtube { - if (downloadLocation == null) { - _getDefaultDownloadDirectory().then( - (value) => this.downloadLocation = value, - ); - } - } - - factory UserPreferences.withDefaults() { - return UserPreferences( - audioQuality: null, - albumColorSync: null, - amoledDarkTheme: null, - checkUpdate: null, - normalizeAudio: null, - showSystemTrayIcon: null, - skipNonMusic: null, - systemTitleBar: null, - closeBehavior: null, - accentColorScheme: null, - layoutMode: null, - locale: null, - recommendationMarket: null, - searchMode: null, - downloadLocation: null, - pipedInstance: null, - themeMode: null, - youtubeApiType: null, - streamMusicCodec: null, - downloadMusicCodec: null, - ); - } - - static Future _getDefaultDownloadDirectory() async { - if (kIsAndroid) return "/storage/emulated/0/Download/Spotube"; - - if (kIsMacOS) { - return path.join((await getLibraryDirectory()).path, "Caches"); - } - - return getDownloadsDirectory().then((dir) { - return path.join(dir!.path, "Spotube"); - }); - } - - static Future fromJson(Map json) async { - final localeMap = - json["locale"] != null ? jsonDecode(json["locale"]) : null; - - final systemTitleBar = json["systemTitleBar"] ?? false; - if (DesktopTools.platform.isDesktop) { - await DesktopTools.window.setTitleBarStyle( - systemTitleBar ? TitleBarStyle.normal : TitleBarStyle.hidden, - ); - } - - final normalizeAudio = json["normalizeAudio"] ?? true; - audioPlayer.setAudioNormalization(normalizeAudio); - - return UserPreferences( - accentColorScheme: json["accentColorScheme"] == null - ? null - : SpotubeColor.fromString(json["accentColorScheme"]), - albumColorSync: json["albumColorSync"], - amoledDarkTheme: json["amoledDarkTheme"], - audioQuality: AudioQuality.values[json["audioQuality"]], - checkUpdate: json["checkUpdate"], - closeBehavior: CloseBehavior.values[json["closeBehavior"]], - downloadLocation: - json["downloadLocation"] ?? await _getDefaultDownloadDirectory(), - downloadMusicCodec: MusicCodec.values[json["downloadMusicCodec"]], - layoutMode: LayoutMode.values[json["layoutMode"]], - locale: - localeMap == null ? null : Locale(localeMap?["lc"], localeMap?["cc"]), - normalizeAudio: json["normalizeAudio"], - pipedInstance: json["pipedInstance"], - recommendationMarket: Market.values[json["recommendationMarket"]], - searchMode: SearchMode.values[json["searchMode"]], - showSystemTrayIcon: json["showSystemTrayIcon"], - skipNonMusic: json["skipNonMusic"], - streamMusicCodec: MusicCodec.values[json["streamMusicCodec"]], - systemTitleBar: json["systemTitleBar"], - themeMode: ThemeMode.values[json["themeMode"]], - youtubeApiType: YoutubeApiType.values[json["youtubeApiType"]], - ); - } - - Map toJson() { - return { - "recommendationMarket": recommendationMarket.index, - "themeMode": themeMode.index, - "accentColorScheme": accentColorScheme.toString(), - "albumColorSync": albumColorSync, - "checkUpdate": checkUpdate, - "audioQuality": audioQuality.index, - "downloadLocation": downloadLocation, - "layoutMode": layoutMode.index, - "closeBehavior": closeBehavior.index, - "showSystemTrayIcon": showSystemTrayIcon, - "locale": - jsonEncode({"lc": locale.languageCode, "cc": locale.countryCode}), - "pipedInstance": pipedInstance, - "searchMode": searchMode.index, - "skipNonMusic": skipNonMusic, - "youtubeApiType": youtubeApiType.index, - 'systemTitleBar': systemTitleBar, - "amoledDarkTheme": amoledDarkTheme, - "normalizeAudio": normalizeAudio, - "streamMusicCodec": streamMusicCodec.index, - "downloadMusicCodec": downloadMusicCodec.index, - }; - } - - UserPreferences copyWith({ - ThemeMode? themeMode, - SpotubeColor? accentColorScheme, - bool? albumColorSync, - bool? checkUpdate, - AudioQuality? audioQuality, - String? downloadLocation, - LayoutMode? layoutMode, - CloseBehavior? closeBehavior, - bool? showSystemTrayIcon, - Locale? locale, - String? pipedInstance, - SearchMode? searchMode, - bool? skipNonMusic, - YoutubeApiType? youtubeApiType, - Market? recommendationMarket, - bool? saveTrackLyrics, - bool? amoledDarkTheme, - bool? normalizeAudio, - MusicCodec? downloadMusicCodec, - MusicCodec? streamMusicCodec, - bool? systemTitleBar, - }) { - return UserPreferences( - themeMode: themeMode ?? this.themeMode, - accentColorScheme: accentColorScheme ?? this.accentColorScheme, - albumColorSync: albumColorSync ?? this.albumColorSync, - checkUpdate: checkUpdate ?? this.checkUpdate, - audioQuality: audioQuality ?? this.audioQuality, - downloadLocation: downloadLocation ?? this.downloadLocation, - layoutMode: layoutMode ?? this.layoutMode, - closeBehavior: closeBehavior ?? this.closeBehavior, - showSystemTrayIcon: showSystemTrayIcon ?? this.showSystemTrayIcon, - locale: locale ?? this.locale, - pipedInstance: pipedInstance ?? this.pipedInstance, - searchMode: searchMode ?? this.searchMode, - skipNonMusic: skipNonMusic ?? this.skipNonMusic, - youtubeApiType: youtubeApiType ?? this.youtubeApiType, - recommendationMarket: recommendationMarket ?? this.recommendationMarket, - amoledDarkTheme: amoledDarkTheme ?? this.amoledDarkTheme, - downloadMusicCodec: downloadMusicCodec ?? this.downloadMusicCodec, - normalizeAudio: normalizeAudio ?? this.normalizeAudio, - streamMusicCodec: streamMusicCodec ?? this.streamMusicCodec, - systemTitleBar: systemTitleBar ?? this.systemTitleBar, - ); - } -} - -class UserPreferencesNotifier extends PersistedStateNotifier { - final Ref ref; - - UserPreferencesNotifier(this.ref) - : super(UserPreferences.withDefaults(), "preferences"); - - void reset() { - state = UserPreferences.withDefaults(); - } - - void setStreamMusicCodec(MusicCodec codec) { - state = state.copyWith(streamMusicCodec: codec); - } - - void setDownloadMusicCodec(MusicCodec codec) { - state = state.copyWith(downloadMusicCodec: codec); - } - - void setThemeMode(ThemeMode mode) { - state = state.copyWith(themeMode: mode); - } - - void setRecommendationMarket(Market country) { - state = state.copyWith(recommendationMarket: country); - } - - void setAccentColorScheme(SpotubeColor color) { - state = state.copyWith(accentColorScheme: color); - } - - void setAlbumColorSync(bool sync) { - state = state.copyWith(albumColorSync: sync); - - if (!sync) { - ref.read(paletteProvider.notifier).state = null; - } else { - ref.read(ProxyPlaylistNotifier.notifier).updatePalette(); - } - } - - void setCheckUpdate(bool check) { - state = state.copyWith(checkUpdate: check); - } - - void setAudioQuality(AudioQuality quality) { - state = state.copyWith(audioQuality: quality); - } - - void setDownloadLocation(String downloadDir) { - if (downloadDir.isEmpty) return; - state = state.copyWith(downloadLocation: downloadDir); - } - - void setLayoutMode(LayoutMode mode) { - state = state.copyWith(layoutMode: mode); - } - - void setCloseBehavior(CloseBehavior behavior) { - state = state.copyWith(closeBehavior: behavior); - } - - void setShowSystemTrayIcon(bool show) { - state = state.copyWith(showSystemTrayIcon: show); - } - - void setLocale(Locale locale) { - state = state.copyWith(locale: locale); - } - - void setPipedInstance(String instance) { - state = state.copyWith(pipedInstance: instance); - } - - void setSearchMode(SearchMode mode) { - state = state.copyWith(searchMode: mode); - } - - void setSkipNonMusic(bool skip) { - state = state.copyWith(skipNonMusic: skip); - } - - void setYoutubeApiType(YoutubeApiType type) { - state = state.copyWith(youtubeApiType: type); - } - - void setSystemTitleBar(bool isSystemTitleBar) { - state = state.copyWith(systemTitleBar: isSystemTitleBar); - if (DesktopTools.platform.isDesktop) { - DesktopTools.window.setTitleBarStyle( - isSystemTitleBar ? TitleBarStyle.normal : TitleBarStyle.hidden, - ); - } - } - - void setAmoledDarkTheme(bool isAmoled) { - state = state.copyWith(amoledDarkTheme: isAmoled); - } - - void setNormalizeAudio(bool normalize) { - state = state.copyWith(normalizeAudio: normalize); - audioPlayer.setAudioNormalization(normalize); - } - - @override - FutureOr fromJson(Map json) { - return UserPreferences.fromJson(json); - } - - @override - Map toJson() { - return state.toJson(); - } -} - -final userPreferencesProvider = - StateNotifierProvider( - (ref) => UserPreferencesNotifier(ref), -); diff --git a/lib/provider/youtube_provider.dart b/lib/provider/youtube_provider.dart index 0e7b7d0e..33e0496f 100644 --- a/lib/provider/youtube_provider.dart +++ b/lib/provider/youtube_provider.dart @@ -1,5 +1,5 @@ import 'package:hooks_riverpod/hooks_riverpod.dart'; -import 'package:spotube/provider/user_preferences_provider.dart'; +import 'package:spotube/provider/user_preferences/user_preferences_provider.dart'; import 'package:spotube/services/youtube/youtube.dart'; final youtubeProvider = Provider((ref) { diff --git a/lib/services/queries/album.dart b/lib/services/queries/album.dart index 2e2e8f14..546b3d15 100644 --- a/lib/services/queries/album.dart +++ b/lib/services/queries/album.dart @@ -4,7 +4,7 @@ import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:spotify/spotify.dart'; import 'package:spotube/hooks/spotify/use_spotify_infinite_query.dart'; import 'package:spotube/hooks/spotify/use_spotify_query.dart'; -import 'package:spotube/provider/user_preferences_provider.dart'; +import 'package:spotube/provider/user_preferences/user_preferences_provider.dart'; class AlbumQueries { const AlbumQueries(); diff --git a/lib/services/queries/category.dart b/lib/services/queries/category.dart index dbdd2a11..960b5702 100644 --- a/lib/services/queries/category.dart +++ b/lib/services/queries/category.dart @@ -6,7 +6,7 @@ import 'package:spotify/spotify.dart'; import 'package:spotube/extensions/context.dart'; import 'package:spotube/hooks/spotify/use_spotify_infinite_query.dart'; import 'package:spotube/provider/custom_spotify_endpoint_provider.dart'; -import 'package:spotube/provider/user_preferences_provider.dart'; +import 'package:spotube/provider/user_preferences/user_preferences_provider.dart'; class CategoryQueries { const CategoryQueries(); diff --git a/lib/services/queries/playlist.dart b/lib/services/queries/playlist.dart index c4532aa8..2c6c38be 100644 --- a/lib/services/queries/playlist.dart +++ b/lib/services/queries/playlist.dart @@ -11,7 +11,7 @@ import 'package:spotube/hooks/spotify/use_spotify_infinite_query.dart'; import 'package:spotube/hooks/spotify/use_spotify_query.dart'; import 'package:spotube/pages/library/playlist_generate/playlist_generate.dart'; import 'package:spotube/provider/custom_spotify_endpoint_provider.dart'; -import 'package:spotube/provider/user_preferences_provider.dart'; +import 'package:spotube/provider/user_preferences/user_preferences_provider.dart'; typedef RecommendationParameters = ({ RecommendationAttribute acousticness, diff --git a/lib/services/queries/views.dart b/lib/services/queries/views.dart index b56f07d9..4864ffe1 100644 --- a/lib/services/queries/views.dart +++ b/lib/services/queries/views.dart @@ -5,7 +5,7 @@ import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:spotube/extensions/context.dart'; import 'package:spotube/provider/authentication_provider.dart'; import 'package:spotube/provider/custom_spotify_endpoint_provider.dart'; -import 'package:spotube/provider/user_preferences_provider.dart'; +import 'package:spotube/provider/user_preferences/user_preferences_provider.dart'; class ViewsQueries { const ViewsQueries(); diff --git a/lib/services/youtube/youtube.dart b/lib/services/youtube/youtube.dart index c8c277e3..2b52864b 100644 --- a/lib/services/youtube/youtube.dart +++ b/lib/services/youtube/youtube.dart @@ -4,7 +4,7 @@ import 'package:piped_client/piped_client.dart'; import 'package:spotube/collections/routes.dart'; import 'package:spotube/components/shared/dialogs/piped_down_dialog.dart'; import 'package:spotube/models/matched_track.dart'; -import 'package:spotube/provider/user_preferences_provider.dart'; +import 'package:spotube/provider/user_preferences/user_preferences_state.dart'; import 'package:spotube/utils/primitive_utils.dart'; import 'package:youtube_explode_dart/youtube_explode_dart.dart'; From 14069cd4fe08597c8d9aa0810270fb4c386c1d55 Mon Sep 17 00:00:00 2001 From: Kingkor Roy Tirtho Date: Wed, 15 Nov 2023 18:34:46 +0600 Subject: [PATCH 022/195] feat: Add JioSaavn as audio source (#881) * feat: implement new SourcedTrack for youtube and piped * refactor: replace old spotube track with sourced track * feat: add jiosaavn as audio source * fix: download not working other than jiosaavn * Merge branch 'dev' into feat-jiosaavn --- .../library/user_downloads/download_item.dart | 36 +-- .../player/sibling_tracks_sheet.dart | 57 ++-- .../shared/dialogs/track_details_dialog.dart | 31 +- .../shared/track_table/track_options.dart | 2 +- .../shared/track_table/tracks_table_view.dart | 4 +- lib/main.dart | 14 +- lib/models/current_playlist.dart | 9 +- lib/models/matched_track.dart | 69 ----- lib/models/matched_track.g.dart | 86 ------ lib/models/source_match.dart | 54 ++++ lib/models/source_match.g.dart | 119 ++++++++ lib/models/spotube_track.dart | 274 ------------------ lib/pages/album/album.dart | 4 +- lib/pages/playlist/playlist.dart | 4 +- lib/pages/settings/sections/playback.dart | 113 ++++---- lib/provider/download_manager_provider.dart | 73 ++--- lib/provider/piped_instances_provider.dart | 7 +- .../proxy_playlist/next_fetcher_mixin.dart | 53 +--- .../proxy_playlist/proxy_playlist.dart | 18 +- .../proxy_playlist_provider.dart | 91 +++--- .../user_preferences_provider.dart | 12 +- .../user_preferences_state.dart | 63 ++-- .../user_preferences_state.g.dart | 54 ++-- lib/provider/youtube_provider.dart | 8 - lib/services/audio_player/audio_player.dart | 2 +- .../audio_player/audio_player_impl.dart | 8 +- .../audio_services/audio_services.dart | 6 +- .../audio_services/linux_audio_service.dart | 7 +- lib/services/queries/lyrics.dart | 4 +- lib/services/sourced_track/enums.dart | 18 ++ lib/services/sourced_track/exceptions.dart | 7 + .../sourced_track/models/source_info.dart | 33 +++ .../sourced_track/models/source_info.g.dart | 30 ++ .../sourced_track/models/source_map.dart | 58 ++++ .../sourced_track/models/source_map.g.dart | 35 +++ .../sourced_track/models/video_info.dart | 114 ++++++++ lib/services/sourced_track/sourced_track.dart | 171 +++++++++++ .../sourced_track/sources/jiosaavn.dart | 159 ++++++++++ lib/services/sourced_track/sources/piped.dart | 257 ++++++++++++++++ .../sourced_track/sources/youtube.dart | 256 ++++++++++++++++ lib/services/supabase.dart | 6 +- lib/services/youtube/youtube.dart | 248 ---------------- lib/utils/service_utils.dart | 6 +- pubspec.lock | 17 ++ pubspec.yaml | 3 + 45 files changed, 1691 insertions(+), 1009 deletions(-) delete mode 100644 lib/models/matched_track.dart delete mode 100644 lib/models/matched_track.g.dart create mode 100644 lib/models/source_match.dart create mode 100644 lib/models/source_match.g.dart delete mode 100644 lib/models/spotube_track.dart delete mode 100644 lib/provider/youtube_provider.dart create mode 100644 lib/services/sourced_track/enums.dart create mode 100644 lib/services/sourced_track/exceptions.dart create mode 100644 lib/services/sourced_track/models/source_info.dart create mode 100644 lib/services/sourced_track/models/source_info.g.dart create mode 100644 lib/services/sourced_track/models/source_map.dart create mode 100644 lib/services/sourced_track/models/source_map.g.dart create mode 100644 lib/services/sourced_track/models/video_info.dart create mode 100644 lib/services/sourced_track/sourced_track.dart create mode 100644 lib/services/sourced_track/sources/jiosaavn.dart create mode 100644 lib/services/sourced_track/sources/piped.dart create mode 100644 lib/services/sourced_track/sources/youtube.dart delete mode 100644 lib/services/youtube/youtube.dart diff --git a/lib/components/library/user_downloads/download_item.dart b/lib/components/library/user_downloads/download_item.dart index ae8a2513..10dec410 100644 --- a/lib/components/library/user_downloads/download_item.dart +++ b/lib/components/library/user_downloads/download_item.dart @@ -5,9 +5,9 @@ import 'package:spotify/spotify.dart'; import 'package:spotube/collections/spotube_icons.dart'; import 'package:spotube/components/shared/image/universal_image.dart'; import 'package:spotube/extensions/context.dart'; -import 'package:spotube/models/spotube_track.dart'; import 'package:spotube/provider/download_manager_provider.dart'; import 'package:spotube/services/download_manager/download_status.dart'; +import 'package:spotube/services/sourced_track/sourced_track.dart'; import 'package:spotube/utils/type_conversion_utils.dart'; class DownloadItem extends HookConsumerWidget { @@ -24,25 +24,25 @@ class DownloadItem extends HookConsumerWidget { final taskStatus = useState(null); useEffect(() { - if (track is! SpotubeTrack) return null; - final notifier = downloadManager.getStatusNotifier(track as SpotubeTrack); + if (track is! SourcedTrack) return null; + final notifier = downloadManager.getStatusNotifier(track as SourcedTrack); taskStatus.value = notifier?.value; - listener() { + + void listener() { taskStatus.value = notifier?.value; } - downloadManager - .getStatusNotifier(track as SpotubeTrack) - ?.addListener(listener); + notifier?.addListener(listener); return () { - downloadManager - .getStatusNotifier(track as SpotubeTrack) - ?.removeListener(listener); + notifier?.removeListener(listener); }; }, [track]); + final isQueryingSourceInfo = + taskStatus.value == null || track is! SourcedTrack; + return ListTile( leading: Padding( padding: const EdgeInsets.symmetric(horizontal: 5), @@ -63,7 +63,7 @@ class DownloadItem extends HookConsumerWidget { track.artists ?? [], mainAxisAlignment: WrapAlignment.start, ), - trailing: taskStatus.value == null || track is! SpotubeTrack + trailing: isQueryingSourceInfo ? Text( context.l10n.querying_info, style: Theme.of(context).textTheme.labelMedium, @@ -72,7 +72,7 @@ class DownloadItem extends HookConsumerWidget { DownloadStatus.downloading => HookBuilder(builder: (context) { final taskProgress = useListenable(useMemoized( () => downloadManager - .getProgressNotifier(track as SpotubeTrack), + .getProgressNotifier(track as SourcedTrack), [track], )); return SizedBox( @@ -86,13 +86,13 @@ class DownloadItem extends HookConsumerWidget { IconButton( icon: const Icon(SpotubeIcons.pause), onPressed: () { - downloadManager.pause(track as SpotubeTrack); + downloadManager.pause(track as SourcedTrack); }), const SizedBox(width: 10), IconButton( icon: const Icon(SpotubeIcons.close), onPressed: () { - downloadManager.cancel(track as SpotubeTrack); + downloadManager.cancel(track as SourcedTrack); }), ], ), @@ -104,13 +104,13 @@ class DownloadItem extends HookConsumerWidget { IconButton( icon: const Icon(SpotubeIcons.play), onPressed: () { - downloadManager.resume(track as SpotubeTrack); + downloadManager.resume(track as SourcedTrack); }), const SizedBox(width: 10), IconButton( icon: const Icon(SpotubeIcons.close), onPressed: () { - downloadManager.cancel(track as SpotubeTrack); + downloadManager.cancel(track as SourcedTrack); }) ], ), @@ -126,7 +126,7 @@ class DownloadItem extends HookConsumerWidget { IconButton( icon: const Icon(SpotubeIcons.refresh), onPressed: () { - downloadManager.retry(track as SpotubeTrack); + downloadManager.retry(track as SourcedTrack); }, ), ], @@ -137,7 +137,7 @@ class DownloadItem extends HookConsumerWidget { DownloadStatus.queued => IconButton( icon: const Icon(SpotubeIcons.close), onPressed: () { - downloadManager.removeFromQueue(track as SpotubeTrack); + downloadManager.removeFromQueue(track as SourcedTrack); }), }, ); diff --git a/lib/components/player/sibling_tracks_sheet.dart b/lib/components/player/sibling_tracks_sheet.dart index ee8d9719..cf1429b9 100644 --- a/lib/components/player/sibling_tracks_sheet.dart +++ b/lib/components/player/sibling_tracks_sheet.dart @@ -1,5 +1,6 @@ import 'dart:ui'; +import 'package:collection/collection.dart'; import 'package:flutter/material.dart'; import 'package:flutter_hooks/flutter_hooks.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; @@ -12,13 +13,13 @@ import 'package:spotube/extensions/constrains.dart'; import 'package:spotube/extensions/context.dart'; import 'package:spotube/extensions/duration.dart'; import 'package:spotube/hooks/utils/use_debounce.dart'; -import 'package:spotube/models/matched_track.dart'; -import 'package:spotube/models/spotube_track.dart'; import 'package:spotube/provider/proxy_playlist/proxy_playlist_provider.dart'; import 'package:spotube/provider/user_preferences/user_preferences_provider.dart'; import 'package:spotube/provider/user_preferences/user_preferences_state.dart'; -import 'package:spotube/provider/youtube_provider.dart'; -import 'package:spotube/services/youtube/youtube.dart'; +import 'package:spotube/services/sourced_track/models/source_info.dart'; +import 'package:spotube/services/sourced_track/models/video_info.dart'; +import 'package:spotube/services/sourced_track/sourced_track.dart'; +import 'package:spotube/services/sourced_track/sources/youtube.dart'; import 'package:spotube/utils/service_utils.dart'; import 'package:spotube/utils/type_conversion_utils.dart'; @@ -35,7 +36,6 @@ class SiblingTracksSheet extends HookConsumerWidget { final playlist = ref.watch(ProxyPlaylistNotifier.provider); final playlistNotifier = ref.watch(ProxyPlaylistNotifier.notifier); final preferences = ref.watch(userPreferencesProvider); - final youtube = ref.watch(youtubeProvider); final isSearching = useState(false); final searchMode = useState(preferences.searchMode); @@ -61,18 +61,31 @@ class SiblingTracksSheet extends HookConsumerWidget { final searchRequest = useMemoized(() async { if (searchTerm.trim().isEmpty) { - return []; + return []; } - return youtube.search(searchTerm.trim()); + final results = await youtubeClient.search.search(searchTerm.trim()); + + return await Future.wait( + results.map(YoutubeVideoInfo.fromVideo).mapIndexed((i, video) async { + final siblingType = await YoutubeSourcedTrack.toSiblingType(i, video); + return siblingType.info; + }), + ); }, [ searchTerm, searchMode.value, ]); - final siblings = playlist.isFetching == false - ? (playlist.activeTrack as SpotubeTrack).siblings - : []; + final siblings = useMemoized( + () => playlist.isFetching == false + ? [ + (playlist.activeTrack as SourcedTrack).sourceInfo, + ...(playlist.activeTrack as SourcedTrack).siblings, + ] + : [], + [playlist.isFetching, playlist.activeTrack], + ); final borderRadius = floating ? BorderRadius.circular(10) @@ -82,21 +95,21 @@ class SiblingTracksSheet extends HookConsumerWidget { ); useEffect(() { - if (playlist.activeTrack is SpotubeTrack && - (playlist.activeTrack as SpotubeTrack).siblings.isEmpty) { + if (playlist.activeTrack is SourcedTrack && + (playlist.activeTrack as SourcedTrack).siblings.isEmpty) { playlistNotifier.populateSibling(); } return null; }, [playlist.activeTrack]); final itemBuilder = useCallback( - (YoutubeVideoInfo video) { + (SourceInfo sourceInfo) { return ListTile( - title: Text(video.title), + title: Text(sourceInfo.title), leading: Padding( padding: const EdgeInsets.all(8.0), child: UniversalImage( - path: video.thumbnailUrl, + path: sourceInfo.thumbnail, height: 60, width: 60, ), @@ -104,16 +117,18 @@ class SiblingTracksSheet extends HookConsumerWidget { shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(5), ), - trailing: Text(video.duration.toHumanReadableString()), - subtitle: Text(video.channelName), + trailing: Text(sourceInfo.duration.toHumanReadableString()), + subtitle: Text(sourceInfo.artist), enabled: playlist.isFetching != true, selected: playlist.isFetching != true && - video.id == (playlist.activeTrack as SpotubeTrack).ytTrack.id, + sourceInfo.id == + (playlist.activeTrack as SourcedTrack).sourceInfo.id, selectedTileColor: theme.popupMenuTheme.color, onTap: () { if (playlist.isFetching == false && - video.id != (playlist.activeTrack as SpotubeTrack).ytTrack.id) { - playlistNotifier.swapSibling(video); + sourceInfo.id != + (playlist.activeTrack as SourcedTrack).sourceInfo.id) { + playlistNotifier.swapSibling(sourceInfo); Navigator.of(context).pop(); } }, @@ -175,7 +190,7 @@ class SiblingTracksSheet extends HookConsumerWidget { }, ) else ...[ - if (preferences.youtubeApiType == YoutubeApiType.piped) + if (preferences.audioSource == AudioSource.piped) PopupMenuButton( icon: const Icon(SpotubeIcons.filter, size: 18), onSelected: (SearchMode mode) { diff --git a/lib/components/shared/dialogs/track_details_dialog.dart b/lib/components/shared/dialogs/track_details_dialog.dart index 9e29c32d..8634776f 100644 --- a/lib/components/shared/dialogs/track_details_dialog.dart +++ b/lib/components/shared/dialogs/track_details_dialog.dart @@ -6,8 +6,7 @@ import 'package:spotube/components/shared/links/hyper_link.dart'; import 'package:spotube/components/shared/links/link_text.dart'; import 'package:spotube/extensions/constrains.dart'; import 'package:spotube/extensions/context.dart'; -import 'package:spotube/models/spotube_track.dart'; -import 'package:spotube/utils/primitive_utils.dart'; +import 'package:spotube/services/sourced_track/sourced_track.dart'; import 'package:spotube/utils/type_conversion_utils.dart'; import 'package:spotube/extensions/duration.dart'; @@ -37,8 +36,8 @@ class TrackDetailsDialog extends HookWidget { overflow: TextOverflow.ellipsis, style: const TextStyle(color: Colors.blue), ), - context.l10n.duration: (track is SpotubeTrack - ? (track as SpotubeTrack).ytTrack.duration + context.l10n.duration: (track is SourcedTrack + ? (track as SourcedTrack).sourceInfo.duration : track.duration!) .toHumanReadableString(), if (track.album!.releaseDate != null) @@ -46,33 +45,27 @@ class TrackDetailsDialog extends HookWidget { context.l10n.popularity: track.popularity?.toString() ?? "0", }; - final ytTrack = - track is SpotubeTrack ? (track as SpotubeTrack).ytTrack : null; + final sourceInfo = + track is SourcedTrack ? (track as SourcedTrack).sourceInfo : null; - final ytTracksDetailsMap = ytTrack == null + final ytTracksDetailsMap = sourceInfo == null ? {} : { context.l10n.youtube: Hyperlink( - "https://piped.video/watch?v=${ytTrack.id}", - "https://piped.video/watch?v=${ytTrack.id}", + "https://piped.video/watch?v=${sourceInfo.id}", + "https://piped.video/watch?v=${sourceInfo.id}", maxLines: 2, overflow: TextOverflow.ellipsis, ), context.l10n.channel: Hyperlink( - ytTrack.channelName, - "https://youtube.com${ytTrack.channelName}", + sourceInfo.artist, + sourceInfo.artistUrl, maxLines: 2, overflow: TextOverflow.ellipsis, ), - context.l10n.likes: - PrimitiveUtils.toReadableNumber(ytTrack.likes.toDouble()), - context.l10n.dislikes: - PrimitiveUtils.toReadableNumber(ytTrack.dislikes.toDouble()), - context.l10n.views: - PrimitiveUtils.toReadableNumber(ytTrack.views.toDouble()), context.l10n.streamUrl: Hyperlink( - (track as SpotubeTrack).ytUri, - (track as SpotubeTrack).ytUri, + (track as SourcedTrack).url, + (track as SourcedTrack).url, maxLines: 2, overflow: TextOverflow.ellipsis, ), diff --git a/lib/components/shared/track_table/track_options.dart b/lib/components/shared/track_table/track_options.dart index 96bd8b60..b0633d34 100644 --- a/lib/components/shared/track_table/track_options.dart +++ b/lib/components/shared/track_table/track_options.dart @@ -110,7 +110,7 @@ class TrackOptions extends HookConsumerWidget { ]); final progressNotifier = useMemoized(() { - final spotubeTrack = downloadManager.mapToSpotubeTrack(track); + final spotubeTrack = downloadManager.mapToSourcedTrack(track); if (spotubeTrack == null) return null; return downloadManager.getProgressNotifier(spotubeTrack); }); diff --git a/lib/components/shared/track_table/tracks_table_view.dart b/lib/components/shared/track_table/tracks_table_view.dart index 14a4f1a9..003662f5 100644 --- a/lib/components/shared/track_table/tracks_table_view.dart +++ b/lib/components/shared/track_table/tracks_table_view.dart @@ -60,7 +60,7 @@ class TracksTableView extends HookConsumerWidget { ref.watch(downloadManagerProvider); final downloader = ref.watch(downloadManagerProvider.notifier); final apiType = - ref.watch(userPreferencesProvider.select((s) => s.youtubeApiType)); + ref.watch(userPreferencesProvider.select((s) => s.audioSource)); const tableHeadStyle = TextStyle(fontWeight: FontWeight.bold, fontSize: 16); final selected = useState>([]); @@ -195,7 +195,7 @@ class TracksTableView extends HookConsumerWidget { switch (action) { case "download": { - final confirmed = apiType == YoutubeApiType.piped || + final confirmed = apiType == AudioSource.piped || await showDialog( context: context, builder: (context) { diff --git a/lib/main.dart b/lib/main.dart index f46f02c1..5d7ae2a7 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -18,8 +18,8 @@ import 'package:spotube/hooks/configurators/use_disable_battery_optimizations.da import 'package:spotube/hooks/configurators/use_get_storage_perms.dart'; import 'package:spotube/l10n/l10n.dart'; import 'package:spotube/models/logger.dart'; -import 'package:spotube/models/matched_track.dart'; import 'package:spotube/models/skip_segment.dart'; +import 'package:spotube/models/source_match.dart'; import 'package:spotube/provider/palette_provider.dart'; import 'package:spotube/provider/user_preferences/user_preferences_provider.dart'; import 'package:spotube/services/audio_player/audio_player.dart'; @@ -71,16 +71,18 @@ Future main(List rawArgs) async { cacheDir: hiveCacheDir, connectivity: FlQueryInternetConnectionCheckerAdapter(), ); - Hive.registerAdapter(MatchedTrackAdapter()); + Hive.registerAdapter(SkipSegmentAdapter()); - Hive.registerAdapter(SearchModeAdapter()); + + Hive.registerAdapter(SourceMatchAdapter()); + Hive.registerAdapter(SourceTypeAdapter()); // Cache versioning entities with Adapter - MatchedTrack.version = 'v1'; + SourceMatch.version = 'v1'; SkipSegment.version = 'v1'; - await Hive.openLazyBox( - MatchedTrack.boxName, + await Hive.openLazyBox( + SourceMatch.boxName, path: hiveCacheDir, ); await Hive.openLazyBox( diff --git a/lib/models/current_playlist.dart b/lib/models/current_playlist.dart index 1c3f8e16..53ea2799 100644 --- a/lib/models/current_playlist.dart +++ b/lib/models/current_playlist.dart @@ -1,6 +1,7 @@ +import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:spotify/spotify.dart'; -import 'package:spotube/models/spotube_track.dart'; import 'package:spotube/extensions/track.dart'; +import 'package:spotube/services/sourced_track/sourced_track.dart'; class CurrentPlaylist { List? _tempTrack; @@ -18,13 +19,13 @@ class CurrentPlaylist { this.isLocal = false, }); - static CurrentPlaylist fromJson(Map map) { + static CurrentPlaylist fromJson(Map map, Ref ref) { return CurrentPlaylist( id: map["id"], tracks: List.castFrom(map["tracks"] .map( (track) => map["isLocal"] == true - ? SpotubeTrack.fromJson(track) + ? SourcedTrack.fromJson(track, ref: ref) : Track.fromJson(track), ) .toList()), @@ -66,7 +67,7 @@ class CurrentPlaylist { "name": name, "tracks": tracks .map((track) => - track is SpotubeTrack ? track.toJson() : track.toJson()) + track is SourcedTrack ? track.toJson() : track.toJson()) .toList(), "thumbnail": thumbnail, "isLocal": isLocal, diff --git a/lib/models/matched_track.dart b/lib/models/matched_track.dart deleted file mode 100644 index b7cc0a3f..00000000 --- a/lib/models/matched_track.dart +++ /dev/null @@ -1,69 +0,0 @@ -import "package:hive/hive.dart"; -part "matched_track.g.dart"; - -@HiveType(typeId: 1) -class MatchedTrack { - @HiveField(0) - String youtubeId; - @HiveField(1) - String spotifyId; - @HiveField(2) - SearchMode searchMode; - - String? id; - DateTime? createdAt; - - bool get isSynced => id != null; - - static String version = 'v1'; - static final boxName = "oss.krtirtho.spotube.matched_tracks.$version"; - - static LazyBox get box => Hive.lazyBox(boxName); - - MatchedTrack({ - required this.youtubeId, - required this.spotifyId, - required this.searchMode, - this.id, - this.createdAt, - }); - - factory MatchedTrack.fromJson(Map json) { - return MatchedTrack( - searchMode: SearchMode.fromString(json["searchMode"]), - youtubeId: json["youtube_id"], - spotifyId: json["spotify_id"], - id: json["id"], - createdAt: DateTime.parse(json["created_at"]), - ); - } - - Map toJson() { - return { - "youtube_id": youtubeId, - "spotify_id": spotifyId, - "id": id, - "searchMode": searchMode.name, - "created_at": createdAt?.toString() - }..removeWhere((key, value) => value == null); - } -} - -@HiveType(typeId: 4) -enum SearchMode { - @HiveField(0) - youtube._internal('YouTube'), - @HiveField(1) - youtubeMusic._internal('YouTube Music'); - - final String label; - - const SearchMode._internal(this.label); - - factory SearchMode.fromString(String value) { - return SearchMode.values.firstWhere( - (element) => element.name == value, - orElse: () => SearchMode.youtube, - ); - } -} diff --git a/lib/models/matched_track.g.dart b/lib/models/matched_track.g.dart deleted file mode 100644 index dd166e77..00000000 --- a/lib/models/matched_track.g.dart +++ /dev/null @@ -1,86 +0,0 @@ -// GENERATED CODE - DO NOT MODIFY BY HAND - -part of 'matched_track.dart'; - -// ************************************************************************** -// TypeAdapterGenerator -// ************************************************************************** - -class MatchedTrackAdapter extends TypeAdapter { - @override - final int typeId = 1; - - @override - MatchedTrack read(BinaryReader reader) { - final numOfFields = reader.readByte(); - final fields = { - for (int i = 0; i < numOfFields; i++) reader.readByte(): reader.read(), - }; - return MatchedTrack( - youtubeId: fields[0] as String, - spotifyId: fields[1] as String, - searchMode: fields[2] as SearchMode, - ); - } - - @override - void write(BinaryWriter writer, MatchedTrack obj) { - writer - ..writeByte(3) - ..writeByte(0) - ..write(obj.youtubeId) - ..writeByte(1) - ..write(obj.spotifyId) - ..writeByte(2) - ..write(obj.searchMode); - } - - @override - int get hashCode => typeId.hashCode; - - @override - bool operator ==(Object other) => - identical(this, other) || - other is MatchedTrackAdapter && - runtimeType == other.runtimeType && - typeId == other.typeId; -} - -class SearchModeAdapter extends TypeAdapter { - @override - final int typeId = 4; - - @override - SearchMode read(BinaryReader reader) { - switch (reader.readByte()) { - case 0: - return SearchMode.youtube; - case 1: - return SearchMode.youtubeMusic; - default: - return SearchMode.youtube; - } - } - - @override - void write(BinaryWriter writer, SearchMode obj) { - switch (obj) { - case SearchMode.youtube: - writer.writeByte(0); - break; - case SearchMode.youtubeMusic: - writer.writeByte(1); - break; - } - } - - @override - int get hashCode => typeId.hashCode; - - @override - bool operator ==(Object other) => - identical(this, other) || - other is SearchModeAdapter && - runtimeType == other.runtimeType && - typeId == other.typeId; -} diff --git a/lib/models/source_match.dart b/lib/models/source_match.dart new file mode 100644 index 00000000..57a9f963 --- /dev/null +++ b/lib/models/source_match.dart @@ -0,0 +1,54 @@ +import 'package:hive/hive.dart'; +import 'package:json_annotation/json_annotation.dart'; + +part 'source_match.g.dart'; + +@JsonEnum() +@HiveType(typeId: 5) +enum SourceType { + @HiveField(0) + youtube._("YouTube"), + + @HiveField(1) + youtubeMusic._("YouTube Music"), + + @HiveField(2) + jiosaavn._("JioSaavn"); + + final String label; + + const SourceType._(this.label); +} + +@JsonSerializable() +@HiveType(typeId: 6) +class SourceMatch { + @HiveField(0) + String id; + + @HiveField(1) + String sourceId; + + @HiveField(2) + SourceType sourceType; + + @HiveField(3) + DateTime createdAt; + + SourceMatch({ + required this.id, + required this.sourceId, + required this.sourceType, + required this.createdAt, + }); + + factory SourceMatch.fromJson(Map json) => + _$SourceMatchFromJson(json); + + Map toJson() => _$SourceMatchToJson(this); + + static String version = 'v1'; + static final boxName = "oss.krtirtho.spotube.source_matches.$version"; + + static LazyBox get box => Hive.lazyBox(boxName); +} diff --git a/lib/models/source_match.g.dart b/lib/models/source_match.g.dart new file mode 100644 index 00000000..11f34bf3 --- /dev/null +++ b/lib/models/source_match.g.dart @@ -0,0 +1,119 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +part of 'source_match.dart'; + +// ************************************************************************** +// TypeAdapterGenerator +// ************************************************************************** + +class SourceMatchAdapter extends TypeAdapter { + @override + final int typeId = 6; + + @override + SourceMatch read(BinaryReader reader) { + final numOfFields = reader.readByte(); + final fields = { + for (int i = 0; i < numOfFields; i++) reader.readByte(): reader.read(), + }; + return SourceMatch( + id: fields[0] as String, + sourceId: fields[1] as String, + sourceType: fields[2] as SourceType, + createdAt: fields[3] as DateTime, + ); + } + + @override + void write(BinaryWriter writer, SourceMatch obj) { + writer + ..writeByte(4) + ..writeByte(0) + ..write(obj.id) + ..writeByte(1) + ..write(obj.sourceId) + ..writeByte(2) + ..write(obj.sourceType) + ..writeByte(3) + ..write(obj.createdAt); + } + + @override + int get hashCode => typeId.hashCode; + + @override + bool operator ==(Object other) => + identical(this, other) || + other is SourceMatchAdapter && + runtimeType == other.runtimeType && + typeId == other.typeId; +} + +class SourceTypeAdapter extends TypeAdapter { + @override + final int typeId = 5; + + @override + SourceType read(BinaryReader reader) { + switch (reader.readByte()) { + case 0: + return SourceType.youtube; + case 1: + return SourceType.youtubeMusic; + case 2: + return SourceType.jiosaavn; + default: + return SourceType.youtube; + } + } + + @override + void write(BinaryWriter writer, SourceType obj) { + switch (obj) { + case SourceType.youtube: + writer.writeByte(0); + break; + case SourceType.youtubeMusic: + writer.writeByte(1); + break; + case SourceType.jiosaavn: + writer.writeByte(2); + break; + } + } + + @override + int get hashCode => typeId.hashCode; + + @override + bool operator ==(Object other) => + identical(this, other) || + other is SourceTypeAdapter && + runtimeType == other.runtimeType && + typeId == other.typeId; +} + +// ************************************************************************** +// JsonSerializableGenerator +// ************************************************************************** + +SourceMatch _$SourceMatchFromJson(Map json) => SourceMatch( + id: json['id'] as String, + sourceId: json['sourceId'] as String, + sourceType: $enumDecode(_$SourceTypeEnumMap, json['sourceType']), + createdAt: DateTime.parse(json['createdAt'] as String), + ); + +Map _$SourceMatchToJson(SourceMatch instance) => + { + 'id': instance.id, + 'sourceId': instance.sourceId, + 'sourceType': _$SourceTypeEnumMap[instance.sourceType]!, + 'createdAt': instance.createdAt.toIso8601String(), + }; + +const _$SourceTypeEnumMap = { + SourceType.youtube: 'youtube', + SourceType.youtubeMusic: 'youtubeMusic', + SourceType.jiosaavn: 'jiosaavn', +}; diff --git a/lib/models/spotube_track.dart b/lib/models/spotube_track.dart deleted file mode 100644 index 67b09ad8..00000000 --- a/lib/models/spotube_track.dart +++ /dev/null @@ -1,274 +0,0 @@ -import 'dart:async'; - -import 'package:spotify/spotify.dart'; -import 'package:spotube/extensions/track.dart'; -import 'package:spotube/models/matched_track.dart'; -import 'package:spotube/provider/user_preferences/user_preferences_state.dart'; -import 'package:spotube/services/youtube/youtube.dart'; -import 'package:spotube/utils/service_utils.dart'; -import 'package:collection/collection.dart'; - -final officialMusicRegex = RegExp( - r"official\s(video|audio|music\svideo|lyric\svideo|visualizer)", - caseSensitive: false, -); - -class TrackNotFoundException implements Exception { - factory TrackNotFoundException(Track track) { - throw Exception("Failed to find any results for ${track.name}"); - } -} - -class SpotubeTrack extends Track { - final YoutubeVideoInfo ytTrack; - final String ytUri; - final MusicCodec codec; - - final List siblings; - - SpotubeTrack( - this.ytTrack, - this.ytUri, - this.siblings, - this.codec, - ) : super(); - - SpotubeTrack.fromTrack({ - required Track track, - required this.ytTrack, - required this.ytUri, - required this.siblings, - required this.codec, - }) : super() { - album = track.album; - artists = track.artists; - availableMarkets = track.availableMarkets; - discNumber = track.discNumber; - durationMs = track.durationMs; - explicit = track.explicit; - externalIds = track.externalIds; - externalUrls = track.externalUrls; - href = track.href; - id = track.id; - isPlayable = track.isPlayable; - linkedFrom = track.linkedFrom; - name = track.name; - popularity = track.popularity; - previewUrl = track.previewUrl; - trackNumber = track.trackNumber; - type = track.type; - uri = track.uri; - } - - static Future> fetchSiblings( - Track track, - YoutubeEndpoints client, - ) async { - final artists = (track.artists ?? []) - .map((ar) => ar.name) - .toList() - .whereNotNull() - .toList(); - - final title = ServiceUtils.getTitle( - track.name!, - artists: artists, - onlyCleanArtist: true, - ).trim(); - - final query = "$title - ${artists.join(", ")}"; - final List siblings = await client.search(query).then( - (res) { - final isYoutubeApi = - client.preferences.youtubeApiType == YoutubeApiType.youtube; - final siblings = isYoutubeApi || - client.preferences.searchMode == SearchMode.youtube - ? ServiceUtils.onlyContainsEnglish(query) - ? res - : res - .sorted((a, b) => b.views.compareTo(a.views)) - .map((sibling) { - int score = 0; - - for (final artist in artists) { - final isSameChannelArtist = - sibling.channelName.toLowerCase() == - artist.toLowerCase(); - final channelContainsArtist = sibling.channelName - .toLowerCase() - .contains(artist.toLowerCase()); - - if (isSameChannelArtist || channelContainsArtist) { - score += 1; - } - - final titleContainsArtist = sibling.title - .toLowerCase() - .contains(artist.toLowerCase()); - - if (titleContainsArtist) { - score += 1; - } - } - - final titleContainsTrackName = sibling.title - .toLowerCase() - .contains(track.name!.toLowerCase()); - - final hasOfficialFlag = officialMusicRegex - .hasMatch(sibling.title.toLowerCase()); - - if (titleContainsTrackName) { - score += 3; - } - - if (hasOfficialFlag) { - score += 1; - } - - if (hasOfficialFlag && titleContainsTrackName) { - score += 2; - } - - return (sibling: sibling, score: score); - }) - .sorted((a, b) => b.score.compareTo(a.score)) - .map((e) => e.sibling) - : res.sorted((a, b) => b.views.compareTo(a.views)).where((item) { - return artists.any( - (artist) => - artist.toLowerCase() == item.channelName.toLowerCase(), - ); - }); - - return siblings.take(10).toList(); - }, - ); - - return siblings; - } - - static Future fetchFromTrack( - Track track, - YoutubeEndpoints client, - MusicCodec codec, - ) async { - final matchedCachedTrack = await MatchedTrack.box.get(track.id!); - var siblings = []; - YoutubeVideoInfo ytVideo; - String ytStreamUrl; - if (matchedCachedTrack != null && - matchedCachedTrack.searchMode == client.preferences.searchMode) { - (ytVideo, ytStreamUrl) = await client.video( - matchedCachedTrack.youtubeId, matchedCachedTrack.searchMode, codec); - } else { - siblings = await fetchSiblings(track, client); - if (siblings.isEmpty) { - throw TrackNotFoundException(track); - } - (ytVideo, ytStreamUrl) = await client.video( - siblings.first.id, - siblings.first.searchMode, - codec, - ); - - await MatchedTrack.box.put( - track.id!, - MatchedTrack( - youtubeId: ytVideo.id, - spotifyId: track.id!, - searchMode: siblings.first.searchMode, - ), - ); - } - - return SpotubeTrack.fromTrack( - track: track, - ytTrack: ytVideo, - ytUri: ytStreamUrl, - siblings: siblings, - codec: codec, - ); - } - - Future swappedCopy( - YoutubeVideoInfo video, - YoutubeEndpoints client, - ) async { - // sibling tracks that were manually searched and swapped - final isStepSibling = siblings.none((element) => element.id == video.id); - - final (ytVideo, ytStreamUrl) = await client.video( - video.id, - siblings.first.searchMode, - // siblings are always swapped when streaming - client.preferences.streamMusicCodec, - ); - - if (!isStepSibling) { - await MatchedTrack.box.put( - id!, - MatchedTrack( - youtubeId: video.id, - spotifyId: id!, - searchMode: siblings.first.searchMode, - ), - ); - } - - return SpotubeTrack.fromTrack( - track: this, - ytTrack: ytVideo, - ytUri: ytStreamUrl, - siblings: [ - video, - ...siblings.where((element) => element.id != video.id), - ], - codec: client.preferences.streamMusicCodec, - ); - } - - static SpotubeTrack fromJson(Map map) { - return SpotubeTrack.fromTrack( - track: Track.fromJson(map), - ytTrack: YoutubeVideoInfo.fromJson(map["ytTrack"]), - ytUri: map["ytUri"], - siblings: List.castFrom>(map["siblings"]) - .map((sibling) => YoutubeVideoInfo.fromJson(sibling)) - .toList(), - codec: MusicCodec.values.firstWhere( - (element) => element.name == map["codec"], - orElse: () => MusicCodec.m4a, - ), - ); - } - - Future populatedCopy(YoutubeEndpoints client) async { - if (this.siblings.isNotEmpty) return this; - - final siblings = await fetchSiblings( - this, - client, - ); - - return SpotubeTrack.fromTrack( - track: this, - ytTrack: ytTrack, - ytUri: ytUri, - siblings: siblings, - codec: codec, - ); - } - - Map toJson() { - return { - // super values - ...TrackJson.trackToJson(this), - // this values - "ytTrack": ytTrack.toJson(), - "ytUri": ytUri, - "siblings": siblings.map((sibling) => sibling.toJson()).toList(), - "codec": codec.name, - }; - } -} diff --git a/lib/pages/album/album.dart b/lib/pages/album/album.dart index a585c9e5..5674e721 100644 --- a/lib/pages/album/album.dart +++ b/lib/pages/album/album.dart @@ -8,9 +8,9 @@ import 'package:spotube/components/shared/track_table/track_collection_view/trac import 'package:spotube/components/shared/track_table/track_collection_view/track_collection_view.dart'; import 'package:spotube/components/shared/track_table/tracks_table_view.dart'; import 'package:spotube/extensions/constrains.dart'; -import 'package:spotube/models/spotube_track.dart'; import 'package:spotube/provider/proxy_playlist/proxy_playlist_provider.dart'; import 'package:spotube/services/queries/queries.dart'; +import 'package:spotube/services/sourced_track/sourced_track.dart'; import 'package:spotube/utils/service_utils.dart'; import 'package:spotube/utils/type_conversion_utils.dart'; @@ -68,7 +68,7 @@ class AlbumPage extends HookConsumerWidget { () => tracksSnapshot.data?.any((s) => s.id! == playlist.activeTrack?.id!) == true && - playlist.activeTrack is SpotubeTrack, + playlist.activeTrack is SourcedTrack, [playlist.activeTrack, tracksSnapshot.data], ); diff --git a/lib/pages/playlist/playlist.dart b/lib/pages/playlist/playlist.dart index 1623195b..6a3ec9b9 100644 --- a/lib/pages/playlist/playlist.dart +++ b/lib/pages/playlist/playlist.dart @@ -11,9 +11,9 @@ import 'package:spotube/extensions/constrains.dart'; import 'package:spotube/models/logger.dart'; import 'package:flutter/material.dart'; import 'package:spotify/spotify.dart'; -import 'package:spotube/models/spotube_track.dart'; import 'package:spotube/provider/proxy_playlist/proxy_playlist_provider.dart'; import 'package:spotube/services/queries/queries.dart'; +import 'package:spotube/services/sourced_track/sourced_track.dart'; import 'package:spotube/utils/service_utils.dart'; import 'package:spotube/utils/type_conversion_utils.dart'; @@ -59,7 +59,7 @@ class PlaylistView extends HookConsumerWidget { tracksSnapshot.data ?.any((s) => s.id! == proxyPlaylist.activeTrack?.id!) == true && - proxyPlaylist.activeTrack is SpotubeTrack, + proxyPlaylist.activeTrack is SourcedTrack, [proxyPlaylist.activeTrack, tracksSnapshot.data], ); diff --git a/lib/pages/settings/sections/playback.dart b/lib/pages/settings/sections/playback.dart index 5e000231..a0316b33 100644 --- a/lib/pages/settings/sections/playback.dart +++ b/lib/pages/settings/sections/playback.dart @@ -8,10 +8,10 @@ import 'package:spotube/collections/spotube_icons.dart'; import 'package:spotube/components/settings/section_card_with_heading.dart'; import 'package:spotube/components/shared/adaptive/adaptive_select_tile.dart'; import 'package:spotube/extensions/context.dart'; -import 'package:spotube/models/matched_track.dart'; import 'package:spotube/provider/piped_instances_provider.dart'; import 'package:spotube/provider/user_preferences/user_preferences_provider.dart'; import 'package:spotube/provider/user_preferences/user_preferences_state.dart'; +import 'package:spotube/services/sourced_track/enums.dart'; class SettingsPlaybackSection extends HookConsumerWidget { const SettingsPlaybackSection({Key? key}) : super(key: key); @@ -25,17 +25,21 @@ class SettingsPlaybackSection extends HookConsumerWidget { return SectionCardWithHeading( heading: context.l10n.playback, children: [ - AdaptiveSelectTile( + AdaptiveSelectTile( secondary: const Icon(SpotubeIcons.audioQuality), title: Text(context.l10n.audio_quality), value: preferences.audioQuality, options: [ DropdownMenuItem( - value: AudioQuality.high, + value: SourceQualities.high, child: Text(context.l10n.high), ), DropdownMenuItem( - value: AudioQuality.low, + value: SourceQualities.medium, + child: Text(context.l10n.medium), + ), + DropdownMenuItem( + value: SourceQualities.low, child: Text(context.l10n.low), ), ], @@ -45,11 +49,11 @@ class SettingsPlaybackSection extends HookConsumerWidget { } }, ), - AdaptiveSelectTile( + AdaptiveSelectTile( secondary: const Icon(SpotubeIcons.api), title: Text(context.l10n.youtube_api_type), - value: preferences.youtubeApiType, - options: YoutubeApiType.values + value: preferences.audioSource, + options: AudioSource.values .map((e) => DropdownMenuItem( value: e, child: Text(e.label), @@ -57,12 +61,12 @@ class SettingsPlaybackSection extends HookConsumerWidget { .toList(), onChanged: (value) { if (value == null) return; - preferencesNotifier.setYoutubeApiType(value); + preferencesNotifier.setAudioSource(value); }, ), AnimatedSwitcher( duration: const Duration(milliseconds: 300), - child: preferences.youtubeApiType == YoutubeApiType.youtube + child: preferences.audioSource != AudioSource.piped ? const SizedBox.shrink() : Consumer(builder: (context, ref, child) { final instanceList = ref.watch(pipedInstancesFutureProvider); @@ -129,7 +133,7 @@ class SettingsPlaybackSection extends HookConsumerWidget { ), AnimatedSwitcher( duration: const Duration(milliseconds: 300), - child: preferences.youtubeApiType == YoutubeApiType.youtube + child: preferences.audioSource != AudioSource.piped ? const SizedBox.shrink() : AdaptiveSelectTile( secondary: const Icon(SpotubeIcons.search), @@ -149,17 +153,18 @@ class SettingsPlaybackSection extends HookConsumerWidget { ), AnimatedSwitcher( duration: const Duration(milliseconds: 300), - child: preferences.searchMode == SearchMode.youtubeMusic && - preferences.youtubeApiType == YoutubeApiType.piped - ? const SizedBox.shrink() - : SwitchListTile( + child: preferences.searchMode == SearchMode.youtube && + (preferences.audioSource == AudioSource.piped || + preferences.audioSource == AudioSource.youtube) + ? SwitchListTile( secondary: const Icon(SpotubeIcons.skip), title: Text(context.l10n.skip_non_music), value: preferences.skipNonMusic, onChanged: (state) { preferencesNotifier.setSkipNonMusic(state); }, - ), + ) + : const SizedBox.shrink(), ), ListTile( leading: const Icon(SpotubeIcons.playlistRemove), @@ -176,44 +181,46 @@ class SettingsPlaybackSection extends HookConsumerWidget { value: preferences.normalizeAudio, onChanged: preferencesNotifier.setNormalizeAudio, ), - AdaptiveSelectTile( - secondary: const Icon(SpotubeIcons.stream), - title: Text(context.l10n.streaming_music_codec), - value: preferences.streamMusicCodec, - showValueWhenUnfolded: false, - options: MusicCodec.values - .map((e) => DropdownMenuItem( - value: e, - child: Text( - e.label, - style: theme.textTheme.labelMedium, - ), - )) - .toList(), - onChanged: (value) { - if (value == null) return; - preferencesNotifier.setStreamMusicCodec(value); - }, - ), - AdaptiveSelectTile( - secondary: const Icon(SpotubeIcons.file), - title: Text(context.l10n.download_music_codec), - value: preferences.downloadMusicCodec, - showValueWhenUnfolded: false, - options: MusicCodec.values - .map((e) => DropdownMenuItem( - value: e, - child: Text( - e.label, - style: theme.textTheme.labelMedium, - ), - )) - .toList(), - onChanged: (value) { - if (value == null) return; - preferencesNotifier.setDownloadMusicCodec(value); - }, - ), + if (preferences.audioSource != AudioSource.jiosaavn) + AdaptiveSelectTile( + secondary: const Icon(SpotubeIcons.stream), + title: Text(context.l10n.streaming_music_codec), + value: preferences.streamMusicCodec, + showValueWhenUnfolded: false, + options: SourceCodecs.values + .map((e) => DropdownMenuItem( + value: e, + child: Text( + e.label, + style: theme.textTheme.labelMedium, + ), + )) + .toList(), + onChanged: (value) { + if (value == null) return; + preferencesNotifier.setStreamMusicCodec(value); + }, + ), + if (preferences.audioSource != AudioSource.jiosaavn) + AdaptiveSelectTile( + secondary: const Icon(SpotubeIcons.file), + title: Text(context.l10n.download_music_codec), + value: preferences.downloadMusicCodec, + showValueWhenUnfolded: false, + options: SourceCodecs.values + .map((e) => DropdownMenuItem( + value: e, + child: Text( + e.label, + style: theme.textTheme.labelMedium, + ), + )) + .toList(), + onChanged: (value) { + if (value == null) return; + preferencesNotifier.setDownloadMusicCodec(value); + }, + ), ], ); } diff --git a/lib/provider/download_manager_provider.dart b/lib/provider/download_manager_provider.dart index 889641f4..691a1385 100644 --- a/lib/provider/download_manager_provider.dart +++ b/lib/provider/download_manager_provider.dart @@ -9,25 +9,23 @@ import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:metadata_god/metadata_god.dart'; import 'package:path/path.dart'; import 'package:spotify/spotify.dart'; -import 'package:spotube/models/spotube_track.dart'; import 'package:spotube/provider/user_preferences/user_preferences_provider.dart'; -import 'package:spotube/provider/user_preferences/user_preferences_state.dart'; -import 'package:spotube/provider/youtube_provider.dart'; import 'package:spotube/services/download_manager/download_manager.dart'; -import 'package:spotube/services/youtube/youtube.dart'; +import 'package:spotube/services/sourced_track/enums.dart'; +import 'package:spotube/services/sourced_track/sourced_track.dart'; import 'package:spotube/utils/primitive_utils.dart'; import 'package:spotube/utils/type_conversion_utils.dart'; class DownloadManagerProvider extends ChangeNotifier { DownloadManagerProvider({required this.ref}) - : $history = {}, + : $history = {}, $backHistory = {}, dl = DownloadManager() { dl.statusStream.listen((event) async { final (:request, :status) = event; final track = $history.firstWhereOrNull( - (element) => element.ytUri == request.url, + (element) => element.url == request.url, ); if (track == null) return; @@ -45,7 +43,7 @@ class DownloadManagerProvider extends ChangeNotifier { //? WebA audiotagging is not supported yet //? Although in future by converting weba to opus & then tagging it //? is possible using vorbis comments - downloadCodec == MusicCodec.weba) return; + downloadCodec == SourceCodecs.weba) return; final file = File(request.path); @@ -91,10 +89,9 @@ class DownloadManagerProvider extends ChangeNotifier { final Ref ref; - YoutubeEndpoints get yt => ref.read(youtubeProvider); String get downloadDirectory => ref.read(userPreferencesProvider.select((s) => s.downloadLocation)); - MusicCodec get downloadCodec => + SourceCodecs get downloadCodec => ref.read(userPreferencesProvider.select((s) => s.downloadMusicCodec)); int get $downloadCount => dl @@ -107,7 +104,7 @@ class DownloadManagerProvider extends ChangeNotifier { ) .length; - final Set $history; + final Set $history; // these are the tracks which metadata hasn't been fetched yet final Set $backHistory; final DownloadManager dl; @@ -144,9 +141,9 @@ class DownloadManagerProvider extends ChangeNotifier { bool isActive(Track track) { if ($backHistory.contains(track)) return true; - final spotubeTrack = mapToSpotubeTrack(track); + final sourcedTrack = mapToSourcedTrack(track); - if (spotubeTrack == null) return false; + if (sourcedTrack == null) return false; return dl .getAllDownloads() @@ -157,7 +154,7 @@ class DownloadManagerProvider extends ChangeNotifier { download.status.value == DownloadStatus.queued, ) .map((e) => e.request.url) - .contains(spotubeTrack.ytUri); + .contains(sourcedTrack.getUrlOfCodec(downloadCodec)); } /// For singular downloads @@ -173,21 +170,27 @@ class DownloadManagerProvider extends ChangeNotifier { await oldFile.rename("$savePath.old"); } - if (track is SpotubeTrack && track.codec == downloadCodec) { - final downloadTask = await dl.addDownload(track.ytUri, savePath); + if (track is SourcedTrack && track.codec == downloadCodec) { + final downloadTask = + await dl.addDownload(track.getUrlOfCodec(downloadCodec), savePath); if (downloadTask != null) { $history.add(track); } } else { $backHistory.add(track); - final spotubeTrack = - await SpotubeTrack.fetchFromTrack(track, yt, downloadCodec).then((d) { + final sourcedTrack = await SourcedTrack.fetchFromTrack( + ref: ref, + track: track, + ).then((d) { $backHistory.remove(track); return d; }); - final downloadTask = await dl.addDownload(spotubeTrack.ytUri, savePath); + final downloadTask = await dl.addDownload( + sourcedTrack.getUrlOfCodec(downloadCodec), + savePath, + ); if (downloadTask != null) { - $history.add(spotubeTrack); + $history.add(sourcedTrack); } } @@ -196,7 +199,7 @@ class DownloadManagerProvider extends ChangeNotifier { Future batchAddToQueue(List tracks) async { $backHistory.addAll( - tracks.where((element) => element is! SpotubeTrack), + tracks.where((element) => element is! SourcedTrack), ); notifyListeners(); for (final track in tracks) { @@ -216,25 +219,25 @@ class DownloadManagerProvider extends ChangeNotifier { } } - Future removeFromQueue(SpotubeTrack track) async { - await dl.removeDownload(track.ytUri); + Future removeFromQueue(SourcedTrack track) async { + await dl.removeDownload(track.getUrlOfCodec(downloadCodec)); $history.remove(track); } - Future pause(SpotubeTrack track) { - return dl.pauseDownload(track.ytUri); + Future pause(SourcedTrack track) { + return dl.pauseDownload(track.getUrlOfCodec(downloadCodec)); } - Future resume(SpotubeTrack track) { - return dl.resumeDownload(track.ytUri); + Future resume(SourcedTrack track) { + return dl.resumeDownload(track.getUrlOfCodec(downloadCodec)); } - Future retry(SpotubeTrack track) { + Future retry(SourcedTrack track) { return addToQueue(track); } - void cancel(SpotubeTrack track) { - dl.cancelDownload(track.ytUri); + void cancel(SourcedTrack track) { + dl.cancelDownload(track.getUrlOfCodec(downloadCodec)); } void cancelAll() { @@ -244,20 +247,20 @@ class DownloadManagerProvider extends ChangeNotifier { } } - SpotubeTrack? mapToSpotubeTrack(Track track) { - if (track is SpotubeTrack) { + SourcedTrack? mapToSourcedTrack(Track track) { + if (track is SourcedTrack) { return track; } else { return $history.firstWhereOrNull((element) => element.id == track.id); } } - ValueNotifier? getStatusNotifier(SpotubeTrack track) { - return dl.getDownload(track.ytUri)?.status; + ValueNotifier? getStatusNotifier(SourcedTrack track) { + return dl.getDownload(track.getUrlOfCodec(downloadCodec))?.status; } - ValueNotifier? getProgressNotifier(SpotubeTrack track) { - return dl.getDownload(track.ytUri)?.progress; + ValueNotifier? getProgressNotifier(SourcedTrack track) { + return dl.getDownload(track.getUrlOfCodec(downloadCodec))?.progress; } } diff --git a/lib/provider/piped_instances_provider.dart b/lib/provider/piped_instances_provider.dart index 290ad2c4..264b7048 100644 --- a/lib/provider/piped_instances_provider.dart +++ b/lib/provider/piped_instances_provider.dart @@ -1,10 +1,11 @@ import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:piped_client/piped_client.dart'; -import 'package:spotube/provider/youtube_provider.dart'; +import 'package:spotube/services/sourced_track/sources/piped.dart'; final pipedInstancesFutureProvider = FutureProvider>( (ref) async { - final youtube = ref.watch(youtubeProvider); - return await youtube.piped?.instanceList() ?? []; + final pipedClient = ref.watch(pipedProvider); + + return await pipedClient.instanceList(); }, ); diff --git a/lib/provider/proxy_playlist/next_fetcher_mixin.dart b/lib/provider/proxy_playlist/next_fetcher_mixin.dart index b447f1ef..1d2cfde8 100644 --- a/lib/provider/proxy_playlist/next_fetcher_mixin.dart +++ b/lib/provider/proxy_playlist/next_fetcher_mixin.dart @@ -3,36 +3,30 @@ import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:spotify/spotify.dart'; import 'package:spotube/models/local_track.dart'; import 'package:spotube/models/logger.dart'; -import 'package:spotube/models/matched_track.dart'; -import 'package:spotube/models/spotube_track.dart'; import 'package:spotube/provider/proxy_playlist/proxy_playlist.dart'; -import 'package:spotube/provider/user_preferences/user_preferences_state.dart'; -import 'package:spotube/services/supabase.dart'; -import 'package:spotube/services/youtube/youtube.dart'; +import 'package:spotube/services/sourced_track/sourced_track.dart'; final logger = getLogger("NextFetcherMixin"); mixin NextFetcher on StateNotifier { - Future> fetchTracks( - UserPreferences preferences, - YoutubeEndpoints youtube, { + Future> fetchTracks( + Ref ref, { int count = 3, int offset = 0, }) async { - /// get [count] [state.tracks] that are not [SpotubeTrack] and [LocalTrack] + /// get [count] [state.tracks] that are not [SourcedTrack] and [LocalTrack] final bareTracks = state.tracks .skip(offset) - .where((element) => element is! SpotubeTrack && element is! LocalTrack) + .where((element) => element is! SourcedTrack && element is! LocalTrack) .take(count); /// fetch [bareTracks] one by one with 100ms delay final fetchedTracks = await Future.wait( bareTracks.mapIndexed((i, track) async { - final future = SpotubeTrack.fetchFromTrack( - track, - youtube, - preferences.streamMusicCodec, + final future = SourcedTrack.fetchFromTrack( + ref: ref, + track: track, ); if (i == 0) { return await future; @@ -47,9 +41,9 @@ mixin NextFetcher on StateNotifier { return fetchedTracks; } - /// Merges List of [SpotubeTrack]s with [Track]s and outputs a mixed List + /// Merges List of [SourcedTrack]s with [Track]s and outputs a mixed List Set mergeTracks( - Iterable fetchTracks, + Iterable fetchTracks, Iterable tracks, ) { return tracks.map((track) { @@ -80,12 +74,12 @@ mixin NextFetcher on StateNotifier { /// Returns appropriate Media source for [Track] /// - /// * If [Track] is [SpotubeTrack] then return [SpotubeTrack.ytUri] + /// * If [Track] is [SourcedTrack] then return [SourcedTrack.ytUri] /// * If [Track] is [LocalTrack] then return [LocalTrack.path] /// * If [Track] is [Track] then return [Track.id] with [isUnPlayable] source String makeAppropriateSource(Track track) { - if (track is SpotubeTrack) { - return track.ytUri; + if (track is SourcedTrack) { + return track.url; } else if (track is LocalTrack) { return track.path; } else { @@ -103,7 +97,7 @@ mixin NextFetcher on StateNotifier { final track = state.tracks.firstWhereOrNull( (track) => trackToUnplayableSource(track) == source || - (track is SpotubeTrack && track.ytUri == source) || + (track is SourcedTrack && track.url == source) || (track is LocalTrack && track.path == source), ); return track; @@ -111,23 +105,4 @@ mixin NextFetcher on StateNotifier { .whereNotNull() .toList(); } - - /// This method must be called after any playback operation as - /// it can increase the latency - Future storeTrack(Track track, SpotubeTrack spotubeTrack) async { - try { - if (track is! SpotubeTrack) { - await supabase.insertTrack( - MatchedTrack( - youtubeId: spotubeTrack.ytTrack.id, - spotifyId: spotubeTrack.id!, - searchMode: spotubeTrack.ytTrack.searchMode, - ), - ); - } - } catch (e, stackTrace) { - logger.e(e.toString()); - logger.t(stackTrace); - } - } } diff --git a/lib/provider/proxy_playlist/proxy_playlist.dart b/lib/provider/proxy_playlist/proxy_playlist.dart index e5dfa7e8..026b3403 100644 --- a/lib/provider/proxy_playlist/proxy_playlist.dart +++ b/lib/provider/proxy_playlist/proxy_playlist.dart @@ -1,8 +1,9 @@ import 'package:collection/collection.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:spotify/spotify.dart'; import 'package:spotube/extensions/track.dart'; import 'package:spotube/models/local_track.dart'; -import 'package:spotube/models/spotube_track.dart'; +import 'package:spotube/services/sourced_track/sourced_track.dart'; class ProxyPlaylist { final Set tracks; @@ -11,11 +12,14 @@ class ProxyPlaylist { ProxyPlaylist(this.tracks, [this.active, this.collections = const {}]); - factory ProxyPlaylist.fromJson(Map json) { + factory ProxyPlaylist.fromJson( + Map json, + Ref ref, + ) { return ProxyPlaylist( List.castFrom>( json['tracks'] ?? >[], - ).map(_makeAppropriateTrack).toSet(), + ).map((t) => _makeAppropriateTrack(t, ref)).toSet(), json['active'] as int?, json['collections'] == null ? {} @@ -28,7 +32,7 @@ class ProxyPlaylist { bool get isFetching => activeTrack != null && - activeTrack is! SpotubeTrack && + activeTrack is! SourcedTrack && activeTrack is! LocalTrack; bool containsCollection(String collection) { @@ -44,9 +48,9 @@ class ProxyPlaylist { return tracks.every(containsTrack); } - static Track _makeAppropriateTrack(Map track) { + static Track _makeAppropriateTrack(Map track, Ref ref) { if (track.containsKey("ytUri")) { - return SpotubeTrack.fromJson(track); + return SourcedTrack.fromJson(track, ref: ref); } else if (track.containsKey("path")) { return LocalTrack.fromJson(track); } else { @@ -59,7 +63,7 @@ class ProxyPlaylist { static Map _makeAppropriateTrackJson(Track track) { return switch (track.runtimeType) { LocalTrack => track.toJson(), - SpotubeTrack => track.toJson(), + SourcedTrack => track.toJson(), _ => track.toJson(), }; } diff --git a/lib/provider/proxy_playlist/proxy_playlist_provider.dart b/lib/provider/proxy_playlist/proxy_playlist_provider.dart index 50024661..bd3934a7 100644 --- a/lib/provider/proxy_playlist/proxy_playlist_provider.dart +++ b/lib/provider/proxy_playlist/proxy_playlist_provider.dart @@ -12,9 +12,10 @@ import 'package:spotify/spotify.dart'; import 'package:spotube/components/shared/image/universal_image.dart'; import 'package:spotube/models/local_track.dart'; import 'package:spotube/models/logger.dart'; -import 'package:spotube/models/matched_track.dart'; + import 'package:spotube/models/skip_segment.dart'; -import 'package:spotube/models/spotube_track.dart'; +import 'package:spotube/models/source_match.dart'; + import 'package:spotube/provider/blacklist_provider.dart'; import 'package:spotube/provider/palette_provider.dart'; import 'package:spotube/provider/proxy_playlist/next_fetcher_mixin.dart'; @@ -22,17 +23,20 @@ import 'package:spotube/provider/proxy_playlist/proxy_playlist.dart'; import 'package:spotube/provider/scrobbler_provider.dart'; import 'package:spotube/provider/user_preferences/user_preferences_provider.dart'; import 'package:spotube/provider/user_preferences/user_preferences_state.dart'; -import 'package:spotube/provider/youtube_provider.dart'; import 'package:spotube/services/audio_player/audio_player.dart'; import 'package:spotube/services/audio_services/audio_services.dart'; -import 'package:spotube/services/youtube/youtube.dart'; +import 'package:spotube/services/sourced_track/exceptions.dart'; +import 'package:spotube/services/sourced_track/models/source_info.dart'; +import 'package:spotube/services/sourced_track/sourced_track.dart'; +import 'package:spotube/services/supabase.dart'; + import 'package:spotube/utils/persisted_state_notifier.dart'; import 'package:spotube/utils/type_conversion_utils.dart'; /// Things implemented: /// * [x] Sponsor-Block skip -/// * [x] Prefetch next track as [SpotubeTrack] on 80% of current track -/// * [x] Mixed Queue containing both [SpotubeTrack] and [LocalTrack] +/// * [x] Prefetch next track as [SourcedTrack] on 80% of current track +/// * [x] Mixed Queue containing both [SourcedTrack] and [LocalTrack] /// * [x] Modification of the Queue /// * [x] Add track at the end /// * [x] Add track at the beginning @@ -56,7 +60,6 @@ class ProxyPlaylistNotifier extends PersistedStateNotifier ScrobblerNotifier get scrobbler => ref.read(scrobblerProvider.notifier); UserPreferences get preferences => ref.read(userPreferencesProvider); - YoutubeEndpoints get youtube => ref.read(youtubeProvider); ProxyPlaylist get playlist => state; BlackListNotifier get blacklist => ref.read(BlackListNotifier.provider.notifier); @@ -168,11 +171,11 @@ class ProxyPlaylistNotifier extends PersistedStateNotifier return; } try { - final isYTMusicMode = - preferences.youtubeApiType == YoutubeApiType.piped && - preferences.searchMode == SearchMode.youtubeMusic; + final isNotYTMode = preferences.audioSource != AudioSource.youtube || + (preferences.audioSource == AudioSource.piped && + preferences.searchMode == SearchMode.youtubeMusic); - if (isYTMusicMode || !preferences.skipNonMusic) return; + if (isNotYTMode || !preferences.skipNonMusic) return; final isNotSameSegmentId = currentSegments.value?.source != audioPlayer.currentSource; @@ -184,7 +187,7 @@ class ProxyPlaylistNotifier extends PersistedStateNotifier currentSegments.value = ( source: audioPlayer.currentSource!, segments: await getAndCacheSkipSegments( - (state.activeTrack as SpotubeTrack).ytTrack.id, + (state.activeTrack as SourcedTrack).sourceInfo.id, ), ); } catch (e) { @@ -237,7 +240,7 @@ class ProxyPlaylistNotifier extends PersistedStateNotifier }(); } - Future ensureSourcePlayable(String source) async { + Future ensureSourcePlayable(String source) async { if (isPlayable(source)) return null; final track = mapSourcesToTracks([source]).firstOrNull; @@ -247,17 +250,13 @@ class ProxyPlaylistNotifier extends PersistedStateNotifier } final nthFetchedTrack = switch (track.runtimeType) { - SpotubeTrack => track as SpotubeTrack, - _ => await SpotubeTrack.fetchFromTrack( - track, - youtube, - preferences.streamMusicCodec, - ), + SourcedTrack => track as SourcedTrack, + _ => await SourcedTrack.fetchFromTrack(ref: ref, track: track), }; await audioPlayer.replaceSource( source, - nthFetchedTrack.ytUri, + nthFetchedTrack.url, ); return nthFetchedTrack; @@ -335,15 +334,13 @@ class ProxyPlaylistNotifier extends PersistedStateNotifier ); await notificationService.addTrack(indexTrack); } else { - final addableTrack = await SpotubeTrack.fetchFromTrack( - tracks.elementAtOrNull(initialIndex) ?? tracks.first, - youtube, - preferences.streamMusicCodec, + final addableTrack = await SourcedTrack.fetchFromTrack( + ref: ref, + track: tracks.elementAtOrNull(initialIndex) ?? tracks.first, ).catchError((e, stackTrace) { - return SpotubeTrack.fetchFromTrack( - tracks.elementAtOrNull(initialIndex + 1) ?? tracks.first, - youtube, - preferences.streamMusicCodec, + return SourcedTrack.fetchFromTrack( + ref: ref, + track: tracks.elementAtOrNull(initialIndex + 1) ?? tracks.first, ); }); @@ -437,9 +434,9 @@ class ProxyPlaylistNotifier extends PersistedStateNotifier } Future populateSibling() async { - if (state.activeTrack is SpotubeTrack) { + if (state.activeTrack is SourcedTrack) { final activeTrackWithSiblingsForSure = - await (state.activeTrack as SpotubeTrack).populatedCopy(youtube); + await (state.activeTrack as SourcedTrack).copyWithSibling(); state = state.copyWith( tracks: mergeTracks([activeTrackWithSiblingsForSure], state.tracks), @@ -449,11 +446,11 @@ class ProxyPlaylistNotifier extends PersistedStateNotifier } } - Future swapSibling(YoutubeVideoInfo video) async { - if (state.activeTrack is SpotubeTrack) { + Future swapSibling(SourceInfo sibling) async { + if (state.activeTrack is SourcedTrack) { await populateSibling(); final newTrack = - await (state.activeTrack as SpotubeTrack).swappedCopy(video, youtube); + await (state.activeTrack as SourcedTrack).swapWithSibling(sibling); if (newTrack == null) return; state = state.copyWith( tracks: mergeTracks([newTrack], state.tracks), @@ -564,7 +561,7 @@ class ProxyPlaylistNotifier extends PersistedStateNotifier Future> getAndCacheSkipSegments(String id) async { if (!preferences.skipNonMusic || - (preferences.youtubeApiType == YoutubeApiType.piped && + (preferences.audioSource == AudioSource.piped && preferences.searchMode == SearchMode.youtubeMusic)) return []; try { @@ -628,6 +625,30 @@ class ProxyPlaylistNotifier extends PersistedStateNotifier } } + /// This method must be called after any playback operation as + /// it can increase the latency + Future storeTrack(Track track, SourcedTrack sourcedTrack) async { + try { + if (track is! SourcedTrack) { + await supabase.insertTrack( + SourceMatch( + id: sourcedTrack.id!, + createdAt: DateTime.now(), + sourceId: sourcedTrack.sourceInfo.id, + sourceType: preferences.audioSource == AudioSource.jiosaavn + ? SourceType.jiosaavn + : preferences.searchMode == SearchMode.youtube + ? SourceType.youtube + : SourceType.youtubeMusic, + ), + ); + } + } catch (e, stackTrace) { + logger.e(e.toString()); + logger.t(stackTrace); + } + } + @override set state(state) { super.state = state; @@ -652,7 +673,7 @@ class ProxyPlaylistNotifier extends PersistedStateNotifier @override FutureOr fromJson(Map json) { - return ProxyPlaylist.fromJson(json); + return ProxyPlaylist.fromJson(json, ref); } @override diff --git a/lib/provider/user_preferences/user_preferences_provider.dart b/lib/provider/user_preferences/user_preferences_provider.dart index db4b73dc..88a0df2e 100644 --- a/lib/provider/user_preferences/user_preferences_provider.dart +++ b/lib/provider/user_preferences/user_preferences_provider.dart @@ -6,11 +6,11 @@ import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:path_provider/path_provider.dart'; import 'package:spotify/spotify.dart'; import 'package:spotube/components/settings/color_scheme_picker_dialog.dart'; -import 'package:spotube/models/matched_track.dart'; import 'package:spotube/provider/palette_provider.dart'; import 'package:spotube/provider/proxy_playlist/proxy_playlist_provider.dart'; import 'package:spotube/provider/user_preferences/user_preferences_state.dart'; import 'package:spotube/services/audio_player/audio_player.dart'; +import 'package:spotube/services/sourced_track/enums.dart'; import 'package:spotube/utils/persisted_state_notifier.dart'; import 'package:spotube/utils/platform.dart'; @@ -26,11 +26,11 @@ class UserPreferencesNotifier extends PersistedStateNotifier { state = UserPreferences.withDefaults(); } - void setStreamMusicCodec(MusicCodec codec) { + void setStreamMusicCodec(SourceCodecs codec) { state = state.copyWith(streamMusicCodec: codec); } - void setDownloadMusicCodec(MusicCodec codec) { + void setDownloadMusicCodec(SourceCodecs codec) { state = state.copyWith(downloadMusicCodec: codec); } @@ -60,7 +60,7 @@ class UserPreferencesNotifier extends PersistedStateNotifier { state = state.copyWith(checkUpdate: check); } - void setAudioQuality(AudioQuality quality) { + void setAudioQuality(SourceQualities quality) { state = state.copyWith(audioQuality: quality); } @@ -97,8 +97,8 @@ class UserPreferencesNotifier extends PersistedStateNotifier { state = state.copyWith(skipNonMusic: skip); } - void setYoutubeApiType(YoutubeApiType type) { - state = state.copyWith(youtubeApiType: type); + void setAudioSource(AudioSource type) { + state = state.copyWith(audioSource: type); } void setSystemTitleBar(bool isSystemTitleBar) { diff --git a/lib/provider/user_preferences/user_preferences_state.dart b/lib/provider/user_preferences/user_preferences_state.dart index ff98fa8e..b3d7fe8a 100644 --- a/lib/provider/user_preferences/user_preferences_state.dart +++ b/lib/provider/user_preferences/user_preferences_state.dart @@ -4,7 +4,7 @@ import 'package:flutter/material.dart'; import 'package:json_annotation/json_annotation.dart'; import 'package:spotify/spotify.dart'; import 'package:spotube/components/settings/color_scheme_picker_dialog.dart'; -import 'package:spotube/models/matched_track.dart'; +import 'package:spotube/services/sourced_track/enums.dart'; part 'user_preferences_state.g.dart'; @@ -15,12 +15,6 @@ enum LayoutMode { adaptive, } -@JsonEnum() -enum AudioQuality { - high, - low, -} - @JsonEnum() enum CloseBehavior { minimizeToTray, @@ -28,9 +22,10 @@ enum CloseBehavior { } @JsonEnum() -enum YoutubeApiType { +enum AudioSource { youtube, - piped; + piped, + jiosaavn; String get label => name[0].toUpperCase() + name.substring(1); } @@ -44,13 +39,27 @@ enum MusicCodec { const MusicCodec._(this.label); } +@JsonEnum() +enum SearchMode { + youtube._("YouTube"), + youtubeMusic._("YouTube Music"); + + final String label; + + const SearchMode._(this.label); + + factory SearchMode.fromString(String key) { + return SearchMode.values.firstWhere((e) => e.name == key); + } +} + @JsonSerializable() final class UserPreferences { @JsonKey( - defaultValue: AudioQuality.high, - unknownEnumValue: AudioQuality.high, + defaultValue: SourceQualities.high, + unknownEnumValue: SourceQualities.high, ) - final AudioQuality audioQuality; + final SourceQualities audioQuality; @JsonKey(defaultValue: true) final bool albumColorSync; @@ -172,22 +181,22 @@ final class UserPreferences { final ThemeMode themeMode; @JsonKey( - defaultValue: YoutubeApiType.youtube, - unknownEnumValue: YoutubeApiType.youtube, + defaultValue: AudioSource.youtube, + unknownEnumValue: AudioSource.youtube, ) - final YoutubeApiType youtubeApiType; + final AudioSource audioSource; @JsonKey( - defaultValue: MusicCodec.weba, - unknownEnumValue: MusicCodec.weba, + defaultValue: SourceCodecs.weba, + unknownEnumValue: SourceCodecs.weba, ) - final MusicCodec streamMusicCodec; + final SourceCodecs streamMusicCodec; @JsonKey( - defaultValue: MusicCodec.m4a, - unknownEnumValue: MusicCodec.m4a, + defaultValue: SourceCodecs.m4a, + unknownEnumValue: SourceCodecs.m4a, ) - final MusicCodec downloadMusicCodec; + final SourceCodecs downloadMusicCodec; UserPreferences({ required this.audioQuality, @@ -207,7 +216,7 @@ final class UserPreferences { required this.downloadLocation, required this.pipedInstance, required this.themeMode, - required this.youtubeApiType, + required this.audioSource, required this.streamMusicCodec, required this.downloadMusicCodec, }); @@ -229,7 +238,7 @@ final class UserPreferences { SpotubeColor? accentColorScheme, bool? albumColorSync, bool? checkUpdate, - AudioQuality? audioQuality, + SourceQualities? audioQuality, String? downloadLocation, LayoutMode? layoutMode, CloseBehavior? closeBehavior, @@ -238,13 +247,13 @@ final class UserPreferences { String? pipedInstance, SearchMode? searchMode, bool? skipNonMusic, - YoutubeApiType? youtubeApiType, + AudioSource? audioSource, Market? recommendationMarket, bool? saveTrackLyrics, bool? amoledDarkTheme, bool? normalizeAudio, - MusicCodec? downloadMusicCodec, - MusicCodec? streamMusicCodec, + SourceCodecs? downloadMusicCodec, + SourceCodecs? streamMusicCodec, bool? systemTitleBar, }) { return UserPreferences( @@ -261,7 +270,7 @@ final class UserPreferences { pipedInstance: pipedInstance ?? this.pipedInstance, searchMode: searchMode ?? this.searchMode, skipNonMusic: skipNonMusic ?? this.skipNonMusic, - youtubeApiType: youtubeApiType ?? this.youtubeApiType, + audioSource: audioSource ?? this.audioSource, recommendationMarket: recommendationMarket ?? this.recommendationMarket, amoledDarkTheme: amoledDarkTheme ?? this.amoledDarkTheme, downloadMusicCodec: downloadMusicCodec ?? this.downloadMusicCodec, diff --git a/lib/provider/user_preferences/user_preferences_state.g.dart b/lib/provider/user_preferences/user_preferences_state.g.dart index 9e3eeee9..54cd3aa2 100644 --- a/lib/provider/user_preferences/user_preferences_state.g.dart +++ b/lib/provider/user_preferences/user_preferences_state.g.dart @@ -9,9 +9,9 @@ part of 'user_preferences_state.dart'; UserPreferences _$UserPreferencesFromJson(Map json) => UserPreferences( audioQuality: $enumDecodeNullable( - _$AudioQualityEnumMap, json['audioQuality'], - unknownValue: AudioQuality.high) ?? - AudioQuality.high, + _$SourceQualitiesEnumMap, json['audioQuality'], + unknownValue: SourceQualities.high) ?? + SourceQualities.high, albumColorSync: json['albumColorSync'] as bool? ?? true, amoledDarkTheme: json['amoledDarkTheme'] as bool? ?? false, checkUpdate: json['checkUpdate'] as bool? ?? true, @@ -51,23 +51,23 @@ UserPreferences _$UserPreferencesFromJson(Map json) => themeMode: $enumDecodeNullable(_$ThemeModeEnumMap, json['themeMode'], unknownValue: ThemeMode.system) ?? ThemeMode.system, - youtubeApiType: $enumDecodeNullable( - _$YoutubeApiTypeEnumMap, json['youtubeApiType'], - unknownValue: YoutubeApiType.youtube) ?? - YoutubeApiType.youtube, + audioSource: $enumDecodeNullable( + _$AudioSourceEnumMap, json['audioSource'], + unknownValue: AudioSource.youtube) ?? + AudioSource.youtube, streamMusicCodec: $enumDecodeNullable( - _$MusicCodecEnumMap, json['streamMusicCodec'], - unknownValue: MusicCodec.weba) ?? - MusicCodec.weba, + _$SourceCodecsEnumMap, json['streamMusicCodec'], + unknownValue: SourceCodecs.weba) ?? + SourceCodecs.weba, downloadMusicCodec: $enumDecodeNullable( - _$MusicCodecEnumMap, json['downloadMusicCodec'], - unknownValue: MusicCodec.m4a) ?? - MusicCodec.m4a, + _$SourceCodecsEnumMap, json['downloadMusicCodec'], + unknownValue: SourceCodecs.m4a) ?? + SourceCodecs.m4a, ); Map _$UserPreferencesToJson(UserPreferences instance) => { - 'audioQuality': _$AudioQualityEnumMap[instance.audioQuality]!, + 'audioQuality': _$SourceQualitiesEnumMap[instance.audioQuality]!, 'albumColorSync': instance.albumColorSync, 'amoledDarkTheme': instance.amoledDarkTheme, 'checkUpdate': instance.checkUpdate, @@ -85,14 +85,15 @@ Map _$UserPreferencesToJson(UserPreferences instance) => 'downloadLocation': instance.downloadLocation, 'pipedInstance': instance.pipedInstance, 'themeMode': _$ThemeModeEnumMap[instance.themeMode]!, - 'youtubeApiType': _$YoutubeApiTypeEnumMap[instance.youtubeApiType]!, - 'streamMusicCodec': _$MusicCodecEnumMap[instance.streamMusicCodec]!, - 'downloadMusicCodec': _$MusicCodecEnumMap[instance.downloadMusicCodec]!, + 'audioSource': _$AudioSourceEnumMap[instance.audioSource]!, + 'streamMusicCodec': _$SourceCodecsEnumMap[instance.streamMusicCodec]!, + 'downloadMusicCodec': _$SourceCodecsEnumMap[instance.downloadMusicCodec]!, }; -const _$AudioQualityEnumMap = { - AudioQuality.high: 'high', - AudioQuality.low: 'low', +const _$SourceQualitiesEnumMap = { + SourceQualities.high: 'high', + SourceQualities.medium: 'medium', + SourceQualities.low: 'low', }; const _$CloseBehaviorEnumMap = { @@ -370,12 +371,13 @@ const _$ThemeModeEnumMap = { ThemeMode.dark: 'dark', }; -const _$YoutubeApiTypeEnumMap = { - YoutubeApiType.youtube: 'youtube', - YoutubeApiType.piped: 'piped', +const _$AudioSourceEnumMap = { + AudioSource.youtube: 'youtube', + AudioSource.piped: 'piped', + AudioSource.jiosaavn: 'jiosaavn', }; -const _$MusicCodecEnumMap = { - MusicCodec.m4a: 'm4a', - MusicCodec.weba: 'weba', +const _$SourceCodecsEnumMap = { + SourceCodecs.m4a: 'm4a', + SourceCodecs.weba: 'weba', }; diff --git a/lib/provider/youtube_provider.dart b/lib/provider/youtube_provider.dart deleted file mode 100644 index 33e0496f..00000000 --- a/lib/provider/youtube_provider.dart +++ /dev/null @@ -1,8 +0,0 @@ -import 'package:hooks_riverpod/hooks_riverpod.dart'; -import 'package:spotube/provider/user_preferences/user_preferences_provider.dart'; -import 'package:spotube/services/youtube/youtube.dart'; - -final youtubeProvider = Provider((ref) { - final preferences = ref.watch(userPreferencesProvider); - return YoutubeEndpoints(preferences); -}); diff --git a/lib/services/audio_player/audio_player.dart b/lib/services/audio_player/audio_player.dart index c944004c..b3957964 100644 --- a/lib/services/audio_player/audio_player.dart +++ b/lib/services/audio_player/audio_player.dart @@ -5,9 +5,9 @@ import 'dart:async'; import 'package:media_kit/media_kit.dart' as mk; -import 'package:spotube/models/spotube_track.dart'; import 'package:spotube/services/audio_player/loop_mode.dart'; import 'package:spotube/services/audio_player/playback_state.dart'; +import 'package:spotube/services/sourced_track/sourced_track.dart'; part 'audio_players_streams_mixin.dart'; part 'audio_player_impl.dart'; diff --git a/lib/services/audio_player/audio_player_impl.dart b/lib/services/audio_player/audio_player_impl.dart index 4576ce8d..2af94dd7 100644 --- a/lib/services/audio_player/audio_player_impl.dart +++ b/lib/services/audio_player/audio_player_impl.dart @@ -121,11 +121,13 @@ class SpotubeAudioPlayer extends AudioPlayerInterface // } } - List resolveTracksForSource(List tracks) { - return tracks.where((e) => sources.contains(e.ytUri)).toList(); + // TODO: Make sure audio player soruces are also + // TODO: changed when preferences sources are changed + List resolveTracksForSource(List tracks) { + return tracks.where((e) => sources.contains(e.url)).toList(); } - bool tracksExistsInPlaylist(List tracks) { + bool tracksExistsInPlaylist(List tracks) { return resolveTracksForSource(tracks).length == tracks.length; } diff --git a/lib/services/audio_services/audio_services.dart b/lib/services/audio_services/audio_services.dart index 645548fb..a6ecac3f 100644 --- a/lib/services/audio_services/audio_services.dart +++ b/lib/services/audio_services/audio_services.dart @@ -2,10 +2,10 @@ import 'package:audio_service/audio_service.dart'; import 'package:flutter_desktop_tools/flutter_desktop_tools.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:spotify/spotify.dart'; -import 'package:spotube/models/spotube_track.dart'; import 'package:spotube/provider/proxy_playlist/proxy_playlist_provider.dart'; import 'package:spotube/services/audio_services/mobile_audio_service.dart'; import 'package:spotube/services/audio_services/windows_audio_service.dart'; +import 'package:spotube/services/sourced_track/sourced_track.dart'; import 'package:spotube/utils/type_conversion_utils.dart'; class AudioServices { @@ -47,8 +47,8 @@ class AudioServices { album: track.album?.name ?? "", title: track.name!, artist: TypeConversionUtils.artists_X_String(track.artists ?? []), - duration: track is SpotubeTrack - ? track.ytTrack.duration + duration: track is SourcedTrack + ? track.sourceInfo.duration : Duration(milliseconds: track.durationMs ?? 0), artUri: Uri.parse(TypeConversionUtils.image_X_UrlString( track.album?.images ?? [], diff --git a/lib/services/audio_services/linux_audio_service.dart b/lib/services/audio_services/linux_audio_service.dart index bfe022d6..436627e6 100644 --- a/lib/services/audio_services/linux_audio_service.dart +++ b/lib/services/audio_services/linux_audio_service.dart @@ -3,13 +3,12 @@ import 'dart:io'; import 'package:dbus/dbus.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; -import 'package:spotube/models/spotube_track.dart'; import 'package:spotube/provider/proxy_playlist/proxy_playlist.dart'; import 'package:spotube/provider/proxy_playlist/proxy_playlist_provider.dart'; import 'package:spotube/services/audio_player/audio_player.dart'; import 'package:spotube/services/audio_player/loop_mode.dart'; +import 'package:spotube/services/sourced_track/sourced_track.dart'; import 'package:spotube/utils/type_conversion_utils.dart'; -import 'package:window_manager/window_manager.dart'; final dbus = DBusClient.session(); @@ -321,8 +320,8 @@ class _MprisMediaPlayer2Player extends DBusObject { ), "xesam:title": DBusString(playlist.activeTrack!.name!), "xesam:url": DBusString( - playlist.activeTrack is SpotubeTrack - ? (playlist.activeTrack as SpotubeTrack).ytUri + playlist.activeTrack is SourcedTrack + ? (playlist.activeTrack as SourcedTrack).url : playlist.activeTrack!.previewUrl ?? "", ), "xesam:genre": const DBusString("Unknown"), diff --git a/lib/services/queries/lyrics.dart b/lib/services/queries/lyrics.dart index b51016b4..faa5bdec 100644 --- a/lib/services/queries/lyrics.dart +++ b/lib/services/queries/lyrics.dart @@ -8,7 +8,7 @@ import 'package:spotify/spotify.dart'; import 'package:spotube/extensions/map.dart'; import 'package:spotube/hooks/spotify/use_spotify_query.dart'; import 'package:spotube/models/lyrics.dart'; -import 'package:spotube/models/spotube_track.dart'; +import 'package:spotube/services/sourced_track/sourced_track.dart'; import 'package:spotube/utils/service_utils.dart'; import 'package:http/http.dart' as http; @@ -44,7 +44,7 @@ class LyricsQueries { return useQuery( "synced-lyrics/${track?.id}}", () async { - if (track == null || track is! SpotubeTrack) { + if (track == null || track is! SourcedTrack) { throw "No track currently"; } final timedLyrics = await ServiceUtils.getTimedLyrics(track); diff --git a/lib/services/sourced_track/enums.dart b/lib/services/sourced_track/enums.dart new file mode 100644 index 00000000..48ce1cbd --- /dev/null +++ b/lib/services/sourced_track/enums.dart @@ -0,0 +1,18 @@ +import 'package:spotube/services/sourced_track/models/source_info.dart'; +import 'package:spotube/services/sourced_track/models/source_map.dart'; + +enum SourceCodecs { + m4a._("M4a (Best for downloaded music)"), + weba._("WebA (Best for streamed music)\nDoesn't support audio metadata"); + + final String label; + const SourceCodecs._(this.label); +} + +enum SourceQualities { + high, + medium, + low, +} + +typedef SiblingType = ({SourceInfo info, SourceMap? source}); diff --git a/lib/services/sourced_track/exceptions.dart b/lib/services/sourced_track/exceptions.dart new file mode 100644 index 00000000..517d6ba4 --- /dev/null +++ b/lib/services/sourced_track/exceptions.dart @@ -0,0 +1,7 @@ +import 'package:spotify/spotify.dart'; + +class TrackNotFoundException implements Exception { + factory TrackNotFoundException(Track track) { + throw Exception("Failed to find any results for ${track.name}"); + } +} diff --git a/lib/services/sourced_track/models/source_info.dart b/lib/services/sourced_track/models/source_info.dart new file mode 100644 index 00000000..4ba90355 --- /dev/null +++ b/lib/services/sourced_track/models/source_info.dart @@ -0,0 +1,33 @@ +import 'package:json_annotation/json_annotation.dart'; + +part 'source_info.g.dart'; + +@JsonSerializable() +class SourceInfo { + final String id; + final String title; + final String artist; + final String artistUrl; + final String? album; + + final String thumbnail; + final String pageUrl; + + final Duration duration; + + SourceInfo({ + required this.id, + required this.title, + required this.artist, + required this.thumbnail, + required this.pageUrl, + required this.duration, + required this.artistUrl, + this.album, + }); + + factory SourceInfo.fromJson(Map json) => + _$SourceInfoFromJson(json); + + Map toJson() => _$SourceInfoToJson(this); +} diff --git a/lib/services/sourced_track/models/source_info.g.dart b/lib/services/sourced_track/models/source_info.g.dart new file mode 100644 index 00000000..1ec9f75f --- /dev/null +++ b/lib/services/sourced_track/models/source_info.g.dart @@ -0,0 +1,30 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +part of 'source_info.dart'; + +// ************************************************************************** +// JsonSerializableGenerator +// ************************************************************************** + +SourceInfo _$SourceInfoFromJson(Map json) => SourceInfo( + id: json['id'] as String, + title: json['title'] as String, + artist: json['artist'] as String, + thumbnail: json['thumbnail'] as String, + pageUrl: json['pageUrl'] as String, + duration: Duration(microseconds: json['duration'] as int), + artistUrl: json['artistUrl'] as String, + album: json['album'] as String?, + ); + +Map _$SourceInfoToJson(SourceInfo instance) => + { + 'id': instance.id, + 'title': instance.title, + 'artist': instance.artist, + 'artistUrl': instance.artistUrl, + 'album': instance.album, + 'thumbnail': instance.thumbnail, + 'pageUrl': instance.pageUrl, + 'duration': instance.duration.inMicroseconds, + }; diff --git a/lib/services/sourced_track/models/source_map.dart b/lib/services/sourced_track/models/source_map.dart new file mode 100644 index 00000000..f99f95e4 --- /dev/null +++ b/lib/services/sourced_track/models/source_map.dart @@ -0,0 +1,58 @@ +import 'package:json_annotation/json_annotation.dart'; +import 'package:spotube/services/sourced_track/enums.dart'; + +part 'source_map.g.dart'; + +@JsonSerializable() +class SourceQualityMap { + final String high; + final String medium; + final String low; + + const SourceQualityMap({ + required this.high, + required this.medium, + required this.low, + }); + + factory SourceQualityMap.fromJson(Map json) => + _$SourceQualityMapFromJson(json); + + Map toJson() => _$SourceQualityMapToJson(this); + + operator [](SourceQualities key) { + switch (key) { + case SourceQualities.high: + return high; + case SourceQualities.medium: + return medium; + case SourceQualities.low: + return low; + } + } +} + +@JsonSerializable() +class SourceMap { + final SourceQualityMap? weba; + final SourceQualityMap? m4a; + + const SourceMap({ + this.weba, + this.m4a, + }); + + factory SourceMap.fromJson(Map json) => + _$SourceMapFromJson(json); + + Map toJson() => _$SourceMapToJson(this); + + operator [](SourceCodecs key) { + switch (key) { + case SourceCodecs.weba: + return weba; + case SourceCodecs.m4a: + return m4a; + } + } +} diff --git a/lib/services/sourced_track/models/source_map.g.dart b/lib/services/sourced_track/models/source_map.g.dart new file mode 100644 index 00000000..e1085aa8 --- /dev/null +++ b/lib/services/sourced_track/models/source_map.g.dart @@ -0,0 +1,35 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +part of 'source_map.dart'; + +// ************************************************************************** +// JsonSerializableGenerator +// ************************************************************************** + +SourceQualityMap _$SourceQualityMapFromJson(Map json) => + SourceQualityMap( + high: json['high'] as String, + medium: json['medium'] as String, + low: json['low'] as String, + ); + +Map _$SourceQualityMapToJson(SourceQualityMap instance) => + { + 'high': instance.high, + 'medium': instance.medium, + 'low': instance.low, + }; + +SourceMap _$SourceMapFromJson(Map json) => SourceMap( + weba: json['weba'] == null + ? null + : SourceQualityMap.fromJson(json['weba'] as Map), + m4a: json['m4a'] == null + ? null + : SourceQualityMap.fromJson(json['m4a'] as Map), + ); + +Map _$SourceMapToJson(SourceMap instance) => { + 'weba': instance.weba, + 'm4a': instance.m4a, + }; diff --git a/lib/services/sourced_track/models/video_info.dart b/lib/services/sourced_track/models/video_info.dart new file mode 100644 index 00000000..031a8943 --- /dev/null +++ b/lib/services/sourced_track/models/video_info.dart @@ -0,0 +1,114 @@ +import 'package:piped_client/piped_client.dart'; +import 'package:spotube/provider/user_preferences/user_preferences_state.dart'; +import 'package:youtube_explode_dart/youtube_explode_dart.dart'; + +class YoutubeVideoInfo { + final SearchMode searchMode; + final String title; + final Duration duration; + final String thumbnailUrl; + final String id; + final int likes; + final int dislikes; + final int views; + final String channelName; + final String channelId; + final DateTime publishedAt; + + YoutubeVideoInfo({ + required this.searchMode, + required this.title, + required this.duration, + required this.thumbnailUrl, + required this.id, + required this.likes, + required this.dislikes, + required this.views, + required this.channelName, + required this.publishedAt, + required this.channelId, + }); + + YoutubeVideoInfo.fromJson(Map json) + : title = json['title'], + searchMode = SearchMode.fromString(json['searchMode']), + duration = Duration(seconds: json['duration']), + thumbnailUrl = json['thumbnailUrl'], + id = json['id'], + likes = json['likes'], + dislikes = json['dislikes'], + views = json['views'], + channelName = json['channelName'], + channelId = json['channelId'], + publishedAt = DateTime.tryParse(json['publishedAt']) ?? DateTime.now(); + + Map toJson() => { + 'title': title, + 'duration': duration.inSeconds, + 'thumbnailUrl': thumbnailUrl, + 'id': id, + 'likes': likes, + 'dislikes': dislikes, + 'views': views, + 'channelName': channelName, + 'channelId': channelId, + 'publishedAt': publishedAt.toIso8601String(), + 'searchMode': searchMode.name, + }; + + factory YoutubeVideoInfo.fromVideo(Video video) { + return YoutubeVideoInfo( + searchMode: SearchMode.youtube, + title: video.title, + duration: video.duration ?? Duration.zero, + thumbnailUrl: video.thumbnails.mediumResUrl, + id: video.id.value, + likes: video.engagement.likeCount ?? 0, + dislikes: video.engagement.dislikeCount ?? 0, + views: video.engagement.viewCount, + channelName: video.author, + channelId: '/c/${video.channelId.value}', + publishedAt: video.uploadDate ?? DateTime(2003, 9, 9), + ); + } + + factory YoutubeVideoInfo.fromSearchItemStream( + PipedSearchItemStream searchItem, + SearchMode searchMode, + ) { + return YoutubeVideoInfo( + searchMode: searchMode, + title: searchItem.title, + duration: searchItem.duration, + thumbnailUrl: searchItem.thumbnail, + id: searchItem.id, + likes: 0, + dislikes: 0, + views: searchItem.views, + channelName: searchItem.uploaderName, + channelId: searchItem.uploaderUrl ?? "", + publishedAt: searchItem.uploadedDate != null + ? DateTime.tryParse(searchItem.uploadedDate!) ?? DateTime(2003, 9, 9) + : DateTime(2003, 9, 9), + ); + } + + factory YoutubeVideoInfo.fromStreamResponse( + PipedStreamResponse stream, SearchMode searchMode) { + return YoutubeVideoInfo( + searchMode: searchMode, + title: stream.title, + duration: stream.duration, + thumbnailUrl: stream.thumbnailUrl, + id: stream.id, + likes: stream.likes, + dislikes: stream.dislikes, + views: stream.views, + channelName: stream.uploader, + publishedAt: stream.uploadedDate != null + ? DateTime.tryParse(stream.uploadedDate!) ?? DateTime(2003, 9, 9) + : DateTime(2003, 9, 9), + channelId: stream.uploaderUrl, + ); + } +} diff --git a/lib/services/sourced_track/sourced_track.dart b/lib/services/sourced_track/sourced_track.dart new file mode 100644 index 00000000..d2dd6f59 --- /dev/null +++ b/lib/services/sourced_track/sourced_track.dart @@ -0,0 +1,171 @@ +import 'package:collection/collection.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; +import 'package:spotify/spotify.dart'; +import 'package:spotube/provider/user_preferences/user_preferences_provider.dart'; +import 'package:spotube/provider/user_preferences/user_preferences_state.dart'; +import 'package:spotube/services/sourced_track/enums.dart'; +import 'package:spotube/services/sourced_track/models/source_info.dart'; +import 'package:spotube/services/sourced_track/models/source_map.dart'; +import 'package:spotube/services/sourced_track/sources/jiosaavn.dart'; +import 'package:spotube/services/sourced_track/sources/piped.dart'; +import 'package:spotube/services/sourced_track/sources/youtube.dart'; +import 'package:spotube/utils/service_utils.dart'; + +abstract class SourcedTrack extends Track { + final SourceMap source; + final List siblings; + final SourceInfo sourceInfo; + final Ref ref; + + SourcedTrack({ + required this.ref, + required this.source, + required this.siblings, + required this.sourceInfo, + required Track track, + }) { + id = track.id; + name = track.name; + artists = track.artists; + album = track.album; + durationMs = track.durationMs; + discNumber = track.discNumber; + explicit = track.explicit; + externalIds = track.externalIds; + href = track.href; + isPlayable = track.isPlayable; + linkedFrom = track.linkedFrom; + popularity = track.popularity; + previewUrl = track.previewUrl; + trackNumber = track.trackNumber; + type = track.type; + uri = track.uri; + } + + static SourcedTrack fromJson( + Map json, { + required Ref ref, + }) { + final preferences = ref.read(userPreferencesProvider); + + final sourceInfo = SourceInfo.fromJson(json); + final source = SourceMap.fromJson(json); + final track = Track.fromJson(json); + final siblings = (json["siblings"] as List) + .map((sibling) => SourceInfo.fromJson(sibling)) + .toList() + .cast(); + + return switch (preferences.audioSource) { + AudioSource.youtube => YoutubeSourcedTrack( + ref: ref, + source: source, + siblings: siblings, + sourceInfo: sourceInfo, + track: track, + ), + AudioSource.piped => PipedSourcedTrack( + ref: ref, + source: source, + siblings: siblings, + sourceInfo: sourceInfo, + track: track, + ), + AudioSource.jiosaavn => JioSaavnSourcedTrack( + ref: ref, + source: source, + siblings: siblings, + sourceInfo: sourceInfo, + track: track, + ), + }; + } + + static String getSearchTerm(Track track) { + final artists = (track.artists ?? []) + .map((ar) => ar.name) + .toList() + .whereNotNull() + .toList(); + + final title = ServiceUtils.getTitle( + track.name!, + artists: artists, + onlyCleanArtist: true, + ).trim(); + + return "$title - ${artists.join(", ")}"; + } + + static Future fetchFromTrack({ + required Track track, + required Ref ref, + }) async { + try { + final preferences = ref.read(userPreferencesProvider); + + return switch (preferences.audioSource) { + AudioSource.piped => + await PipedSourcedTrack.fetchFromTrack(track: track, ref: ref), + AudioSource.youtube => + await YoutubeSourcedTrack.fetchFromTrack(track: track, ref: ref), + AudioSource.jiosaavn => + await JioSaavnSourcedTrack.fetchFromTrack(track: track, ref: ref), + }; + } catch (e) { + print("Got error: $e"); + return YoutubeSourcedTrack.fetchFromTrack(track: track, ref: ref); + } + } + + static Future> fetchSiblings({ + required Track track, + required Ref ref, + }) { + final preferences = ref.read(userPreferencesProvider); + + return switch (preferences.audioSource) { + AudioSource.piped => + PipedSourcedTrack.fetchSiblings(track: track, ref: ref), + AudioSource.youtube => + YoutubeSourcedTrack.fetchSiblings(track: track, ref: ref), + AudioSource.jiosaavn => + JioSaavnSourcedTrack.fetchSiblings(track: track, ref: ref), + }; + } + + Future copyWithSibling(); + + Future swapWithSibling(SourceInfo sibling); + + Future swapWithSiblingOfIndex(int index) { + return swapWithSibling(siblings[index]); + } + + String get url { + final preferences = ref.read(userPreferencesProvider); + + final codec = preferences.audioSource == AudioSource.jiosaavn + ? SourceCodecs.m4a + : preferences.streamMusicCodec; + + return getUrlOfCodec(codec); + } + + String getUrlOfCodec(SourceCodecs codec) { + final preferences = ref.read(userPreferencesProvider); + + return source[codec]?[preferences.audioQuality] ?? + // this will ensure playback doesn't break + source[codec == SourceCodecs.m4a ? SourceCodecs.weba : SourceCodecs.m4a] + [preferences.audioQuality]; + } + + SourceCodecs get codec { + final preferences = ref.read(userPreferencesProvider); + + return preferences.audioSource == AudioSource.jiosaavn + ? SourceCodecs.m4a + : preferences.streamMusicCodec; + } +} diff --git a/lib/services/sourced_track/sources/jiosaavn.dart b/lib/services/sourced_track/sources/jiosaavn.dart new file mode 100644 index 00000000..b25eca3b --- /dev/null +++ b/lib/services/sourced_track/sources/jiosaavn.dart @@ -0,0 +1,159 @@ +import 'package:collection/collection.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; +import 'package:spotify/spotify.dart'; +import 'package:spotube/models/source_match.dart'; +import 'package:spotube/services/sourced_track/enums.dart'; +import 'package:spotube/services/sourced_track/exceptions.dart'; +import 'package:spotube/services/sourced_track/models/source_info.dart'; +import 'package:spotube/services/sourced_track/models/source_map.dart'; +import 'package:spotube/services/sourced_track/sourced_track.dart'; +import 'package:jiosaavn/jiosaavn.dart'; + +final jiosaavnClient = JioSaavnClient(); + +class JioSaavnSourcedTrack extends SourcedTrack { + JioSaavnSourcedTrack({ + required super.ref, + required super.source, + required super.siblings, + required super.sourceInfo, + required super.track, + }); + + static Future fetchFromTrack({ + required Track track, + required Ref ref, + }) async { + final cachedSource = await SourceMatch.box.get(track.id); + + if (cachedSource == null || + cachedSource.sourceType != SourceType.jiosaavn) { + final siblings = await fetchSiblings(ref: ref, track: track); + + if (siblings.isEmpty) { + throw TrackNotFoundException(track); + } + + await SourceMatch.box.put( + track.id!, + SourceMatch( + id: track.id!, + sourceType: SourceType.jiosaavn, + createdAt: DateTime.now(), + sourceId: siblings.first.info.id, + ), + ); + + return JioSaavnSourcedTrack( + ref: ref, + siblings: siblings.map((s) => s.info).skip(1).toList(), + source: siblings.first.source!, + sourceInfo: siblings.first.info, + track: track, + ); + } + + final [item] = + await jiosaavnClient.songs.detailsById([cachedSource.sourceId]); + + final (:info, :source) = toSiblingType(item); + + return JioSaavnSourcedTrack( + ref: ref, + siblings: [], + source: source!, + sourceInfo: info, + track: track, + ); + } + + static SiblingType toSiblingType(SongResponse result) { + final SiblingType sibling = ( + info: SourceInfo( + artist: [ + result.primaryArtists, + if (result.featuredArtists.isNotEmpty) ", ", + result.featuredArtists + ].join("").replaceAll("&", "&"), + artistUrl: + "https://www.jiosaavn.com/artist/${result.primaryArtistsId.split(",").firstOrNull ?? ""}", + duration: Duration(seconds: int.parse(result.duration)), + id: result.id, + pageUrl: result.url, + thumbnail: result.image?.last.link ?? "", + title: result.name!, + album: result.album.name, + ), + source: SourceMap( + m4a: SourceQualityMap( + high: result.downloadUrl! + .firstWhere((element) => element.quality == "320kbps") + .link, + medium: result.downloadUrl! + .firstWhere((element) => element.quality == "160kbps") + .link, + low: result.downloadUrl! + .firstWhere((element) => element.quality == "96kbps") + .link, + ), + ), + ); + + return sibling; + } + + static Future> fetchSiblings({ + required Track track, + required Ref ref, + }) async { + final query = SourcedTrack.getSearchTerm(track); + + final SongSearchResponse(:results) = + await jiosaavnClient.search.songs(query, limit: 20); + + return results.map(toSiblingType).toList(); + } + + @override + Future copyWithSibling() async { + if (siblings.isNotEmpty) { + return this; + } + final fetchedSiblings = await fetchSiblings(ref: ref, track: this); + + return JioSaavnSourcedTrack( + ref: ref, + siblings: fetchedSiblings + .where((s) => s.info.id != sourceInfo.id) + .map((s) => s.info) + .toList(), + source: source, + sourceInfo: sourceInfo, + track: this, + ); + } + + @override + Future swapWithSibling(SourceInfo sibling) async { + if (sibling.id == sourceInfo.id || + siblings.none((s) => s.id == sibling.id)) { + return null; + } + + final newSourceInfo = siblings.firstWhere((s) => s.id == sibling.id); + final newSiblings = siblings.where((s) => s.id != sibling.id).toList() + ..insert(0, sourceInfo); + + final [item] = await jiosaavnClient.songs.detailsById([newSourceInfo.id]); + + final (:info, :source) = toSiblingType(item); + + return JioSaavnSourcedTrack( + ref: ref, + siblings: newSiblings, + source: source!, + sourceInfo: info, + track: this, + ); + } +} diff --git a/lib/services/sourced_track/sources/piped.dart b/lib/services/sourced_track/sources/piped.dart new file mode 100644 index 00000000..0778a7cf --- /dev/null +++ b/lib/services/sourced_track/sources/piped.dart @@ -0,0 +1,257 @@ +import 'package:collection/collection.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; +import 'package:piped_client/piped_client.dart'; +import 'package:spotify/spotify.dart'; +import 'package:spotube/models/source_match.dart'; +import 'package:spotube/provider/user_preferences/user_preferences_provider.dart'; +import 'package:spotube/provider/user_preferences/user_preferences_state.dart'; +import 'package:spotube/services/sourced_track/enums.dart'; +import 'package:spotube/services/sourced_track/exceptions.dart'; +import 'package:spotube/services/sourced_track/models/source_info.dart'; +import 'package:spotube/services/sourced_track/models/source_map.dart'; +import 'package:spotube/services/sourced_track/models/video_info.dart'; +import 'package:spotube/services/sourced_track/sourced_track.dart'; +import 'package:spotube/services/sourced_track/sources/youtube.dart'; +import 'package:spotube/utils/service_utils.dart'; + +final pipedProvider = Provider( + (ref) { + final instance = + ref.watch(userPreferencesProvider.select((s) => s.pipedInstance)); + return PipedClient(instance: instance); + }, +); + +class PipedSourcedTrack extends SourcedTrack { + PipedSourcedTrack({ + required super.ref, + required super.source, + required super.siblings, + required super.sourceInfo, + required super.track, + }); + + static Future fetchFromTrack({ + required Track track, + required Ref ref, + }) async { + final cachedSource = await SourceMatch.box.get(track.id); + final preferences = ref.read(userPreferencesProvider); + final pipedClient = ref.read(pipedProvider); + + if (cachedSource == null) { + final siblings = await fetchSiblings(ref: ref, track: track); + if (siblings.isEmpty) { + throw TrackNotFoundException(track); + } + + await SourceMatch.box.put( + track.id!, + SourceMatch( + id: track.id!, + sourceType: preferences.searchMode == SearchMode.youtube + ? SourceType.youtube + : SourceType.youtubeMusic, + createdAt: DateTime.now(), + sourceId: siblings.first.info.id, + ), + ); + + return PipedSourcedTrack( + ref: ref, + siblings: siblings.map((s) => s.info).skip(1).toList(), + source: siblings.first.source as SourceMap, + sourceInfo: siblings.first.info, + track: track, + ); + } else { + final manifest = await pipedClient.streams(cachedSource.sourceId); + + return PipedSourcedTrack( + ref: ref, + siblings: [], + source: toSourceMap(manifest), + sourceInfo: SourceInfo( + id: manifest.id, + artist: manifest.uploader, + artistUrl: manifest.uploaderUrl, + pageUrl: "https://www.youtube.com/watch?v=${manifest.id}", + thumbnail: manifest.thumbnailUrl, + title: manifest.title, + duration: manifest.duration, + album: null, + ), + track: track, + ); + } + } + + static SourceMap toSourceMap(PipedStreamResponse manifest) { + final m4a = manifest.audioStreams + .where((audio) => audio.format == PipedAudioStreamFormat.m4a) + .sorted((a, b) => a.bitrate.compareTo(b.bitrate)); + + final weba = manifest.audioStreams + .where((audio) => audio.format == PipedAudioStreamFormat.webm) + .sorted((a, b) => a.bitrate.compareTo(b.bitrate)); + + return SourceMap( + m4a: SourceQualityMap( + high: m4a.first.url.toString(), + medium: (m4a.elementAtOrNull(m4a.length ~/ 2) ?? m4a[1]).url.toString(), + low: m4a.last.url.toString(), + ), + weba: SourceQualityMap( + high: weba.first.url.toString(), + medium: + (weba.elementAtOrNull(weba.length ~/ 2) ?? weba[1]).url.toString(), + low: weba.last.url.toString(), + ), + ); + } + + static Future toSiblingType( + int index, + YoutubeVideoInfo item, + PipedClient pipedClient, + ) async { + SourceMap? sourceMap; + if (index == 0) { + final manifest = await pipedClient.streams(item.id); + sourceMap = toSourceMap(manifest); + } + + final SiblingType sibling = ( + info: SourceInfo( + id: item.id, + artist: item.channelName, + artistUrl: "https://www.youtube.com/${item.channelId}", + pageUrl: "https://www.youtube.com/watch?v=${item.id}", + thumbnail: item.thumbnailUrl, + title: item.title, + duration: item.duration, + album: null, + ), + source: sourceMap, + ); + + return sibling; + } + + static Future> fetchSiblings({ + required Track track, + required Ref ref, + }) async { + final pipedClient = ref.read(pipedProvider); + final preference = ref.read(userPreferencesProvider); + final query = SourcedTrack.getSearchTerm(track); + + final PipedSearchResult(items: searchResults) = await pipedClient.search( + query, + preference.searchMode == SearchMode.youtube + ? PipedFilter.video + : PipedFilter.musicSongs, + ); + + final isYouTubeMusic = preference.searchMode == SearchMode.youtubeMusic; + + if (isYouTubeMusic) { + final artists = (track.artists ?? []) + .map((ar) => ar.name) + .toList() + .whereNotNull() + .toList(); + + return await Future.wait( + searchResults + .map( + (result) => YoutubeVideoInfo.fromSearchItemStream( + result as PipedSearchItemStream, + preference.searchMode, + ), + ) + .sorted((a, b) => b.views.compareTo(a.views)) + .where( + (item) => artists.any( + (artist) => + artist.toLowerCase() == item.channelName.toLowerCase(), + ), + ) + .mapIndexed((i, r) => toSiblingType(i, r, pipedClient)), + ); + } + + if (ServiceUtils.onlyContainsEnglish(query)) { + return await Future.wait( + searchResults + .whereType() + .map( + (result) => YoutubeVideoInfo.fromSearchItemStream( + result, + preference.searchMode, + ), + ) + .mapIndexed((i, r) => toSiblingType(i, r, pipedClient)), + ); + } + + final rankedSiblings = YoutubeSourcedTrack.rankResults( + searchResults + .map( + (result) => YoutubeVideoInfo.fromSearchItemStream( + result as PipedSearchItemStream, + preference.searchMode, + ), + ) + .toList(), + track, + ); + + return await Future.wait( + rankedSiblings.mapIndexed((i, r) => toSiblingType(i, r, pipedClient)), + ); + } + + @override + Future copyWithSibling() async { + if (siblings.isNotEmpty) { + return this; + } + final fetchedSiblings = await fetchSiblings(ref: ref, track: this); + + return PipedSourcedTrack( + ref: ref, + siblings: fetchedSiblings + .where((s) => s.info.id != sourceInfo.id) + .map((s) => s.info) + .toList(), + source: source, + sourceInfo: sourceInfo, + track: this, + ); + } + + @override + Future swapWithSibling(SourceInfo sibling) async { + if (sibling.id == sourceInfo.id || + siblings.none((s) => s.id == sibling.id)) { + return null; + } + + final newSourceInfo = siblings.firstWhere((s) => s.id == sibling.id); + final newSiblings = siblings.where((s) => s.id != sibling.id).toList() + ..insert(0, sourceInfo); + + final pipedClient = ref.read(pipedProvider); + + final manifest = await pipedClient.streams(newSourceInfo.id); + + return PipedSourcedTrack( + ref: ref, + siblings: newSiblings, + source: toSourceMap(manifest), + sourceInfo: newSourceInfo, + track: this, + ); + } +} diff --git a/lib/services/sourced_track/sources/youtube.dart b/lib/services/sourced_track/sources/youtube.dart new file mode 100644 index 00000000..096de2d4 --- /dev/null +++ b/lib/services/sourced_track/sources/youtube.dart @@ -0,0 +1,256 @@ +import 'package:collection/collection.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; +import 'package:spotify/spotify.dart'; +import 'package:spotube/models/source_match.dart'; +import 'package:spotube/services/sourced_track/enums.dart'; +import 'package:spotube/services/sourced_track/exceptions.dart'; +import 'package:spotube/services/sourced_track/models/source_info.dart'; +import 'package:spotube/services/sourced_track/models/source_map.dart'; +import 'package:spotube/services/sourced_track/models/video_info.dart'; +import 'package:spotube/services/sourced_track/sourced_track.dart'; +import 'package:spotube/utils/service_utils.dart'; +import 'package:youtube_explode_dart/youtube_explode_dart.dart'; + +final youtubeClient = YoutubeExplode(); +final officialMusicRegex = RegExp( + r"official\s(video|audio|music\svideo|lyric\svideo|visualizer)", + caseSensitive: false, +); + +class YoutubeSourcedTrack extends SourcedTrack { + YoutubeSourcedTrack({ + required super.source, + required super.siblings, + required super.sourceInfo, + required super.track, + required super.ref, + }); + + static Future fetchFromTrack({ + required Track track, + required Ref ref, + }) async { + final cachedSource = await SourceMatch.box.get(track.id); + + if (cachedSource == null || cachedSource.sourceType != SourceType.youtube) { + final siblings = await fetchSiblings(ref: ref, track: track); + if (siblings.isEmpty) { + throw TrackNotFoundException(track); + } + + await SourceMatch.box.put( + track.id!, + SourceMatch( + id: track.id!, + sourceType: SourceType.youtube, + createdAt: DateTime.now(), + sourceId: siblings.first.info.id, + ), + ); + + return YoutubeSourcedTrack( + ref: ref, + siblings: siblings.map((s) => s.info).skip(1).toList(), + source: siblings.first.source as SourceMap, + sourceInfo: siblings.first.info, + track: track, + ); + } + final item = await youtubeClient.videos.get(cachedSource.sourceId); + final manifest = await youtubeClient.videos.streamsClient.getManifest( + cachedSource.sourceId, + ); + return YoutubeSourcedTrack( + ref: ref, + siblings: [], + source: toSourceMap(manifest), + sourceInfo: SourceInfo( + id: item.id.value, + artist: item.author, + artistUrl: "https://www.youtube.com/channel/${item.channelId}", + pageUrl: item.url, + thumbnail: item.thumbnails.highResUrl, + title: item.title, + duration: item.duration ?? Duration.zero, + album: null, + ), + track: track, + ); + } + + static SourceMap toSourceMap(StreamManifest manifest) { + final m4a = manifest.audioOnly + .where((audio) => audio.codec.mimeType == "audio/mp4") + .sortByBitrate(); + + final weba = manifest.audioOnly + .where((audio) => audio.codec.mimeType == "audio/webm") + .sortByBitrate(); + + return SourceMap( + m4a: SourceQualityMap( + high: m4a.first.url.toString(), + medium: (m4a.elementAtOrNull(m4a.length ~/ 2) ?? m4a[1]).url.toString(), + low: m4a.last.url.toString(), + ), + weba: SourceQualityMap( + high: weba.first.url.toString(), + medium: + (weba.elementAtOrNull(weba.length ~/ 2) ?? weba[1]).url.toString(), + low: weba.last.url.toString(), + ), + ); + } + + static Future toSiblingType( + int index, + YoutubeVideoInfo item, + ) async { + SourceMap? sourceMap; + if (index == 0) { + final manifest = + await youtubeClient.videos.streamsClient.getManifest(item.id); + sourceMap = toSourceMap(manifest); + } + + final SiblingType sibling = ( + info: SourceInfo( + id: item.id, + artist: item.channelName, + artistUrl: "https://www.youtube.com/channel/${item.channelId}", + pageUrl: "https://www.youtube.com/watch?v=${item.id}", + thumbnail: item.thumbnailUrl, + title: item.title, + duration: item.duration, + album: null, + ), + source: sourceMap, + ); + + return sibling; + } + + static List rankResults( + List results, Track track) { + final artists = (track.artists ?? []) + .map((ar) => ar.name) + .toList() + .whereNotNull() + .toList(); + + return results + .sorted((a, b) => b.views.compareTo(a.views)) + .map((sibling) { + int score = 0; + + for (final artist in artists) { + final isSameChannelArtist = + sibling.channelName.toLowerCase() == artist.toLowerCase(); + final channelContainsArtist = sibling.channelName + .toLowerCase() + .contains(artist.toLowerCase()); + + if (isSameChannelArtist || channelContainsArtist) { + score += 1; + } + + final titleContainsArtist = + sibling.title.toLowerCase().contains(artist.toLowerCase()); + + if (titleContainsArtist) { + score += 1; + } + } + + final titleContainsTrackName = + sibling.title.toLowerCase().contains(track.name!.toLowerCase()); + + final hasOfficialFlag = + officialMusicRegex.hasMatch(sibling.title.toLowerCase()); + + if (titleContainsTrackName) { + score += 3; + } + + if (hasOfficialFlag) { + score += 1; + } + + if (hasOfficialFlag && titleContainsTrackName) { + score += 2; + } + + return (sibling: sibling, score: score); + }) + .sorted((a, b) => b.score.compareTo(a.score)) + .map((e) => e.sibling) + .toList(); + } + + static Future> fetchSiblings({ + required Track track, + required Ref ref, + }) async { + final query = SourcedTrack.getSearchTerm(track); + + final searchResults = await youtubeClient.search.search( + query, + filter: TypeFilters.video, + ); + + if (ServiceUtils.onlyContainsEnglish(query)) { + return await Future.wait(searchResults + .map(YoutubeVideoInfo.fromVideo) + .mapIndexed(toSiblingType)); + } + + final rankedSiblings = rankResults( + searchResults.map(YoutubeVideoInfo.fromVideo).toList(), + track, + ); + + return await Future.wait(rankedSiblings.mapIndexed(toSiblingType)); + } + + @override + Future swapWithSibling(SourceInfo sibling) async { + if (sibling.id == sourceInfo.id || + siblings.none((s) => s.id == sibling.id)) { + return null; + } + + final newSourceInfo = siblings.firstWhere((s) => s.id == sibling.id); + final newSiblings = siblings.where((s) => s.id != sibling.id).toList() + ..insert(0, sourceInfo); + + final manifest = + await youtubeClient.videos.streamsClient.getManifest(newSourceInfo.id); + + return YoutubeSourcedTrack( + ref: ref, + siblings: newSiblings, + source: toSourceMap(manifest), + sourceInfo: newSourceInfo, + track: this, + ); + } + + @override + Future copyWithSibling() async { + if (siblings.isNotEmpty) { + return this; + } + final fetchedSiblings = await fetchSiblings(ref: ref, track: this); + + return YoutubeSourcedTrack( + ref: ref, + siblings: fetchedSiblings + .where((s) => s.info.id != sourceInfo.id) + .map((s) => s.info) + .toList(), + source: source, + sourceInfo: sourceInfo, + track: this, + ); + } +} diff --git a/lib/services/supabase.dart b/lib/services/supabase.dart index d42d8eeb..ef3fa87c 100644 --- a/lib/services/supabase.dart +++ b/lib/services/supabase.dart @@ -1,5 +1,5 @@ import 'package:spotube/collections/env.dart'; -import 'package:spotube/models/matched_track.dart'; +import 'package:spotube/models/source_match.dart'; import 'package:supabase/supabase.dart'; class SupabaseService { @@ -8,7 +8,9 @@ class SupabaseService { Env.supabaseAnonKey ?? "", ); - Future insertTrack(MatchedTrack track) async { + Future insertTrack(SourceMatch track) async { + return null; + // TODO: Fix this await api.from("tracks").insert(track.toJson()); } } diff --git a/lib/services/youtube/youtube.dart b/lib/services/youtube/youtube.dart deleted file mode 100644 index 2b52864b..00000000 --- a/lib/services/youtube/youtube.dart +++ /dev/null @@ -1,248 +0,0 @@ -import 'package:dio/dio.dart'; -import 'package:flutter/material.dart'; -import 'package:piped_client/piped_client.dart'; -import 'package:spotube/collections/routes.dart'; -import 'package:spotube/components/shared/dialogs/piped_down_dialog.dart'; -import 'package:spotube/models/matched_track.dart'; -import 'package:spotube/provider/user_preferences/user_preferences_state.dart'; -import 'package:spotube/utils/primitive_utils.dart'; -import 'package:youtube_explode_dart/youtube_explode_dart.dart'; - -class YoutubeVideoInfo { - final SearchMode searchMode; - final String title; - final Duration duration; - final String thumbnailUrl; - final String id; - final int likes; - final int dislikes; - final int views; - final String channelName; - final String channelId; - final DateTime publishedAt; - - YoutubeVideoInfo({ - required this.searchMode, - required this.title, - required this.duration, - required this.thumbnailUrl, - required this.id, - required this.likes, - required this.dislikes, - required this.views, - required this.channelName, - required this.publishedAt, - required this.channelId, - }); - - YoutubeVideoInfo.fromJson(Map json) - : title = json['title'], - searchMode = SearchMode.fromString(json['searchMode']), - duration = Duration(seconds: json['duration']), - thumbnailUrl = json['thumbnailUrl'], - id = json['id'], - likes = json['likes'], - dislikes = json['dislikes'], - views = json['views'], - channelName = json['channelName'], - channelId = json['channelId'], - publishedAt = DateTime.tryParse(json['publishedAt']) ?? DateTime.now(); - - Map toJson() => { - 'title': title, - 'duration': duration.inSeconds, - 'thumbnailUrl': thumbnailUrl, - 'id': id, - 'likes': likes, - 'dislikes': dislikes, - 'views': views, - 'channelName': channelName, - 'channelId': channelId, - 'publishedAt': publishedAt.toIso8601String(), - 'searchMode': searchMode.name, - }; - - factory YoutubeVideoInfo.fromVideo(Video video) { - return YoutubeVideoInfo( - searchMode: SearchMode.youtube, - title: video.title, - duration: video.duration ?? Duration.zero, - thumbnailUrl: video.thumbnails.mediumResUrl, - id: video.id.value, - likes: video.engagement.likeCount ?? 0, - dislikes: video.engagement.dislikeCount ?? 0, - views: video.engagement.viewCount, - channelName: video.author, - channelId: '/c/${video.channelId.value}', - publishedAt: video.uploadDate ?? DateTime(2003, 9, 9), - ); - } - - factory YoutubeVideoInfo.fromSearchItemStream( - PipedSearchItemStream searchItem, - SearchMode searchMode, - ) { - return YoutubeVideoInfo( - searchMode: searchMode, - title: searchItem.title, - duration: searchItem.duration, - thumbnailUrl: searchItem.thumbnail, - id: searchItem.id, - likes: 0, - dislikes: 0, - views: searchItem.views, - channelName: searchItem.uploaderName, - channelId: searchItem.uploaderUrl ?? "", - publishedAt: searchItem.uploadedDate != null - ? DateTime.tryParse(searchItem.uploadedDate!) ?? DateTime(2003, 9, 9) - : DateTime(2003, 9, 9), - ); - } - - factory YoutubeVideoInfo.fromStreamResponse( - PipedStreamResponse stream, SearchMode searchMode) { - return YoutubeVideoInfo( - searchMode: searchMode, - title: stream.title, - duration: stream.duration, - thumbnailUrl: stream.thumbnailUrl, - id: stream.id, - likes: stream.likes, - dislikes: stream.dislikes, - views: stream.views, - channelName: stream.uploader, - publishedAt: stream.uploadedDate != null - ? DateTime.tryParse(stream.uploadedDate!) ?? DateTime(2003, 9, 9) - : DateTime(2003, 9, 9), - channelId: stream.uploaderUrl, - ); - } -} - -class YoutubeEndpoints { - PipedClient? piped; - YoutubeExplode? youtube; - - final UserPreferences preferences; - - YoutubeEndpoints(this.preferences) { - switch (preferences.youtubeApiType) { - case YoutubeApiType.youtube: - youtube = YoutubeExplode(); - break; - case YoutubeApiType.piped: - piped = PipedClient(instance: preferences.pipedInstance); - break; - } - } - - Future showPipedErrorDialog(Exception e) async { - if (e is DioException && (e.response?.statusCode ?? 0) >= 500) { - final context = rootNavigatorKey?.currentContext; - if (context != null) { - await showDialog( - context: context, - builder: (context) => const PipedDownDialog(), - ); - } - } - } - - Future> search(String query) async { - if (youtube != null) { - final res = await youtube!.search( - query, - filter: TypeFilters.video, - ); - - return res.map(YoutubeVideoInfo.fromVideo).toList(); - } else { - try { - final res = await piped!.search( - query, - switch (preferences.searchMode) { - SearchMode.youtube => PipedFilter.video, - SearchMode.youtubeMusic => PipedFilter.musicSongs, - }, - ); - return res.items - .whereType() - .map( - (e) => YoutubeVideoInfo.fromSearchItemStream( - e, - preferences.searchMode, - ), - ) - .toList(); - } on Exception catch (e) { - await showPipedErrorDialog(e); - rethrow; - } - } - } - - String _pipedStreamResponseToStreamUrl( - PipedStreamResponse stream, - MusicCodec codec, - ) { - final pipedStreamFormat = switch (codec) { - MusicCodec.m4a => PipedAudioStreamFormat.m4a, - MusicCodec.weba => PipedAudioStreamFormat.webm, - }; - - return switch (preferences.audioQuality) { - AudioQuality.high => - stream.highestBitrateAudioStreamOfFormat(pipedStreamFormat)!.url, - AudioQuality.low => - stream.lowestBitrateAudioStreamOfFormat(pipedStreamFormat)!.url, - }; - } - - Future streamingUrl(String id, MusicCodec codec) async { - if (youtube != null) { - final res = await PrimitiveUtils.raceMultiple( - () => youtube!.videos.streams.getManifest(id), - ); - final audioOnlyManifests = res.audioOnly.where((info) { - return switch (codec) { - MusicCodec.m4a => info.codec.mimeType == "audio/mp4", - MusicCodec.weba => info.codec.mimeType == "audio/webm", - }; - }); - - return switch (preferences.audioQuality) { - AudioQuality.high => - audioOnlyManifests.withHighestBitrate().url.toString(), - AudioQuality.low => - audioOnlyManifests.sortByBitrate().last.url.toString(), - }; - } else { - return _pipedStreamResponseToStreamUrl(await piped!.streams(id), codec); - } - } - - Future<(YoutubeVideoInfo info, String streamingUrl)> video( - String id, - SearchMode searchMode, - MusicCodec codec, - ) async { - if (youtube != null) { - final res = await youtube!.videos.get(id); - return ( - YoutubeVideoInfo.fromVideo(res), - await streamingUrl(id, codec), - ); - } else { - try { - final res = await piped!.streams(id); - return ( - YoutubeVideoInfo.fromStreamResponse(res, searchMode), - _pipedStreamResponseToStreamUrl(res, codec), - ); - } on Exception catch (e) { - await showPipedErrorDialog(e); - rethrow; - } - } - } -} diff --git a/lib/utils/service_utils.dart b/lib/utils/service_utils.dart index 0be1dd97..9e3b5893 100644 --- a/lib/utils/service_utils.dart +++ b/lib/utils/service_utils.dart @@ -8,7 +8,7 @@ import 'package:spotube/components/library/user_local_tracks.dart'; import 'package:spotube/models/logger.dart'; import 'package:http/http.dart' as http; import 'package:spotube/models/lyrics.dart'; -import 'package:spotube/models/spotube_track.dart'; +import 'package:spotube/services/sourced_track/sourced_track.dart'; import 'package:spotube/utils/primitive_utils.dart'; import 'package:collection/collection.dart'; @@ -171,7 +171,7 @@ abstract class ServiceUtils { static const baseUri = "https://www.rentanadviser.com/subtitles"; @Deprecated("In favor spotify lyrics api, this isn't needed anymore") - static Future getTimedLyrics(SpotubeTrack track) async { + static Future getTimedLyrics(SourcedTrack track) async { final artistNames = track.artists?.map((artist) => artist.name!).toList() ?? []; final query = getTitle( @@ -199,7 +199,7 @@ abstract class ServiceUtils { false; final hasTrackName = title.contains(track.name!.toLowerCase()); final isNotLive = !PrimitiveUtils.containsTextInBracket(title, "live"); - final exactYtMatch = title == track.ytTrack.title.toLowerCase(); + final exactYtMatch = title == track.sourceInfo.title.toLowerCase(); if (exactYtMatch) points = 7; for (final criteria in [hasTrackName, hasAllArtists, isNotLive]) { if (criteria) points++; diff --git a/pubspec.lock b/pubspec.lock index 39e92028..54f6d934 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -385,6 +385,14 @@ packages: url: "https://pub.dev" source: hosted version: "1.0.3" + dart_des: + dependency: transitive + description: + name: dart_des + sha256: "0a66afb8883368c824497fd2a1fd67bdb1a785965a3956728382c03d40747c33" + url: "https://pub.dev" + source: hosted + version: "1.0.2" dart_style: dependency: transitive description: @@ -1174,6 +1182,15 @@ packages: url: "https://pub.dev" source: hosted version: "1.0.4" + jiosaavn: + dependency: "direct main" + description: + path: "." + ref: HEAD + resolved-ref: "8a7cda9b8b687cde28e0f7fcb10adb0d4fde1007" + url: "https://github.com/KRTirtho/jiosaavn.git" + source: git + version: "0.1.0" js: dependency: transitive description: diff --git a/pubspec.yaml b/pubspec.yaml index 590aaae4..b3fd3c3e 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -106,6 +106,9 @@ dependencies: simple_icons: ^7.10.0 audio_service_mpris: ^0.1.0 file_picker: ^6.0.0 + jiosaavn: + git: + url: https://github.com/KRTirtho/jiosaavn.git draggable_scrollbar: git: url: https://github.com/thielepaul/flutter-draggable-scrollbar.git From 28a5d6bb3820ab0bd4007664f73d685f6e1d2c90 Mon Sep 17 00:00:00 2001 From: Kingkor Roy Tirtho Date: Fri, 17 Nov 2023 13:14:25 +0600 Subject: [PATCH 023/195] feat: paginated playlist and album page --- lib/collections/routes.dart | 16 +- lib/components/album/album_card.dart | 79 ++-- lib/components/library/user_local_tracks.dart | 10 +- lib/components/player/player_queue.dart | 2 +- lib/components/playlist/playlist_card.dart | 48 ++- .../expandable_search/expandable_search.dart | 21 +- .../shimmers/shimmer_artist_profile.dart | 2 +- .../shared/shimmers/shimmer_track_tile.dart | 56 +-- .../track_collection_heading.dart | 229 ----------- .../track_collection_view.dart | 274 ------------- .../shared/track_table/tracks_table_view.dart | 368 ------------------ .../track_options.dart | 0 .../track_tile.dart | 2 +- .../sections/body/track_view_body.dart | 124 ++++++ .../body/track_view_body_headers.dart | 106 +++++ .../sections/body/track_view_options.dart | 131 +++++++ .../sections/body/use_is_user_playlist.dart | 18 + .../sections/header/flexible_header.dart | 142 +++++++ .../sections/header/header_actions.dart | 82 ++++ .../sections/header/header_buttons.dart | 137 +++++++ .../shared/tracks_view/track_view.dart | 44 +++ .../shared/tracks_view/track_view_props.dart | 102 +++++ .../tracks_view/track_view_provider.dart | 64 +++ lib/extensions/infinite_query.dart | 30 ++ lib/pages/album/album.dart | 192 +++------ lib/pages/artist/artist.dart | 2 +- lib/pages/home/genres.dart | 6 +- lib/pages/playlist/liked_playlist.dart | 45 +++ lib/pages/playlist/playlist.dart | 212 +++------- lib/pages/search/sections/tracks.dart | 2 +- lib/services/queries/album.dart | 48 ++- lib/services/queries/playlist.dart | 65 ++-- pubspec.lock | 16 + pubspec.yaml | 2 + 34 files changed, 1376 insertions(+), 1301 deletions(-) delete mode 100644 lib/components/shared/track_table/track_collection_view/track_collection_heading.dart delete mode 100644 lib/components/shared/track_table/track_collection_view/track_collection_view.dart delete mode 100644 lib/components/shared/track_table/tracks_table_view.dart rename lib/components/shared/{track_table => track_tile}/track_options.dart (100%) rename lib/components/shared/{track_table => track_tile}/track_tile.dart (99%) create mode 100644 lib/components/shared/tracks_view/sections/body/track_view_body.dart create mode 100644 lib/components/shared/tracks_view/sections/body/track_view_body_headers.dart create mode 100644 lib/components/shared/tracks_view/sections/body/track_view_options.dart create mode 100644 lib/components/shared/tracks_view/sections/body/use_is_user_playlist.dart create mode 100644 lib/components/shared/tracks_view/sections/header/flexible_header.dart create mode 100644 lib/components/shared/tracks_view/sections/header/header_actions.dart create mode 100644 lib/components/shared/tracks_view/sections/header/header_buttons.dart create mode 100644 lib/components/shared/tracks_view/track_view.dart create mode 100644 lib/components/shared/tracks_view/track_view_props.dart create mode 100644 lib/components/shared/tracks_view/track_view_provider.dart create mode 100644 lib/extensions/infinite_query.dart create mode 100644 lib/pages/playlist/liked_playlist.dart diff --git a/lib/collections/routes.dart b/lib/collections/routes.dart index 81ebb3e6..82597ddb 100644 --- a/lib/collections/routes.dart +++ b/lib/collections/routes.dart @@ -3,29 +3,29 @@ import 'package:flutter/foundation.dart'; import 'package:flutter/widgets.dart'; import 'package:go_router/go_router.dart'; import 'package:spotify/spotify.dart' hide Search; +import 'package:spotube/pages/album/album.dart'; import 'package:spotube/pages/home/home.dart'; import 'package:spotube/pages/lastfm_login/lastfm_login.dart'; import 'package:spotube/pages/library/playlist_generate/playlist_generate.dart'; +import 'package:spotube/pages/library/playlist_generate/playlist_generate_result.dart'; import 'package:spotube/pages/lyrics/mini_lyrics.dart'; +import 'package:spotube/pages/playlist/liked_playlist.dart'; +import 'package:spotube/pages/playlist/playlist.dart'; import 'package:spotube/pages/search/search.dart'; import 'package:spotube/pages/settings/blacklist.dart'; import 'package:spotube/pages/settings/about.dart'; import 'package:spotube/pages/settings/logs.dart'; import 'package:spotube/utils/platform.dart'; import 'package:spotube/components/shared/spotube_page_route.dart'; -import 'package:spotube/pages/album/album.dart'; import 'package:spotube/pages/artist/artist.dart'; import 'package:spotube/pages/library/library.dart'; import 'package:spotube/pages/desktop_login/login_tutorial.dart'; import 'package:spotube/pages/desktop_login/desktop_login.dart'; import 'package:spotube/pages/lyrics/lyrics.dart'; -import 'package:spotube/pages/playlist/playlist.dart'; import 'package:spotube/pages/root/root_app.dart'; import 'package:spotube/pages/settings/settings.dart'; import 'package:spotube/pages/mobile_login/mobile_login.dart'; -import '../pages/library/playlist_generate/playlist_generate_result.dart'; - final rootNavigatorKey = Catcher2.navigatorKey; final shellRouteNavigatorKey = GlobalKey(); final router = GoRouter( @@ -104,7 +104,9 @@ final router = GoRouter( path: "/album/:id", pageBuilder: (context, state) { assert(state.extra is AlbumSimple); - return SpotubePage(child: AlbumPage(state.extra as AlbumSimple)); + return SpotubePage( + child: AlbumPage(album: state.extra as AlbumSimple), + ); }, ), GoRoute( @@ -119,7 +121,9 @@ final router = GoRouter( pageBuilder: (context, state) { assert(state.extra is PlaylistSimple); return SpotubePage( - child: PlaylistView(state.extra as PlaylistSimple), + child: state.pathParameters["id"] == "user-liked-tracks" + ? LikedPlaylistPage(playlist: state.extra as PlaylistSimple) + : PlaylistPage(playlist: state.extra as PlaylistSimple), ); }, ), diff --git a/lib/components/album/album_card.dart b/lib/components/album/album_card.dart index 945f8ecf..c7ae2f9a 100644 --- a/lib/components/album/album_card.dart +++ b/lib/components/album/album_card.dart @@ -4,9 +4,12 @@ import 'package:flutter_hooks/flutter_hooks.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:spotify/spotify.dart'; import 'package:spotube/components/shared/playbutton_card.dart'; +import 'package:spotube/extensions/context.dart'; +import 'package:spotube/extensions/infinite_query.dart'; import 'package:spotube/provider/proxy_playlist/proxy_playlist_provider.dart'; import 'package:spotube/provider/spotify_provider.dart'; import 'package:spotube/services/audio_player/audio_player.dart'; +import 'package:spotube/services/queries/album.dart'; import 'package:spotube/utils/service_utils.dart'; import 'package:spotube/utils/type_conversion_utils.dart'; @@ -15,7 +18,7 @@ extension FormattedAlbumType on AlbumType { } class AlbumCard extends HookConsumerWidget { - final Album album; + final AlbumSimple album; const AlbumCard( this.album, { Key? key, @@ -27,7 +30,9 @@ class AlbumCard extends HookConsumerWidget { final playing = useStream(audioPlayer.playingStream).data ?? audioPlayer.isPlaying; final playlistNotifier = ref.watch(ProxyPlaylistNotifier.notifier); + final queryClient = useQueryClient(); + bool isPlaylistPlaying = useMemoized( () => playlist.containsCollection(album.id!), [playlist, album.id], @@ -36,6 +41,34 @@ class AlbumCard extends HookConsumerWidget { final updating = useState(false); final spotify = ref.watch(spotifyProvider); + final scaffoldMessenger = ScaffoldMessenger.maybeOf(context); + + Future> fetchAllTrack() async { + if (album.tracks != null && album.tracks!.isNotEmpty) { + return album.tracks! + .map((track) => + TypeConversionUtils.simpleTrack_X_Track(track, album)) + .toList(); + } + final job = AlbumQueries.tracksOfJob(album.id!); + + final query = queryClient.createInfiniteQuery( + job.queryKey, + (page) => job.task(page, (spotify: spotify, album: album)), + initialPage: 0, + nextPage: job.nextPage, + ); + + return await query.fetchAllTracks( + getAllTracks: () async { + final res = await spotify.albums.tracks(album.id!).all(); + return res + .map((e) => TypeConversionUtils.simpleTrack_X_Track(e, album)) + .toList(); + }, + ); + } + return PlaybuttonCard( imageUrl: TypeConversionUtils.image_X_UrlString( album.images, @@ -54,20 +87,15 @@ class AlbumCard extends HookConsumerWidget { onPlaybuttonPressed: () async { updating.value = true; try { - if (isPlaylistPlaying && playing) { - return audioPlayer.pause(); - } else if (isPlaylistPlaying && !playing) { - return audioPlayer.resume(); + if (isPlaylistPlaying) { + return playing ? audioPlayer.pause() : audioPlayer.resume(); } - await playlistNotifier.load( - album.tracks - ?.map((e) => - TypeConversionUtils.simpleTrack_X_Track(e, album)) - .toList() ?? - [], - autoPlay: true, - ); + final fetchedTracks = await fetchAllTrack(); + + if (fetchedTracks.isEmpty) return; + + await playlistNotifier.load(fetchedTracks, autoPlay: true); playlistNotifier.addCollection(album.id!); } finally { updating.value = false; @@ -80,28 +108,16 @@ class AlbumCard extends HookConsumerWidget { updating.value = true; try { - final fetchedTracks = - await queryClient.fetchQuery, SpotifyApi>( - "album-tracks/${album.id}", - () { - return spotify.albums - .tracks(album.id!) - .all() - .then((value) => value.toList()); - }, - ).then( - (tracks) => tracks - ?.map( - (e) => TypeConversionUtils.simpleTrack_X_Track(e, album)) - .toList(), - ); + final fetchedTracks = await fetchAllTrack(); - if (fetchedTracks == null || fetchedTracks.isEmpty) return; + if (fetchedTracks.isEmpty) return; playlistNotifier.addTracks(fetchedTracks); playlistNotifier.addCollection(album.id!); if (context.mounted) { final snackbar = SnackBar( - content: Text("Added ${album.tracks?.length} tracks to queue"), + content: Text( + context.l10n.added_to_queue(fetchedTracks.length), + ), action: SnackBarAction( label: "Undo", onPressed: () { @@ -110,7 +126,8 @@ class AlbumCard extends HookConsumerWidget { }, ), ); - ScaffoldMessenger.maybeOf(context)?.showSnackBar(snackbar); + + scaffoldMessenger?.showSnackBar(snackbar); } } finally { updating.value = false; diff --git a/lib/components/library/user_local_tracks.dart b/lib/components/library/user_local_tracks.dart index 354d9fe6..cc8b10cf 100644 --- a/lib/components/library/user_local_tracks.dart +++ b/lib/components/library/user_local_tracks.dart @@ -18,7 +18,7 @@ import 'package:spotube/components/shared/expandable_search/expandable_search.da import 'package:spotube/components/shared/inter_scrollbar/inter_scrollbar.dart'; import 'package:spotube/components/shared/shimmers/shimmer_track_tile.dart'; import 'package:spotube/components/shared/sort_tracks_dropdown.dart'; -import 'package:spotube/components/shared/track_table/track_tile.dart'; +import 'package:spotube/components/shared/track_tile/track_tile.dart'; import 'package:spotube/extensions/context.dart'; import 'package:spotube/models/local_track.dart'; import 'package:spotube/provider/proxy_playlist/proxy_playlist_provider.dart'; @@ -199,7 +199,8 @@ class UserLocalTracks extends HookConsumerWidget { ), const Spacer(), ExpandableSearchButton( - isFiltering: isFiltering, + isFiltering: isFiltering.value, + onPressed: (value) => isFiltering.value = value, searchFocus: searchFocus, ), const SizedBox(width: 10), @@ -222,7 +223,8 @@ class UserLocalTracks extends HookConsumerWidget { ExpandableSearchField( searchController: searchController, searchFocus: searchFocus, - isFiltering: isFiltering, + isFiltering: isFiltering.value, + onChangeFiltering: (value) => isFiltering.value = value, ), trackSnapshot.when( data: (tracks) { @@ -284,7 +286,7 @@ class UserLocalTracks extends HookConsumerWidget { ); }, loading: () => - const Expanded(child: ShimmerTrackTile(noSliver: true)), + const Expanded(child: ShimmerTrackTileGroup(noSliver: true)), error: (error, stackTrace) => Text(error.toString() + stackTrace.toString()), ) diff --git a/lib/components/player/player_queue.dart b/lib/components/player/player_queue.dart index a6f69925..8142740c 100644 --- a/lib/components/player/player_queue.dart +++ b/lib/components/player/player_queue.dart @@ -11,7 +11,7 @@ import 'package:scroll_to_index/scroll_to_index.dart'; import 'package:spotube/collections/spotube_icons.dart'; import 'package:spotube/components/shared/fallbacks/not_found.dart'; import 'package:spotube/components/shared/inter_scrollbar/inter_scrollbar.dart'; -import 'package:spotube/components/shared/track_table/track_tile.dart'; +import 'package:spotube/components/shared/track_tile/track_tile.dart'; import 'package:spotube/extensions/constrains.dart'; import 'package:spotube/extensions/context.dart'; import 'package:spotube/hooks/controllers/use_auto_scroll_controller.dart'; diff --git a/lib/components/playlist/playlist_card.dart b/lib/components/playlist/playlist_card.dart index 0438e559..f429a0ab 100644 --- a/lib/components/playlist/playlist_card.dart +++ b/lib/components/playlist/playlist_card.dart @@ -4,6 +4,7 @@ import 'package:flutter_hooks/flutter_hooks.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:spotify/spotify.dart'; import 'package:spotube/components/shared/playbutton_card.dart'; +import 'package:spotube/extensions/infinite_query.dart'; import 'package:spotube/provider/proxy_playlist/proxy_playlist_provider.dart'; import 'package:spotube/provider/spotify_provider.dart'; import 'package:spotube/services/audio_player/audio_player.dart'; @@ -23,7 +24,7 @@ class PlaylistCard extends HookConsumerWidget { final playlistNotifier = ref.watch(ProxyPlaylistNotifier.notifier); final playing = useStream(audioPlayer.playingStream).data ?? audioPlayer.isPlaying; - final queryBowl = QueryClient.of(context); + final queryClient = QueryClient.of(context); final tracks = useState?>(null); bool isPlaylistPlaying = useMemoized( () => playlistQueue.containsCollection(playlist.id!), @@ -34,6 +35,31 @@ class PlaylistCard extends HookConsumerWidget { final spotify = ref.watch(spotifyProvider); final me = useQueries.user.me(ref); + Future> fetchAllTracks() async { + if (playlist.id == 'user-liked-tracks') { + return await queryClient.fetchQuery( + "user-liked-tracks", + () => useQueries.playlist.likedTracks(spotify), + ) ?? + []; + } + + final query = queryClient.createInfiniteQuery, dynamic, int>( + "playlist-tracks/${playlist.id}", + (page) => useQueries.playlist.tracksOf(page, spotify, playlist.id!), + initialPage: 0, + nextPage: useQueries.playlist.tracksOfQueryNextPage, + ); + + return await query.fetchAllTracks( + getAllTracks: () async { + final res = + await spotify.playlists.getTracksByPlaylistId(playlist.id!).all(); + return res.toList(); + }, + ); + } + return PlaybuttonCard( margin: const EdgeInsets.symmetric(horizontal: 10), title: playlist.name!, @@ -62,18 +88,7 @@ class PlaylistCard extends HookConsumerWidget { return audioPlayer.resume(); } - List fetchedTracks = playlist.id == 'user-liked-tracks' - ? await queryBowl.fetchQuery( - "user-liked-tracks", - () => useQueries.playlist.likedTracks(spotify, ref), - ) ?? - [] - : await queryBowl.fetchQuery( - "playlist-tracks/${playlist.id}", - () => useQueries.playlist - .tracksOf(playlist.id!, spotify, ref), - ) ?? - []; + List fetchedTracks = await fetchAllTracks(); if (fetchedTracks.isEmpty) return; @@ -90,11 +105,8 @@ class PlaylistCard extends HookConsumerWidget { updating.value = true; try { if (isPlaylistPlaying) return; - List fetchedTracks = await queryBowl.fetchQuery( - "playlist-tracks/${playlist.id}", - () => useQueries.playlist.tracksOf(playlist.id!, spotify, ref), - ) ?? - []; + + final fetchedTracks = await fetchAllTracks(); if (fetchedTracks.isEmpty) return; diff --git a/lib/components/shared/expandable_search/expandable_search.dart b/lib/components/shared/expandable_search/expandable_search.dart index 684e373e..75ac6841 100644 --- a/lib/components/shared/expandable_search/expandable_search.dart +++ b/lib/components/shared/expandable_search/expandable_search.dart @@ -4,13 +4,15 @@ import 'package:spotube/collections/spotube_icons.dart'; import 'package:spotube/extensions/context.dart'; class ExpandableSearchField extends StatelessWidget { - final ValueNotifier isFiltering; + final bool isFiltering; + final ValueChanged onChangeFiltering; final TextEditingController searchController; final FocusNode searchFocus; const ExpandableSearchField({ Key? key, required this.isFiltering, + required this.onChangeFiltering, required this.searchController, required this.searchFocus, }) : super(key: key); @@ -19,17 +21,17 @@ class ExpandableSearchField extends StatelessWidget { Widget build(BuildContext context) { return AnimatedOpacity( duration: const Duration(milliseconds: 200), - opacity: isFiltering.value ? 1 : 0, + opacity: isFiltering ? 1 : 0, child: AnimatedSize( duration: const Duration(milliseconds: 200), child: SizedBox( - height: isFiltering.value ? 50 : 0, + height: isFiltering ? 50 : 0, child: Padding( padding: const EdgeInsets.symmetric(horizontal: 8), child: CallbackShortcuts( bindings: { LogicalKeySet(LogicalKeyboardKey.escape): () { - isFiltering.value = false; + onChangeFiltering(false); searchController.clear(); searchFocus.unfocus(); } @@ -52,7 +54,7 @@ class ExpandableSearchField extends StatelessWidget { } class ExpandableSearchButton extends StatelessWidget { - final ValueNotifier isFiltering; + final bool isFiltering; final FocusNode searchFocus; final Widget icon; final ValueChanged? onPressed; @@ -73,18 +75,17 @@ class ExpandableSearchButton extends StatelessWidget { icon: icon, style: IconButton.styleFrom( backgroundColor: - isFiltering.value ? theme.colorScheme.secondaryContainer : null, - foregroundColor: isFiltering.value ? theme.colorScheme.secondary : null, + isFiltering ? theme.colorScheme.secondaryContainer : null, + foregroundColor: isFiltering ? theme.colorScheme.secondary : null, minimumSize: const Size(25, 25), ), onPressed: () { - isFiltering.value = !isFiltering.value; - if (isFiltering.value) { + if (isFiltering) { searchFocus.requestFocus(); } else { searchFocus.unfocus(); } - onPressed?.call(isFiltering.value); + onPressed?.call(!isFiltering); }, ); } diff --git a/lib/components/shared/shimmers/shimmer_artist_profile.dart b/lib/components/shared/shimmers/shimmer_artist_profile.dart index d0b0288f..75e50cd0 100644 --- a/lib/components/shared/shimmers/shimmer_artist_profile.dart +++ b/lib/components/shared/shimmers/shimmer_artist_profile.dart @@ -50,7 +50,7 @@ class ShimmerArtistProfile extends HookWidget { ), ), const SizedBox(width: 10), - const Flexible(child: ShimmerTrackTile(noSliver: true)), + const Flexible(child: ShimmerTrackTileGroup(noSliver: true)), ], ); } diff --git a/lib/components/shared/shimmers/shimmer_track_tile.dart b/lib/components/shared/shimmers/shimmer_track_tile.dart index 070b2f09..dcb634ed 100644 --- a/lib/components/shared/shimmers/shimmer_track_tile.dart +++ b/lib/components/shared/shimmers/shimmer_track_tile.dart @@ -70,8 +70,7 @@ class ShimmerTrackTilePainter extends CustomPainter { } class ShimmerTrackTile extends StatelessWidget { - final bool noSliver; - const ShimmerTrackTile({super.key, this.noSliver = false}); + const ShimmerTrackTile({super.key}); @override Widget build(BuildContext context) { @@ -82,39 +81,42 @@ class ShimmerTrackTile extends StatelessWidget { shimmerColor: isDark ? Colors.grey[800] : Colors.grey[300], ); + return Padding( + padding: const EdgeInsets.only(bottom: 8.0, left: 8, right: 8), + child: CustomPaint( + size: const Size(double.infinity, 60), + painter: ShimmerTrackTilePainter( + background: shimmerTheme.shimmerBackgroundColor ?? + theme.scaffoldBackgroundColor, + foreground: shimmerTheme.shimmerColor ?? theme.cardColor, + ), + ), + ); + } +} + +class ShimmerTrackTileGroup extends StatelessWidget { + final bool noSliver; + final int count; + const ShimmerTrackTileGroup({ + super.key, + this.noSliver = false, + this.count = 5, + }); + + @override + Widget build(BuildContext context) { if (noSliver) { return ListView.builder( itemCount: 5, - itemBuilder: (context, index) { - return Padding( - padding: const EdgeInsets.only(bottom: 8.0, left: 8, right: 8), - child: CustomPaint( - size: const Size(double.infinity, 60), - painter: ShimmerTrackTilePainter( - background: shimmerTheme.shimmerBackgroundColor ?? - theme.scaffoldBackgroundColor, - foreground: shimmerTheme.shimmerColor ?? theme.cardColor, - ), - ), - ); - }, + itemBuilder: (context, index) => const ShimmerTrackTile(), ); } return SliverList( delegate: SliverChildBuilderDelegate( - (BuildContext context, int index) => Padding( - padding: const EdgeInsets.only(bottom: 8.0, left: 8, right: 8), - child: CustomPaint( - size: const Size(double.infinity, 60), - painter: ShimmerTrackTilePainter( - background: shimmerTheme.shimmerBackgroundColor ?? - theme.scaffoldBackgroundColor, - foreground: shimmerTheme.shimmerColor ?? theme.cardColor, - ), - ), - ), - childCount: 5, + (BuildContext context, int index) => const ShimmerTrackTile(), + childCount: count, ), ); } diff --git a/lib/components/shared/track_table/track_collection_view/track_collection_heading.dart b/lib/components/shared/track_table/track_collection_view/track_collection_heading.dart deleted file mode 100644 index 6436f7cd..00000000 --- a/lib/components/shared/track_table/track_collection_view/track_collection_heading.dart +++ /dev/null @@ -1,229 +0,0 @@ -import 'dart:ui'; - -import 'package:auto_size_text/auto_size_text.dart'; -import 'package:fl_query/fl_query.dart'; -import 'package:flutter/material.dart'; -import 'package:hooks_riverpod/hooks_riverpod.dart'; -import 'package:palette_generator/palette_generator.dart'; -import 'package:spotify/spotify.dart'; -import 'package:spotube/collections/assets.gen.dart'; -import 'package:spotube/collections/spotube_icons.dart'; -import 'package:spotube/components/album/album_card.dart'; -import 'package:spotube/components/shared/image/universal_image.dart'; -import 'package:spotube/components/shared/playbutton_card.dart'; -import 'package:spotube/extensions/constrains.dart'; -import 'package:spotube/extensions/context.dart'; - -enum PlayButtonState { - playing, - notPlaying, - loading, -} - -class TrackCollectionHeading extends HookConsumerWidget { - final String title; - final String? description; - final String titleImage; - final List buttons; - final AlbumSimple? album; - final Query, T> tracksSnapshot; - final PlayButtonState playingState; - final void Function([Track? currentTrack]) onPlay; - final void Function([Track? currentTrack]) onShuffledPlay; - final PaletteColor? color; - - const TrackCollectionHeading({ - Key? key, - required this.title, - required this.titleImage, - required this.buttons, - required this.tracksSnapshot, - required this.playingState, - required this.onPlay, - required this.onShuffledPlay, - required this.color, - this.description, - this.album, - }) : super(key: key); - - @override - Widget build(BuildContext context, ref) { - final theme = Theme.of(context); - - final cleanDescription = useDescription(description); - - return LayoutBuilder( - builder: (context, constrains) { - return DecoratedBox( - decoration: BoxDecoration( - image: DecorationImage( - image: UniversalImage.imageProvider(titleImage), - fit: BoxFit.cover, - ), - ), - child: BackdropFilter( - filter: ImageFilter.blur(sigmaX: 10, sigmaY: 10), - child: DecoratedBox( - decoration: BoxDecoration( - gradient: LinearGradient( - colors: [ - Colors.black45, - theme.colorScheme.surface, - ], - begin: const FractionalOffset(0, 0), - end: const FractionalOffset(0, 1), - tileMode: TileMode.clamp, - ), - ), - child: Material( - type: MaterialType.transparency, - child: Padding( - padding: const EdgeInsets.symmetric( - horizontal: 20, - ), - child: SafeArea( - child: Flex( - direction: constrains.mdAndDown - ? Axis.vertical - : Axis.horizontal, - mainAxisAlignment: MainAxisAlignment.center, - children: [ - ConstrainedBox( - constraints: const BoxConstraints(maxHeight: 200), - child: ClipRRect( - borderRadius: BorderRadius.circular(10), - child: UniversalImage( - path: titleImage, - placeholder: Assets.albumPlaceholder.path, - ), - ), - ), - const SizedBox(width: 10, height: 10), - Column( - crossAxisAlignment: CrossAxisAlignment.start, - mainAxisAlignment: MainAxisAlignment.center, - mainAxisSize: MainAxisSize.max, - children: [ - ConstrainedBox( - constraints: BoxConstraints( - maxWidth: constrains.mdAndDown ? 400 : 300, - ), - child: AutoSizeText( - title, - style: theme.textTheme.titleLarge!.copyWith( - color: Colors.white, - fontWeight: FontWeight.w600, - ), - maxLines: 2, - minFontSize: 16, - overflow: TextOverflow.ellipsis, - ), - ), - if (album != null) - Text( - "${album?.albumType?.formatted} • ${context.l10n.released} • ${DateTime.tryParse( - album?.releaseDate ?? "", - )?.year}", - style: theme.textTheme.titleMedium!.copyWith( - color: Colors.white, - fontWeight: FontWeight.normal, - ), - ), - if (cleanDescription != null) - ConstrainedBox( - constraints: BoxConstraints( - maxWidth: constrains.mdAndDown ? 400 : 300, - ), - child: AutoSizeText( - cleanDescription, - style: const TextStyle(color: Colors.white), - maxLines: 2, - overflow: TextOverflow.fade, - minFontSize: 14, - ), - ), - const SizedBox(height: 10), - IconTheme( - data: theme.iconTheme.copyWith( - color: Colors.white, - ), - child: Row( - mainAxisSize: MainAxisSize.min, - children: buttons, - ), - ), - const SizedBox(height: 10), - ConstrainedBox( - constraints: BoxConstraints( - maxWidth: constrains.mdAndDown ? 400 : 300, - ), - child: Row( - mainAxisSize: constrains.smAndUp - ? MainAxisSize.min - : MainAxisSize.min, - children: [ - Expanded( - child: FilledButton.icon( - style: ElevatedButton.styleFrom( - backgroundColor: Colors.white, - foregroundColor: Colors.black, - ), - label: Text(context.l10n.shuffle), - icon: const Icon(SpotubeIcons.shuffle), - onPressed: tracksSnapshot.data == null || - playingState == - PlayButtonState.playing - ? null - : onShuffledPlay, - ), - ), - const SizedBox(width: 10), - Expanded( - child: FilledButton.icon( - style: ElevatedButton.styleFrom( - backgroundColor: color?.color, - foregroundColor: color?.bodyTextColor, - ), - onPressed: tracksSnapshot.data != null || - playingState == - PlayButtonState.loading - ? onPlay - : null, - icon: switch (playingState) { - PlayButtonState.playing => - const Icon(SpotubeIcons.pause), - PlayButtonState.notPlaying => - const Icon(SpotubeIcons.play), - PlayButtonState.loading => - const SizedBox( - height: 20, - width: 20, - child: CircularProgressIndicator( - strokeWidth: .7, - ), - ), - }, - label: Text( - playingState == PlayButtonState.playing - ? context.l10n.stop - : context.l10n.play, - ), - ), - ), - ], - ), - ), - ], - ) - ], - ), - ), - ), - ), - ), - ), - ); - }, - ); - } -} diff --git a/lib/components/shared/track_table/track_collection_view/track_collection_view.dart b/lib/components/shared/track_table/track_collection_view/track_collection_view.dart deleted file mode 100644 index f211a521..00000000 --- a/lib/components/shared/track_table/track_collection_view/track_collection_view.dart +++ /dev/null @@ -1,274 +0,0 @@ -import 'dart:async'; - -import 'package:fl_query/fl_query.dart'; -import 'package:flutter_hooks/flutter_hooks.dart'; -import 'package:go_router/go_router.dart'; -import 'package:hooks_riverpod/hooks_riverpod.dart'; - -import 'package:spotube/collections/spotube_icons.dart'; -import 'package:spotube/components/playlist/playlist_create_dialog.dart'; -import 'package:spotube/components/shared/inter_scrollbar/inter_scrollbar.dart'; -import 'package:spotube/components/shared/shimmers/shimmer_track_tile.dart'; -import 'package:spotube/components/shared/page_window_title_bar.dart'; -import 'package:spotube/components/shared/track_table/track_collection_view/track_collection_heading.dart'; -import 'package:spotube/components/shared/track_table/tracks_table_view.dart'; -import 'package:spotube/extensions/context.dart'; -import 'package:spotube/hooks/utils/use_custom_status_bar_color.dart'; -import 'package:spotube/hooks/utils/use_palette_color.dart'; -import 'package:spotube/models/logger.dart'; -import 'package:flutter/material.dart'; -import 'package:spotify/spotify.dart'; -import 'package:spotube/provider/authentication_provider.dart'; -import 'package:spotube/utils/platform.dart'; -import 'package:spotube/utils/type_conversion_utils.dart'; - -class TrackCollectionView extends HookConsumerWidget { - final logger = getLogger(TrackCollectionView); - final String id; - final String title; - final String? description; - final Query, T> tracksSnapshot; - final String titleImage; - final PlayButtonState playingState; - final Future Function([Track? currentTrack]) onPlay; - final void Function([Track? currentTrack]) onShuffledPlay; - final void Function() onAddToQueue; - final void Function() onShare; - final Widget? heartBtn; - final AlbumSimple? album; - - final bool showShare; - final bool isOwned; - final bool bottomSpace; - - final String routePath; - TrackCollectionView({ - required this.title, - required this.id, - required this.tracksSnapshot, - required this.titleImage, - required this.playingState, - required this.onPlay, - required this.onShuffledPlay, - required this.onAddToQueue, - required this.onShare, - required this.routePath, - this.heartBtn, - this.album, - this.description, - this.showShare = true, - this.isOwned = false, - this.bottomSpace = false, - Key? key, - }) : super(key: key); - - @override - Widget build(BuildContext context, ref) { - final theme = Theme.of(context); - final auth = ref.watch(AuthenticationNotifier.provider); - - final color = usePaletteGenerator(titleImage).dominantColor; - - final List buttons = [ - if (showShare) - IconButton( - icon: const Icon(SpotubeIcons.share), - onPressed: onShare, - ), - if (isOwned) - IconButton( - icon: const Icon(SpotubeIcons.edit), - onPressed: () { - showDialog( - context: context, - builder: (context) { - return PlaylistCreateDialog(playlistId: id); - }, - ); - }, - ), - if (heartBtn != null && auth != null) heartBtn!, - IconButton( - onPressed: playingState == PlayButtonState.playing - ? null - : tracksSnapshot.data != null - ? onAddToQueue - : null, - icon: const Icon( - SpotubeIcons.queueAdd, - ), - ), - ]; - - final controller = useScrollController(); - - final collapsed = useState(false); - - useCustomStatusBarColor( - Colors.transparent, - GoRouterState.of(context).matchedLocation == routePath, - ); - - useEffect(() { - listener() { - if (controller.position.pixels >= 390 && !collapsed.value) { - collapsed.value = true; - } else if (controller.position.pixels < 390 && collapsed.value) { - collapsed.value = false; - } - } - - controller.addListener(listener); - - return () => controller.removeListener(listener); - }, [collapsed.value]); - - return Scaffold( - appBar: kIsDesktop - ? const PageWindowTitleBar( - backgroundColor: Colors.transparent, - foregroundColor: Colors.white, - leadingWidth: 400, - leading: Align( - alignment: Alignment.centerLeft, - child: BackButton(color: Colors.white), - ), - ) - : null, - extendBodyBehindAppBar: kIsDesktop, - body: RefreshIndicator( - onRefresh: () async { - await tracksSnapshot.refresh(); - }, - child: InterScrollbar( - controller: controller, - child: CustomScrollView( - controller: controller, - physics: const AlwaysScrollableScrollPhysics(), - slivers: [ - SliverAppBar( - actions: [ - AnimatedScale( - duration: const Duration(milliseconds: 200), - scale: collapsed.value ? 1 : 0, - child: Row( - mainAxisSize: MainAxisSize.min, - children: buttons, - ), - ), - AnimatedScale( - duration: const Duration(milliseconds: 200), - scale: collapsed.value ? 1 : 0, - child: IconButton( - tooltip: context.l10n.shuffle, - icon: const Icon(SpotubeIcons.shuffle), - onPressed: playingState == PlayButtonState.playing - ? null - : onShuffledPlay, - ), - ), - AnimatedScale( - duration: const Duration(milliseconds: 200), - scale: collapsed.value ? 1 : 0, - child: ElevatedButton( - style: ElevatedButton.styleFrom( - shape: const CircleBorder(), - backgroundColor: theme.colorScheme.inversePrimary, - ), - onPressed: tracksSnapshot.data != null ? onPlay : null, - child: switch (playingState) { - PlayButtonState.playing => - const Icon(SpotubeIcons.pause), - PlayButtonState.notPlaying => - const Icon(SpotubeIcons.play), - PlayButtonState.loading => const SizedBox( - height: 20, - width: 20, - child: CircularProgressIndicator( - strokeWidth: .7, - ), - ), - }, - ), - ), - ], - floating: false, - pinned: true, - expandedHeight: 400, - automaticallyImplyLeading: kIsMobile, - leading: - kIsMobile ? const BackButton(color: Colors.white) : null, - iconTheme: IconThemeData(color: color?.titleTextColor), - primary: true, - backgroundColor: color?.color.withOpacity(.8), - title: collapsed.value - ? Text( - title, - style: theme.textTheme.titleMedium!.copyWith( - color: color?.titleTextColor, - fontWeight: FontWeight.w600, - ), - ) - : null, - centerTitle: true, - flexibleSpace: FlexibleSpaceBar( - background: TrackCollectionHeading( - color: color, - title: title, - description: description, - titleImage: titleImage, - playingState: playingState, - onPlay: onPlay, - onShuffledPlay: onShuffledPlay, - tracksSnapshot: tracksSnapshot, - buttons: buttons, - album: album, - ), - ), - ), - HookBuilder( - builder: (context) { - if (tracksSnapshot.isLoading || !tracksSnapshot.hasData) { - return const ShimmerTrackTile(); - } else if (tracksSnapshot.hasError) { - return SliverToBoxAdapter( - child: Text( - context.l10n.error(tracksSnapshot.error ?? ""), - ), - ); - } - - return TracksTableView( - (tracksSnapshot.data ?? []).map( - (track) { - if (track is Track) { - return track; - } else { - return TypeConversionUtils.simpleTrack_X_Track( - track, - album!, - ); - } - }, - ).toList(), - onTrackPlayButtonPressed: onPlay, - playlistId: id, - userPlaylist: isOwned, - onFiltering: () { - // scroll the flexible space - // to allow more space for search results - controller.animateTo( - 330, - duration: const Duration(milliseconds: 200), - curve: Curves.easeInOut, - ); - }, - ); - }, - ) - ], - ), - ), - )); - } -} diff --git a/lib/components/shared/track_table/tracks_table_view.dart b/lib/components/shared/track_table/tracks_table_view.dart deleted file mode 100644 index 003662f5..00000000 --- a/lib/components/shared/track_table/tracks_table_view.dart +++ /dev/null @@ -1,368 +0,0 @@ -import 'dart:async'; - -import 'package:collection/collection.dart'; -import 'package:flutter/material.dart'; -import 'package:flutter_hooks/flutter_hooks.dart'; -import 'package:fuzzywuzzy/fuzzywuzzy.dart'; -import 'package:hooks_riverpod/hooks_riverpod.dart'; - -import 'package:spotify/spotify.dart'; -import 'package:spotube/collections/spotube_icons.dart'; -import 'package:spotube/components/shared/adaptive/adaptive_pop_sheet_list.dart'; -import 'package:spotube/components/shared/dialogs/confirm_download_dialog.dart'; -import 'package:spotube/components/shared/dialogs/playlist_add_track_dialog.dart'; -import 'package:spotube/components/shared/expandable_search/expandable_search.dart'; -import 'package:spotube/components/shared/fallbacks/not_found.dart'; -import 'package:spotube/components/shared/sort_tracks_dropdown.dart'; -import 'package:spotube/components/shared/track_table/track_tile.dart'; -import 'package:spotube/components/library/user_local_tracks.dart'; -import 'package:spotube/extensions/constrains.dart'; -import 'package:spotube/extensions/context.dart'; - -import 'package:spotube/provider/download_manager_provider.dart'; -import 'package:spotube/provider/blacklist_provider.dart'; -import 'package:spotube/provider/proxy_playlist/proxy_playlist_provider.dart'; -import 'package:spotube/provider/user_preferences/user_preferences_provider.dart'; -import 'package:spotube/provider/user_preferences/user_preferences_state.dart'; -import 'package:spotube/utils/service_utils.dart'; - -final trackCollectionSortState = - StateProvider.family((ref, _) => SortBy.none); - -class TracksTableView extends HookConsumerWidget { - final Future Function(Track currentTrack)? onTrackPlayButtonPressed; - final List tracks; - final bool userPlaylist; - final String? playlistId; - final bool isSliver; - - final Widget? heading; - - final VoidCallback? onFiltering; - - const TracksTableView( - this.tracks, { - Key? key, - this.onTrackPlayButtonPressed, - this.onFiltering, - this.userPlaylist = false, - this.playlistId, - this.heading, - this.isSliver = true, - }) : super(key: key); - - @override - Widget build(context, ref) { - final mediaQuery = MediaQuery.of(context); - - ref.watch(ProxyPlaylistNotifier.provider); - final playback = ref.watch(ProxyPlaylistNotifier.notifier); - ref.watch(downloadManagerProvider); - final downloader = ref.watch(downloadManagerProvider.notifier); - final apiType = - ref.watch(userPreferencesProvider.select((s) => s.audioSource)); - const tableHeadStyle = TextStyle(fontWeight: FontWeight.bold, fontSize: 16); - - final selected = useState>([]); - final showCheck = useState(false); - final sortBy = ref.watch(trackCollectionSortState(playlistId ?? '')); - - final isFiltering = useState(false); - - final searchController = useTextEditingController(); - final searchFocus = useFocusNode(); - - final controller = useScrollController(); - - // this will trigger update on each change in searchController - useValueListenable(searchController); - - final filteredTracks = useMemoized(() { - if (searchController.text.isEmpty) { - return tracks; - } - return tracks - .map((e) => (weightedRatio(e.name!, searchController.text), e)) - .sorted((a, b) => b.$1.compareTo(a.$1)) - .where((e) => e.$1 > 50) - .map((e) => e.$2) - .toList(); - }, [tracks, searchController.text]); - - final sortedTracks = useMemoized( - () { - return ServiceUtils.sortTracks(filteredTracks, sortBy); - }, - [filteredTracks, sortBy], - ); - - final selectedTracks = useMemoized( - () => sortedTracks.where( - (track) => selected.value.contains(track.id), - ), - [sortedTracks], - ); - - final children = tracks.isEmpty - ? [const NotFound(vertical: true)] - : [ - if (heading != null) heading!, - LayoutBuilder(builder: (context, constrains) { - return Row( - children: [ - AnimatedSwitcher( - duration: const Duration(milliseconds: 200), - transitionBuilder: (child, animation) { - return FadeTransition( - opacity: animation, - child: ScaleTransition( - scale: animation, - child: child, - ), - ); - }, - child: showCheck.value - ? Checkbox( - value: selected.value.length == sortedTracks.length, - onChanged: (checked) { - if (!showCheck.value) showCheck.value = true; - if (checked == true) { - selected.value = - sortedTracks.map((s) => s.id!).toList(); - } else { - selected.value = []; - showCheck.value = false; - } - }, - ) - : constrains.mdAndUp - ? const SizedBox(width: 32) - : const SizedBox(width: 16), - ), - Expanded( - flex: 7, - child: Row( - children: [ - Text( - context.l10n.title, - style: tableHeadStyle, - overflow: TextOverflow.ellipsis, - ), - ], - ), - ), - // used alignment of this table-head - if (constrains.mdAndUp) - Expanded( - flex: 3, - child: Row( - children: [ - Text( - context.l10n.album, - overflow: TextOverflow.ellipsis, - style: tableHeadStyle, - ), - ], - ), - ), - SortTracksDropdown( - value: sortBy, - onChanged: (value) { - ref - .read(trackCollectionSortState(playlistId ?? '') - .notifier) - .state = value; - }, - ), - ExpandableSearchButton( - isFiltering: isFiltering, - searchFocus: searchFocus, - onPressed: (value) { - if (isFiltering.value) { - onFiltering?.call(); - } - }, - ), - AdaptivePopSheetList( - tooltip: context.l10n.more_actions, - headings: [ - Text( - context.l10n.more_actions, - style: tableHeadStyle, - ), - ], - onSelected: (action) async { - switch (action) { - case "download": - { - final confirmed = apiType == AudioSource.piped || - await showDialog( - context: context, - builder: (context) { - return const ConfirmDownloadDialog(); - }, - ); - if (confirmed != true) return; - await downloader - .batchAddToQueue(selectedTracks.toList()); - if (context.mounted) { - selected.value = []; - showCheck.value = false; - } - break; - } - case "add-to-playlist": - { - if (context.mounted) { - await showDialog( - context: context, - builder: (context) { - return PlaylistAddTrackDialog( - tracks: selectedTracks.toList(), - ); - }, - ); - } - break; - } - case "play-next": - { - playback.addTracksAtFirst(selectedTracks); - if (playlistId != null) { - playback.addCollection(playlistId!); - } - selected.value = []; - showCheck.value = false; - break; - } - case "add-to-queue": - { - playback.addTracks(selectedTracks); - if (playlistId != null) { - playback.addCollection(playlistId!); - } - selected.value = []; - showCheck.value = false; - break; - } - default: - } - }, - icon: const Icon(SpotubeIcons.moreVertical), - children: [ - PopSheetEntry( - value: "download", - leading: const Icon(SpotubeIcons.download), - enabled: selectedTracks.isNotEmpty, - title: Text( - context.l10n.download_count(selectedTracks.length), - ), - ), - if (!userPlaylist) - PopSheetEntry( - value: "add-to-playlist", - leading: const Icon(SpotubeIcons.playlistAdd), - enabled: selectedTracks.isNotEmpty, - title: Text( - context.l10n - .add_count_to_playlist(selectedTracks.length), - ), - ), - PopSheetEntry( - enabled: selectedTracks.isNotEmpty, - value: "add-to-queue", - leading: const Icon(SpotubeIcons.queueAdd), - title: Text( - context.l10n - .add_count_to_queue(selectedTracks.length), - ), - ), - PopSheetEntry( - enabled: selectedTracks.isNotEmpty, - value: "play-next", - leading: const Icon(SpotubeIcons.lightning), - title: Text( - context.l10n.play_count_next(selectedTracks.length), - ), - ), - ], - ), - const SizedBox(width: 10), - ], - ); - }), - ExpandableSearchField( - isFiltering: isFiltering, - searchController: searchController, - searchFocus: searchFocus, - ), - ...sortedTracks.mapIndexed((i, track) { - return TrackTile( - index: i, - track: track, - selected: selected.value.contains(track.id), - userPlaylist: userPlaylist, - playlistId: playlistId, - onTap: () async { - if (showCheck.value) { - final alreadyChecked = selected.value.contains(track.id); - if (alreadyChecked) { - selected.value = - selected.value.where((id) => id != track.id).toList(); - } else { - selected.value = [...selected.value, track.id!]; - } - } else { - final isBlackListed = ref.read( - BlackListNotifier.provider.select( - (blacklist) => blacklist.contains( - BlacklistedElement.track(track.id!, track.name!), - ), - ), - ); - if (isBlackListed) return; - await onTrackPlayButtonPressed?.call(track); - } - }, - onLongPress: () { - if (showCheck.value) return; - showCheck.value = true; - selected.value = [...selected.value, track.id!]; - }, - onChanged: !showCheck.value - ? null - : (value) { - if (value == null) return; - if (value) { - selected.value = [...selected.value, track.id!]; - } else { - selected.value = selected.value - .where((id) => id != track.id) - .toList(); - } - }, - ); - }), - // extra space for mobile devices where keyboard takes half of the screen - if (isFiltering.value) - SizedBox( - height: mediaQuery.size.height * .75, //75% of the screen - ), - ]; - - if (isSliver) { - return SliverSafeArea( - top: false, - sliver: SliverList( - delegate: SliverChildListDelegate(children), - ), - ); - } - return SafeArea( - child: ListView( - controller: controller, - children: children, - ), - ); - } -} diff --git a/lib/components/shared/track_table/track_options.dart b/lib/components/shared/track_tile/track_options.dart similarity index 100% rename from lib/components/shared/track_table/track_options.dart rename to lib/components/shared/track_tile/track_options.dart diff --git a/lib/components/shared/track_table/track_tile.dart b/lib/components/shared/track_tile/track_tile.dart similarity index 99% rename from lib/components/shared/track_table/track_tile.dart rename to lib/components/shared/track_tile/track_tile.dart index 4980f96b..6d4e236a 100644 --- a/lib/components/shared/track_table/track_tile.dart +++ b/lib/components/shared/track_tile/track_tile.dart @@ -9,7 +9,7 @@ import 'package:spotube/collections/spotube_icons.dart'; import 'package:spotube/components/shared/hover_builder.dart'; import 'package:spotube/components/shared/image/universal_image.dart'; import 'package:spotube/components/shared/links/link_text.dart'; -import 'package:spotube/components/shared/track_table/track_options.dart'; +import 'package:spotube/components/shared/track_tile/track_options.dart'; import 'package:spotube/extensions/constrains.dart'; import 'package:spotube/extensions/duration.dart'; import 'package:spotube/models/local_track.dart'; diff --git a/lib/components/shared/tracks_view/sections/body/track_view_body.dart b/lib/components/shared/tracks_view/sections/body/track_view_body.dart new file mode 100644 index 00000000..486e4405 --- /dev/null +++ b/lib/components/shared/tracks_view/sections/body/track_view_body.dart @@ -0,0 +1,124 @@ +import 'package:collection/collection.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_hooks/flutter_hooks.dart'; +import 'package:fuzzywuzzy/fuzzywuzzy.dart'; +import 'package:gap/gap.dart'; +import 'package:hooks_riverpod/hooks_riverpod.dart'; +import 'package:spotify/spotify.dart'; +import 'package:spotube/components/shared/expandable_search/expandable_search.dart'; +import 'package:spotube/components/shared/shimmers/shimmer_track_tile.dart'; +import 'package:spotube/components/shared/track_tile/track_tile.dart'; +import 'package:spotube/components/shared/tracks_view/sections/body/track_view_body_headers.dart'; +import 'package:spotube/components/shared/tracks_view/sections/body/use_is_user_playlist.dart'; +import 'package:spotube/components/shared/tracks_view/track_view_props.dart'; +import 'package:spotube/components/shared/tracks_view/track_view_provider.dart'; +import 'package:spotube/provider/proxy_playlist/proxy_playlist_provider.dart'; +import 'package:spotube/utils/service_utils.dart'; +import 'package:very_good_infinite_list/very_good_infinite_list.dart'; + +class TrackViewBodySection extends HookConsumerWidget { + const TrackViewBodySection({Key? key}) : super(key: key); + + @override + Widget build(BuildContext context, ref) { + final playlist = ref.watch(ProxyPlaylistNotifier.provider); + final playlistNotifier = ref.watch(ProxyPlaylistNotifier.notifier); + final props = InheritedTrackView.of(context); + + final trackViewState = ref.watch(trackViewProvider(props.tracks)); + + final searchController = useTextEditingController(); + final searchFocus = useFocusNode(); + + useValueListenable(searchController); + final searchQuery = searchController.text; + + final isFiltering = useState(false); + + final tracks = useMemoized(() { + List filteredTracks; + if (searchQuery.isEmpty) { + filteredTracks = props.tracks; + } else { + filteredTracks = props.tracks + .map((e) => (weightedRatio(e.name!, searchQuery), e)) + .sorted((a, b) => b.$1.compareTo(a.$1)) + .where((e) => e.$1 > 50) + .map((e) => e.$2) + .toList(); + } + return ServiceUtils.sortTracks(filteredTracks, trackViewState.sortBy); + }, [trackViewState.sortBy, searchQuery, props.tracks]); + + final isUserPlaylist = useIsUserPlaylist(ref, props.collectionId); + + final isActive = playlist.collections.contains(props.collectionId); + + return SliverMainAxisGroup( + slivers: [ + SliverToBoxAdapter( + child: TrackViewBodyHeaders( + isFiltering: isFiltering, + searchFocus: searchFocus, + ), + ), + const SliverGap(8), + SliverToBoxAdapter( + child: ExpandableSearchField( + isFiltering: isFiltering.value, + onChangeFiltering: (value) { + isFiltering.value = value; + }, + searchController: searchController, + searchFocus: searchFocus, + ), + ), + SliverSafeArea( + top: false, + sliver: SliverInfiniteList( + itemCount: tracks.length, + onFetchData: props.pagination.onFetchMore, + isLoading: props.pagination.isLoading, + hasReachedMax: !props.pagination.hasNextPage, + loadingBuilder: (context) => const ShimmerTrackTile(), + itemBuilder: (context, index) { + final track = tracks[index]; + return TrackTile( + track: track, + index: index, + selected: trackViewState.selectedTrackIds.contains(track.id!), + playlistId: props.collectionId, + userPlaylist: isUserPlaylist, + onChanged: !trackViewState.isSelecting + ? null + : (value) { + trackViewState.toggleTrackSelection(track.id!); + }, + onLongPress: () { + trackViewState.selectTrack(track.id!); + }, + onTap: () async { + if (trackViewState.isSelecting) { + trackViewState.toggleTrackSelection(track.id!); + return; + } + + if (isActive || playlist.tracks.contains(track)) { + await playlistNotifier.jumpToTrack(track); + } else { + await playlistNotifier.load( + props.tracks, + initialIndex: index, + autoPlay: true, + ); + playlistNotifier.addCollection(props.collectionId); + } + }, + ); + }, + ), + ), + ], + ); + } +} diff --git a/lib/components/shared/tracks_view/sections/body/track_view_body_headers.dart b/lib/components/shared/tracks_view/sections/body/track_view_body_headers.dart new file mode 100644 index 00000000..57d8b296 --- /dev/null +++ b/lib/components/shared/tracks_view/sections/body/track_view_body_headers.dart @@ -0,0 +1,106 @@ +import 'package:flutter/material.dart'; +import 'package:hooks_riverpod/hooks_riverpod.dart'; +import 'package:spotube/components/shared/expandable_search/expandable_search.dart'; +import 'package:spotube/components/shared/sort_tracks_dropdown.dart'; +import 'package:spotube/components/shared/tracks_view/sections/body/track_view_options.dart'; +import 'package:spotube/components/shared/tracks_view/track_view_props.dart'; +import 'package:spotube/components/shared/tracks_view/track_view_provider.dart'; +import 'package:spotube/extensions/constrains.dart'; +import 'package:spotube/extensions/context.dart'; + +class TrackViewBodyHeaders extends HookConsumerWidget { + final ValueNotifier isFiltering; + final FocusNode searchFocus; + + const TrackViewBodyHeaders({ + Key? key, + required this.isFiltering, + required this.searchFocus, + }) : super(key: key); + + @override + Widget build(BuildContext context, ref) { + final ThemeData(:textTheme) = Theme.of(context); + final props = InheritedTrackView.of(context); + final trackViewState = ref.watch(trackViewProvider(props.tracks)); + return LayoutBuilder( + builder: (context, constrains) { + return Row( + children: [ + AnimatedSwitcher( + duration: const Duration(milliseconds: 200), + transitionBuilder: (child, animation) { + return FadeTransition( + opacity: animation, + child: ScaleTransition( + scale: animation, + child: child, + ), + ); + }, + child: trackViewState.isSelecting + ? Checkbox( + value: trackViewState.hasSelectedAll, + onChanged: (checked) { + if (checked == true) { + trackViewState.selectAll(); + } else { + trackViewState.deselectAll(); + } + }, + ) + : constrains.mdAndUp + ? const SizedBox(width: 32) + : const SizedBox(width: 16), + ), + Expanded( + flex: 7, + child: Row( + children: [ + Text( + context.l10n.title, + style: textTheme.bodyLarge, + overflow: TextOverflow.ellipsis, + ), + ], + ), + ), + // used alignment of this table-head + if (constrains.mdAndUp) + Expanded( + flex: 3, + child: Row( + children: [ + Text( + context.l10n.album, + overflow: TextOverflow.ellipsis, + style: textTheme.bodyLarge, + ), + ], + ), + ), + SortTracksDropdown( + value: trackViewState.sortBy, + onChanged: (value) { + trackViewState.sort(value); + }, + ), + ExpandableSearchButton( + isFiltering: isFiltering.value, + searchFocus: searchFocus, + onPressed: (value) { + isFiltering.value = value; + if (value) { + searchFocus.requestFocus(); + } else { + searchFocus.unfocus(); + } + }, + ), + const TrackViewBodyOptions(), + ], + ); + }, + ); + } +} diff --git a/lib/components/shared/tracks_view/sections/body/track_view_options.dart b/lib/components/shared/tracks_view/sections/body/track_view_options.dart new file mode 100644 index 00000000..4fcd0a59 --- /dev/null +++ b/lib/components/shared/tracks_view/sections/body/track_view_options.dart @@ -0,0 +1,131 @@ +import 'package:flutter/material.dart'; +import 'package:hooks_riverpod/hooks_riverpod.dart'; +import 'package:spotube/collections/spotube_icons.dart'; +import 'package:spotube/components/shared/adaptive/adaptive_pop_sheet_list.dart'; +import 'package:spotube/components/shared/dialogs/confirm_download_dialog.dart'; +import 'package:spotube/components/shared/dialogs/playlist_add_track_dialog.dart'; +import 'package:spotube/components/shared/tracks_view/track_view_props.dart'; +import 'package:spotube/components/shared/tracks_view/track_view_provider.dart'; +import 'package:spotube/extensions/context.dart'; +import 'package:spotube/provider/download_manager_provider.dart'; +import 'package:spotube/provider/proxy_playlist/proxy_playlist_provider.dart'; +import 'package:spotube/provider/user_preferences/user_preferences_provider.dart'; +import 'package:spotube/provider/user_preferences/user_preferences_state.dart'; +import 'package:spotube/services/queries/queries.dart'; + +class TrackViewBodyOptions extends HookConsumerWidget { + const TrackViewBodyOptions({Key? key}) : super(key: key); + + @override + Widget build(BuildContext context, ref) { + final props = InheritedTrackView.of(context); + final ThemeData(:textTheme) = Theme.of(context); + + ref.watch(downloadManagerProvider); + final downloader = ref.watch(downloadManagerProvider.notifier); + final playlistNotifier = ref.watch(ProxyPlaylistNotifier.notifier); + final audioSource = + ref.watch(userPreferencesProvider.select((s) => s.audioSource)); + + final trackViewState = ref.watch(trackViewProvider(props.tracks)); + final selectedTracks = trackViewState.selectedTracks; + + final userPlaylists = useQueries.playlist.ofMineAll(ref); + + final isUserPlaylist = + userPlaylists.data?.any((e) => e.id == props.collectionId) ?? false; + + return AdaptivePopSheetList( + tooltip: context.l10n.more_actions, + headings: [ + Text( + context.l10n.more_actions, + style: textTheme.bodyLarge, + ), + ], + onSelected: (action) async { + switch (action) { + case "download": + { + final confirmed = audioSource == AudioSource.piped || + await showDialog( + context: context, + builder: (context) { + return const ConfirmDownloadDialog(); + }, + ); + if (confirmed != true) return; + await downloader.batchAddToQueue(selectedTracks); + trackViewState.deselectAll(); + break; + } + case "add-to-playlist": + { + if (context.mounted) { + await showDialog( + context: context, + builder: (context) { + return PlaylistAddTrackDialog( + tracks: selectedTracks.toList(), + ); + }, + ); + } + break; + } + case "play-next": + { + playlistNotifier.addTracksAtFirst(selectedTracks); + playlistNotifier.addCollection(props.collectionId); + trackViewState.deselectAll(); + break; + } + case "add-to-queue": + { + playlistNotifier.addTracks(selectedTracks); + playlistNotifier.addCollection(props.collectionId); + trackViewState.deselectAll(); + break; + } + default: + } + }, + icon: const Icon(SpotubeIcons.moreVertical), + children: [ + PopSheetEntry( + value: "download", + leading: const Icon(SpotubeIcons.download), + enabled: selectedTracks.isNotEmpty, + title: Text( + context.l10n.download_count(selectedTracks.length), + ), + ), + if (!isUserPlaylist) + PopSheetEntry( + value: "add-to-playlist", + leading: const Icon(SpotubeIcons.playlistAdd), + enabled: selectedTracks.isNotEmpty, + title: Text( + context.l10n.add_count_to_playlist(selectedTracks.length), + ), + ), + PopSheetEntry( + enabled: selectedTracks.isNotEmpty, + value: "add-to-queue", + leading: const Icon(SpotubeIcons.queueAdd), + title: Text( + context.l10n.add_count_to_queue(selectedTracks.length), + ), + ), + PopSheetEntry( + enabled: selectedTracks.isNotEmpty, + value: "play-next", + leading: const Icon(SpotubeIcons.lightning), + title: Text( + context.l10n.play_count_next(selectedTracks.length), + ), + ), + ], + ); + } +} diff --git a/lib/components/shared/tracks_view/sections/body/use_is_user_playlist.dart b/lib/components/shared/tracks_view/sections/body/use_is_user_playlist.dart new file mode 100644 index 00000000..ca3c6706 --- /dev/null +++ b/lib/components/shared/tracks_view/sections/body/use_is_user_playlist.dart @@ -0,0 +1,18 @@ +import 'package:flutter_hooks/flutter_hooks.dart'; +import 'package:hooks_riverpod/hooks_riverpod.dart'; +import 'package:spotube/services/queries/queries.dart'; + +bool useIsUserPlaylist(WidgetRef ref, String playlistId) { + final userPlaylistsQuery = useQueries.playlist.ofMineAll(ref); + final me = useQueries.user.me(ref); + + return useMemoized( + () => + userPlaylistsQuery.data?.any((e) => + e.id == playlistId && + me.data != null && + e.owner?.id == me.data?.id) ?? + false, + [userPlaylistsQuery.data, playlistId, me.data], + ); +} diff --git a/lib/components/shared/tracks_view/sections/header/flexible_header.dart b/lib/components/shared/tracks_view/sections/header/flexible_header.dart new file mode 100644 index 00000000..e63161fa --- /dev/null +++ b/lib/components/shared/tracks_view/sections/header/flexible_header.dart @@ -0,0 +1,142 @@ +import 'dart:ui'; + +import 'package:cached_network_image/cached_network_image.dart'; +import 'package:flutter/material.dart'; +import 'package:hooks_riverpod/hooks_riverpod.dart'; +import 'package:spotube/collections/assets.gen.dart'; +import 'package:spotube/components/shared/image/universal_image.dart'; +import 'package:spotube/components/shared/playbutton_card.dart'; +import 'package:spotube/components/shared/tracks_view/sections/header/header_actions.dart'; +import 'package:spotube/components/shared/tracks_view/sections/header/header_buttons.dart'; +import 'package:spotube/components/shared/tracks_view/track_view_props.dart'; +import 'package:gap/gap.dart'; +import 'package:spotube/extensions/constrains.dart'; +import 'package:spotube/hooks/utils/use_palette_color.dart'; + +class TrackViewFlexHeader extends HookConsumerWidget { + const TrackViewFlexHeader({Key? key}) : super(key: key); + + @override + Widget build(BuildContext context, ref) { + final props = InheritedTrackView.of(context); + final ThemeData(:colorScheme, :textTheme, :iconTheme) = Theme.of(context); + final defaultTextStyle = DefaultTextStyle.of(context); + final mediaQuery = MediaQuery.of(context); + + final description = useDescription(props.description); + + final palette = usePaletteColor(props.image, ref); + + return IconTheme( + data: iconTheme.copyWith(color: palette.bodyTextColor), + child: SliverLayoutBuilder( + builder: (context, constrains) { + final isExpanded = constrains.scrollOffset < 350; + + final headingStyle = (mediaQuery.mdAndDown + ? textTheme.headlineSmall + : textTheme.headlineMedium) + ?.copyWith( + color: palette.bodyTextColor, + ); + return SliverAppBar( + iconTheme: iconTheme.copyWith( + color: palette.bodyTextColor, + size: 16, + ), + actions: isExpanded + ? [] + : [ + const TrackViewHeaderActions(), + TrackViewHeaderButtons(compact: true, color: palette), + ], + floating: false, + pinned: true, + expandedHeight: 400, + automaticallyImplyLeading: false, + backgroundColor: palette.color, + title: isExpanded ? null : Text(props.title, style: headingStyle), + flexibleSpace: FlexibleSpaceBar( + background: Container( + clipBehavior: Clip.hardEdge, + decoration: BoxDecoration( + image: DecorationImage( + image: CachedNetworkImageProvider(props.image), + fit: BoxFit.cover, + ), + ), + child: BackdropFilter( + filter: ImageFilter.blur(sigmaX: 10, sigmaY: 10), + child: DecoratedBox( + decoration: BoxDecoration( + gradient: LinearGradient( + colors: [ + Colors.black45, + colorScheme.surface, + ], + begin: const FractionalOffset(0, 0), + end: const FractionalOffset(0, 1), + tileMode: TileMode.clamp, + ), + ), + child: Padding( + padding: const EdgeInsets.all(8.0), + child: Column( + mainAxisSize: MainAxisSize.min, + mainAxisAlignment: MainAxisAlignment.center, + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + Flex( + direction: mediaQuery.mdAndDown + ? Axis.vertical + : Axis.horizontal, + mainAxisSize: MainAxisSize.min, + children: [ + ClipRRect( + borderRadius: BorderRadius.circular(10), + child: UniversalImage( + path: props.image, + width: 200, + height: 200, + placeholder: Assets.albumPlaceholder.path, + ), + ), + const Gap(20), + Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: mediaQuery.mdAndDown + ? CrossAxisAlignment.center + : CrossAxisAlignment.start, + children: [ + Text(props.title, style: headingStyle), + const SizedBox(height: 10), + if (description != null) + Text( + description, + style: defaultTextStyle.style.copyWith( + color: palette.bodyTextColor, + ), + maxLines: 2, + overflow: TextOverflow.ellipsis, + ), + const Gap(10), + const TrackViewHeaderActions(), + const Gap(10), + TrackViewHeaderButtons(color: palette), + ], + ), + ], + ), + ], + ), + ), + ), + ), + ), + ), + ); + }, + ), + ); + } +} diff --git a/lib/components/shared/tracks_view/sections/header/header_actions.dart b/lib/components/shared/tracks_view/sections/header/header_actions.dart new file mode 100644 index 00000000..954f266d --- /dev/null +++ b/lib/components/shared/tracks_view/sections/header/header_actions.dart @@ -0,0 +1,82 @@ +import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; +import 'package:go_router/go_router.dart'; +import 'package:hooks_riverpod/hooks_riverpod.dart'; +import 'package:spotube/collections/spotube_icons.dart'; +import 'package:spotube/components/shared/heart_button.dart'; +import 'package:spotube/components/shared/tracks_view/sections/body/use_is_user_playlist.dart'; +import 'package:spotube/components/shared/tracks_view/track_view_props.dart'; +import 'package:spotube/extensions/context.dart'; +import 'package:spotube/provider/authentication_provider.dart'; +import 'package:spotube/provider/proxy_playlist/proxy_playlist_provider.dart'; + +class TrackViewHeaderActions extends HookConsumerWidget { + const TrackViewHeaderActions({Key? key}) : super(key: key); + + @override + Widget build(BuildContext context, ref) { + final props = InheritedTrackView.of(context); + + final playlist = ref.watch(ProxyPlaylistNotifier.provider); + final playlistNotifier = ref.watch(ProxyPlaylistNotifier.notifier); + + final isActive = playlist.collections.contains(props.collectionId); + + final isUserPlaylist = useIsUserPlaylist(ref, props.collectionId); + + final scaffoldMessenger = ScaffoldMessenger.of(context); + + final auth = ref.watch(AuthenticationNotifier.provider); + + return Row( + mainAxisSize: MainAxisSize.min, + children: [ + IconButton( + tooltip: context.l10n.share, + icon: const Icon(SpotubeIcons.share), + onPressed: () async { + await Clipboard.setData( + ClipboardData(text: props.shareUrl), + ); + + scaffoldMessenger.showSnackBar( + SnackBar( + width: 300, + behavior: SnackBarBehavior.floating, + content: Text( + "Copied ${props.shareUrl} to clipboard", + textAlign: TextAlign.center, + ), + ), + ); + }, + ), + IconButton( + icon: const Icon(SpotubeIcons.queueAdd), + tooltip: context.l10n.add_to_queue, + onPressed: isActive || props.tracks.isEmpty + ? null + : () async { + final tracks = await props.pagination.onFetchAll(); + await playlistNotifier.addTracks(tracks); + playlistNotifier.addCollection(props.collectionId); + }, + ), + if (props.onHeart != null && auth != null) + HeartButton( + isLiked: props.isLiked, + icon: isUserPlaylist ? SpotubeIcons.trash : null, + tooltip: props.isLiked + ? context.l10n.remove_from_favorites + : context.l10n.save_as_favorite, + onPressed: () { + props.onHeart?.call(); + if (isUserPlaylist) { + context.pop(); + } + }, + ), + ], + ); + } +} diff --git a/lib/components/shared/tracks_view/sections/header/header_buttons.dart b/lib/components/shared/tracks_view/sections/header/header_buttons.dart new file mode 100644 index 00000000..c006ec08 --- /dev/null +++ b/lib/components/shared/tracks_view/sections/header/header_buttons.dart @@ -0,0 +1,137 @@ +import 'dart:math'; + +import 'package:flutter/material.dart'; +import 'package:flutter_hooks/flutter_hooks.dart'; +import 'package:gap/gap.dart'; +import 'package:hooks_riverpod/hooks_riverpod.dart'; +import 'package:palette_generator/palette_generator.dart'; +import 'package:spotube/collections/spotube_icons.dart'; +import 'package:spotube/components/shared/tracks_view/track_view_props.dart'; +import 'package:spotube/extensions/context.dart'; +import 'package:spotube/provider/proxy_playlist/proxy_playlist_provider.dart'; +import 'package:spotube/services/audio_player/audio_player.dart'; + +class TrackViewHeaderButtons extends HookConsumerWidget { + final PaletteColor color; + final bool compact; + const TrackViewHeaderButtons({ + Key? key, + required this.color, + this.compact = false, + }) : super(key: key); + + @override + Widget build(BuildContext context, ref) { + final props = InheritedTrackView.of(context); + final playlist = ref.watch(ProxyPlaylistNotifier.provider); + final playlistNotifier = ref.watch(ProxyPlaylistNotifier.notifier); + + final isActive = playlist.collections.contains(props.collectionId); + + final isLoading = useState(false); + + const progressIndicator = Center( + child: SizedBox.square( + dimension: 20, + child: CircularProgressIndicator(strokeWidth: .8), + ), + ); + + void onShuffle() async { + try { + isLoading.value = true; + + final allTracks = await props.pagination.onFetchAll(); + + await playlistNotifier.load( + allTracks, + autoPlay: true, + initialIndex: Random().nextInt(allTracks.length), + ); + await audioPlayer.setShuffle(true); + playlistNotifier.addCollection(props.collectionId); + } finally { + isLoading.value = false; + } + } + + void onPlay() async { + try { + isLoading.value = true; + + final allTracks = await props.pagination.onFetchAll(); + + await playlistNotifier.load(allTracks, autoPlay: true); + playlistNotifier.addCollection(props.collectionId); + } finally { + isLoading.value = false; + } + } + + if (compact) { + return Row( + mainAxisSize: MainAxisSize.min, + children: [ + if (!isActive && !isLoading.value) + IconButton( + icon: const Icon(SpotubeIcons.shuffle), + onPressed: props.tracks.isEmpty ? null : onShuffle, + ), + const Gap(10), + IconButton.filledTonal( + icon: isActive + ? const Icon(SpotubeIcons.pause) + : isLoading.value + ? progressIndicator + : const Icon(SpotubeIcons.play), + onPressed: isActive || props.tracks.isEmpty || isLoading.value + ? null + : onPlay, + ), + const Gap(10), + ], + ); + } + + return Row( + mainAxisSize: MainAxisSize.min, + children: [ + AnimatedOpacity( + duration: const Duration(milliseconds: 300), + opacity: isActive || isLoading.value ? 0 : 1, + child: AnimatedSize( + duration: const Duration(milliseconds: 300), + child: SizedBox.square( + dimension: isActive || isLoading.value ? 0 : null, + child: FilledButton.icon( + style: ElevatedButton.styleFrom( + backgroundColor: Colors.white, + foregroundColor: Colors.black, + ), + label: Text(context.l10n.shuffle), + icon: const Icon(SpotubeIcons.shuffle), + onPressed: props.tracks.isEmpty ? null : onShuffle, + ), + ), + ), + ), + const Gap(10), + FilledButton.icon( + style: ElevatedButton.styleFrom( + backgroundColor: color.color, + foregroundColor: color.bodyTextColor, + ), + onPressed: isActive || props.tracks.isEmpty || isLoading.value + ? null + : onPlay, + icon: isActive + ? const Icon(SpotubeIcons.pause) + : isLoading.value + ? progressIndicator + : const Icon(SpotubeIcons.play), + label: Text(context.l10n.play), + ), + ], + ); + } +} diff --git a/lib/components/shared/tracks_view/track_view.dart b/lib/components/shared/tracks_view/track_view.dart new file mode 100644 index 00000000..a65bcff1 --- /dev/null +++ b/lib/components/shared/tracks_view/track_view.dart @@ -0,0 +1,44 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_desktop_tools/flutter_desktop_tools.dart'; +import 'package:hooks_riverpod/hooks_riverpod.dart'; +import 'package:sliver_tools/sliver_tools.dart'; +import 'package:spotube/components/shared/page_window_title_bar.dart'; +import 'package:spotube/components/shared/shimmers/shimmer_track_tile.dart'; +import 'package:spotube/components/shared/tracks_view/sections/header/flexible_header.dart'; +import 'package:spotube/components/shared/tracks_view/sections/body/track_view_body.dart'; +import 'package:spotube/components/shared/tracks_view/track_view_props.dart'; + +class TrackView extends HookConsumerWidget { + const TrackView({Key? key}) : super(key: key); + + @override + Widget build(BuildContext context, ref) { + final props = InheritedTrackView.of(context); + + return Scaffold( + appBar: DesktopTools.platform.isDesktop + ? const PageWindowTitleBar( + backgroundColor: Colors.transparent, + foregroundColor: Colors.white, + leadingWidth: 400, + leading: Align( + alignment: Alignment.centerLeft, + child: BackButton(color: Colors.white), + ), + ) + : null, + extendBodyBehindAppBar: true, + body: CustomScrollView( + slivers: [ + const TrackViewFlexHeader(), + SliverAnimatedSwitcher( + duration: const Duration(milliseconds: 500), + child: props.tracks.isEmpty + ? const ShimmerTrackTileGroup() + : const TrackViewBodySection(), + ), + ], + ), + ); + } +} diff --git a/lib/components/shared/tracks_view/track_view_props.dart b/lib/components/shared/tracks_view/track_view_props.dart new file mode 100644 index 00000000..59c05db2 --- /dev/null +++ b/lib/components/shared/tracks_view/track_view_props.dart @@ -0,0 +1,102 @@ +import 'package:fl_query/fl_query.dart'; +import 'package:flutter/material.dart' hide Page; +import 'package:spotify/spotify.dart'; + +class PaginationProps { + final bool hasNextPage; + final bool isLoading; + final VoidCallback onFetchMore; + final Future> Function() onFetchAll; + + const PaginationProps({ + required this.hasNextPage, + required this.isLoading, + required this.onFetchMore, + required this.onFetchAll, + }); + + factory PaginationProps.fromQuery( + InfiniteQuery, dynamic, int> query, { + required Future> Function() onFetchAll, + }) { + return PaginationProps( + hasNextPage: query.hasNextPage, + isLoading: query.isLoadingNextPage, + onFetchMore: query.fetchNext, + onFetchAll: onFetchAll, + ); + } + + @override + operator ==(Object other) { + return other is PaginationProps && + other.hasNextPage == hasNextPage && + other.isLoading == isLoading && + other.onFetchMore == onFetchMore && + other.onFetchAll == onFetchAll; + } + + @override + int get hashCode => + super.hashCode ^ + hasNextPage.hashCode ^ + isLoading.hashCode ^ + onFetchMore.hashCode ^ + onFetchAll.hashCode; +} + +class InheritedTrackView extends InheritedWidget { + final String collectionId; + final String title; + final String? description; + final String image; + final String routePath; + final List tracks; + final PaginationProps pagination; + final bool isLiked; + final String shareUrl; + + // events + final VoidCallback? onHeart; // if null heart button will hidden + + const InheritedTrackView({ + super.key, + required super.child, + required this.collectionId, + required this.title, + this.description, + required this.image, + required this.tracks, + required this.pagination, + required this.routePath, + required this.shareUrl, + this.isLiked = false, + this.onHeart, + }); + + @override + bool updateShouldNotify(InheritedTrackView oldWidget) { + return oldWidget.title != title || + oldWidget.description != description || + oldWidget.image != image || + oldWidget.tracks != tracks || + oldWidget.pagination != pagination || + oldWidget.isLiked != isLiked || + oldWidget.onHeart != onHeart || + oldWidget.shareUrl != shareUrl || + oldWidget.routePath != routePath || + oldWidget.collectionId != collectionId || + oldWidget.child != child; + } + + static InheritedTrackView of(BuildContext context) { + final widget = + context.dependOnInheritedWidgetOfExactType(); + if (widget == null) { + throw Exception( + 'InheritedTrackView not found. Make sure to wrap [TrackView] with [InheritedTrackView]', + ); + } + return widget; + } +} diff --git a/lib/components/shared/tracks_view/track_view_provider.dart b/lib/components/shared/tracks_view/track_view_provider.dart new file mode 100644 index 00000000..14dc1136 --- /dev/null +++ b/lib/components/shared/tracks_view/track_view_provider.dart @@ -0,0 +1,64 @@ +import 'package:flutter/material.dart'; +import 'package:hooks_riverpod/hooks_riverpod.dart'; +import 'package:spotify/spotify.dart'; +import 'package:spotube/components/library/user_local_tracks.dart'; + +class TrackViewNotifier extends ChangeNotifier { + List tracks; + List selectedTrackIds; + SortBy sortBy; + String? searchQuery; + + TrackViewNotifier( + this.tracks, { + this.selectedTrackIds = const [], + this.sortBy = SortBy.none, + this.searchQuery, + }); + + bool get isSelecting => selectedTrackIds.isNotEmpty; + + bool get hasSelectedAll => + selectedTrackIds.length == tracks.length && tracks.isNotEmpty; + + List get selectedTracks => + tracks.where((e) => selectedTrackIds.contains(e.id)).toList(); + + void selectTrack(String trackId) { + selectedTrackIds = [...selectedTrackIds, trackId]; + notifyListeners(); + } + + void unselectTrack(String trackId) { + selectedTrackIds = selectedTrackIds.where((e) => e != trackId).toList(); + notifyListeners(); + } + + void toggleTrackSelection(String trackId) { + if (selectedTrackIds.contains(trackId)) { + unselectTrack(trackId); + } else { + selectTrack(trackId); + } + } + + void selectAll() { + selectedTrackIds = tracks.map((e) => e.id!).toList(); + notifyListeners(); + } + + void deselectAll() { + selectedTrackIds = []; + notifyListeners(); + } + + void sort(SortBy sortBy) { + this.sortBy = sortBy; + notifyListeners(); + } +} + +final trackViewProvider = ChangeNotifierProvider.autoDispose + .family>((ref, tracks) { + return TrackViewNotifier(tracks); +}); diff --git a/lib/extensions/infinite_query.dart b/lib/extensions/infinite_query.dart new file mode 100644 index 00000000..86a2aaa6 --- /dev/null +++ b/lib/extensions/infinite_query.dart @@ -0,0 +1,30 @@ +import 'package:fl_query/fl_query.dart'; +import 'package:spotify/spotify.dart'; + +extension FetchAllTracks on InfiniteQuery, dynamic, int> { + Future> fetchAllTracks({ + required Future> Function() getAllTracks, + }) async { + if (!hasNextPage) { + return pages.expand((page) => page).toList(); + } + final tracks = await getAllTracks(); + final pagedTracks = tracks.fold( + >{}, + (acc, element) { + final index = acc.length; + final groupIndex = index ~/ 20; + final group = acc[groupIndex] ?? []; + group.add(element); + acc[groupIndex] = group; + return acc; + }, + ); + + for (final group in pagedTracks.entries) { + setPageData(group.key, group.value); + } + + return tracks.toList(); + } +} diff --git a/lib/pages/album/album.dart b/lib/pages/album/album.dart index 5674e721..72f9a9af 100644 --- a/lib/pages/album/album.dart +++ b/lib/pages/album/album.dart @@ -1,157 +1,79 @@ +import 'package:fl_query_hooks/fl_query_hooks.dart'; import 'package:flutter/material.dart'; -import 'package:flutter/services.dart'; import 'package:flutter_hooks/flutter_hooks.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:spotify/spotify.dart'; -import 'package:spotube/components/shared/heart_button.dart'; -import 'package:spotube/components/shared/track_table/track_collection_view/track_collection_heading.dart'; -import 'package:spotube/components/shared/track_table/track_collection_view/track_collection_view.dart'; -import 'package:spotube/components/shared/track_table/tracks_table_view.dart'; -import 'package:spotube/extensions/constrains.dart'; -import 'package:spotube/provider/proxy_playlist/proxy_playlist_provider.dart'; +import 'package:spotube/components/shared/tracks_view/track_view.dart'; +import 'package:spotube/components/shared/tracks_view/track_view_props.dart'; +import 'package:spotube/extensions/context.dart'; +import 'package:spotube/extensions/infinite_query.dart'; +import 'package:spotube/provider/spotify_provider.dart'; +import 'package:spotube/services/mutations/mutations.dart'; import 'package:spotube/services/queries/queries.dart'; -import 'package:spotube/services/sourced_track/sourced_track.dart'; -import 'package:spotube/utils/service_utils.dart'; import 'package:spotube/utils/type_conversion_utils.dart'; class AlbumPage extends HookConsumerWidget { final AlbumSimple album; - const AlbumPage(this.album, {Key? key}) : super(key: key); - - Future playPlaylist( - List tracks, - WidgetRef ref, { - Track? currentTrack, - }) async { - final playlist = ref.read(ProxyPlaylistNotifier.provider); - final playback = ref.read(ProxyPlaylistNotifier.notifier); - final sortBy = ref.read(trackCollectionSortState(album.id!)); - final sortedTracks = ServiceUtils.sortTracks(tracks, sortBy); - currentTrack ??= sortedTracks.first; - final isAlbumPlaying = playlist.containsTracks(tracks); - if (!isAlbumPlaying) { - playback.addCollection(album.id!); // for enabling loading indicator - await playback.load( - sortedTracks, - initialIndex: sortedTracks.indexWhere((s) => s.id == currentTrack?.id), - ); - playback.addCollection(album.id!); - } else if (isAlbumPlaying && - currentTrack.id != null && - currentTrack.id != playlist.activeTrack?.id) { - await playback.jumpToTrack(currentTrack); - } - } + const AlbumPage({ + Key? key, + required this.album, + }) : super(key: key); @override Widget build(BuildContext context, ref) { - final playlist = ref.watch(ProxyPlaylistNotifier.provider); - final playback = ref.watch(ProxyPlaylistNotifier.notifier); + final spotify = ref.watch(spotifyProvider); + final tracksQuery = useQueries.album.tracksOf(ref, album); - final tracksSnapshot = useQueries.album.tracksOf(ref, album.id!); + final tracks = useMemoized(() { + return tracksQuery.pages.expand((element) => element).toList(); + }, [tracksQuery.pages]); - final albumArt = useMemoized( - () => TypeConversionUtils.image_X_UrlString( - album.images, - placeholder: ImagePlaceholder.albumArt, - ), - [album.images]); + final client = useQueryClient(); - final mediaQuery = MediaQuery.of(context); + final albumIsSaved = useQueries.album.isSavedForMe(ref, album.id!); + final isLiked = albumIsSaved.data ?? false; - final isAlbumPlaying = useMemoized( - () => playlist.collections.contains(album.id!), - [playlist, album], - ); - - final albumTrackPlaying = useMemoized( - () => - tracksSnapshot.data?.any((s) => s.id! == playlist.activeTrack?.id!) == - true && - playlist.activeTrack is SourcedTrack, - [playlist.activeTrack, tracksSnapshot.data], - ); - - return TrackCollectionView( - id: album.id!, - playingState: isAlbumPlaying && albumTrackPlaying - ? PlayButtonState.playing - : isAlbumPlaying && !albumTrackPlaying - ? PlayButtonState.loading - : PlayButtonState.notPlaying, - title: album.name!, - titleImage: albumArt, - tracksSnapshot: tracksSnapshot, - album: album, - routePath: "/album/${album.id}", - bottomSpace: mediaQuery.mdAndDown, - onPlay: ([track]) async { - if (tracksSnapshot.hasData) { - if (!isAlbumPlaying) { - await playPlaylist( - tracksSnapshot.data! - .map((track) => - TypeConversionUtils.simpleTrack_X_Track(track, album)) - .toList(), - ref, - ); - } else if (isAlbumPlaying && track != null) { - await playPlaylist( - tracksSnapshot.data! - .map((track) => - TypeConversionUtils.simpleTrack_X_Track(track, album)) - .toList(), - currentTrack: track, - ref, - ); - } else { - await playback - .removeTracks(tracksSnapshot.data!.map((track) => track.id!)); - } - } + final toggleAlbumLike = useMutations.album.toggleFavorite( + ref, + album.id!, + refreshQueries: [albumIsSaved.key], + onData: (_, __) async { + await client.refreshInfiniteQueryAllPages("current-user-albums"); }, - onAddToQueue: () { - if (tracksSnapshot.hasData && !isAlbumPlaying) { - playback.addTracks( - tracksSnapshot.data! + ); + + return InheritedTrackView( + collectionId: album.id!, + image: TypeConversionUtils.image_X_UrlString( + album.images, + placeholder: ImagePlaceholder.albumArt, + ), + title: album.name!, + description: + "${context.l10n.released} • ${album.releaseDate} • ${album.artists!.first.name}", + tracks: tracks, + pagination: PaginationProps.fromQuery( + tracksQuery, + onFetchAll: () { + return tracksQuery.fetchAllTracks(getAllTracks: () async { + final res = await spotify.albums.tracks(album.id!).all(); + + return res .map((track) => TypeConversionUtils.simpleTrack_X_Track(track, album)) - .toList(), - ); - playback.addCollection(album.id!); - } - }, - onShare: () { - Clipboard.setData( - ClipboardData(text: "https://open.spotify.com/album/${album.id}"), - ); - }, - heartBtn: AlbumHeartButton(album: album), - onShuffledPlay: ([track]) { - // Shuffle the tracks (create a copy of playlist) - if (tracksSnapshot.hasData) { - final tracks = tracksSnapshot.data! - .map((track) => - TypeConversionUtils.simpleTrack_X_Track(track, album)) - .toList() - ..shuffle(); - if (!isAlbumPlaying) { - playPlaylist( - tracks, - ref, - ); - } else if (isAlbumPlaying && track != null) { - playPlaylist( - tracks, - ref, - currentTrack: track, - ); - } else { - // TODO: Disable ability to stop playback from playlist/album - // playback.stop(); - } - } - }, + .toList(); + }); + }, + ), + routePath: "/album/${album.id}", + shareUrl: album.externalUrls!.spotify!, + isLiked: isLiked, + onHeart: albumIsSaved.hasData + ? () { + toggleAlbumLike.mutate(isLiked); + } + : null, + child: const TrackView(), ); } } diff --git a/lib/pages/artist/artist.dart b/lib/pages/artist/artist.dart index 299bf9f5..8b57c2a8 100644 --- a/lib/pages/artist/artist.dart +++ b/lib/pages/artist/artist.dart @@ -10,7 +10,7 @@ import 'package:spotube/collections/spotube_icons.dart'; import 'package:spotube/components/shared/inter_scrollbar/inter_scrollbar.dart'; import 'package:spotube/components/shared/shimmers/shimmer_artist_profile.dart'; import 'package:spotube/components/shared/page_window_title_bar.dart'; -import 'package:spotube/components/shared/track_table/track_tile.dart'; +import 'package:spotube/components/shared/track_tile/track_tile.dart'; import 'package:spotube/components/shared/image/universal_image.dart'; import 'package:spotube/components/artist/artist_album_list.dart'; import 'package:spotube/components/artist/artist_card.dart'; diff --git a/lib/pages/home/genres.dart b/lib/pages/home/genres.dart index b3904e2e..54fb6786 100644 --- a/lib/pages/home/genres.dart +++ b/lib/pages/home/genres.dart @@ -70,7 +70,8 @@ class GenrePage extends HookConsumerWidget { child: Column( children: [ ExpandableSearchField( - isFiltering: isFiltering, + isFiltering: isFiltering.value, + onChangeFiltering: (value) => isFiltering.value = value, searchController: searchController, searchFocus: searchFocus, ), @@ -103,10 +104,11 @@ class GenrePage extends HookConsumerWidget { top: 0, right: 10, child: ExpandableSearchButton( - isFiltering: isFiltering, + isFiltering: isFiltering.value, searchFocus: searchFocus, icon: const Icon(SpotubeIcons.search), onPressed: (value) { + isFiltering.value = value; if (isFiltering.value) { scrollController.animateTo( 0, diff --git a/lib/pages/playlist/liked_playlist.dart b/lib/pages/playlist/liked_playlist.dart new file mode 100644 index 00000000..1f252ed4 --- /dev/null +++ b/lib/pages/playlist/liked_playlist.dart @@ -0,0 +1,45 @@ +import 'package:flutter/widgets.dart'; +import 'package:hooks_riverpod/hooks_riverpod.dart'; +import 'package:spotify/spotify.dart'; +import 'package:spotube/components/shared/tracks_view/track_view.dart'; +import 'package:spotube/components/shared/tracks_view/track_view_props.dart'; +import 'package:spotube/services/queries/queries.dart'; +import 'package:spotube/utils/type_conversion_utils.dart'; + +class LikedPlaylistPage extends HookConsumerWidget { + final PlaylistSimple playlist; + const LikedPlaylistPage({ + Key? key, + required this.playlist, + }) : super(key: key); + + @override + Widget build(BuildContext context, ref) { + final likedTracks = useQueries.playlist.likedTracksQuery(ref); + final tracks = likedTracks.data ?? []; + + return InheritedTrackView( + collectionId: playlist.id!, + image: TypeConversionUtils.image_X_UrlString( + playlist.images, + placeholder: ImagePlaceholder.collection, + ), + pagination: PaginationProps( + hasNextPage: false, + isLoading: false, + onFetchMore: () {}, + onFetchAll: () async { + return tracks.toList(); + }, + ), + title: playlist.name!, + description: playlist.description, + tracks: tracks, + routePath: '/playlist/${playlist.id}', + isLiked: false, + shareUrl: "", + onHeart: null, + child: const TrackView(), + ); + } +} diff --git a/lib/pages/playlist/playlist.dart b/lib/pages/playlist/playlist.dart index 6a3ec9b9..ab39b225 100644 --- a/lib/pages/playlist/playlist.dart +++ b/lib/pages/playlist/playlist.dart @@ -1,178 +1,82 @@ -import 'package:flutter/services.dart'; +import 'package:flutter/material.dart' hide Page; import 'package:flutter_hooks/flutter_hooks.dart'; -import 'package:go_router/go_router.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; -import 'package:spotube/collections/spotube_icons.dart'; -import 'package:spotube/components/shared/heart_button.dart'; -import 'package:spotube/components/shared/track_table/track_collection_view/track_collection_heading.dart'; -import 'package:spotube/components/shared/track_table/track_collection_view/track_collection_view.dart'; -import 'package:spotube/components/shared/track_table/tracks_table_view.dart'; -import 'package:spotube/extensions/constrains.dart'; -import 'package:spotube/models/logger.dart'; -import 'package:flutter/material.dart'; import 'package:spotify/spotify.dart'; -import 'package:spotube/provider/proxy_playlist/proxy_playlist_provider.dart'; +import 'package:spotube/components/shared/tracks_view/track_view.dart'; +import 'package:spotube/components/shared/tracks_view/track_view_props.dart'; +import 'package:spotube/extensions/infinite_query.dart'; +import 'package:spotube/provider/spotify_provider.dart'; +import 'package:spotube/services/mutations/mutations.dart'; import 'package:spotube/services/queries/queries.dart'; -import 'package:spotube/services/sourced_track/sourced_track.dart'; - -import 'package:spotube/utils/service_utils.dart'; import 'package:spotube/utils/type_conversion_utils.dart'; -class PlaylistView extends HookConsumerWidget { - final logger = getLogger(PlaylistView); - final PlaylistSimple playlistSimple; - PlaylistView(this.playlistSimple, {Key? key}) : super(key: key); +class PlaylistPage extends HookConsumerWidget { + final PlaylistSimple playlist; + const PlaylistPage({ + Key? key, + required this.playlist, + }) : super(key: key); @override Widget build(BuildContext context, ref) { - final proxyPlaylist = ref.watch(ProxyPlaylistNotifier.provider); - final playlistNotifier = ref.watch(ProxyPlaylistNotifier.notifier); + final spotify = ref.watch(spotifyProvider); + final tracksQuery = useQueries.playlist.tracksOfQuery(ref, playlist.id!); - final mediaQuery = MediaQuery.of(context); - - final meSnapshot = useQueries.user.me(ref); - - final playlistQuery = useQueries.playlist.byId(ref, playlistSimple.id!); - final playlist = playlistQuery.data ?? playlistSimple; - - final playlistTrackSnapshot = - useQueries.playlist.tracksOfQuery(ref, playlist.id!); - final likedTracksSnapshot = useQueries.playlist.likedTracksQuery(ref); - final tracksSnapshot = playlist.id! == "user-liked-tracks" - ? likedTracksSnapshot - : playlistTrackSnapshot; - - final isPlaylistPlaying = useMemoized( - () => proxyPlaylist.collections.contains(playlist.id!), - [proxyPlaylist, playlist], + final tracks = useMemoized( + () { + return tracksQuery.pages.expand((page) => page).toList(); + }, + [tracksQuery.pages], ); - final titleImage = useMemoized( - () => TypeConversionUtils.image_X_UrlString( - playlist.images, - placeholder: ImagePlaceholder.collection, - ), - [playlist.images]); + final me = useQueries.user.me(ref); - final playlistTrackPlaying = useMemoized( - () => - tracksSnapshot.data - ?.any((s) => s.id! == proxyPlaylist.activeTrack?.id!) == - true && - proxyPlaylist.activeTrack is SourcedTrack, - [proxyPlaylist.activeTrack, tracksSnapshot.data], + final isLikedQuery = useQueries.playlist.doesUserFollow( + ref, + playlist.id!, + me.data?.id ?? '', ); - final playPlaylist = useCallback(( - List tracks, - WidgetRef ref, { - Track? currentTrack, - }) async { - final playback = ref.read(ProxyPlaylistNotifier.notifier); - final sortBy = ref.read(trackCollectionSortState(playlist.id!)); - final sortedTracks = ServiceUtils.sortTracks(tracks, sortBy); - currentTrack ??= sortedTracks.first; - final isPlaylistPlaying = proxyPlaylist.containsTracks(tracks); - if (!isPlaylistPlaying) { - playback.addCollection(playlist.id!); // for enabling loading indicator - await playback.load( - sortedTracks, - initialIndex: - sortedTracks.indexWhere((s) => s.id == currentTrack?.id), - autoPlay: true, - ); - playback.addCollection(playlist.id!); - } else if (isPlaylistPlaying && - currentTrack.id != null && - currentTrack.id != proxyPlaylist.activeTrack?.id) { - await playback.jumpToTrack(currentTrack); - } - }, [proxyPlaylist, playlist]); + final togglePlaylistLike = useMutations.playlist.toggleFavorite( + ref, + playlist.id!, + refreshQueries: [ + isLikedQuery.key, + ], + ); - final ownPlaylist = - playlist.owner?.id != null && playlist.owner?.id == meSnapshot.data?.id; - - return TrackCollectionView( - id: playlist.id!, - playingState: isPlaylistPlaying && playlistTrackPlaying - ? PlayButtonState.playing - : isPlaylistPlaying && !playlistTrackPlaying - ? PlayButtonState.loading - : PlayButtonState.notPlaying, - title: playlist.name!, - titleImage: titleImage, - tracksSnapshot: tracksSnapshot, - description: playlist.description, - isOwned: ownPlaylist, - onPlay: ([track]) async { - if (tracksSnapshot.hasData) { - if (!isPlaylistPlaying || (isPlaylistPlaying && track != null)) { - await playPlaylist( - tracksSnapshot.data!, - ref, - currentTrack: track, - ); - } else { - await playlistNotifier - .removeTracks(tracksSnapshot.data!.map((e) => e.id!)); - } - } - }, - onAddToQueue: () { - if (tracksSnapshot.hasData && !isPlaylistPlaying) { - playlistNotifier.addTracks(tracksSnapshot.data!); - playlistNotifier.addCollection(playlist.id!); - } - }, - bottomSpace: mediaQuery.mdAndDown, - showShare: playlist.id != "user-liked-tracks", - routePath: "/playlist/${playlist.id}", - onShare: () { - final data = "https://open.spotify.com/playlist/${playlist.id}"; - Clipboard.setData( - ClipboardData(text: data), - ).then((_) { - ScaffoldMessenger.of(context).showSnackBar( - SnackBar( - width: 300, - behavior: SnackBarBehavior.floating, - content: Text( - "Copied $data to clipboard", - textAlign: TextAlign.center, - ), - ), + return InheritedTrackView( + collectionId: playlist.id!, + image: TypeConversionUtils.image_X_UrlString( + playlist.images, + placeholder: ImagePlaceholder.collection, + ), + pagination: PaginationProps.fromQuery( + tracksQuery, + onFetchAll: () async { + return tracksQuery.fetchAllTracks( + getAllTracks: () async { + final res = await spotify.playlists + .getTracksByPlaylistId(playlist.id!) + .all(); + return res.toList(); + }, ); - }); - }, - heartBtn: PlaylistHeartButton( - playlist: playlist, - icon: ownPlaylist ? SpotubeIcons.trash : null, - onData: (data) { - GoRouter.of(context).pop(); }, ), - onShuffledPlay: ([track]) { - final tracks = [...?tracksSnapshot.data]..shuffle(); - - if (tracksSnapshot.hasData) { - if (!isPlaylistPlaying) { - playPlaylist( - tracks, - ref, - currentTrack: track, - ); - } else if (isPlaylistPlaying && track != null) { - playPlaylist( - tracks, - ref, - currentTrack: track, - ); - } else { - // TODO: Remove the ability to stop the playlist - // playlistNotifier.stop(); - } + title: playlist.name!, + description: playlist.description, + tracks: tracks, + routePath: '/playlist/${playlist.id}', + isLiked: isLikedQuery.data ?? false, + shareUrl: playlist.externalUrls?.spotify ?? "", + onHeart: () async { + if (!isLikedQuery.hasData || togglePlaylistLike.isMutating) { + return; } + await togglePlaylistLike.mutate(isLikedQuery.data!); }, + child: const TrackView(), ); } } diff --git a/lib/pages/search/sections/tracks.dart b/lib/pages/search/sections/tracks.dart index 59c6a4e1..e77cd8f2 100644 --- a/lib/pages/search/sections/tracks.dart +++ b/lib/pages/search/sections/tracks.dart @@ -5,7 +5,7 @@ import 'package:flutter_hooks/flutter_hooks.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:spotify/spotify.dart'; import 'package:spotube/components/shared/dialogs/prompt_dialog.dart'; -import 'package:spotube/components/shared/track_table/track_tile.dart'; +import 'package:spotube/components/shared/track_tile/track_tile.dart'; import 'package:spotube/extensions/context.dart'; import 'package:spotube/provider/proxy_playlist/proxy_playlist_provider.dart'; diff --git a/lib/services/queries/album.dart b/lib/services/queries/album.dart index 546b3d15..0cc10256 100644 --- a/lib/services/queries/album.dart +++ b/lib/services/queries/album.dart @@ -1,10 +1,13 @@ import 'package:catcher_2/catcher_2.dart'; import 'package:fl_query/fl_query.dart'; +import 'package:fl_query_hooks/fl_query_hooks.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:spotify/spotify.dart'; import 'package:spotube/hooks/spotify/use_spotify_infinite_query.dart'; import 'package:spotube/hooks/spotify/use_spotify_query.dart'; +import 'package:spotube/provider/spotify_provider.dart'; import 'package:spotube/provider/user_preferences/user_preferences_provider.dart'; +import 'package:spotube/utils/type_conversion_utils.dart'; class AlbumQueries { const AlbumQueries(); @@ -27,19 +30,42 @@ class AlbumQueries { ); } - Query, dynamic> tracksOf( + static final tracksOfJob = InfiniteQueryJob.withVariableKey< + List, + dynamic, + int, + ({ + SpotifyApi spotify, + AlbumSimple album, + })>( + baseQueryKey: "album-tracks", + initialPage: 0, + task: (albumId, page, args) async { + final res = + await args!.spotify.albums.tracks(albumId).getPage(20, page * 20); + return res.items + ?.map((track) => + TypeConversionUtils.simpleTrack_X_Track(track, args.album)) + .toList() ?? + []; + }, + nextPage: (lastPage, lastPageData) { + if (lastPageData.length < 20) { + return null; + } + return lastPage + 1; + }, + ); + + InfiniteQuery, dynamic, int> tracksOf( WidgetRef ref, - String albumId, + AlbumSimple album, ) { - return useSpotifyQuery, dynamic>( - "album-tracks/$albumId", - (spotify) { - return spotify.albums - .getTracks(albumId) - .all() - .then((value) => value.toList()); - }, - ref: ref, + final spotify = ref.watch(spotifyProvider); + + return useInfiniteQueryJob( + job: tracksOfJob(album.id!), + args: (spotify: spotify, album: album), ); } diff --git a/lib/services/queries/playlist.dart b/lib/services/queries/playlist.dart index 2c6c38be..836f9d72 100644 --- a/lib/services/queries/playlist.dart +++ b/lib/services/queries/playlist.dart @@ -166,17 +166,14 @@ class PlaylistQueries { ); } - Future> likedTracks( - SpotifyApi spotify, - WidgetRef ref, - ) async { + Future> likedTracks(SpotifyApi spotify) async { final tracks = await spotify.tracks.me.saved.all(); return tracks.map((e) => e.track!).toList(); } Query, dynamic> likedTracksQuery(WidgetRef ref) { - final query = useCallback((spotify) => likedTracks(spotify, ref), []); + final query = useCallback((spotify) => likedTracks(spotify), []); final context = useContext(); return useSpotifyQuery, dynamic>( @@ -201,28 +198,6 @@ class PlaylistQueries { ); } - Future> tracksOf( - String playlistId, - SpotifyApi spotify, - WidgetRef ref, - ) async { - if (playlistId == "user-liked-tracks") return []; - return spotify.playlists.getTracksByPlaylistId(playlistId).all().then( - (value) => value.where((track) => track.id != null).toList(), - ); - } - - Query, dynamic> tracksOfQuery( - WidgetRef ref, - String playlistId, - ) { - return useSpotifyQuery, dynamic>( - "playlist-tracks/$playlistId", - (spotify) => tracksOf(playlistId, spotify, ref), - ref: ref, - ); - } - Query byId(WidgetRef ref, String id) { return useSpotifyQuery( "playlist/$id", @@ -233,6 +208,42 @@ class PlaylistQueries { ); } + Future> tracksOf( + int pageParam, + SpotifyApi spotify, + String playlistId, + ) async { + try { + final playlists = await spotify.playlists + .getTracksByPlaylistId(playlistId) + .getPage(20, pageParam * 20); + return playlists.items?.toList() ?? []; + } catch (e, stack) { + Catcher2.reportCheckedError(e, stack); + rethrow; + } + } + + int? tracksOfQueryNextPage(int lastPage, List lastPageData) { + if (lastPageData.length < 20) { + return null; + } + return lastPage + 1; + } + + InfiniteQuery, dynamic, int> tracksOfQuery( + WidgetRef ref, + String playlistId, + ) { + return useSpotifyInfiniteQuery, dynamic, int>( + "playlist-tracks/$playlistId", + (page, spotify) => tracksOf(page, spotify, playlistId), + initialPage: 0, + nextPage: tracksOfQueryNextPage, + ref: ref, + ); + } + InfiniteQuery, dynamic, int> featured( WidgetRef ref, ) { diff --git a/pubspec.lock b/pubspec.lock index 54f6d934..2a8dbb71 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -969,6 +969,14 @@ packages: url: "https://pub.dev" source: hosted version: "1.1.6" + gap: + dependency: "direct main" + description: + name: gap + sha256: f19387d4e32f849394758b91377f9153a1b41d79513ef7668c088c77dbc6955d + url: "https://pub.dev" + source: hosted + version: "3.0.1" glob: dependency: transitive description: @@ -1861,6 +1869,14 @@ packages: description: flutter source: sdk version: "0.0.99" + sliver_tools: + dependency: "direct main" + description: + name: sliver_tools + sha256: eae28220badfb9d0559207badcbbc9ad5331aac829a88cb0964d330d2a4636a6 + url: "https://pub.dev" + source: hosted + version: "0.2.12" smtc_windows: dependency: "direct main" description: diff --git a/pubspec.yaml b/pubspec.yaml index b3fd3c3e..4d31085c 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -114,6 +114,8 @@ dependencies: url: https://github.com/thielepaul/flutter-draggable-scrollbar.git ref: cfd570035bf393de541d32e9b28808b5d7e602df very_good_infinite_list: ^0.7.1 + gap: ^3.0.1 + sliver_tools: ^0.2.12 dev_dependencies: build_runner: ^2.3.2 From 1b087c6eb37ff21a8b8576f713c212500286d058 Mon Sep 17 00:00:00 2001 From: Kingkor Roy Tirtho Date: Fri, 17 Nov 2023 13:23:31 +0600 Subject: [PATCH 024/195] chore: hide empty description --- .../shared/tracks_view/sections/header/flexible_header.dart | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/components/shared/tracks_view/sections/header/flexible_header.dart b/lib/components/shared/tracks_view/sections/header/flexible_header.dart index e63161fa..26c8a526 100644 --- a/lib/components/shared/tracks_view/sections/header/flexible_header.dart +++ b/lib/components/shared/tracks_view/sections/header/flexible_header.dart @@ -110,7 +110,8 @@ class TrackViewFlexHeader extends HookConsumerWidget { children: [ Text(props.title, style: headingStyle), const SizedBox(height: 10), - if (description != null) + if (description != null && + description.isNotEmpty) Text( description, style: defaultTextStyle.style.copyWith( From fc4a39e9f3cba550f9fd06775b6bd40ee10ca09b Mon Sep 17 00:00:00 2001 From: Kingkor Roy Tirtho Date: Fri, 17 Nov 2023 13:44:00 +0600 Subject: [PATCH 025/195] chore: fix safearea of flexible header --- .../sections/header/flexible_header.dart | 103 +++++++++--------- 1 file changed, 53 insertions(+), 50 deletions(-) diff --git a/lib/components/shared/tracks_view/sections/header/flexible_header.dart b/lib/components/shared/tracks_view/sections/header/flexible_header.dart index 26c8a526..57089975 100644 --- a/lib/components/shared/tracks_view/sections/header/flexible_header.dart +++ b/lib/components/shared/tracks_view/sections/header/flexible_header.dart @@ -2,6 +2,7 @@ import 'dart:ui'; import 'package:cached_network_image/cached_network_image.dart'; import 'package:flutter/material.dart'; +import 'package:flutter_desktop_tools/flutter_desktop_tools.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:spotube/collections/assets.gen.dart'; import 'package:spotube/components/shared/image/universal_image.dart'; @@ -52,8 +53,8 @@ class TrackViewFlexHeader extends HookConsumerWidget { ], floating: false, pinned: true, - expandedHeight: 400, - automaticallyImplyLeading: false, + expandedHeight: 450, + automaticallyImplyLeading: DesktopTools.platform.isMobile, backgroundColor: palette.color, title: isExpanded ? null : Text(props.title, style: headingStyle), flexibleSpace: FlexibleSpaceBar( @@ -79,56 +80,58 @@ class TrackViewFlexHeader extends HookConsumerWidget { tileMode: TileMode.clamp, ), ), - child: Padding( - padding: const EdgeInsets.all(8.0), - child: Column( - mainAxisSize: MainAxisSize.min, - mainAxisAlignment: MainAxisAlignment.center, - crossAxisAlignment: CrossAxisAlignment.center, - children: [ - Flex( - direction: mediaQuery.mdAndDown - ? Axis.vertical - : Axis.horizontal, - mainAxisSize: MainAxisSize.min, - children: [ - ClipRRect( - borderRadius: BorderRadius.circular(10), - child: UniversalImage( - path: props.image, - width: 200, - height: 200, - placeholder: Assets.albumPlaceholder.path, + child: SafeArea( + child: Padding( + padding: const EdgeInsets.all(8.0), + child: Column( + mainAxisSize: MainAxisSize.min, + mainAxisAlignment: MainAxisAlignment.center, + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + Flex( + direction: mediaQuery.mdAndDown + ? Axis.vertical + : Axis.horizontal, + mainAxisSize: MainAxisSize.min, + children: [ + ClipRRect( + borderRadius: BorderRadius.circular(10), + child: UniversalImage( + path: props.image, + width: 200, + height: 200, + placeholder: Assets.albumPlaceholder.path, + ), ), - ), - const Gap(20), - Column( - mainAxisSize: MainAxisSize.min, - crossAxisAlignment: mediaQuery.mdAndDown - ? CrossAxisAlignment.center - : CrossAxisAlignment.start, - children: [ - Text(props.title, style: headingStyle), - const SizedBox(height: 10), - if (description != null && - description.isNotEmpty) - Text( - description, - style: defaultTextStyle.style.copyWith( - color: palette.bodyTextColor, + const Gap(20), + Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: mediaQuery.mdAndDown + ? CrossAxisAlignment.center + : CrossAxisAlignment.start, + children: [ + Text(props.title, style: headingStyle), + const SizedBox(height: 10), + if (description != null && + description.isNotEmpty) + Text( + description, + style: defaultTextStyle.style.copyWith( + color: palette.bodyTextColor, + ), + maxLines: 2, + overflow: TextOverflow.ellipsis, ), - maxLines: 2, - overflow: TextOverflow.ellipsis, - ), - const Gap(10), - const TrackViewHeaderActions(), - const Gap(10), - TrackViewHeaderButtons(color: palette), - ], - ), - ], - ), - ], + const Gap(10), + const TrackViewHeaderActions(), + const Gap(10), + TrackViewHeaderButtons(color: palette), + ], + ), + ], + ), + ], + ), ), ), ), From ed63032a8281fe4420db69c0d67b0e4b888fd265 Mon Sep 17 00:00:00 2001 From: Kingkor Roy Tirtho Date: Fri, 17 Nov 2023 22:41:40 +0600 Subject: [PATCH 026/195] cd: fix distutils not found for macos --- .github/workflows/spotube-release-binary.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/spotube-release-binary.yml b/.github/workflows/spotube-release-binary.yml index d461e296..ab42dcb9 100644 --- a/.github/workflows/spotube-release-binary.yml +++ b/.github/workflows/spotube-release-binary.yml @@ -319,6 +319,7 @@ jobs: - name: Package Macos App run: | + python3 -m pip install setuptools npm install -g appdmg mkdir -p build/${{ env.BUILD_VERSION }} appdmg appdmg.json build/Spotube-macos-universal.dmg From 03b5f08102a0837cd41bc52fe200aa15c339236a Mon Sep 17 00:00:00 2001 From: Kingkor Roy Tirtho Date: Tue, 21 Nov 2023 20:03:22 +0600 Subject: [PATCH 027/195] chore: remove supabase dep --- .circleci/config.yml | 2 - .env.example | 3 - lib/collections/env.dart | 6 - .../proxy_playlist/next_fetcher_mixin.dart | 22 ---- .../proxy_playlist_provider.dart | 30 ----- lib/services/supabase.dart | 16 --- pubspec.lock | 106 +++--------------- pubspec.yaml | 1 - windows/flutter/CMakeLists.txt | 7 +- 9 files changed, 23 insertions(+), 170 deletions(-) delete mode 100644 lib/services/supabase.dart diff --git a/.circleci/config.yml b/.circleci/config.yml index a5c71033..a55310ce 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -82,8 +82,6 @@ jobs: name: Generate .env file command: | echo "SPOTIFY_SECRETS=${SPOTIFY_SECRETS}" >> .env - echo "SUPABASE_URL=${SUPABASE_URL}" >> .env - echo "SUPABASE_API_KEY=${SUPABASE_API_KEY}" >> .env - run: name: Replace Version in files diff --git a/.env.example b/.env.example index 67d1be8e..22abd24b 100644 --- a/.env.example +++ b/.env.example @@ -1,6 +1,3 @@ -SUPABASE_URL= -SUPABASE_API_KEY= - # The format: # SPOTIFY_SECRETS=clintId1:clientSecret1,clientId2:clientSecret2 SPOTIFY_SECRETS= diff --git a/lib/collections/env.dart b/lib/collections/env.dart index 1b9de3de..3923435b 100644 --- a/lib/collections/env.dart +++ b/lib/collections/env.dart @@ -4,12 +4,6 @@ part 'env.g.dart'; @Envied(obfuscate: true, requireEnvFile: true, path: ".env") abstract class Env { - @EnviedField(varName: 'SUPABASE_URL') - static final String? supabaseUrl = _Env.supabaseUrl; - - @EnviedField(varName: 'SUPABASE_API_KEY') - static final String? supabaseAnonKey = _Env.supabaseAnonKey; - @EnviedField(varName: 'SPOTIFY_SECRETS') static final String rawSpotifySecrets = _Env.rawSpotifySecrets; diff --git a/lib/provider/proxy_playlist/next_fetcher_mixin.dart b/lib/provider/proxy_playlist/next_fetcher_mixin.dart index 61b86d8c..fa7fdfe8 100644 --- a/lib/provider/proxy_playlist/next_fetcher_mixin.dart +++ b/lib/provider/proxy_playlist/next_fetcher_mixin.dart @@ -1,14 +1,11 @@ import 'package:collection/collection.dart'; -import 'package:flutter/foundation.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:spotify/spotify.dart'; import 'package:spotube/models/local_track.dart'; import 'package:spotube/models/logger.dart'; -import 'package:spotube/models/matched_track.dart'; import 'package:spotube/models/spotube_track.dart'; import 'package:spotube/provider/proxy_playlist/proxy_playlist.dart'; import 'package:spotube/provider/user_preferences_provider.dart'; -import 'package:spotube/services/supabase.dart'; import 'package:spotube/services/youtube/youtube.dart'; final logger = getLogger("NextFetcherMixin"); @@ -112,23 +109,4 @@ mixin NextFetcher on StateNotifier { .whereNotNull() .toList(); } - - /// This method must be called after any playback operation as - /// it can increase the latency - Future storeTrack(Track track, SpotubeTrack spotubeTrack) async { - try { - if (track is! SpotubeTrack) { - await supabase.insertTrack( - MatchedTrack( - youtubeId: spotubeTrack.ytTrack.id, - spotifyId: spotubeTrack.id!, - searchMode: spotubeTrack.ytTrack.searchMode, - ), - ); - } - } catch (e, stackTrace) { - logger.e(e.toString()); - logger.t(stackTrace); - } - } } diff --git a/lib/provider/proxy_playlist/proxy_playlist_provider.dart b/lib/provider/proxy_playlist/proxy_playlist_provider.dart index 685a9942..69537979 100644 --- a/lib/provider/proxy_playlist/proxy_playlist_provider.dart +++ b/lib/provider/proxy_playlist/proxy_playlist_provider.dart @@ -138,13 +138,6 @@ class ProxyPlaylistNotifier extends PersistedStateNotifier if (track != null) { state = state.copyWith(tracks: mergeTracks([track], state.tracks)); } - - if (oldTrack != null && track != null) { - await storeTrack( - oldTrack, - track, - ); - } } catch (e, stackTrace) { // Removing tracks that were not found to avoid queue interruption // TODO: Add a flag to enable/disable skip not found tracks @@ -332,10 +325,6 @@ class ProxyPlaylistNotifier extends PersistedStateNotifier collections: {}, ); await notificationService.addTrack(addableTrack); - await storeTrack( - tracks.elementAt(initialIndex), - addableTrack, - ); } await audioPlayer.openPlaylist( @@ -365,13 +354,6 @@ class ProxyPlaylistNotifier extends PersistedStateNotifier if (oldTrack != null || track != null) { await notificationService.addTrack(track ?? oldTrack!); } - - if (oldTrack != null && track != null) { - await storeTrack( - oldTrack, - track, - ); - } } Future jumpToTrack(Track track) async { @@ -474,12 +456,6 @@ class ProxyPlaylistNotifier extends PersistedStateNotifier if (oldTrack != null || track != null) { await notificationService.addTrack(track ?? oldTrack!); } - if (oldTrack != null && track != null) { - await storeTrack( - oldTrack, - track, - ); - } } Future previous() async { @@ -505,12 +481,6 @@ class ProxyPlaylistNotifier extends PersistedStateNotifier if (oldTrack != null || track != null) { await notificationService.addTrack(track ?? oldTrack!); } - if (oldTrack != null && track != null) { - await storeTrack( - oldTrack, - track, - ); - } } Future stop() async { diff --git a/lib/services/supabase.dart b/lib/services/supabase.dart deleted file mode 100644 index d42d8eeb..00000000 --- a/lib/services/supabase.dart +++ /dev/null @@ -1,16 +0,0 @@ -import 'package:spotube/collections/env.dart'; -import 'package:spotube/models/matched_track.dart'; -import 'package:supabase/supabase.dart'; - -class SupabaseService { - static final api = SupabaseClient( - Env.supabaseUrl ?? "", - Env.supabaseAnonKey ?? "", - ); - - Future insertTrack(MatchedTrack track) async { - await api.from("tracks").insert(track.toJson()); - } -} - -final supabase = SupabaseService(); diff --git a/pubspec.lock b/pubspec.lock index 3dbc3cbf..093a133b 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -325,10 +325,10 @@ packages: dependency: "direct main" description: name: collection - sha256: f092b211a4319e98e5ff58223576de6c2803db36221657b46c82574721240687 + sha256: ee67cb0715911d28db6bf4af1026078bd6f0128b07a5f66fb2ed94ec6783c09a url: "https://pub.dev" source: hosted - version: "1.17.2" + version: "1.18.0" color: dependency: transitive description: @@ -931,14 +931,6 @@ packages: description: flutter source: sdk version: "0.0.0" - functions_client: - dependency: transitive - description: - name: functions_client - sha256: "3b157b4d3ae9e38614fd80fab76d1ef1e0e39ff3412a45de2651f27cecb9d2d2" - url: "https://pub.dev" - source: hosted - version: "1.3.2" fuzzywuzzy: dependency: "direct main" description: @@ -971,14 +963,6 @@ packages: url: "https://pub.dev" source: hosted version: "5.1.0" - gotrue: - dependency: transitive - description: - name: gotrue - sha256: af61c5c6a2374d9032b7e4b388de0bb0442f4bedc56372d5382c1ef61c85f1f3 - url: "https://pub.dev" - source: hosted - version: "1.12.1" graphs: dependency: transitive description: @@ -1192,14 +1176,6 @@ packages: url: "https://pub.dev" source: hosted version: "0.4.2" - jwt_decode: - dependency: transitive - description: - name: jwt_decode - sha256: d2e9f68c052b2225130977429d30f187aa1981d789c76ad104a32243cfdebfbb - url: "https://pub.dev" - source: hosted - version: "0.3.1" lints: dependency: transitive description: @@ -1324,10 +1300,10 @@ packages: dependency: transitive description: name: meta - sha256: "3c74dbf8763d36539f114c799d8a2d87343b5067e9d796ca22b5eb8437090ee3" + sha256: a6e590c838b18133bb482a2745ad77c5bb7715fb0451209e1a7567d416678b8e url: "https://pub.dev" source: hosted - version: "1.9.1" + version: "1.10.0" metadata_god: dependency: "direct main" description: @@ -1540,10 +1516,10 @@ packages: dependency: transitive description: name: platform - sha256: "4a451831508d7d6ca779f7ac6e212b4023dd5a7d08a27a63da33756410e32b76" + sha256: ae68c7bfcd7383af3629daafb32fb4e8681c7154428da4febcff06200585f102 url: "https://pub.dev" source: hosted - version: "3.1.0" + version: "3.1.2" plugin_platform_interface: dependency: transitive description: @@ -1576,14 +1552,6 @@ packages: url: "https://pub.dev" source: hosted version: "0.2.8+2" - postgrest: - dependency: transitive - description: - name: postgrest - sha256: d6cc0f60c7dc761f84d1c6d11d9e02b3ad90399bd84639a28c1c024adbaa9bde - url: "https://pub.dev" - source: hosted - version: "1.5.0" process: dependency: transitive description: @@ -1648,22 +1616,6 @@ packages: url: "https://pub.dev" source: hosted version: "3.2.1" - realtime_client: - dependency: transitive - description: - name: realtime_client - sha256: b4b7bb293417dafc73943ed639209b2dcb796db8495e56bba29a4e26fadef5cd - url: "https://pub.dev" - source: hosted - version: "1.2.1" - retry: - dependency: transitive - description: - name: retry - sha256: "822e118d5b3aafed083109c72d5f484c6dc66707885e07c0fbcb8b986bba7efc" - url: "https://pub.dev" - source: hosted - version: "3.1.2" riverpod: dependency: transitive description: @@ -1890,10 +1842,10 @@ packages: dependency: transitive description: name: stack_trace - sha256: c3c7d8edb15bee7f0f74debd4b9c5f3c2ea86766fe4178eb2a18eb30a0bdaed5 + sha256: "73713990125a6d93122541237550ee3352a2d84baad52d375a4cad2eb9b7ce0b" url: "https://pub.dev" source: hosted - version: "1.11.0" + version: "1.11.1" state_notifier: dependency: transitive description: @@ -1902,22 +1854,14 @@ packages: url: "https://pub.dev" source: hosted version: "0.7.2+1" - storage_client: - dependency: transitive - description: - name: storage_client - sha256: "4bf2fc76f09c3698f0ba3f1a44d567995796f6aef76501f194631d0c03752ab7" - url: "https://pub.dev" - source: hosted - version: "1.5.2" stream_channel: dependency: transitive description: name: stream_channel - sha256: "83615bee9045c1d322bbbd1ba209b7a749c2cbcdcb3fdd1df8eb488b3279c1c8" + sha256: ba2aa5d8cc609d96bbb2899c28934f9e1af5cddbd60a827822ea467161eb54e7 url: "https://pub.dev" source: hosted - version: "2.1.1" + version: "2.1.2" stream_transform: dependency: transitive description: @@ -1942,14 +1886,6 @@ packages: url: "https://pub.dev" source: hosted version: "0.0.2" - supabase: - dependency: "direct main" - description: - name: supabase - sha256: "4bfa8f673b39c036ed82829a2ddc462dcacfc36fe168b680664ab954c7d91ccd" - url: "https://pub.dev" - source: hosted - version: "1.11.3" sync_http: dependency: transitive description: @@ -2002,10 +1938,10 @@ packages: dependency: transitive description: name: test_api - sha256: "75760ffd7786fffdfb9597c35c5b27eaeec82be8edfb6d71d32651128ed7aab8" + sha256: "5c2f730018264d276c20e4f1503fd1308dfbbae39ec8ee63c5236311ac06954b" url: "https://pub.dev" source: hosted - version: "0.6.0" + version: "0.6.1" time: dependency: transitive description: @@ -2178,10 +2114,10 @@ packages: dependency: transitive description: name: vm_service - sha256: c620a6f783fa22436da68e42db7ebbf18b8c44b9a46ab911f666ff09ffd9153f + sha256: c538be99af830f478718b51630ec1b6bee5e74e52c8a802d328d9e71d35d2583 url: "https://pub.dev" source: hosted - version: "11.7.1" + version: "11.10.0" watcher: dependency: transitive description: @@ -2194,10 +2130,10 @@ packages: dependency: transitive description: name: web - sha256: dc8ccd225a2005c1be616fe02951e2e342092edf968cf0844220383757ef8f10 + sha256: afe077240a270dcfd2aafe77602b4113645af95d0ad31128cc02bce5ac5d5152 url: "https://pub.dev" source: hosted - version: "0.1.4-beta" + version: "0.3.0" web_socket_channel: dependency: transitive description: @@ -2271,14 +2207,6 @@ packages: url: "https://pub.dev" source: hosted version: "3.1.2" - yet_another_json_isolate: - dependency: transitive - description: - name: yet_another_json_isolate - sha256: "86fad76026c4241a32831d6c7febd8f9bded5019e2cd36c5b148499808d8307d" - url: "https://pub.dev" - source: hosted - version: "1.1.1" youtube_explode_dart: dependency: "direct main" description: @@ -2288,5 +2216,5 @@ packages: source: hosted version: "2.0.2" sdks: - dart: ">=3.1.0 <4.0.0" + dart: ">=3.2.0-194.0.dev <4.0.0" flutter: ">=3.13.0" diff --git a/pubspec.yaml b/pubspec.yaml index 04f2d8b8..f8e36ada 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -98,7 +98,6 @@ dependencies: smtc_windows: ^0.1.1 spotify: ^0.12.0 stroke_text: ^0.0.2 - supabase: ^1.9.9 system_theme: ^2.1.0 titlebar_buttons: ^1.0.0 url_launcher: ^6.1.7 diff --git a/windows/flutter/CMakeLists.txt b/windows/flutter/CMakeLists.txt index b2e4bd8d..4f2af69b 100644 --- a/windows/flutter/CMakeLists.txt +++ b/windows/flutter/CMakeLists.txt @@ -9,6 +9,11 @@ include(${EPHEMERAL_DIR}/generated_config.cmake) # https://github.com/flutter/flutter/issues/57146. set(WRAPPER_ROOT "${EPHEMERAL_DIR}/cpp_client_wrapper") +# Set fallback configurations for older versions of the flutter tool. +if (NOT DEFINED FLUTTER_TARGET_PLATFORM) + set(FLUTTER_TARGET_PLATFORM "windows-x64") +endif() + # === Flutter Library === set(FLUTTER_LIBRARY "${EPHEMERAL_DIR}/flutter_windows.dll") @@ -91,7 +96,7 @@ add_custom_command( COMMAND ${CMAKE_COMMAND} -E env ${FLUTTER_TOOL_ENVIRONMENT} "${FLUTTER_ROOT}/packages/flutter_tools/bin/tool_backend.bat" - windows-x64 $ + ${FLUTTER_TARGET_PLATFORM} $ VERBATIM ) add_custom_target(flutter_assemble DEPENDS From 75c0c4fff4352531827ecaf4b8c4ac6cb44fd149 Mon Sep 17 00:00:00 2001 From: Kingkor Roy Tirtho Date: Tue, 21 Nov 2023 20:11:08 +0600 Subject: [PATCH 028/195] Merge branch 'master' into dev --- .circleci/config.yml | 2 - .env.example | 3 - README.md | 2 +- lib/collections/env.dart | 6 - .../proxy_playlist_provider.dart | 59 ---------- lib/services/supabase.dart | 18 --- pubspec.lock | 106 +++--------------- pubspec.yaml | 1 - windows/flutter/CMakeLists.txt | 7 +- 9 files changed, 24 insertions(+), 180 deletions(-) delete mode 100644 lib/services/supabase.dart diff --git a/.circleci/config.yml b/.circleci/config.yml index a5c71033..a55310ce 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -82,8 +82,6 @@ jobs: name: Generate .env file command: | echo "SPOTIFY_SECRETS=${SPOTIFY_SECRETS}" >> .env - echo "SUPABASE_URL=${SUPABASE_URL}" >> .env - echo "SUPABASE_API_KEY=${SUPABASE_API_KEY}" >> .env - run: name: Replace Version in files diff --git a/.env.example b/.env.example index 67d1be8e..22abd24b 100644 --- a/.env.example +++ b/.env.example @@ -1,6 +1,3 @@ -SUPABASE_URL= -SUPABASE_API_KEY= - # The format: # SPOTIFY_SECRETS=clintId1:clientSecret1,clientId2:clientSecret2 SPOTIFY_SECRETS= diff --git a/README.md b/README.md index 71589794..d82af783 100644 --- a/README.md +++ b/README.md @@ -108,7 +108,7 @@ This handy table lists all methods you can use to install Spotube: Debian/Ubuntu Download -

Then run: sudo apt install Spotube-linux-x86_64.deb

+

Then run: sudo apt install ./Spotube-linux-x86_64.deb

diff --git a/lib/collections/env.dart b/lib/collections/env.dart index 8086ada7..28941201 100644 --- a/lib/collections/env.dart +++ b/lib/collections/env.dart @@ -5,12 +5,6 @@ part 'env.g.dart'; @Envied(obfuscate: true, requireEnvFile: true, path: ".env") abstract class Env { - @EnviedField(varName: 'SUPABASE_URL') - static final String? supabaseUrl = _Env.supabaseUrl; - - @EnviedField(varName: 'SUPABASE_API_KEY') - static final String? supabaseAnonKey = _Env.supabaseAnonKey; - @EnviedField(varName: 'SPOTIFY_SECRETS') static final String rawSpotifySecrets = _Env.rawSpotifySecrets; diff --git a/lib/provider/proxy_playlist/proxy_playlist_provider.dart b/lib/provider/proxy_playlist/proxy_playlist_provider.dart index bd3934a7..258f1d9e 100644 --- a/lib/provider/proxy_playlist/proxy_playlist_provider.dart +++ b/lib/provider/proxy_playlist/proxy_playlist_provider.dart @@ -14,7 +14,6 @@ import 'package:spotube/models/local_track.dart'; import 'package:spotube/models/logger.dart'; import 'package:spotube/models/skip_segment.dart'; -import 'package:spotube/models/source_match.dart'; import 'package:spotube/provider/blacklist_provider.dart'; import 'package:spotube/provider/palette_provider.dart'; @@ -28,7 +27,6 @@ import 'package:spotube/services/audio_services/audio_services.dart'; import 'package:spotube/services/sourced_track/exceptions.dart'; import 'package:spotube/services/sourced_track/models/source_info.dart'; import 'package:spotube/services/sourced_track/sourced_track.dart'; -import 'package:spotube/services/supabase.dart'; import 'package:spotube/utils/persisted_state_notifier.dart'; import 'package:spotube/utils/type_conversion_utils.dart'; @@ -134,21 +132,11 @@ class ProxyPlaylistNotifier extends PersistedStateNotifier try { isPreSearching.value = true; - final oldTrack = - mapSourcesToTracks([audioPlayer.nextSource!]).firstOrNull; - final track = await ensureSourcePlayable(audioPlayer.nextSource!); if (track != null) { state = state.copyWith(tracks: mergeTracks([track], state.tracks)); } - - if (oldTrack != null && track != null) { - await storeTrack( - oldTrack, - track, - ); - } } catch (e, stackTrace) { // Removing tracks that were not found to avoid queue interruption // TODO: Add a flag to enable/disable skip not found tracks @@ -350,10 +338,6 @@ class ProxyPlaylistNotifier extends PersistedStateNotifier collections: {}, ); await notificationService.addTrack(addableTrack); - await storeTrack( - tracks.elementAt(initialIndex), - addableTrack, - ); } await audioPlayer.openPlaylist( @@ -383,13 +367,6 @@ class ProxyPlaylistNotifier extends PersistedStateNotifier if (oldTrack != null || track != null) { await notificationService.addTrack(track ?? oldTrack!); } - - if (oldTrack != null && track != null) { - await storeTrack( - oldTrack, - track, - ); - } } Future jumpToTrack(Track track) async { @@ -492,12 +469,6 @@ class ProxyPlaylistNotifier extends PersistedStateNotifier if (oldTrack != null || track != null) { await notificationService.addTrack(track ?? oldTrack!); } - if (oldTrack != null && track != null) { - await storeTrack( - oldTrack, - track, - ); - } } Future previous() async { @@ -523,12 +494,6 @@ class ProxyPlaylistNotifier extends PersistedStateNotifier if (oldTrack != null || track != null) { await notificationService.addTrack(track ?? oldTrack!); } - if (oldTrack != null && track != null) { - await storeTrack( - oldTrack, - track, - ); - } } Future stop() async { @@ -625,30 +590,6 @@ class ProxyPlaylistNotifier extends PersistedStateNotifier } } - /// This method must be called after any playback operation as - /// it can increase the latency - Future storeTrack(Track track, SourcedTrack sourcedTrack) async { - try { - if (track is! SourcedTrack) { - await supabase.insertTrack( - SourceMatch( - id: sourcedTrack.id!, - createdAt: DateTime.now(), - sourceId: sourcedTrack.sourceInfo.id, - sourceType: preferences.audioSource == AudioSource.jiosaavn - ? SourceType.jiosaavn - : preferences.searchMode == SearchMode.youtube - ? SourceType.youtube - : SourceType.youtubeMusic, - ), - ); - } - } catch (e, stackTrace) { - logger.e(e.toString()); - logger.t(stackTrace); - } - } - @override set state(state) { super.state = state; diff --git a/lib/services/supabase.dart b/lib/services/supabase.dart deleted file mode 100644 index ef3fa87c..00000000 --- a/lib/services/supabase.dart +++ /dev/null @@ -1,18 +0,0 @@ -import 'package:spotube/collections/env.dart'; -import 'package:spotube/models/source_match.dart'; -import 'package:supabase/supabase.dart'; - -class SupabaseService { - static final api = SupabaseClient( - Env.supabaseUrl ?? "", - Env.supabaseAnonKey ?? "", - ); - - Future insertTrack(SourceMatch track) async { - return null; - // TODO: Fix this - await api.from("tracks").insert(track.toJson()); - } -} - -final supabase = SupabaseService(); diff --git a/pubspec.lock b/pubspec.lock index 2a8dbb71..8826c439 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -325,10 +325,10 @@ packages: dependency: "direct main" description: name: collection - sha256: f092b211a4319e98e5ff58223576de6c2803db36221657b46c82574721240687 + sha256: ee67cb0715911d28db6bf4af1026078bd6f0128b07a5f66fb2ed94ec6783c09a url: "https://pub.dev" source: hosted - version: "1.17.2" + version: "1.18.0" color: dependency: transitive description: @@ -953,14 +953,6 @@ packages: description: flutter source: sdk version: "0.0.0" - functions_client: - dependency: transitive - description: - name: functions_client - sha256: "3b157b4d3ae9e38614fd80fab76d1ef1e0e39ff3412a45de2651f27cecb9d2d2" - url: "https://pub.dev" - source: hosted - version: "1.3.2" fuzzywuzzy: dependency: "direct main" description: @@ -1001,14 +993,6 @@ packages: url: "https://pub.dev" source: hosted version: "5.1.0" - gotrue: - dependency: transitive - description: - name: gotrue - sha256: af61c5c6a2374d9032b7e4b388de0bb0442f4bedc56372d5382c1ef61c85f1f3 - url: "https://pub.dev" - source: hosted - version: "1.12.1" graphs: dependency: transitive description: @@ -1231,14 +1215,6 @@ packages: url: "https://pub.dev" source: hosted version: "0.4.2" - jwt_decode: - dependency: transitive - description: - name: jwt_decode - sha256: d2e9f68c052b2225130977429d30f187aa1981d789c76ad104a32243cfdebfbb - url: "https://pub.dev" - source: hosted - version: "0.3.1" lints: dependency: transitive description: @@ -1363,10 +1339,10 @@ packages: dependency: transitive description: name: meta - sha256: "3c74dbf8763d36539f114c799d8a2d87343b5067e9d796ca22b5eb8437090ee3" + sha256: a6e590c838b18133bb482a2745ad77c5bb7715fb0451209e1a7567d416678b8e url: "https://pub.dev" source: hosted - version: "1.9.1" + version: "1.10.0" metadata_god: dependency: "direct main" description: @@ -1579,10 +1555,10 @@ packages: dependency: transitive description: name: platform - sha256: "4a451831508d7d6ca779f7ac6e212b4023dd5a7d08a27a63da33756410e32b76" + sha256: ae68c7bfcd7383af3629daafb32fb4e8681c7154428da4febcff06200585f102 url: "https://pub.dev" source: hosted - version: "3.1.0" + version: "3.1.2" plugin_platform_interface: dependency: transitive description: @@ -1615,14 +1591,6 @@ packages: url: "https://pub.dev" source: hosted version: "0.2.8+2" - postgrest: - dependency: transitive - description: - name: postgrest - sha256: d6cc0f60c7dc761f84d1c6d11d9e02b3ad90399bd84639a28c1c024adbaa9bde - url: "https://pub.dev" - source: hosted - version: "1.5.0" process: dependency: transitive description: @@ -1687,22 +1655,6 @@ packages: url: "https://pub.dev" source: hosted version: "3.2.1" - realtime_client: - dependency: transitive - description: - name: realtime_client - sha256: b4b7bb293417dafc73943ed639209b2dcb796db8495e56bba29a4e26fadef5cd - url: "https://pub.dev" - source: hosted - version: "1.2.1" - retry: - dependency: transitive - description: - name: retry - sha256: "822e118d5b3aafed083109c72d5f484c6dc66707885e07c0fbcb8b986bba7efc" - url: "https://pub.dev" - source: hosted - version: "3.1.2" riverpod: dependency: transitive description: @@ -1937,10 +1889,10 @@ packages: dependency: transitive description: name: stack_trace - sha256: c3c7d8edb15bee7f0f74debd4b9c5f3c2ea86766fe4178eb2a18eb30a0bdaed5 + sha256: "73713990125a6d93122541237550ee3352a2d84baad52d375a4cad2eb9b7ce0b" url: "https://pub.dev" source: hosted - version: "1.11.0" + version: "1.11.1" state_notifier: dependency: transitive description: @@ -1949,22 +1901,14 @@ packages: url: "https://pub.dev" source: hosted version: "0.7.2+1" - storage_client: - dependency: transitive - description: - name: storage_client - sha256: "4bf2fc76f09c3698f0ba3f1a44d567995796f6aef76501f194631d0c03752ab7" - url: "https://pub.dev" - source: hosted - version: "1.5.2" stream_channel: dependency: transitive description: name: stream_channel - sha256: "83615bee9045c1d322bbbd1ba209b7a749c2cbcdcb3fdd1df8eb488b3279c1c8" + sha256: ba2aa5d8cc609d96bbb2899c28934f9e1af5cddbd60a827822ea467161eb54e7 url: "https://pub.dev" source: hosted - version: "2.1.1" + version: "2.1.2" stream_transform: dependency: transitive description: @@ -1989,14 +1933,6 @@ packages: url: "https://pub.dev" source: hosted version: "0.0.2" - supabase: - dependency: "direct main" - description: - name: supabase - sha256: "4bfa8f673b39c036ed82829a2ddc462dcacfc36fe168b680664ab954c7d91ccd" - url: "https://pub.dev" - source: hosted - version: "1.11.3" sync_http: dependency: transitive description: @@ -2049,10 +1985,10 @@ packages: dependency: transitive description: name: test_api - sha256: "75760ffd7786fffdfb9597c35c5b27eaeec82be8edfb6d71d32651128ed7aab8" + sha256: "5c2f730018264d276c20e4f1503fd1308dfbbae39ec8ee63c5236311ac06954b" url: "https://pub.dev" source: hosted - version: "0.6.0" + version: "0.6.1" time: dependency: transitive description: @@ -2233,10 +2169,10 @@ packages: dependency: transitive description: name: vm_service - sha256: c620a6f783fa22436da68e42db7ebbf18b8c44b9a46ab911f666ff09ffd9153f + sha256: c538be99af830f478718b51630ec1b6bee5e74e52c8a802d328d9e71d35d2583 url: "https://pub.dev" source: hosted - version: "11.7.1" + version: "11.10.0" watcher: dependency: transitive description: @@ -2249,10 +2185,10 @@ packages: dependency: transitive description: name: web - sha256: dc8ccd225a2005c1be616fe02951e2e342092edf968cf0844220383757ef8f10 + sha256: afe077240a270dcfd2aafe77602b4113645af95d0ad31128cc02bce5ac5d5152 url: "https://pub.dev" source: hosted - version: "0.1.4-beta" + version: "0.3.0" web_socket_channel: dependency: transitive description: @@ -2326,14 +2262,6 @@ packages: url: "https://pub.dev" source: hosted version: "3.1.2" - yet_another_json_isolate: - dependency: transitive - description: - name: yet_another_json_isolate - sha256: "86fad76026c4241a32831d6c7febd8f9bded5019e2cd36c5b148499808d8307d" - url: "https://pub.dev" - source: hosted - version: "1.1.1" youtube_explode_dart: dependency: "direct main" description: @@ -2343,5 +2271,5 @@ packages: source: hosted version: "2.0.2" sdks: - dart: ">=3.1.0 <4.0.0" + dart: ">=3.2.0-194.0.dev <4.0.0" flutter: ">=3.13.0" diff --git a/pubspec.yaml b/pubspec.yaml index 4d31085c..5a88c39a 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -89,7 +89,6 @@ dependencies: smtc_windows: ^0.1.1 spotify: ^0.12.0 stroke_text: ^0.0.2 - supabase: ^1.9.9 system_theme: ^2.1.0 titlebar_buttons: ^1.0.0 url_launcher: ^6.1.7 diff --git a/windows/flutter/CMakeLists.txt b/windows/flutter/CMakeLists.txt index b2e4bd8d..4f2af69b 100644 --- a/windows/flutter/CMakeLists.txt +++ b/windows/flutter/CMakeLists.txt @@ -9,6 +9,11 @@ include(${EPHEMERAL_DIR}/generated_config.cmake) # https://github.com/flutter/flutter/issues/57146. set(WRAPPER_ROOT "${EPHEMERAL_DIR}/cpp_client_wrapper") +# Set fallback configurations for older versions of the flutter tool. +if (NOT DEFINED FLUTTER_TARGET_PLATFORM) + set(FLUTTER_TARGET_PLATFORM "windows-x64") +endif() + # === Flutter Library === set(FLUTTER_LIBRARY "${EPHEMERAL_DIR}/flutter_windows.dll") @@ -91,7 +96,7 @@ add_custom_command( COMMAND ${CMAKE_COMMAND} -E env ${FLUTTER_TOOL_ENVIRONMENT} "${FLUTTER_ROOT}/packages/flutter_tools/bin/tool_backend.bat" - windows-x64 $ + ${FLUTTER_TARGET_PLATFORM} $ VERBATIM ) add_custom_target(flutter_assemble DEPENDS From 7818574356d0fb8ff567e1f6a83fd0b6f2ee7c8a Mon Sep 17 00:00:00 2001 From: Kingkor Roy Tirtho Date: Tue, 21 Nov 2023 21:23:08 +0600 Subject: [PATCH 029/195] fix(windows): media control not working #641 --- lib/services/audio_services/windows_audio_service.dart | 2 -- 1 file changed, 2 deletions(-) diff --git a/lib/services/audio_services/windows_audio_service.dart b/lib/services/audio_services/windows_audio_service.dart index 4481140b..fde88145 100644 --- a/lib/services/audio_services/windows_audio_service.dart +++ b/lib/services/audio_services/windows_audio_service.dart @@ -51,11 +51,9 @@ class WindowsAudioService { break; case AudioPlaybackState.stopped: await smtc.setPlaybackStatus(PlaybackStatus.Stopped); - await smtc.disableSmtc(); break; case AudioPlaybackState.completed: await smtc.setPlaybackStatus(PlaybackStatus.Changing); - await smtc.disableSmtc(); break; default: break; From dcbb1568337969841acc0abe0e7185ee5e4c3590 Mon Sep 17 00:00:00 2001 From: Kingkor Roy Tirtho Date: Tue, 21 Nov 2023 22:56:45 +0600 Subject: [PATCH 030/195] feat(mini_player): show/hide lyrics #851 --- lib/collections/spotube_icons.dart | 1 + lib/pages/lyrics/mini_lyrics.dart | 83 +++++++++++++++++++---------- lib/pages/lyrics/synced_lyrics.dart | 2 +- 3 files changed, 57 insertions(+), 29 deletions(-) diff --git a/lib/collections/spotube_icons.dart b/lib/collections/spotube_icons.dart index 5c769498..78cbb52c 100644 --- a/lib/collections/spotube_icons.dart +++ b/lib/collections/spotube_icons.dart @@ -40,6 +40,7 @@ abstract class SpotubeIcons { static const trash = FeatherIcons.trash2; static const clock = FeatherIcons.clock; static const lyrics = Icons.lyrics_rounded; + static const lyricsOff = Icons.lyrics_outlined; static const logout = FeatherIcons.logOut; static const login = FeatherIcons.logIn; static const dashboard = FeatherIcons.grid; diff --git a/lib/pages/lyrics/mini_lyrics.dart b/lib/pages/lyrics/mini_lyrics.dart index be32dbc9..2cf73728 100644 --- a/lib/pages/lyrics/mini_lyrics.dart +++ b/lib/pages/lyrics/mini_lyrics.dart @@ -1,6 +1,7 @@ import 'package:flutter/material.dart'; import 'package:flutter_desktop_tools/flutter_desktop_tools.dart'; import 'package:flutter_hooks/flutter_hooks.dart'; +import 'package:gap/gap.dart'; import 'package:go_router/go_router.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:palette_generator/palette_generator.dart'; @@ -32,6 +33,7 @@ class MiniLyricsPage extends HookConsumerWidget { final areaActive = useState(false); final hoverMode = useState(true); + final showLyrics = useState(true); useEffect(() { WidgetsBinding.instance.addPostFrameCallback((_) async { @@ -82,17 +84,41 @@ class MiniLyricsPage extends HookConsumerWidget { child: Sidebar.brandLogo(), ), const Spacer(), - SizedBox( - height: 30, - child: TabBar( - tabs: [ - Tab(text: context.l10n.synced), - Tab(text: context.l10n.plain), - ], - isScrollable: true, + if (showLyrics.value) + SizedBox( + height: 30, + child: TabBar( + tabs: [ + Tab(text: context.l10n.synced), + Tab(text: context.l10n.plain), + ], + isScrollable: true, + ), ), - ), const Spacer(), + IconButton( + tooltip: context.l10n.lyrics, + icon: showLyrics.value + ? const Icon(SpotubeIcons.lyrics) + : const Icon(SpotubeIcons.lyricsOff), + style: ButtonStyle( + foregroundColor: showLyrics.value + ? MaterialStateProperty.all( + theme.colorScheme.primary) + : null, + ), + onPressed: () async { + showLyrics.value = !showLyrics.value; + areaActive.value = true; + hoverMode.value = false; + + await DesktopTools.window.setSize( + showLyrics.value + ? const Size(400, 500) + : const Size(400, 150), + ); + }, + ), IconButton( tooltip: context.l10n.show_hide_ui_on_hover, icon: hoverMode.value @@ -105,9 +131,7 @@ class MiniLyricsPage extends HookConsumerWidget { : null, ), onPressed: () async { - if (!hoverMode.value == true) { - areaActive.value = true; - } + areaActive.value = true; hoverMode.value = !hoverMode.value; }, ), @@ -150,22 +174,25 @@ class MiniLyricsPage extends HookConsumerWidget { playlistQueue.activeTrack!.name!, style: theme.textTheme.titleMedium, ), - Expanded( - child: TabBarView( - children: [ - SyncedLyrics( - palette: PaletteColor(theme.colorScheme.background, 0), - isModal: true, - defaultTextZoom: 65, - ), - PlainLyrics( - palette: PaletteColor(theme.colorScheme.background, 0), - isModal: true, - defaultTextZoom: 65, - ), - ], - ), - ), + if (showLyrics.value) + Expanded( + child: TabBarView( + children: [ + SyncedLyrics( + palette: PaletteColor(theme.colorScheme.background, 0), + isModal: true, + defaultTextZoom: 65, + ), + PlainLyrics( + palette: PaletteColor(theme.colorScheme.background, 0), + isModal: true, + defaultTextZoom: 65, + ), + ], + ), + ) + else + const Gap(20), AnimatedCrossFade( crossFadeState: areaActive.value ? CrossFadeState.showFirst diff --git a/lib/pages/lyrics/synced_lyrics.dart b/lib/pages/lyrics/synced_lyrics.dart index 8147915f..36a9f316 100644 --- a/lib/pages/lyrics/synced_lyrics.dart +++ b/lib/pages/lyrics/synced_lyrics.dart @@ -112,7 +112,7 @@ class SyncedLyrics extends HookConsumerWidget { final lyricSlice = lyricValue.lyrics[index]; final isActive = lyricSlice.time.inSeconds == currentTime; - if (isActive && isUnSyncLyric == true) { + if (isActive) { controller.scrollToIndex( index, preferPosition: AutoScrollPosition.middle, From 98aff8f3b94af6d1d3137df8aee36b9e8d5007f9 Mon Sep 17 00:00:00 2001 From: Kingkor Roy Tirtho Date: Tue, 21 Nov 2023 23:13:57 +0600 Subject: [PATCH 031/195] chore: fix jiosaavn exact match --- lib/services/sourced_track/sourced_track.dart | 1 - .../sourced_track/sources/jiosaavn.dart | 19 ++++++++++++++++++- 2 files changed, 18 insertions(+), 2 deletions(-) diff --git a/lib/services/sourced_track/sourced_track.dart b/lib/services/sourced_track/sourced_track.dart index d2dd6f59..3ceafbf7 100644 --- a/lib/services/sourced_track/sourced_track.dart +++ b/lib/services/sourced_track/sourced_track.dart @@ -113,7 +113,6 @@ abstract class SourcedTrack extends Track { await JioSaavnSourcedTrack.fetchFromTrack(track: track, ref: ref), }; } catch (e) { - print("Got error: $e"); return YoutubeSourcedTrack.fetchFromTrack(track: track, ref: ref); } } diff --git a/lib/services/sourced_track/sources/jiosaavn.dart b/lib/services/sourced_track/sources/jiosaavn.dart index b25eca3b..01c041ad 100644 --- a/lib/services/sourced_track/sources/jiosaavn.dart +++ b/lib/services/sourced_track/sources/jiosaavn.dart @@ -111,7 +111,24 @@ class JioSaavnSourcedTrack extends SourcedTrack { final SongSearchResponse(:results) = await jiosaavnClient.search.songs(query, limit: 20); - return results.map(toSiblingType).toList(); + final trackArtistNames = track.artists?.map((ar) => ar.name).toList(); + return results + .where( + (s) { + final sameName = s.name?.replaceAll("&", "&") == track.name; + final artistNames = + "${s.primaryArtists}${s.featuredArtists.isNotEmpty ? ", " : ""}${s.featuredArtists}" + .replaceAll("&", "&"); + final sameArtists = artistNames.split(", ").any( + (artist) => + trackArtistNames?.any((ar) => artist == ar) ?? false, + ); + + return sameName && sameArtists; + }, + ) + .map(toSiblingType) + .toList(); } @override From 92deb0cc6ac8ad781377fb99e1f49dec1519a716 Mon Sep 17 00:00:00 2001 From: Kingkor Roy Tirtho Date: Wed, 22 Nov 2023 08:55:42 +0600 Subject: [PATCH 032/195] chore: fix playbutton not playing anything --- .../tracks_view/sections/header/flexible_header.dart | 3 +++ .../tracks_view/sections/header/header_buttons.dart | 12 ++++++------ lib/extensions/infinite_query.dart | 2 +- 3 files changed, 10 insertions(+), 7 deletions(-) diff --git a/lib/components/shared/tracks_view/sections/header/flexible_header.dart b/lib/components/shared/tracks_view/sections/header/flexible_header.dart index 57089975..7c469654 100644 --- a/lib/components/shared/tracks_view/sections/header/flexible_header.dart +++ b/lib/components/shared/tracks_view/sections/header/flexible_header.dart @@ -119,6 +119,9 @@ class TrackViewFlexHeader extends HookConsumerWidget { style: defaultTextStyle.style.copyWith( color: palette.bodyTextColor, ), + textAlign: mediaQuery.mdAndDown + ? TextAlign.center + : TextAlign.start, maxLines: 2, overflow: TextOverflow.ellipsis, ), diff --git a/lib/components/shared/tracks_view/sections/header/header_buttons.dart b/lib/components/shared/tracks_view/sections/header/header_buttons.dart index c006ec08..bae47f12 100644 --- a/lib/components/shared/tracks_view/sections/header/header_buttons.dart +++ b/lib/components/shared/tracks_view/sections/header/header_buttons.dart @@ -105,9 +105,9 @@ class TrackViewHeaderButtons extends HookConsumerWidget { dimension: isActive || isLoading.value ? 0 : null, child: FilledButton.icon( style: ElevatedButton.styleFrom( - backgroundColor: Colors.white, - foregroundColor: Colors.black, - ), + backgroundColor: Colors.white, + foregroundColor: Colors.black, + minimumSize: const Size(150, 40)), label: Text(context.l10n.shuffle), icon: const Icon(SpotubeIcons.shuffle), onPressed: props.tracks.isEmpty ? null : onShuffle, @@ -118,9 +118,9 @@ class TrackViewHeaderButtons extends HookConsumerWidget { const Gap(10), FilledButton.icon( style: ElevatedButton.styleFrom( - backgroundColor: color.color, - foregroundColor: color.bodyTextColor, - ), + backgroundColor: color.color, + foregroundColor: color.bodyTextColor, + minimumSize: const Size(150, 40)), onPressed: isActive || props.tracks.isEmpty || isLoading.value ? null : onPlay, diff --git a/lib/extensions/infinite_query.dart b/lib/extensions/infinite_query.dart index 86a2aaa6..90dcf73e 100644 --- a/lib/extensions/infinite_query.dart +++ b/lib/extensions/infinite_query.dart @@ -5,7 +5,7 @@ extension FetchAllTracks on InfiniteQuery, dynamic, int> { Future> fetchAllTracks({ required Future> Function() getAllTracks, }) async { - if (!hasNextPage) { + if (pages.isNotEmpty && !hasNextPage) { return pages.expand((page) => page).toList(); } final tracks = await getAllTracks(); From 88b8785cb86a19900f3a867b044c1ccb2fe400bb Mon Sep 17 00:00:00 2001 From: Kingkor Roy Tirtho Date: Wed, 22 Nov 2023 09:32:05 +0600 Subject: [PATCH 033/195] feat: discord RPC integration #98 --- lib/collections/env.dart | 2 + lib/main.dart | 5 +++ .../proxy_playlist_provider.dart | 8 ++++ lib/services/discord/discord.dart | 44 +++++++++++++++++++ linux/flutter/generated_plugin_registrant.cc | 4 ++ linux/flutter/generated_plugins.cmake | 1 + pubspec.lock | 9 ++++ pubspec.yaml | 3 ++ .../flutter/generated_plugin_registrant.cc | 3 ++ windows/flutter/generated_plugins.cmake | 1 + 10 files changed, 80 insertions(+) create mode 100644 lib/services/discord/discord.dart diff --git a/lib/collections/env.dart b/lib/collections/env.dart index 28941201..50fe1e6a 100644 --- a/lib/collections/env.dart +++ b/lib/collections/env.dart @@ -27,4 +27,6 @@ abstract class Env { static bool get enableUpdateChecker => DesktopTools.platform.isFlatpak || _enableUpdateChecker == "1"; + + static String discordAppId = "1176718791388975124"; } diff --git a/lib/main.dart b/lib/main.dart index 5d7ae2a7..7bb96543 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -1,4 +1,5 @@ import 'package:catcher_2/catcher_2.dart'; +import 'package:dart_discord_rpc/dart_discord_rpc.dart'; import 'package:device_preview/device_preview.dart'; import 'package:fl_query/fl_query.dart'; import 'package:flutter/foundation.dart'; @@ -63,6 +64,10 @@ Future main(List rawArgs) async { MetadataGod.initialize(); } + if (DesktopTools.platform.isWindows || DesktopTools.platform.isLinux) { + DiscordRPC.initialize(); + } + final hiveCacheDir = kIsWeb ? null : (await getApplicationSupportDirectory()).path; diff --git a/lib/provider/proxy_playlist/proxy_playlist_provider.dart b/lib/provider/proxy_playlist/proxy_playlist_provider.dart index 258f1d9e..89bb8a6c 100644 --- a/lib/provider/proxy_playlist/proxy_playlist_provider.dart +++ b/lib/provider/proxy_playlist/proxy_playlist_provider.dart @@ -24,6 +24,7 @@ import 'package:spotube/provider/user_preferences/user_preferences_provider.dart import 'package:spotube/provider/user_preferences/user_preferences_state.dart'; import 'package:spotube/services/audio_player/audio_player.dart'; import 'package:spotube/services/audio_services/audio_services.dart'; +import 'package:spotube/services/discord/discord.dart'; import 'package:spotube/services/sourced_track/exceptions.dart'; import 'package:spotube/services/sourced_track/models/source_info.dart'; import 'package:spotube/services/sourced_track/sourced_track.dart'; @@ -92,6 +93,7 @@ class ProxyPlaylistNotifier extends PersistedStateNotifier } notificationService.addTrack(newActiveTrack); + discord.updatePresence(newActiveTrack); state = state.copyWith( active: state.tracks .toList() @@ -321,6 +323,7 @@ class ProxyPlaylistNotifier extends PersistedStateNotifier collections: {}, ); await notificationService.addTrack(indexTrack); + discord.updatePresence(indexTrack); } else { final addableTrack = await SourcedTrack.fetchFromTrack( ref: ref, @@ -338,6 +341,7 @@ class ProxyPlaylistNotifier extends PersistedStateNotifier collections: {}, ); await notificationService.addTrack(addableTrack); + discord.updatePresence(addableTrack); } await audioPlayer.openPlaylist( @@ -366,6 +370,7 @@ class ProxyPlaylistNotifier extends PersistedStateNotifier if (oldTrack != null || track != null) { await notificationService.addTrack(track ?? oldTrack!); + discord.updatePresence(track ?? oldTrack!); } } @@ -468,6 +473,7 @@ class ProxyPlaylistNotifier extends PersistedStateNotifier if (oldTrack != null || track != null) { await notificationService.addTrack(track ?? oldTrack!); + discord.updatePresence(track ?? oldTrack!); } } @@ -493,12 +499,14 @@ class ProxyPlaylistNotifier extends PersistedStateNotifier await audioPlayer.skipToPrevious(); if (oldTrack != null || track != null) { await notificationService.addTrack(track ?? oldTrack!); + discord.updatePresence(track ?? oldTrack!); } } Future stop() async { state = ProxyPlaylist({}); await audioPlayer.stop(); + discord.clear(); } Future updatePalette() async { diff --git a/lib/services/discord/discord.dart b/lib/services/discord/discord.dart new file mode 100644 index 00000000..2a40e388 --- /dev/null +++ b/lib/services/discord/discord.dart @@ -0,0 +1,44 @@ +import 'package:dart_discord_rpc/dart_discord_rpc.dart'; +import 'package:flutter_desktop_tools/flutter_desktop_tools.dart'; +import 'package:spotify/spotify.dart'; +import 'package:spotube/collections/env.dart'; +import 'package:spotube/utils/type_conversion_utils.dart'; + +class Discord { + final DiscordRPC? discordRPC; + + Discord() + : discordRPC = + DesktopTools.platform.isWindows || DesktopTools.platform.isLinux + ? DiscordRPC(applicationId: Env.discordAppId) + : null { + discordRPC?.start(autoRegister: true); + } + + void updatePresence(Track track) { + clear(); + final artistNames = + TypeConversionUtils.artists_X_String(track.artists ?? []); + discordRPC?.updatePresence( + DiscordPresence( + details: "Song: ${track.name} by $artistNames", + state: "Vibing in Music", + startTimeStamp: DateTime.now().millisecondsSinceEpoch, + largeImageKey: "spotube-logo-foreground", + largeImageText: "Spotube", + smallImageKey: "spotube-logo-foreground", + smallImageText: "Spotube", + ), + ); + } + + void clear() { + discordRPC?.clearPresence(); + } + + void shutdown() { + discordRPC?.shutDown(); + } +} + +final discord = Discord(); diff --git a/linux/flutter/generated_plugin_registrant.cc b/linux/flutter/generated_plugin_registrant.cc index d455dc02..a07f7f9b 100644 --- a/linux/flutter/generated_plugin_registrant.cc +++ b/linux/flutter/generated_plugin_registrant.cc @@ -6,6 +6,7 @@ #include "generated_plugin_registrant.h" +#include #include #include #include @@ -18,6 +19,9 @@ #include void fl_register_plugins(FlPluginRegistry* registry) { + g_autoptr(FlPluginRegistrar) dart_discord_rpc_registrar = + fl_plugin_registry_get_registrar_for_plugin(registry, "DartDiscordRpcPlugin"); + dart_discord_rpc_plugin_register_with_registrar(dart_discord_rpc_registrar); g_autoptr(FlPluginRegistrar) file_selector_linux_registrar = fl_plugin_registry_get_registrar_for_plugin(registry, "FileSelectorPlugin"); file_selector_plugin_register_with_registrar(file_selector_linux_registrar); diff --git a/linux/flutter/generated_plugins.cmake b/linux/flutter/generated_plugins.cmake index 22319e92..97d541b3 100644 --- a/linux/flutter/generated_plugins.cmake +++ b/linux/flutter/generated_plugins.cmake @@ -3,6 +3,7 @@ # list(APPEND FLUTTER_PLUGIN_LIST + dart_discord_rpc file_selector_linux flutter_secure_storage_linux local_notifier diff --git a/pubspec.lock b/pubspec.lock index 8826c439..19b52a8d 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -393,6 +393,15 @@ packages: url: "https://pub.dev" source: hosted version: "1.0.2" + dart_discord_rpc: + dependency: "direct main" + description: + path: "." + ref: HEAD + resolved-ref: "4d05017838ebeadcdb832e1893fabad1506fddba" + url: "https://github.com/Tommypop2/dart_discord_rpc.git" + source: git + version: "0.0.3" dart_style: dependency: transitive description: diff --git a/pubspec.yaml b/pubspec.yaml index 5a88c39a..eb26c94f 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -115,6 +115,9 @@ dependencies: very_good_infinite_list: ^0.7.1 gap: ^3.0.1 sliver_tools: ^0.2.12 + dart_discord_rpc: + git: + url: https://github.com/Tommypop2/dart_discord_rpc.git dev_dependencies: build_runner: ^2.3.2 diff --git a/windows/flutter/generated_plugin_registrant.cc b/windows/flutter/generated_plugin_registrant.cc index ff25c4e3..b9c6a481 100644 --- a/windows/flutter/generated_plugin_registrant.cc +++ b/windows/flutter/generated_plugin_registrant.cc @@ -6,6 +6,7 @@ #include "generated_plugin_registrant.h" +#include #include #include #include @@ -19,6 +20,8 @@ #include void RegisterPlugins(flutter::PluginRegistry* registry) { + DartDiscordRpcPluginRegisterWithRegistrar( + registry->GetRegistrarForPlugin("DartDiscordRpcPlugin")); FileSelectorWindowsRegisterWithRegistrar( registry->GetRegistrarForPlugin("FileSelectorWindows")); FlutterSecureStorageWindowsPluginRegisterWithRegistrar( diff --git a/windows/flutter/generated_plugins.cmake b/windows/flutter/generated_plugins.cmake index 0a5ab976..5cd55ff3 100644 --- a/windows/flutter/generated_plugins.cmake +++ b/windows/flutter/generated_plugins.cmake @@ -3,6 +3,7 @@ # list(APPEND FLUTTER_PLUGIN_LIST + dart_discord_rpc file_selector_windows flutter_secure_storage_windows local_notifier From 7d05c40dc0d04208b059f2483c1e4de199c8b51d Mon Sep 17 00:00:00 2001 From: Kingkor Roy Tirtho Date: Wed, 22 Nov 2023 10:02:11 +0600 Subject: [PATCH 034/195] fix: use CustomScrollView for personalized page --- lib/extensions/string.dart | 11 +++ lib/pages/home/personalized.dart | 95 +++++++++++-------- .../sourced_track/sources/jiosaavn.dart | 15 +-- pubspec.lock | 8 ++ pubspec.yaml | 1 + 5 files changed, 85 insertions(+), 45 deletions(-) create mode 100644 lib/extensions/string.dart diff --git a/lib/extensions/string.dart b/lib/extensions/string.dart new file mode 100644 index 00000000..b7ab7514 --- /dev/null +++ b/lib/extensions/string.dart @@ -0,0 +1,11 @@ +import 'package:html_unescape/html_unescape.dart'; + +final htmlEscape = HtmlUnescape(); + +extension UnescapeHtml on String { + String unescapeHtml() => htmlEscape.convert(this); +} + +extension NullableUnescapeHtml on String? { + String? unescapeHtml() => this == null ? null : htmlEscape.convert(this!); +} diff --git a/lib/pages/home/personalized.dart b/lib/pages/home/personalized.dart index 16cfc3a8..7fbd27ae 100644 --- a/lib/pages/home/personalized.dart +++ b/lib/pages/home/personalized.dart @@ -46,47 +46,64 @@ class PersonalizedPage extends HookConsumerWidget { [newReleases.pages], ); - return ListView( + return CustomScrollView( controller: controller, - children: [ - if (!featuredPlaylistsQuery.hasPageData && - !featuredPlaylistsQuery.isLoadingNextPage) - const ShimmerCategories() - else - HorizontalPlaybuttonCardView( - items: playlists.toList(), - title: Text(context.l10n.featured), - isLoadingNextPage: featuredPlaylistsQuery.isLoadingNextPage, - hasNextPage: featuredPlaylistsQuery.hasNextPage, - onFetchMore: featuredPlaylistsQuery.fetchNext, + slivers: [ + SliverList.list( + children: [ + AnimatedSwitcher( + duration: const Duration(milliseconds: 300), + child: !featuredPlaylistsQuery.hasPageData && + !featuredPlaylistsQuery.isLoadingNextPage + ? const ShimmerCategories() + : HorizontalPlaybuttonCardView( + items: playlists.toList(), + title: Text(context.l10n.featured), + isLoadingNextPage: + featuredPlaylistsQuery.isLoadingNextPage, + hasNextPage: featuredPlaylistsQuery.hasNextPage, + onFetchMore: featuredPlaylistsQuery.fetchNext, + ), + ), + if (auth != null) + AnimatedSwitcher( + duration: const Duration(milliseconds: 300), + child: newReleases.hasPageData && + userArtistsQuery.hasData && + !newReleases.isLoadingNextPage + ? HorizontalPlaybuttonCardView( + items: albums, + title: Text(context.l10n.new_releases), + isLoadingNextPage: newReleases.isLoadingNextPage, + hasNextPage: newReleases.hasNextPage, + onFetchMore: newReleases.fetchNext, + ) + : const ShimmerCategories(), + ), + ], + ), + SliverSafeArea( + sliver: SliverList.builder( + itemCount: madeForUser.data?["content"]?["items"]?.length ?? 0, + itemBuilder: (context, index) { + final item = madeForUser.data?["content"]?["items"]?[index]; + final playlists = item["content"]?["items"] + ?.where((itemL2) => itemL2["type"] == "playlist") + .map((itemL2) => PlaylistSimple.fromJson(itemL2)) + .toList() + .cast() ?? + []; + if (playlists.isEmpty) return const SizedBox.shrink(); + return HorizontalPlaybuttonCardView( + items: playlists, + title: Text(item["name"] ?? ""), + hasNextPage: false, + isLoadingNextPage: false, + onFetchMore: () {}, + ); + }, ), - if (auth != null && - newReleases.hasPageData && - userArtistsQuery.hasData && - !newReleases.isLoadingNextPage) - HorizontalPlaybuttonCardView( - items: albums, - title: Text(context.l10n.new_releases), - isLoadingNextPage: newReleases.isLoadingNextPage, - hasNextPage: newReleases.hasNextPage, - onFetchMore: newReleases.fetchNext, - ), - ...?madeForUser.data?["content"]?["items"]?.map((item) { - final playlists = item["content"]?["items"] - ?.where((itemL2) => itemL2["type"] == "playlist") - .map((itemL2) => PlaylistSimple.fromJson(itemL2)) - .toList() - .cast() ?? - []; - if (playlists.isEmpty) return const SizedBox.shrink(); - return HorizontalPlaybuttonCardView( - items: playlists, - title: Text(item["name"] ?? ""), - hasNextPage: false, - isLoadingNextPage: false, - onFetchMore: () {}, - ); - }) + ), ], ); } diff --git a/lib/services/sourced_track/sources/jiosaavn.dart b/lib/services/sourced_track/sources/jiosaavn.dart index 01c041ad..a447b0c1 100644 --- a/lib/services/sourced_track/sources/jiosaavn.dart +++ b/lib/services/sourced_track/sources/jiosaavn.dart @@ -8,6 +8,7 @@ import 'package:spotube/services/sourced_track/models/source_info.dart'; import 'package:spotube/services/sourced_track/models/source_map.dart'; import 'package:spotube/services/sourced_track/sourced_track.dart'; import 'package:jiosaavn/jiosaavn.dart'; +import 'package:spotube/extensions/string.dart'; final jiosaavnClient = JioSaavnClient(); @@ -74,14 +75,14 @@ class JioSaavnSourcedTrack extends SourcedTrack { result.primaryArtists, if (result.featuredArtists.isNotEmpty) ", ", result.featuredArtists - ].join("").replaceAll("&", "&"), + ].join("").unescapeHtml(), artistUrl: "https://www.jiosaavn.com/artist/${result.primaryArtistsId.split(",").firstOrNull ?? ""}", duration: Duration(seconds: int.parse(result.duration)), id: result.id, pageUrl: result.url, thumbnail: result.image?.last.link ?? "", - title: result.name!, + title: result.name!.unescapeHtml(), album: result.album.name, ), source: SourceMap( @@ -115,10 +116,12 @@ class JioSaavnSourcedTrack extends SourcedTrack { return results .where( (s) { - final sameName = s.name?.replaceAll("&", "&") == track.name; - final artistNames = - "${s.primaryArtists}${s.featuredArtists.isNotEmpty ? ", " : ""}${s.featuredArtists}" - .replaceAll("&", "&"); + final sameName = s.name?.unescapeHtml() == track.name; + final artistNames = [ + s.primaryArtists, + if (s.featuredArtists.isNotEmpty) ", ", + s.featuredArtists + ].join("").unescapeHtml(); final sameArtists = artistNames.split(", ").any( (artist) => trackArtistNames?.any((ar) => artist == ar) ?? false, diff --git a/pubspec.lock b/pubspec.lock index 19b52a8d..6c822604 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -1058,6 +1058,14 @@ packages: url: "https://pub.dev" source: hosted version: "0.15.4" + html_unescape: + dependency: "direct main" + description: + name: html_unescape + sha256: "15362d7a18f19d7b742ef8dcb811f5fd2a2df98db9f80ea393c075189e0b61e3" + url: "https://pub.dev" + source: hosted + version: "2.0.0" http: dependency: "direct main" description: diff --git a/pubspec.yaml b/pubspec.yaml index eb26c94f..6a33d294 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -118,6 +118,7 @@ dependencies: dart_discord_rpc: git: url: https://github.com/Tommypop2/dart_discord_rpc.git + html_unescape: ^2.0.0 dev_dependencies: build_runner: ^2.3.2 From 4511a0bd006d8004dcac50e056b397bf2763720d Mon Sep 17 00:00:00 2001 From: Kingkor Roy Tirtho Date: Wed, 22 Nov 2023 10:49:00 +0600 Subject: [PATCH 035/195] chore: bring back edit user playlist button --- lib/components/shared/playbutton_card.dart | 18 ------------------ .../sections/header/header_actions.dart | 16 ++++++++++++++++ lib/services/mutations/playlist.dart | 4 +--- 3 files changed, 17 insertions(+), 21 deletions(-) diff --git a/lib/components/shared/playbutton_card.dart b/lib/components/shared/playbutton_card.dart index 4fef72c0..d9c48640 100644 --- a/lib/components/shared/playbutton_card.dart +++ b/lib/components/shared/playbutton_card.dart @@ -63,26 +63,8 @@ class PlaybuttonCard extends HookWidget { others: 15, ); - final textsHeight = useState( - (textsKey.currentContext?.findRenderObject() as RenderBox?) - ?.size - .height ?? - 110.00, - ); - final cleanDescription = useDescription(description); - useEffect(() { - WidgetsBinding.instance.addPostFrameCallback((_) { - textsHeight.value = - (textsKey.currentContext?.findRenderObject() as RenderBox?) - ?.size - .height ?? - textsHeight.value; - }); - return null; - }, [textsKey]); - return Container( constraints: BoxConstraints(maxWidth: size), margin: margin, diff --git a/lib/components/shared/tracks_view/sections/header/header_actions.dart b/lib/components/shared/tracks_view/sections/header/header_actions.dart index 954f266d..b050c199 100644 --- a/lib/components/shared/tracks_view/sections/header/header_actions.dart +++ b/lib/components/shared/tracks_view/sections/header/header_actions.dart @@ -3,6 +3,7 @@ import 'package:flutter/services.dart'; import 'package:go_router/go_router.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:spotube/collections/spotube_icons.dart'; +import 'package:spotube/components/playlist/playlist_create_dialog.dart'; import 'package:spotube/components/shared/heart_button.dart'; import 'package:spotube/components/shared/tracks_view/sections/body/use_is_user_playlist.dart'; import 'package:spotube/components/shared/tracks_view/track_view_props.dart'; @@ -76,6 +77,21 @@ class TrackViewHeaderActions extends HookConsumerWidget { } }, ), + if (isUserPlaylist) + IconButton( + icon: const Icon(SpotubeIcons.edit), + onPressed: () { + showDialog( + context: context, + builder: (context) { + return PlaylistCreateDialog( + playlistId: props.collectionId, + trackIds: props.tracks.map((e) => e.id!).toList(), + ); + }, + ); + }, + ), ], ); } diff --git a/lib/services/mutations/playlist.dart b/lib/services/mutations/playlist.dart index a88e8512..077fff06 100644 --- a/lib/services/mutations/playlist.dart +++ b/lib/services/mutations/playlist.dart @@ -131,10 +131,8 @@ class PlaylistMutations { ); } }, - refreshQueries: [ - "playlist/$playlistId", - ], refreshInfiniteQueries: [ + "playlist/$playlistId", "current-user-playlists", ], ref: ref, From 2a698865567883271471ace9a44123bbfd8fcd2f Mon Sep 17 00:00:00 2001 From: Kingkor Roy Tirtho Date: Wed, 22 Nov 2023 20:23:12 +0600 Subject: [PATCH 036/195] feat(artist): modularize page and add wikipedia section --- lib/collections/spotube_icons.dart | 1 + lib/components/library/user_playlists.dart | 49 +- lib/extensions/color.dart | 28 ++ lib/extensions/constrains.dart | 24 + lib/pages/artist/artist.dart | 475 ++---------------- lib/pages/artist/section/footer.dart | 93 ++++ lib/pages/artist/section/header.dart | 257 ++++++++++ lib/pages/artist/section/related_artists.dart | 49 ++ lib/pages/artist/section/top_tracks.dart | 126 +++++ lib/services/queries/artist.dart | 29 +- lib/services/wikipedia/wikipedia.dart | 3 + pubspec.lock | 11 +- pubspec.yaml | 3 + 13 files changed, 693 insertions(+), 455 deletions(-) create mode 100644 lib/extensions/color.dart create mode 100644 lib/pages/artist/section/footer.dart create mode 100644 lib/pages/artist/section/header.dart create mode 100644 lib/pages/artist/section/related_artists.dart create mode 100644 lib/pages/artist/section/top_tracks.dart create mode 100644 lib/services/wikipedia/wikipedia.dart diff --git a/lib/collections/spotube_icons.dart b/lib/collections/spotube_icons.dart index 78cbb52c..d00775c7 100644 --- a/lib/collections/spotube_icons.dart +++ b/lib/collections/spotube_icons.dart @@ -107,4 +107,5 @@ abstract class SpotubeIcons { static const eye = FeatherIcons.eye; static const noEye = FeatherIcons.eyeOff; static const normalize = FeatherIcons.barChart2; + static const wikipedia = SimpleIcons.wikipedia; } diff --git a/lib/components/library/user_playlists.dart b/lib/components/library/user_playlists.dart index 0102a3c7..f7736ca7 100644 --- a/lib/components/library/user_playlists.dart +++ b/lib/components/library/user_playlists.dart @@ -14,6 +14,7 @@ import 'package:spotube/components/shared/shimmers/shimmer_playbutton_card.dart' import 'package:spotube/components/shared/fallbacks/anonymous_fallback.dart'; import 'package:spotube/components/playlist/playlist_card.dart'; import 'package:spotube/components/shared/waypoint.dart'; +import 'package:spotube/extensions/constrains.dart'; import 'package:spotube/extensions/context.dart'; import 'package:spotube/provider/authentication_provider.dart'; import 'package:spotube/services/queries/queries.dart'; @@ -120,31 +121,33 @@ class UserPlaylists extends HookConsumerWidget { const SliverToBoxAdapter( child: SizedBox(height: 10), ), - SliverGrid.builder( - itemCount: playlists.length + 1, - gridDelegate: SliverGridDelegateWithMaxCrossAxisExtent( - maxCrossAxisExtent: 200, - mainAxisExtent: DesktopTools.platform.isMobile ? 225 : 250, - crossAxisSpacing: 8, - mainAxisSpacing: 8, - ), - itemBuilder: (context, index) { - if (index == playlists.length) { - if (!playlistsQuery.hasNextPage) { - return const SizedBox.shrink(); + SliverLayoutBuilder(builder: (context, constrains) { + return SliverGrid.builder( + itemCount: playlists.length + 1, + gridDelegate: SliverGridDelegateWithMaxCrossAxisExtent( + maxCrossAxisExtent: 200, + mainAxisExtent: constrains.smAndDown ? 225 : 250, + crossAxisSpacing: 8, + mainAxisSpacing: 8, + ), + itemBuilder: (context, index) { + if (index == playlists.length) { + if (!playlistsQuery.hasNextPage) { + return const SizedBox.shrink(); + } + + return Waypoint( + controller: controller, + isGrid: true, + onTouchEdge: playlistsQuery.fetchNext, + child: const ShimmerPlaybuttonCard(count: 1), + ); } - return Waypoint( - controller: controller, - isGrid: true, - onTouchEdge: playlistsQuery.fetchNext, - child: const ShimmerPlaybuttonCard(count: 1), - ); - } - - return PlaylistCard(playlists[index]); - }, - ) + return PlaylistCard(playlists[index]); + }, + ); + }) ], ), ), diff --git a/lib/extensions/color.dart b/lib/extensions/color.dart new file mode 100644 index 00000000..68cd8ef7 --- /dev/null +++ b/lib/extensions/color.dart @@ -0,0 +1,28 @@ +import 'package:flutter/material.dart'; + +extension ColorAlterer on Color { + Color darken(double amount) { + assert(amount >= 0 && amount <= 1); + final hsl = HSLColor.fromColor(this); + final hslDark = hsl.withLightness((hsl.lightness - amount).clamp(0.0, 1.0)); + return hslDark.toColor(); + } + + Color lighten(double amount) { + assert(amount >= 0 && amount <= 1); + final hsl = HSLColor.fromColor(this); + final hslLight = + hsl.withLightness((hsl.lightness + amount).clamp(0.0, 1.0)); + return hslLight.toColor(); + } + + bool isLight() { + final luminance = computeLuminance(); + return luminance > 0.5; + } + + bool isDark() { + final luminance = computeLuminance(); + return luminance <= 0.5; + } +} diff --git a/lib/extensions/constrains.dart b/lib/extensions/constrains.dart index 85c84ca9..1177f5ac 100644 --- a/lib/extensions/constrains.dart +++ b/lib/extensions/constrains.dart @@ -1,3 +1,4 @@ +import 'package:flutter/rendering.dart'; import 'package:flutter/widgets.dart'; // ignore: constant_identifier_names @@ -9,6 +10,29 @@ const Breakpoints = ( xl: 1280.0, ); +extension SliverBreakpoints on SliverConstraints { + bool get isXs => crossAxisExtent <= Breakpoints.xs; + bool get isSm => + crossAxisExtent > Breakpoints.xs && crossAxisExtent <= Breakpoints.sm; + bool get isMd => + crossAxisExtent > Breakpoints.sm && crossAxisExtent <= Breakpoints.md; + bool get isLg => + crossAxisExtent > Breakpoints.md && crossAxisExtent <= Breakpoints.lg; + bool get isXl => + crossAxisExtent > Breakpoints.lg && crossAxisExtent <= Breakpoints.xl; + bool get is2Xl => crossAxisExtent > Breakpoints.xl; + + bool get smAndUp => isSm || isMd || isLg || isXl || is2Xl; + bool get mdAndUp => isMd || isLg || isXl || is2Xl; + bool get lgAndUp => isLg || isXl || is2Xl; + bool get xlAndUp => isXl || is2Xl; + + bool get smAndDown => isXs || isSm; + bool get mdAndDown => isXs || isSm || isMd; + bool get lgAndDown => isXs || isSm || isMd || isLg; + bool get xlAndDown => isXs || isSm || isMd || isLg || isXl; +} + extension ContainerBreakpoints on BoxConstraints { bool get isXs => biggest.width <= Breakpoints.xs; bool get isSm => diff --git a/lib/pages/artist/artist.dart b/lib/pages/artist/artist.dart index 8b57c2a8..693e825b 100644 --- a/lib/pages/artist/artist.dart +++ b/lib/pages/artist/artist.dart @@ -1,32 +1,19 @@ -import 'package:collection/collection.dart'; -import 'package:fl_query_hooks/fl_query_hooks.dart'; import 'package:flutter/material.dart'; -import 'package:flutter/services.dart'; import 'package:flutter_hooks/flutter_hooks.dart'; +import 'package:gap/gap.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; -import 'package:spotify/spotify.dart'; -import 'package:spotube/collections/spotube_icons.dart'; -import 'package:spotube/components/shared/inter_scrollbar/inter_scrollbar.dart'; -import 'package:spotube/components/shared/shimmers/shimmer_artist_profile.dart'; import 'package:spotube/components/shared/page_window_title_bar.dart'; -import 'package:spotube/components/shared/track_tile/track_tile.dart'; -import 'package:spotube/components/shared/image/universal_image.dart'; import 'package:spotube/components/artist/artist_album_list.dart'; -import 'package:spotube/components/artist/artist_card.dart'; -import 'package:spotube/extensions/constrains.dart'; +import 'package:spotube/components/shared/shimmers/shimmer_artist_profile.dart'; import 'package:spotube/extensions/context.dart'; -import 'package:spotube/hooks/utils/use_breakpoint_value.dart'; import 'package:spotube/models/logger.dart'; -import 'package:spotube/provider/authentication_provider.dart'; -import 'package:spotube/provider/blacklist_provider.dart'; -import 'package:spotube/provider/spotify_provider.dart'; -import 'package:spotube/provider/proxy_playlist/proxy_playlist_provider.dart'; +import 'package:spotube/pages/artist/section/footer.dart'; +import 'package:spotube/pages/artist/section/header.dart'; +import 'package:spotube/pages/artist/section/related_artists.dart'; +import 'package:spotube/pages/artist/section/top_tracks.dart'; import 'package:spotube/services/queries/queries.dart'; -import 'package:spotube/utils/primitive_utils.dart'; -import 'package:spotube/utils/type_conversion_utils.dart'; - class ArtistPage extends HookConsumerWidget { final String artistId; final logger = getLogger(ArtistPage); @@ -34,427 +21,61 @@ class ArtistPage extends HookConsumerWidget { @override Widget build(BuildContext context, ref) { - SpotifyApi spotify = ref.watch(spotifyProvider); - final parentScrollController = useScrollController(); + final scrollController = useScrollController(); final theme = Theme.of(context); - final scaffoldMessenger = ScaffoldMessenger.of(context); - final textTheme = theme.textTheme; - final chipTextVariant = useBreakpointValue( - xs: textTheme.bodySmall, - sm: textTheme.bodySmall, - md: textTheme.bodyMedium, - lg: textTheme.bodyLarge, - xl: textTheme.titleSmall, - xxl: textTheme.titleMedium, - ); - final mediaQuery = MediaQuery.of(context); - - final avatarWidth = useBreakpointValue( - xs: mediaQuery.size.width * 0.50, - sm: mediaQuery.size.width * 0.50, - md: mediaQuery.size.width * 0.40, - lg: mediaQuery.size.width * 0.18, - xl: mediaQuery.size.width * 0.18, - xxl: mediaQuery.size.width * 0.18, - ); - - final playlistNotifier = ref.watch(ProxyPlaylistNotifier.notifier); - final playlist = ref.watch(ProxyPlaylistNotifier.provider); - - final auth = ref.watch(AuthenticationNotifier.provider); - - final queryClient = useQueryClient(); + final artistQuery = useQueries.artist.get(ref, artistId); return SafeArea( bottom: false, child: Scaffold( appBar: const PageWindowTitleBar( leading: BackButton(), + backgroundColor: Colors.transparent, ), - body: HookBuilder( - builder: (context) { - final artistsQuery = useQueries.artist.get(ref, artistId); - - if (artistsQuery.isLoading || !artistsQuery.hasData) { - return const ShimmerArtistProfile(); - } else if (artistsQuery.hasError) { - return Center( - child: Text(artistsQuery.error.toString()), - ); - } - - final data = artistsQuery.data!; - - final blacklist = ref.watch(BlackListNotifier.provider); - final isBlackListed = blacklist.contains( - BlacklistedElement.artist(artistId, data.name!), - ); - - return InterScrollbar( - controller: parentScrollController, - child: SingleChildScrollView( - controller: parentScrollController, + extendBodyBehindAppBar: true, + body: Builder(builder: (context) { + if (artistQuery.isLoading || !artistQuery.hasData) { + const ShimmerArtistProfile(); + } else if (artistQuery.hasError) { + return Center(child: Text(artistQuery.error.toString())); + } + return CustomScrollView( + controller: scrollController, + slivers: [ + SliverToBoxAdapter( child: SafeArea( - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Wrap( - crossAxisAlignment: WrapCrossAlignment.center, - runAlignment: WrapAlignment.center, - children: [ - const SizedBox(width: 50), - Padding( - padding: const EdgeInsets.all(16), - child: CircleAvatar( - radius: avatarWidth, - backgroundImage: UniversalImage.imageProvider( - TypeConversionUtils.image_X_UrlString( - data.images, - placeholder: ImagePlaceholder.artist, - ), - ), - ), - ), - Padding( - padding: const EdgeInsets.all(20), - child: Column( - mainAxisSize: MainAxisSize.min, - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Row( - mainAxisSize: MainAxisSize.min, - children: [ - Container( - padding: const EdgeInsets.symmetric( - horizontal: 10, vertical: 5), - decoration: BoxDecoration( - color: Colors.blue, - borderRadius: - BorderRadius.circular(50)), - child: Text( - data.type!.toUpperCase(), - style: chipTextVariant.copyWith( - color: Colors.white, - ), - ), - ), - if (isBlackListed) ...[ - const SizedBox(width: 5), - Container( - padding: const EdgeInsets.symmetric( - horizontal: 10, vertical: 5), - decoration: BoxDecoration( - color: Colors.red[400], - borderRadius: - BorderRadius.circular(50)), - child: Text( - context.l10n.blacklisted, - style: chipTextVariant.copyWith( - color: Colors.white, - ), - ), - ), - ] - ], - ), - Text( - data.name!, - style: mediaQuery.smAndDown - ? textTheme.headlineSmall - : textTheme.headlineMedium, - ), - Text( - context.l10n.followers( - PrimitiveUtils.toReadableNumber( - data.followers!.total!.toDouble(), - ), - ), - style: textTheme.bodyMedium?.copyWith( - fontWeight: mediaQuery.mdAndUp - ? FontWeight.bold - : null, - ), - ), - const SizedBox(height: 20), - Row( - mainAxisSize: MainAxisSize.min, - children: [ - if (auth != null) - HookBuilder( - builder: (context) { - final isFollowingQuery = useQueries - .artist - .doIFollow(ref, artistId); - - final followUnfollow = - useCallback(() async { - try { - isFollowingQuery.data! - ? await spotify.me.unfollow( - FollowingType.artist, - [artistId], - ) - : await spotify.me.follow( - FollowingType.artist, - [artistId], - ); - await isFollowingQuery.refresh(); - - queryClient - .refreshInfiniteQueryAllPages( - "user-following-artists"); - } finally { - queryClient.refreshQuery( - "user-follows-artists-query/$artistId", - ); - } - }, [isFollowingQuery]); - - if (isFollowingQuery.isLoading || - !isFollowingQuery.hasData) { - return const SizedBox( - height: 20, - width: 20, - child: - CircularProgressIndicator(), - ); - } - - if (isFollowingQuery.data!) { - return OutlinedButton( - onPressed: followUnfollow, - child: - Text(context.l10n.following), - ); - } - - return FilledButton( - onPressed: followUnfollow, - child: Text(context.l10n.follow), - ); - }, - ), - const SizedBox(width: 5), - IconButton( - tooltip: - context.l10n.add_artist_to_blacklist, - icon: Icon( - SpotubeIcons.userRemove, - color: !isBlackListed - ? Colors.red[400] - : Colors.white, - ), - style: IconButton.styleFrom( - backgroundColor: isBlackListed - ? Colors.red[400] - : null, - ), - onPressed: () async { - if (isBlackListed) { - ref - .read(BlackListNotifier - .provider.notifier) - .remove( - BlacklistedElement.artist( - data.id!, data.name!), - ); - } else { - ref - .read(BlackListNotifier - .provider.notifier) - .add( - BlacklistedElement.artist( - data.id!, data.name!), - ); - } - }, - ), - IconButton( - icon: const Icon(SpotubeIcons.share), - onPressed: () async { - if (data.externalUrls?.spotify != - null) { - await Clipboard.setData( - ClipboardData( - text: data.externalUrls!.spotify!, - ), - ); - } - - if (!context.mounted) return; - - scaffoldMessenger.showSnackBar( - SnackBar( - width: 300, - behavior: SnackBarBehavior.floating, - content: Text( - context.l10n.artist_url_copied, - textAlign: TextAlign.center, - ), - ), - ); - }, - ) - ], - ) - ], - ), - ), - ], - ), - const SizedBox(height: 50), - HookBuilder( - builder: (context) { - final topTracksQuery = useQueries.artist.topTracksOf( - ref, - artistId, - ); - - final isPlaylistPlaying = playlist.containsTracks( - topTracksQuery.data ?? [], - ); - - if (topTracksQuery.isLoading || - !topTracksQuery.hasData) { - return const CircularProgressIndicator(); - } else if (topTracksQuery.hasError) { - return Center( - child: Text(topTracksQuery.error.toString()), - ); - } - - final topTracks = topTracksQuery.data!; - - void playPlaylist(List tracks, - {Track? currentTrack}) async { - currentTrack ??= tracks.first; - if (!isPlaylistPlaying) { - playlistNotifier.load( - tracks, - initialIndex: tracks.indexWhere( - (s) => s.id == currentTrack?.id), - autoPlay: true, - ); - } else if (isPlaylistPlaying && - currentTrack.id != null && - currentTrack.id != playlist.activeTrack?.id) { - await playlistNotifier.jumpToTrack(currentTrack); - } - } - - return Column( - children: [ - Row( - children: [ - Padding( - padding: const EdgeInsets.all(8.0), - child: Text( - context.l10n.top_tracks, - style: theme.textTheme.headlineSmall, - ), - ), - if (!isPlaylistPlaying) - IconButton( - icon: const Icon( - SpotubeIcons.queueAdd, - ), - onPressed: () { - playlistNotifier - .addTracks(topTracks.toList()); - scaffoldMessenger.showSnackBar( - SnackBar( - width: 300, - behavior: SnackBarBehavior.floating, - content: Text( - context.l10n.added_to_queue( - topTracks.length, - ), - textAlign: TextAlign.center, - ), - ), - ); - }, - ), - const SizedBox(width: 5), - IconButton( - icon: Icon( - isPlaylistPlaying - ? SpotubeIcons.stop - : SpotubeIcons.play, - color: Colors.white, - ), - style: IconButton.styleFrom( - backgroundColor: - theme.colorScheme.primary, - ), - onPressed: () => - playPlaylist(topTracks.toList()), - ) - ], - ), - ...topTracks.mapIndexed((i, track) { - return TrackTile( - index: i, - track: track, - onTap: () async { - playPlaylist( - topTracks.toList(), - currentTrack: track, - ); - }, - ); - }), - ], - ); - }, - ), - const SizedBox(height: 50), - ArtistAlbumList(artistId), - const SizedBox(height: 20), - Padding( - padding: const EdgeInsets.all(8.0), - child: Text( - context.l10n.fans_also_like, - style: theme.textTheme.headlineSmall, - ), - ), - const SizedBox(height: 10), - HookBuilder( - builder: (context) { - final relatedArtists = - useQueries.artist.relatedArtistsOf( - ref, - artistId, - ); - - if (relatedArtists.isLoading || - !relatedArtists.hasData) { - return const CircularProgressIndicator(); - } else if (relatedArtists.hasError) { - return Center( - child: Text(relatedArtists.error.toString()), - ); - } - - return Center( - child: Wrap( - spacing: 20, - runSpacing: 20, - children: relatedArtists.data! - .map((artist) => ArtistCard(artist)) - .toList(), - ), - ); - }, - ), - ], + bottom: false, + child: ArtistPageHeader(artistId: artistId), + ), + ), + const SliverGap(50), + ArtistPageTopTracks(artistId: artistId), + const SliverGap(50), + SliverToBoxAdapter(child: ArtistAlbumList(artistId)), + const SliverGap(20), + SliverPadding( + padding: const EdgeInsets.all(8.0), + sliver: SliverToBoxAdapter( + child: Text( + context.l10n.fans_also_like, + style: theme.textTheme.headlineSmall, ), ), ), - ); - }, - ), + SliverSafeArea( + sliver: ArtistPageRelatedArtists(artistId: artistId), + ), + if (artistQuery.data != null) + SliverSafeArea( + top: false, + sliver: SliverToBoxAdapter( + child: ArtistPageFooter(artist: artistQuery.data!), + ), + ), + ], + ); + }), ), ); } diff --git a/lib/pages/artist/section/footer.dart b/lib/pages/artist/section/footer.dart new file mode 100644 index 00000000..3c0db8a5 --- /dev/null +++ b/lib/pages/artist/section/footer.dart @@ -0,0 +1,93 @@ +import 'package:flutter/gestures.dart'; +import 'package:flutter/material.dart'; +import 'package:hooks_riverpod/hooks_riverpod.dart'; +import 'package:spotify/spotify.dart'; +import 'package:spotube/collections/spotube_icons.dart'; +import 'package:spotube/components/shared/image/universal_image.dart'; +import 'package:spotube/extensions/constrains.dart'; +import 'package:spotube/services/queries/queries.dart'; +import 'package:spotube/utils/type_conversion_utils.dart'; +import 'package:url_launcher/url_launcher_string.dart'; + +class ArtistPageFooter extends HookConsumerWidget { + final Artist artist; + const ArtistPageFooter({Key? key, required this.artist}) : super(key: key); + + @override + Widget build(BuildContext context, ref) { + final ThemeData(:textTheme) = Theme.of(context); + final mediaQuery = MediaQuery.of(context); + + final artistImage = TypeConversionUtils.image_X_UrlString( + artist.images, + placeholder: ImagePlaceholder.artist, + ); + final summary = useQueries.artist.wikipediaSummary(artist); + if (summary.hasError || !summary.hasData) return const SizedBox.shrink(); + return Container( + margin: const EdgeInsets.all(16), + padding: mediaQuery.smAndDown + ? const EdgeInsets.all(20) + : const EdgeInsets.all(30), + constraints: const BoxConstraints(minHeight: 300), + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(10), + image: DecorationImage( + colorFilter: ColorFilter.mode( + Colors.black.withOpacity(0.5), + BlendMode.darken, + ), + image: UniversalImage.imageProvider( + summary.data!.originalimage?.source_ ?? artistImage, + height: summary.data!.originalimage?.height.toDouble(), + width: summary.data!.originalimage?.width.toDouble(), + ), + fit: BoxFit.cover, + alignment: Alignment.center, + ), + ), + alignment: Alignment.center, + child: RichText( + text: TextSpan( + style: textTheme.bodyLarge?.copyWith( + color: Colors.white, + ), + children: [ + // icon + const WidgetSpan( + child: Icon( + SpotubeIcons.wikipedia, + color: Colors.white, + size: 30, + ), + ), + TextSpan( + text: " Wikipedia", + style: textTheme.titleLarge?.copyWith( + color: Colors.white, + ), + ), + const TextSpan(text: '\n\n'), + TextSpan( + text: summary.data!.extract, + ), + TextSpan( + text: '\n...read more at wikipedia', + style: textTheme.bodyLarge?.copyWith( + color: Colors.lightBlue[300], + decoration: TextDecoration.underline, + decorationColor: Colors.lightBlue[300], + ), + recognizer: TapGestureRecognizer() + ..onTap = () async { + await launchUrlString( + "http://en.wikipedia.org/wiki?curid=${summary.data?.pageid}", + ); + }, + ), + ], + ), + ), + ); + } +} diff --git a/lib/pages/artist/section/header.dart b/lib/pages/artist/section/header.dart new file mode 100644 index 00000000..9fc9d78e --- /dev/null +++ b/lib/pages/artist/section/header.dart @@ -0,0 +1,257 @@ +import 'package:fl_query_hooks/fl_query_hooks.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; +import 'package:flutter_hooks/flutter_hooks.dart'; +import 'package:gap/gap.dart'; +import 'package:hooks_riverpod/hooks_riverpod.dart'; +import 'package:spotify/spotify.dart'; +import 'package:spotube/collections/spotube_icons.dart'; +import 'package:spotube/components/shared/image/universal_image.dart'; +import 'package:spotube/extensions/constrains.dart'; +import 'package:spotube/extensions/context.dart'; +import 'package:spotube/hooks/utils/use_breakpoint_value.dart'; +import 'package:spotube/provider/authentication_provider.dart'; +import 'package:spotube/provider/blacklist_provider.dart'; +import 'package:spotube/provider/spotify_provider.dart'; +import 'package:spotube/services/queries/queries.dart'; +import 'package:spotube/utils/primitive_utils.dart'; +import 'package:spotube/utils/type_conversion_utils.dart'; + +class ArtistPageHeader extends HookConsumerWidget { + final String artistId; + const ArtistPageHeader({Key? key, required this.artistId}) : super(key: key); + + @override + Widget build(BuildContext context, ref) { + final queryClient = useQueryClient(); + final artistQuery = useQueries.artist.get(ref, artistId); + final artist = artistQuery.data; + + final scaffoldMessenger = ScaffoldMessenger.of(context); + final mediaQuery = MediaQuery.of(context); + final theme = Theme.of(context); + final ThemeData(:textTheme) = theme; + + final chipTextVariant = useBreakpointValue( + xs: textTheme.bodySmall, + sm: textTheme.bodySmall, + md: textTheme.bodyMedium, + lg: textTheme.bodyLarge, + xl: textTheme.titleSmall, + xxl: textTheme.titleMedium, + ); + + if (artist == null) { + return const SizedBox.shrink(); + } + + final spotify = ref.read(spotifyProvider); + final auth = ref.watch(AuthenticationNotifier.provider); + final blacklist = ref.watch(BlackListNotifier.provider); + final isBlackListed = blacklist.contains( + BlacklistedElement.artist(artistId, artist.name!), + ); + + final image = TypeConversionUtils.image_X_UrlString( + artist.images, + placeholder: ImagePlaceholder.artist, + ); + + return LayoutBuilder( + builder: (context, constrains) { + return Center( + child: Flex( + mainAxisAlignment: MainAxisAlignment.center, + crossAxisAlignment: constrains.smAndDown + ? CrossAxisAlignment.start + : CrossAxisAlignment.center, + direction: constrains.smAndDown ? Axis.vertical : Axis.horizontal, + children: [ + DecoratedBox( + decoration: BoxDecoration( + boxShadow: kElevationToShadow[2], + borderRadius: BorderRadius.circular(35), + ), + child: ClipRRect( + borderRadius: BorderRadius.circular(35), + child: UniversalImage( + path: image, + width: 250, + height: 250, + fit: BoxFit.cover, + ), + ), + ), + const Gap(20), + Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Row( + mainAxisSize: MainAxisSize.min, + children: [ + Container( + padding: const EdgeInsets.symmetric( + horizontal: 10, vertical: 5), + decoration: BoxDecoration( + color: Colors.blue, + borderRadius: BorderRadius.circular(50)), + child: Text( + artist.type!.toUpperCase(), + style: chipTextVariant.copyWith( + color: Colors.white, + ), + ), + ), + if (isBlackListed) ...[ + const SizedBox(width: 5), + Container( + padding: const EdgeInsets.symmetric( + horizontal: 10, vertical: 5), + decoration: BoxDecoration( + color: Colors.red[400], + borderRadius: BorderRadius.circular(50)), + child: Text( + context.l10n.blacklisted, + style: chipTextVariant.copyWith( + color: Colors.white, + ), + ), + ), + ] + ], + ), + Text( + artist.name!, + style: mediaQuery.smAndDown + ? textTheme.headlineSmall + : textTheme.headlineMedium, + ), + Text( + context.l10n.followers( + PrimitiveUtils.toReadableNumber( + artist.followers!.total!.toDouble(), + ), + ), + style: textTheme.bodyMedium?.copyWith( + fontWeight: mediaQuery.mdAndUp ? FontWeight.bold : null, + ), + ), + const Gap(20), + Row( + mainAxisSize: MainAxisSize.min, + children: [ + if (auth != null) + HookBuilder( + builder: (context) { + final isFollowingQuery = + useQueries.artist.doIFollow(ref, artistId); + + final followUnfollow = useCallback(() async { + try { + isFollowingQuery.data! + ? await spotify.me.unfollow( + FollowingType.artist, + [artistId], + ) + : await spotify.me.follow( + FollowingType.artist, + [artistId], + ); + await isFollowingQuery.refresh(); + + queryClient.refreshInfiniteQueryAllPages( + "user-following-artists"); + } finally { + queryClient.refreshQuery( + "user-follows-artists-query/$artistId", + ); + } + }, [isFollowingQuery]); + + if (isFollowingQuery.isLoading || + !isFollowingQuery.hasData) { + return const SizedBox( + height: 20, + width: 20, + child: CircularProgressIndicator(), + ); + } + + if (isFollowingQuery.data!) { + return OutlinedButton( + onPressed: followUnfollow, + child: Text(context.l10n.following), + ); + } + + return FilledButton( + onPressed: followUnfollow, + child: Text(context.l10n.follow), + ); + }, + ), + const SizedBox(width: 5), + IconButton( + tooltip: context.l10n.add_artist_to_blacklist, + icon: Icon( + SpotubeIcons.userRemove, + color: + !isBlackListed ? Colors.red[400] : Colors.white, + ), + style: IconButton.styleFrom( + backgroundColor: + isBlackListed ? Colors.red[400] : null, + ), + onPressed: () async { + if (isBlackListed) { + ref + .read(BlackListNotifier.provider.notifier) + .remove( + BlacklistedElement.artist( + artist.id!, artist.name!), + ); + } else { + ref.read(BlackListNotifier.provider.notifier).add( + BlacklistedElement.artist( + artist.id!, artist.name!), + ); + } + }, + ), + IconButton( + icon: const Icon(SpotubeIcons.share), + onPressed: () async { + if (artist.externalUrls?.spotify != null) { + await Clipboard.setData( + ClipboardData( + text: artist.externalUrls!.spotify!, + ), + ); + } + + if (!context.mounted) return; + + scaffoldMessenger.showSnackBar( + SnackBar( + width: 300, + behavior: SnackBarBehavior.floating, + content: Text( + context.l10n.artist_url_copied, + textAlign: TextAlign.center, + ), + ), + ); + }, + ) + ], + ) + ], + ), + ], + ), + ); + }, + ); + } +} diff --git a/lib/pages/artist/section/related_artists.dart b/lib/pages/artist/section/related_artists.dart new file mode 100644 index 00000000..2938c084 --- /dev/null +++ b/lib/pages/artist/section/related_artists.dart @@ -0,0 +1,49 @@ +import 'package:flutter/material.dart'; +import 'package:hooks_riverpod/hooks_riverpod.dart'; +import 'package:spotube/components/artist/artist_card.dart'; +import 'package:spotube/services/queries/queries.dart'; + +class ArtistPageRelatedArtists extends HookConsumerWidget { + final String artistId; + const ArtistPageRelatedArtists({ + Key? key, + required this.artistId, + }) : super(key: key); + + @override + Widget build(BuildContext context, ref) { + final relatedArtists = useQueries.artist.relatedArtistsOf( + ref, + artistId, + ); + + if (relatedArtists.isLoading || !relatedArtists.hasData) { + return const SliverToBoxAdapter( + child: Center(child: CircularProgressIndicator())); + } else if (relatedArtists.hasError) { + return SliverToBoxAdapter( + child: Center( + child: Text(relatedArtists.error.toString()), + ), + ); + } + + return SliverPadding( + padding: const EdgeInsets.symmetric(horizontal: 8.0), + sliver: SliverGrid.builder( + itemCount: relatedArtists.data!.length, + gridDelegate: const SliverGridDelegateWithMaxCrossAxisExtent( + maxCrossAxisExtent: 200, + mainAxisExtent: 250, + mainAxisSpacing: 10, + crossAxisSpacing: 10, + childAspectRatio: 0.8, + ), + itemBuilder: (context, index) { + final artist = relatedArtists.data!.elementAt(index); + return ArtistCard(artist); + }, + ), + ); + } +} diff --git a/lib/pages/artist/section/top_tracks.dart b/lib/pages/artist/section/top_tracks.dart new file mode 100644 index 00000000..9e3e4054 --- /dev/null +++ b/lib/pages/artist/section/top_tracks.dart @@ -0,0 +1,126 @@ +import 'package:flutter/material.dart'; +import 'package:hooks_riverpod/hooks_riverpod.dart'; +import 'package:spotify/spotify.dart'; +import 'package:spotube/collections/spotube_icons.dart'; +import 'package:spotube/components/shared/track_tile/track_tile.dart'; +import 'package:spotube/extensions/context.dart'; +import 'package:spotube/provider/proxy_playlist/proxy_playlist_provider.dart'; +import 'package:spotube/services/queries/queries.dart'; + +class ArtistPageTopTracks extends HookConsumerWidget { + final String artistId; + const ArtistPageTopTracks({Key? key, required this.artistId}) + : super(key: key); + + @override + Widget build(BuildContext context, ref) { + final theme = Theme.of(context); + final scaffoldMessenger = ScaffoldMessenger.of(context); + + final playlist = ref.watch(ProxyPlaylistNotifier.provider); + final playlistNotifier = ref.watch(ProxyPlaylistNotifier.notifier); + final topTracksQuery = useQueries.artist.topTracksOf( + ref, + artistId, + ); + + final isPlaylistPlaying = playlist.containsTracks( + topTracksQuery.data ?? [], + ); + + if (topTracksQuery.isLoading || !topTracksQuery.hasData) { + return const SliverToBoxAdapter( + child: Center(child: CircularProgressIndicator()), + ); + } else if (topTracksQuery.hasError) { + return SliverToBoxAdapter( + child: Center( + child: Text(topTracksQuery.error.toString()), + ), + ); + } + + final topTracks = topTracksQuery.data!; + + void playPlaylist(List tracks, {Track? currentTrack}) async { + currentTrack ??= tracks.first; + if (!isPlaylistPlaying) { + playlistNotifier.load( + tracks, + initialIndex: tracks.indexWhere((s) => s.id == currentTrack?.id), + autoPlay: true, + ); + } else if (isPlaylistPlaying && + currentTrack.id != null && + currentTrack.id != playlist.activeTrack?.id) { + await playlistNotifier.jumpToTrack(currentTrack); + } + } + + return SliverMainAxisGroup( + slivers: [ + SliverToBoxAdapter( + child: Row( + children: [ + Padding( + padding: const EdgeInsets.all(8.0), + child: Text( + context.l10n.top_tracks, + style: theme.textTheme.headlineSmall, + ), + ), + if (!isPlaylistPlaying) + IconButton( + icon: const Icon( + SpotubeIcons.queueAdd, + ), + onPressed: () { + playlistNotifier.addTracks(topTracks.toList()); + scaffoldMessenger.showSnackBar( + SnackBar( + width: 300, + behavior: SnackBarBehavior.floating, + content: Text( + context.l10n.added_to_queue( + topTracks.length, + ), + textAlign: TextAlign.center, + ), + ), + ); + }, + ), + const SizedBox(width: 5), + IconButton( + icon: Icon( + isPlaylistPlaying ? SpotubeIcons.stop : SpotubeIcons.play, + color: Colors.white, + ), + style: IconButton.styleFrom( + backgroundColor: theme.colorScheme.primary, + ), + onPressed: () => playPlaylist(topTracks.toList()), + ) + ], + ), + ), + SliverList.builder( + itemCount: topTracks.length, + itemBuilder: (context, index) { + final track = topTracks.elementAt(index); + return TrackTile( + index: index, + track: track, + onTap: () async { + playPlaylist( + topTracks.toList(), + currentTrack: track, + ); + }, + ); + }, + ), + ], + ); + } +} diff --git a/lib/services/queries/artist.dart b/lib/services/queries/artist.dart index 7501d619..1b939c82 100644 --- a/lib/services/queries/artist.dart +++ b/lib/services/queries/artist.dart @@ -1,8 +1,12 @@ import 'package:fl_query/fl_query.dart'; +import 'package:fl_query_hooks/fl_query_hooks.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:spotify/spotify.dart'; import 'package:spotube/hooks/spotify/use_spotify_infinite_query.dart'; import 'package:spotube/hooks/spotify/use_spotify_query.dart'; +import 'package:spotube/provider/user_preferences/user_preferences_provider.dart'; +import 'package:spotube/services/wikipedia/wikipedia.dart'; +import 'package:wikipedia_api/wikipedia_api.dart'; class ArtistQueries { const ArtistQueries(); @@ -72,11 +76,11 @@ class ArtistQueries { return useSpotifyQuery( "user-follows-artists-query/$artist", (spotify) async { - final result = await spotify.me.isFollowing( + final result = await spotify.me.checkFollowing( FollowingType.artist, [artist], ); - return result.first; + return result[artist]; }, ref: ref, ); @@ -86,10 +90,12 @@ class ArtistQueries { WidgetRef ref, String artist, ) { + final preferences = ref.watch(userPreferencesProvider); return useSpotifyQuery, dynamic>( "artist-top-track-query/$artist", (spotify) { - return spotify.artists.getTopTracks(artist, "US"); + return spotify.artists + .topTracks(artist, preferences.recommendationMarket); }, ref: ref, ); @@ -122,9 +128,24 @@ class ArtistQueries { return useSpotifyQuery, dynamic>( "artist-related-artist-query/$artist", (spotify) { - return spotify.artists.getRelatedArtists(artist); + return spotify.artists.relatedArtists(artist); }, ref: ref, ); } + + Query wikipediaSummary(ArtistSimple artist) { + return useQuery( + "artist-wikipedia-query/${artist.id}", + () async { + final query = artist.name!.replaceAll(" ", "_"); + final res = await wikipedia.pageContent.pageSummaryTitleGet(query); + if (res?.type != "standard") { + return await wikipedia.pageContent + .pageSummaryTitleGet("${query}_(singer)"); + } + return res; + }, + ); + } } diff --git a/lib/services/wikipedia/wikipedia.dart b/lib/services/wikipedia/wikipedia.dart new file mode 100644 index 00000000..b571f30f --- /dev/null +++ b/lib/services/wikipedia/wikipedia.dart @@ -0,0 +1,3 @@ +import 'package:wikipedia_api/wikipedia_api.dart'; + +final wikipedia = WikipediaApi(); diff --git a/pubspec.lock b/pubspec.lock index 6c822604..414297c5 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -2222,6 +2222,15 @@ packages: url: "https://pub.dev" source: hosted version: "3.0.2" + wikipedia_api: + dependency: "direct main" + description: + path: "." + ref: HEAD + resolved-ref: cb7590a3d76b25f16ad3f7147ae6603350777a00 + url: "https://github.com/KRTirtho/wikipedia_api.git" + source: git + version: "0.1.0" win32: dependency: transitive description: @@ -2288,5 +2297,5 @@ packages: source: hosted version: "2.0.2" sdks: - dart: ">=3.2.0-194.0.dev <4.0.0" + dart: ">=3.2.0 <4.0.0" flutter: ">=3.13.0" diff --git a/pubspec.yaml b/pubspec.yaml index 6a33d294..fd99e841 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -119,6 +119,9 @@ dependencies: git: url: https://github.com/Tommypop2/dart_discord_rpc.git html_unescape: ^2.0.0 + wikipedia_api: + git: + url: https://github.com/KRTirtho/wikipedia_api.git dev_dependencies: build_runner: ^2.3.2 From 42dd4d68e7ae46c5bfb95f1e065f82fa9e8f5781 Mon Sep 17 00:00:00 2001 From: Kingkor Roy Tirtho Date: Wed, 22 Nov 2023 21:09:29 +0600 Subject: [PATCH 037/195] chore: update deps --- pubspec.lock | 18 ++++++++---------- pubspec.yaml | 8 ++------ 2 files changed, 10 insertions(+), 16 deletions(-) diff --git a/pubspec.lock b/pubspec.lock index 414297c5..06ca8202 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -1194,11 +1194,10 @@ packages: jiosaavn: dependency: "direct main" description: - path: "." - ref: HEAD - resolved-ref: "8a7cda9b8b687cde28e0f7fcb10adb0d4fde1007" - url: "https://github.com/KRTirtho/jiosaavn.git" - source: git + name: jiosaavn + sha256: d32b4f43f26488f942f5d7d19d748a1f2664ae3d41ff9c7d50eeb81705174bd2 + url: "https://pub.dev" + source: hosted version: "0.1.0" js: dependency: transitive @@ -2225,11 +2224,10 @@ packages: wikipedia_api: dependency: "direct main" description: - path: "." - ref: HEAD - resolved-ref: cb7590a3d76b25f16ad3f7147ae6603350777a00 - url: "https://github.com/KRTirtho/wikipedia_api.git" - source: git + name: wikipedia_api + sha256: "8bae02778c40e0c09ea237b7c1952c99a33a19ccbe31545e03c807fdc7c56ec6" + url: "https://pub.dev" + source: hosted version: "0.1.0" win32: dependency: transitive diff --git a/pubspec.yaml b/pubspec.yaml index fd99e841..1ad8fd9f 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -105,9 +105,7 @@ dependencies: simple_icons: ^7.10.0 audio_service_mpris: ^0.1.0 file_picker: ^6.0.0 - jiosaavn: - git: - url: https://github.com/KRTirtho/jiosaavn.git + jiosaavn: ^0.1.0 draggable_scrollbar: git: url: https://github.com/thielepaul/flutter-draggable-scrollbar.git @@ -119,9 +117,7 @@ dependencies: git: url: https://github.com/Tommypop2/dart_discord_rpc.git html_unescape: ^2.0.0 - wikipedia_api: - git: - url: https://github.com/KRTirtho/wikipedia_api.git + wikipedia_api: ^0.1.0 dev_dependencies: build_runner: ^2.3.2 From 82593f1d654f26549965ad0e9c59d798897138e4 Mon Sep 17 00:00:00 2001 From: Kingkor Roy Tirtho Date: Wed, 22 Nov 2023 21:54:56 +0600 Subject: [PATCH 038/195] cd: increment flutter version --- .fvm/fvm_config.json | 2 +- .github/workflows/spotube-release-binary.yml | 2 +- CONTRIBUTION.md | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.fvm/fvm_config.json b/.fvm/fvm_config.json index ba129cfd..f1f9ceed 100644 --- a/.fvm/fvm_config.json +++ b/.fvm/fvm_config.json @@ -1,4 +1,4 @@ { - "flutterSdkVersion": "3.10.0", + "flutterSdkVersion": "3.16.0", "flavors": {} } \ No newline at end of file diff --git a/.github/workflows/spotube-release-binary.yml b/.github/workflows/spotube-release-binary.yml index ab42dcb9..46555de5 100644 --- a/.github/workflows/spotube-release-binary.yml +++ b/.github/workflows/spotube-release-binary.yml @@ -26,7 +26,7 @@ on: default: true env: - FLUTTER_VERSION: '3.13.2' + FLUTTER_VERSION: '3.16.0' jobs: windows: diff --git a/CONTRIBUTION.md b/CONTRIBUTION.md index 11206e6d..b2823e62 100644 --- a/CONTRIBUTION.md +++ b/CONTRIBUTION.md @@ -119,7 +119,7 @@ Enhancement suggestions are tracked as [GitHub issues](https://github.com/KRTirt Do the following: -- Download the latest Flutter SDK (>=3.10.0) & enable desktop support +- Download the latest Flutter SDK (>=3.16.0) & enable desktop support - Install Development dependencies in linux - Debian (>=12/Bookworm)/Ubuntu ```bash From 64080ef2731cef4e370096d2ffe9e917ea06f0c7 Mon Sep 17 00:00:00 2001 From: Kingkor Roy Tirtho Date: Fri, 24 Nov 2023 20:49:25 +0600 Subject: [PATCH 039/195] cd: fix flutter_distributor for windows not working (temporary) --- .github/workflows/spotube-release-binary.yml | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/.github/workflows/spotube-release-binary.yml b/.github/workflows/spotube-release-binary.yml index 46555de5..62dbcace 100644 --- a/.github/workflows/spotube-release-binary.yml +++ b/.github/workflows/spotube-release-binary.yml @@ -33,6 +33,11 @@ jobs: runs-on: windows-latest steps: - uses: actions/checkout@v4 + - uses: actions/checkout@v4 + with: + repository: KRTirtho/flutter_distributor + path: flutter_distributor + ref: fix-windows-build - uses: subosito/flutter-action@v2.10.0 with: cache: true @@ -74,9 +79,10 @@ jobs: - name: Build Windows Executable run: | - dart pub global activate flutter_distributor + dart pub global activate melos + cd flutter_distributor && melos bs && cd .. make innoinstall - flutter_distributor package --platform=windows --targets=exe --skip-clean + dart run ./flutter_distributor/packages/flutter_distributor/bin/main.dart package --platform=windows --targets=exe --skip-clean mv dist/**/spotube-*-windows-setup.exe dist/Spotube-windows-x86_64-setup.exe - name: Create Chocolatey Package and set hash From 722dd86810ea076c0e540ff5cd108fb5f2df2a0f Mon Sep 17 00:00:00 2001 From: Kingkor Roy Tirtho Date: Mon, 27 Nov 2023 19:34:18 +0600 Subject: [PATCH 040/195] chore: track view play not working properly --- .../sections/body/track_view_body.dart | 18 +- lib/extensions/infinite_query.dart | 26 +- lib/pages/artist/section/footer.dart | 6 +- .../playlist_generate/playlist_generate.dart | 513 +++++++++--------- lib/pages/playlist/playlist.dart | 2 +- 5 files changed, 296 insertions(+), 269 deletions(-) diff --git a/lib/components/shared/tracks_view/sections/body/track_view_body.dart b/lib/components/shared/tracks_view/sections/body/track_view_body.dart index 486e4405..1c3ba3fb 100644 --- a/lib/components/shared/tracks_view/sections/body/track_view_body.dart +++ b/lib/components/shared/tracks_view/sections/body/track_view_body.dart @@ -25,8 +25,6 @@ class TrackViewBodySection extends HookConsumerWidget { final playlistNotifier = ref.watch(ProxyPlaylistNotifier.notifier); final props = InheritedTrackView.of(context); - final trackViewState = ref.watch(trackViewProvider(props.tracks)); - final searchController = useTextEditingController(); final searchFocus = useFocusNode(); @@ -35,12 +33,19 @@ class TrackViewBodySection extends HookConsumerWidget { final isFiltering = useState(false); + final uniqTracks = useMemoized(() { + final trackIds = props.tracks.map((e) => e.id).toSet(); + return props.tracks.where((e) => trackIds.remove(e.id)).toList(); + }, [props.tracks]); + + final trackViewState = ref.watch(trackViewProvider(uniqTracks)); + final tracks = useMemoized(() { List filteredTracks; if (searchQuery.isEmpty) { - filteredTracks = props.tracks; + filteredTracks = uniqTracks; } else { - filteredTracks = props.tracks + filteredTracks = uniqTracks .map((e) => (weightedRatio(e.name!, searchQuery), e)) .sorted((a, b) => b.$1.compareTo(a.$1)) .where((e) => e.$1 > 50) @@ -48,7 +53,7 @@ class TrackViewBodySection extends HookConsumerWidget { .toList(); } return ServiceUtils.sortTracks(filteredTracks, trackViewState.sortBy); - }, [trackViewState.sortBy, searchQuery, props.tracks]); + }, [trackViewState.sortBy, searchQuery, uniqTracks]); final isUserPlaylist = useIsUserPlaylist(ref, props.collectionId); @@ -106,8 +111,9 @@ class TrackViewBodySection extends HookConsumerWidget { if (isActive || playlist.tracks.contains(track)) { await playlistNotifier.jumpToTrack(track); } else { + final tracks = await props.pagination.onFetchAll(); await playlistNotifier.load( - props.tracks, + tracks, initialIndex: index, autoPlay: true, ); diff --git a/lib/extensions/infinite_query.dart b/lib/extensions/infinite_query.dart index 90dcf73e..2181ab3c 100644 --- a/lib/extensions/infinite_query.dart +++ b/lib/extensions/infinite_query.dart @@ -9,17 +9,21 @@ extension FetchAllTracks on InfiniteQuery, dynamic, int> { return pages.expand((page) => page).toList(); } final tracks = await getAllTracks(); - final pagedTracks = tracks.fold( - >{}, - (acc, element) { - final index = acc.length; - final groupIndex = index ~/ 20; - final group = acc[groupIndex] ?? []; - group.add(element); - acc[groupIndex] = group; - return acc; - }, - ); + + final numOfPages = (tracks.length / 20).round(); + + final Map> pagedTracks = {}; + + for (var i = 0; i < numOfPages; i++) { + if (i == numOfPages - 1) { + final pageTracks = tracks.sublist(i * 20); + pagedTracks[i] = pageTracks; + break; + } + + final pageTracks = tracks.sublist(i * 20, (i + 1) * 20); + pagedTracks[i] = pageTracks; + } for (final group in pagedTracks.entries) { setPageData(group.key, group.value); diff --git a/lib/pages/artist/section/footer.dart b/lib/pages/artist/section/footer.dart index 3c0db8a5..b01ef705 100644 --- a/lib/pages/artist/section/footer.dart +++ b/lib/pages/artist/section/footer.dart @@ -38,9 +38,9 @@ class ArtistPageFooter extends HookConsumerWidget { BlendMode.darken, ), image: UniversalImage.imageProvider( - summary.data!.originalimage?.source_ ?? artistImage, - height: summary.data!.originalimage?.height.toDouble(), - width: summary.data!.originalimage?.width.toDouble(), + summary.data!.thumbnail?.source_ ?? artistImage, + height: summary.data!.thumbnail?.height.toDouble(), + width: summary.data!.thumbnail?.width.toDouble(), ), fit: BoxFit.cover, alignment: Alignment.center, diff --git a/lib/pages/library/playlist_generate/playlist_generate.dart b/lib/pages/library/playlist_generate/playlist_generate.dart index 4b8dddaf..802b28d3 100644 --- a/lib/pages/library/playlist_generate/playlist_generate.dart +++ b/lib/pages/library/playlist_generate/playlist_generate.dart @@ -242,267 +242,284 @@ class PlaylistGeneratorPage extends HookConsumerWidget { }, ); + final controller = useScrollController(); + return Scaffold( appBar: PageWindowTitleBar( leading: const BackButton(), title: Text(context.l10n.generate_playlist), centerTitle: true, ), - body: Center( - child: ConstrainedBox( - constraints: BoxConstraints(maxWidth: Breakpoints.lg), - child: SliderTheme( - data: const SliderThemeData( - overlayShape: RoundSliderOverlayShape(), - ), - child: SafeArea( - child: LayoutBuilder(builder: (context, constrains) { - return ListView( - padding: const EdgeInsets.all(16), - children: [ - ValueListenableBuilder( - valueListenable: limit, - builder: (context, value, child) { - return Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text( - context.l10n.number_of_tracks_generate, - style: textTheme.titleMedium, - ), - Row( + body: Scrollbar( + controller: controller, + child: Center( + child: ConstrainedBox( + constraints: BoxConstraints(maxWidth: Breakpoints.lg), + child: SliderTheme( + data: const SliderThemeData( + overlayShape: RoundSliderOverlayShape(), + ), + child: SafeArea( + child: LayoutBuilder(builder: (context, constrains) { + return ScrollConfiguration( + behavior: ScrollConfiguration.of(context) + .copyWith(scrollbars: false), + child: ListView( + controller: controller, + padding: const EdgeInsets.all(16), + children: [ + ValueListenableBuilder( + valueListenable: limit, + builder: (context, value, child) { + return Column( + crossAxisAlignment: CrossAxisAlignment.start, children: [ - Container( - width: 40, - height: 40, - alignment: Alignment.center, - decoration: BoxDecoration( - color: theme.colorScheme.primary, - shape: BoxShape.circle, - ), - child: Text( - value.round().toString(), - style: textTheme.bodyLarge?.copyWith( - color: theme.colorScheme.primaryContainer, - ), - ), + Text( + context.l10n.number_of_tracks_generate, + style: textTheme.titleMedium, ), - Expanded( - child: Slider( - value: value.toDouble(), - min: 10, - max: 100, - divisions: 9, - label: value.round().toString(), - onChanged: (value) { - limit.value = value.round(); - }, - ), + Row( + children: [ + Container( + width: 40, + height: 40, + alignment: Alignment.center, + decoration: BoxDecoration( + color: theme.colorScheme.primary, + shape: BoxShape.circle, + ), + child: Text( + value.round().toString(), + style: textTheme.bodyLarge?.copyWith( + color: theme + .colorScheme.primaryContainer, + ), + ), + ), + Expanded( + child: Slider( + value: value.toDouble(), + min: 10, + max: 100, + divisions: 9, + label: value.round().toString(), + onChanged: (value) { + limit.value = value.round(); + }, + ), + ) + ], ) ], - ) - ], - ); - }, - ), - const SizedBox(height: 16), - if (constrains.mdAndUp) - Row( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Expanded( - child: countrySelector, - ), - const SizedBox(width: 16), - Expanded( - child: genreSelector, - ), + ); + }, + ), + const SizedBox(height: 16), + if (constrains.mdAndUp) + Row( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Expanded( + child: countrySelector, + ), + const SizedBox(width: 16), + Expanded( + child: genreSelector, + ), + ], + ) + else ...[ + countrySelector, + const SizedBox(height: 16), + genreSelector, ], - ) - else ...[ - countrySelector, - const SizedBox(height: 16), - genreSelector, - ], - const SizedBox(height: 16), - if (constrains.mdAndUp) - Row( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Expanded( - child: artistAutoComplete, - ), - const SizedBox(width: 16), - Expanded( - child: tracksAutocomplete, - ), + const SizedBox(height: 16), + if (constrains.mdAndUp) + Row( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Expanded( + child: artistAutoComplete, + ), + const SizedBox(width: 16), + Expanded( + child: tracksAutocomplete, + ), + ], + ) + else ...[ + artistAutoComplete, + const SizedBox(height: 16), + tracksAutocomplete, ], - ) - else ...[ - artistAutoComplete, - const SizedBox(height: 16), - tracksAutocomplete, - ], - const SizedBox(height: 16), - RecommendationAttributeDials( - title: Text(context.l10n.acousticness), - values: acousticness.value, - onChanged: (value) { - acousticness.value = value; - }, + const SizedBox(height: 16), + RecommendationAttributeDials( + title: Text(context.l10n.acousticness), + values: acousticness.value, + onChanged: (value) { + acousticness.value = value; + }, + ), + RecommendationAttributeDials( + title: Text(context.l10n.danceability), + values: danceability.value, + onChanged: (value) { + danceability.value = value; + }, + ), + RecommendationAttributeDials( + title: Text(context.l10n.energy), + values: energy.value, + onChanged: (value) { + energy.value = value; + }, + ), + RecommendationAttributeDials( + title: Text(context.l10n.instrumentalness), + values: instrumentalness.value, + onChanged: (value) { + instrumentalness.value = value; + }, + ), + RecommendationAttributeDials( + title: Text(context.l10n.liveness), + values: liveness.value, + onChanged: (value) { + liveness.value = value; + }, + ), + RecommendationAttributeDials( + title: Text(context.l10n.loudness), + values: loudness.value, + onChanged: (value) { + loudness.value = value; + }, + ), + RecommendationAttributeDials( + title: Text(context.l10n.speechiness), + values: speechiness.value, + onChanged: (value) { + speechiness.value = value; + }, + ), + RecommendationAttributeDials( + title: Text(context.l10n.valence), + values: valence.value, + onChanged: (value) { + valence.value = value; + }, + ), + RecommendationAttributeDials( + title: Text(context.l10n.popularity), + values: popularity.value, + base: 100, + onChanged: (value) { + popularity.value = value; + }, + ), + RecommendationAttributeDials( + title: Text(context.l10n.key), + values: key.value, + base: 11, + onChanged: (value) { + key.value = value; + }, + ), + RecommendationAttributeFields( + title: Text(context.l10n.duration), + values: ( + max: durationMs.value.max / 1000, + target: durationMs.value.target / 1000, + min: durationMs.value.min / 1000, + ), + onChanged: (value) { + durationMs.value = ( + max: value.max * 1000, + target: value.target * 1000, + min: value.min * 1000, + ); + }, + presets: { + context.l10n.short: (min: 50, target: 90, max: 120), + context.l10n.medium: ( + min: 120, + target: 180, + max: 200 + ), + context.l10n.long: (min: 480, target: 560, max: 640) + }, + ), + RecommendationAttributeFields( + title: Text(context.l10n.tempo), + values: tempo.value, + onChanged: (value) { + tempo.value = value; + }, + ), + RecommendationAttributeFields( + title: Text(context.l10n.mode), + values: mode.value, + onChanged: (value) { + mode.value = value; + }, + ), + RecommendationAttributeFields( + title: Text(context.l10n.time_signature), + values: timeSignature.value, + onChanged: (value) { + timeSignature.value = value; + }, + ), + const SizedBox(height: 20), + FilledButton.icon( + icon: const Icon(SpotubeIcons.magic), + label: Text(context.l10n.generate_playlist), + onPressed: artists.value.isEmpty && + tracks.value.isEmpty && + genres.value.isEmpty + ? null + : () { + final PlaylistGenerateResultRouteState + routeState = ( + seeds: ( + artists: artists.value + .map((a) => a.id!) + .toList(), + tracks: tracks.value + .map((t) => t.id!) + .toList(), + genres: genres.value + ), + market: market.value, + limit: limit.value, + parameters: ( + acousticness: acousticness.value, + danceability: danceability.value, + energy: energy.value, + instrumentalness: instrumentalness.value, + liveness: liveness.value, + loudness: loudness.value, + speechiness: speechiness.value, + valence: valence.value, + popularity: popularity.value, + key: key.value, + duration_ms: durationMs.value, + tempo: tempo.value, + mode: mode.value, + time_signature: timeSignature.value, + ) + ); + GoRouter.of(context).push( + "/library/generate/result", + extra: routeState, + ); + }, + ), + ], ), - RecommendationAttributeDials( - title: Text(context.l10n.danceability), - values: danceability.value, - onChanged: (value) { - danceability.value = value; - }, - ), - RecommendationAttributeDials( - title: Text(context.l10n.energy), - values: energy.value, - onChanged: (value) { - energy.value = value; - }, - ), - RecommendationAttributeDials( - title: Text(context.l10n.instrumentalness), - values: instrumentalness.value, - onChanged: (value) { - instrumentalness.value = value; - }, - ), - RecommendationAttributeDials( - title: Text(context.l10n.liveness), - values: liveness.value, - onChanged: (value) { - liveness.value = value; - }, - ), - RecommendationAttributeDials( - title: Text(context.l10n.loudness), - values: loudness.value, - onChanged: (value) { - loudness.value = value; - }, - ), - RecommendationAttributeDials( - title: Text(context.l10n.speechiness), - values: speechiness.value, - onChanged: (value) { - speechiness.value = value; - }, - ), - RecommendationAttributeDials( - title: Text(context.l10n.valence), - values: valence.value, - onChanged: (value) { - valence.value = value; - }, - ), - RecommendationAttributeDials( - title: Text(context.l10n.popularity), - values: popularity.value, - base: 100, - onChanged: (value) { - popularity.value = value; - }, - ), - RecommendationAttributeDials( - title: Text(context.l10n.key), - values: key.value, - base: 11, - onChanged: (value) { - key.value = value; - }, - ), - RecommendationAttributeFields( - title: Text(context.l10n.duration), - values: ( - max: durationMs.value.max / 1000, - target: durationMs.value.target / 1000, - min: durationMs.value.min / 1000, - ), - onChanged: (value) { - durationMs.value = ( - max: value.max * 1000, - target: value.target * 1000, - min: value.min * 1000, - ); - }, - presets: { - context.l10n.short: (min: 50, target: 90, max: 120), - context.l10n.medium: (min: 120, target: 180, max: 200), - context.l10n.long: (min: 480, target: 560, max: 640) - }, - ), - RecommendationAttributeFields( - title: Text(context.l10n.tempo), - values: tempo.value, - onChanged: (value) { - tempo.value = value; - }, - ), - RecommendationAttributeFields( - title: Text(context.l10n.mode), - values: mode.value, - onChanged: (value) { - mode.value = value; - }, - ), - RecommendationAttributeFields( - title: Text(context.l10n.time_signature), - values: timeSignature.value, - onChanged: (value) { - timeSignature.value = value; - }, - ), - const SizedBox(height: 20), - FilledButton.icon( - icon: const Icon(SpotubeIcons.magic), - label: Text(context.l10n.generate_playlist), - onPressed: artists.value.isEmpty && - tracks.value.isEmpty && - genres.value.isEmpty - ? null - : () { - final PlaylistGenerateResultRouteState - routeState = ( - seeds: ( - artists: - artists.value.map((a) => a.id!).toList(), - tracks: - tracks.value.map((t) => t.id!).toList(), - genres: genres.value - ), - market: market.value, - limit: limit.value, - parameters: ( - acousticness: acousticness.value, - danceability: danceability.value, - energy: energy.value, - instrumentalness: instrumentalness.value, - liveness: liveness.value, - loudness: loudness.value, - speechiness: speechiness.value, - valence: valence.value, - popularity: popularity.value, - key: key.value, - duration_ms: durationMs.value, - tempo: tempo.value, - mode: mode.value, - time_signature: timeSignature.value, - ) - ); - GoRouter.of(context).push( - "/library/generate/result", - extra: routeState, - ); - }, - ), - ], - ); - }), + ); + }), + ), ), ), ), diff --git a/lib/pages/playlist/playlist.dart b/lib/pages/playlist/playlist.dart index ab39b225..29601a09 100644 --- a/lib/pages/playlist/playlist.dart +++ b/lib/pages/playlist/playlist.dart @@ -53,7 +53,7 @@ class PlaylistPage extends HookConsumerWidget { ), pagination: PaginationProps.fromQuery( tracksQuery, - onFetchAll: () async { + onFetchAll: () { return tracksQuery.fetchAllTracks( getAllTracks: () async { final res = await spotify.playlists From ee8229020b3b03fc074b316db4b322af13b807bd Mon Sep 17 00:00:00 2001 From: Kingkor Roy Tirtho Date: Mon, 27 Nov 2023 19:39:53 +0600 Subject: [PATCH 041/195] fix: settings page scrollbar position --- lib/pages/search/search.dart | 5 +++-- lib/pages/settings/settings.dart | 15 ++++++++------- 2 files changed, 11 insertions(+), 9 deletions(-) diff --git a/lib/pages/search/search.dart b/lib/pages/search/search.dart index b19162fa..f4a78d4f 100644 --- a/lib/pages/search/search.dart +++ b/lib/pages/search/search.dart @@ -114,8 +114,9 @@ class SearchPage extends HookConsumerWidget { ), color: theme.scaffoldBackgroundColor, child: TextField( - autofocus: - queries.none((s) => s.hasPageData && !s.hasPageError), + autofocus: queries + .none((s) => s.hasPageData && !s.hasPageError) && + !kIsMobile, decoration: InputDecoration( prefixIcon: const Icon(SpotubeIcons.search), hintText: "${context.l10n.search}...", diff --git a/lib/pages/settings/settings.dart b/lib/pages/settings/settings.dart index 842d5240..f773b809 100644 --- a/lib/pages/settings/settings.dart +++ b/lib/pages/settings/settings.dart @@ -30,12 +30,13 @@ class SettingsPage extends HookConsumerWidget { title: Text(context.l10n.settings), centerTitle: true, ), - body: Row( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - Flexible( - child: Container( - constraints: const BoxConstraints(maxWidth: 1366), + body: Scrollbar( + controller: controller, + child: Center( + child: ConstrainedBox( + constraints: const BoxConstraints(maxWidth: 1366), + child: ScrollConfiguration( + behavior: const ScrollBehavior().copyWith(scrollbars: false), child: ListView( controller: controller, children: [ @@ -59,7 +60,7 @@ class SettingsPage extends HookConsumerWidget { ), ), ), - ], + ), ), ), ); From cd31798870208bffef4d2ac9727c9e683237475b Mon Sep 17 00:00:00 2001 From: Kingkor Roy Tirtho Date: Mon, 27 Nov 2023 20:10:56 +0600 Subject: [PATCH 042/195] chore: get ready for release --- .github/workflows/spotube-release-binary.yml | 2 +- CHANGELOG.md | 38 ++++++++++++++++++++ README.md | 32 +++++++++++------ bin/gen-credits.dart | 26 +++++++++----- pubspec.yaml | 2 +- 5 files changed, 79 insertions(+), 21 deletions(-) diff --git a/.github/workflows/spotube-release-binary.yml b/.github/workflows/spotube-release-binary.yml index 62dbcace..d57cc0e8 100644 --- a/.github/workflows/spotube-release-binary.yml +++ b/.github/workflows/spotube-release-binary.yml @@ -4,7 +4,7 @@ on: inputs: version: description: Version to release (x.x.x) - default: 3.2.0 + default: 3.3.0 required: true channel: type: choice diff --git a/CHANGELOG.md b/CHANGELOG.md index 3710d812..dbdf1326 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,44 @@ All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines. +## [3.3.0](https://github.com/KRTirtho/spotube/compare/v3.2.0...v3.3.0) (2023-11-27) + + +### Features + +* Add JioSaavn as audio source ([#881](https://github.com/KRTirtho/spotube/issues/881)) ([14069cd](https://github.com/KRTirtho/spotube/commit/14069cd4fe08597c8d9aa0810270fb4c386c1d55)) +* **android:** better quick scroll/drag to scroll implementation ([2e2c44f](https://github.com/KRTirtho/spotube/commit/2e2c44f0afef69bf9bc485db97d45127a0847c8e)) +* **artist:** modularize page and add wikipedia section ([2a69886](https://github.com/KRTirtho/spotube/commit/2a698865567883271471ace9a44123bbfd8fcd2f)) +* discord RPC integration [#98](https://github.com/KRTirtho/spotube/issues/98) ([88b8785](https://github.com/KRTirtho/spotube/commit/88b8785cb86a19900f3a867b044c1ccb2fe400bb)) +* **mini_player:** show/hide lyrics [#851](https://github.com/KRTirtho/spotube/issues/851) ([dcbb156](https://github.com/KRTirtho/spotube/commit/dcbb1568337969841acc0abe0e7185ee5e4c3590)) +* paginated playlist and album page ([28a5d6b](https://github.com/KRTirtho/spotube/commit/28a5d6bb3820ab0bd4007664f73d685f6e1d2c90)) +* **translations:** add Turkish translations ([0c22469](https://github.com/KRTirtho/spotube/commit/0c22469503f32dbbf1a5d31419c1b76c699fa966)) + + +### Bug Fixes + +* 0:00 media duration in queue after application restart [#782](https://github.com/KRTirtho/spotube/issues/782) ([83c0b49](https://github.com/KRTirtho/spotube/commit/83c0b49da962d9f3d40de9525f90f0b320e8f7b8)) +* Add to Playlist Dialog memory leak [#817](https://github.com/KRTirtho/spotube/issues/817) ([fed36ec](https://github.com/KRTirtho/spotube/commit/fed36ecdd81e8a0f8358693eff0a6233dea32e5d)) +* **album_card:** show loading state during adding track to queue/play ([5633367](https://github.com/KRTirtho/spotube/commit/5633367397812148f6d712d06e97a4f84033f968)) +* alternative track source safearea overflow [#876](https://github.com/KRTirtho/spotube/issues/876) ([7b72a90](https://github.com/KRTirtho/spotube/commit/7b72a90bc65b541cbe2e24ef2234524b522ad71d)) +* android invalid download location Download not starting or not explaining error [#720](https://github.com/KRTirtho/spotube/issues/720) ([d056dbf](https://github.com/KRTirtho/spotube/commit/d056dbf9eeef7033dbc012d0c05800063e820042)) +* changed settings are not persisting after force stop [#821](https://github.com/KRTirtho/spotube/issues/821) ([e29a38d](https://github.com/KRTirtho/spotube/commit/e29a38dfa43ddf7a38046d1d40424f01dbe62261)) +* check for unsynced lyrics and error handling for timed lyrics query ([1d77556](https://github.com/KRTirtho/spotube/commit/1d77556157d158600f29cf2ea5f26c567607dec7)) +* **genres:** lag while scrolling ([dc980b0](https://github.com/KRTirtho/spotube/commit/dc980b024edad3132e72cbb2f0087297a4b76469)) +* infinite list disappearing for a moment everytime new page is fetched ([1334a62](https://github.com/KRTirtho/spotube/commit/1334a62aaea31f97031b3ebf455e94c583f37314)) +* last track of queue keeps repeating [#718](https://github.com/KRTirtho/spotube/issues/718) ([58e5698](https://github.com/KRTirtho/spotube/commit/58e569864dddd74c3064624998dfc184046e97eb)) +* Navigating to settings, redirects to home page [#812](https://github.com/KRTirtho/spotube/issues/812) ([da04f06](https://github.com/KRTirtho/spotube/commit/da04f068f9b7effff8d50cb5714d93ea80c22b7f)) +* new releases section flickering on scroll glitch ([ee94b7c](https://github.com/KRTirtho/spotube/commit/ee94b7cbb24e0f0bc22a6d49c830d4055aa02895)) +* **playbutton_card:** annoying animation ([574406d](https://github.com/KRTirtho/spotube/commit/574406dd5fc410914b27e7fce374323696845012)) +* scrobbling not working for first track or single track ([0a6b54d](https://github.com/KRTirtho/spotube/commit/0a6b54da367345b73fe6e954f1d9368d9f9ead71)) +* settings page scrollbar position ([ee82290](https://github.com/KRTirtho/spotube/commit/ee8229020b3b03fc074b316db4b322af13b807bd)) +* shuffle doesn't move active track to top ([4956bf3](https://github.com/KRTirtho/spotube/commit/4956bf367baae39c88b5de7c6c136513a14f8ad2)) +* spotube doesn't exit properly, hangs in infinite loop [#768](https://github.com/KRTirtho/spotube/issues/768) ([353ca79](https://github.com/KRTirtho/spotube/commit/353ca79be334077c3ac27b4f64e8b4b15eca7175)) +* trim login field padding ([286ef83](https://github.com/KRTirtho/spotube/commit/286ef83e8ec516db70019398d9e3e724437a4172)) +* use CustomScrollView for personalized page ([7d05c40](https://github.com/KRTirtho/spotube/commit/7d05c40dc0d04208b059f2483c1e4de199c8b51d)) +* user_playlists layout, track tile index, ([487c2ed](https://github.com/KRTirtho/spotube/commit/487c2ed6bdc4af33006ba52532eb4eaaa261dceb)) +* **windows:** media control not working [#641](https://github.com/KRTirtho/spotube/issues/641) ([7818574](https://github.com/KRTirtho/spotube/commit/7818574356d0fb8ff567e1f6a83fd0b6f2ee7c8a)) + ## [3.2.0](https://github.com/KRTirtho/spotube/compare/v3.1.2...v3.2.0) (2023-10-16) diff --git a/README.md b/README.md index d82af783..498c45de 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ Spotube Logo An open source, cross-platform Spotify client compatible across multiple platforms
-utilizing Spotify's data API and YouTube (or Piped.video) as an audio source,
+utilizing Spotify's data API and YouTube (or Piped.video or JioSaavn) as an audio source,
eliminating the need for Spotify Premium Btw it's not another Electron app😉 @@ -184,19 +184,23 @@ If you are concerned, you can [read the reason of choosing this license](https:/
-

[Click to show] 🙏 Library/Plugin/Framework Credits

+

[Click to show] 🙏 Services/Package/Plugin Credits

+### Services 1. [Flutter](https://flutter.dev) - Flutter transforms the app development process. Build, test, and deploy beautiful mobile, web, desktop, and embedded apps from a single codebase 1. [Spotify API](https://developer.spotify.com/documentation/web-api) - The Spotify Web API is a RESTful API that provides access to Spotify data 1. [Piped](https://piped-docs.kavin.rocks/) - Piped is a privacy friendly alternative YouTube frontend, which is efficient and scalable by design. 1. [YouTube](https://youtube.com/) - YouTube is an American online video-sharing platform headquartered in San Bruno, California. Three former PayPal employees—Chad Hurley, Steve Chen, and Jawed Karim—created the service in February 2005 +1. [JioSaavn](https://www.jiosaavn.com) - JioSaavn is an Indian online music streaming service and a digital distributor of Bollywood, English and other regional Indian music across the world. Since it was founded in 2007 as Saavn, the company has acquired rights to over 5 crore (50 million) music tracks in 15 languages 1. [Linux](https://www.linux.org) - Linux is a family of open-source Unix-like operating systems based on the Linux kernel, an operating system kernel first released on September 17, 1991, by Linus Torvalds. Linux is typically packaged in a Linux distribution 1. [AUR](https://aur.archlinux.org) - AUR stands for Arch User Repository. It is a community-driven repository for Arch-based Linux distributions users 1. [Flatpak](https://flatpak.org) - Flatpak is a utility for software deployment and package management for Linux 1. [SponsorBlock](https://sponsor.ajay.app) - SponsorBlock is an open-source crowdsourced browser extension and open API for skipping sponsor segments in YouTube videos. 1. [Inno Setup](https://jrsoftware.org/isinfo.php) - Inno Setup is a free installer for Windows programs by Jordan Russell and Martijn Laan 1. [F-Droid](https://f-droid.org) - F-Droid is an installable catalogue of FOSS (Free and Open Source Software) applications for the Android platform. The client makes it easy to browse, install, and keep track of updates on your device + +### Dependencies 1. [args](https://pub.dev/packages/args) - Library for defining parsers for parsing raw command-line arguments into a set of options and values using GNU and POSIX style options. 1. [async](https://pub.dev/packages/async) - Utility functions and classes related to the 'dart:async' library. 1. [audio_service](https://pub.dev/packages/audio_service) - Flutter plugin to play audio in the background while the screen is off. @@ -216,7 +220,10 @@ If you are concerned, you can [read the reason of choosing this license](https:/ 1. [duration](https://github.com/desktop-dart/duration) - Utilities to make working with 'Duration's easier. Formats duration in human readable form and also parses duration in human readable form to Dart's Duration. 1. [envied](https://github.com/petercinibulk/envied) - Explicitly reads environment variables into a dart file from a .env file for more security and faster start up times. 1. [file_selector](https://pub.dev/packages/file_selector) - Flutter plugin for opening and saving files, or selecting directories, using native file selection UI. -1. [fluentui_system_icons](https://github.com/microsoft/fluentui-system-icons/tree/main) - Fluent UI System Icons are a collection of familiar, friendly and modern icons from Microsoft. +1. [fl_query](https://fl-query.krtirtho.dev) - Asynchronous data caching, refetching & invalidation library for Flutter +1. [fl_query_hooks](https://fl-query.krtirtho.dev) - Elite flutter_hooks compatible library for fl_query, the Asynchronous data caching, refetching & invalidation library for Flutter +1. [fl_query_devtools](https://fl-query.krtirtho.dev) - Devtools support for Fl-Query +1. [fluentui_system_icons](https://github.com/microsoft/fluentui-system-icons/tree/main) - Fluent UI System Icons are a collection of familiar, friendly and modern icons from Microsoft. 1. [flutter_cache_manager](https://github.com/Baseflow/flutter_cache_manager/tree/develop/flutter_cache_manager) - Generic cache manager for flutter. Saves web files on the storages of the device and saves the cache info using sqflite. 1. [flutter_displaymode](https://github.com/ajinasokan/flutter_displaymode) - A Flutter plugin to set display mode (resolution, refresh rate) on Android platform. Allows to enable high refresh rate on supported devices. 1. [flutter_feather_icons](https://github.com/muj-programmer/flutter_feather_icons) - Feather is a collection of simply beautiful open source icons. Each icon is designed on a 24x24 grid with an emphasis on simplicity, consistency and usability. @@ -227,7 +234,7 @@ If you are concerned, you can [read the reason of choosing this license](https:/ 1. [flutter_secure_storage](https://pub.dev/packages/flutter_secure_storage) - Flutter Secure Storage provides API to store data in secure storage. Keychain is used in iOS, KeyStore based solution is used in Android. 1. [flutter_svg](https://pub.dev/packages/flutter_svg) - An SVG rendering and widget library for Flutter, which allows painting and displaying Scalable Vector Graphics 1.1 files. 1. [form_validator](https://github.com/TheMisir/form-validator) - Simplest form validation library for flutter's form field widgets -1. [fuzzywuzzy](https://github.com/sphericalkat/dart-fuzzywuzzy) - An implementation of the popular fuzzywuzzy package in Dart, to suit all your fuzzy string matching/searching needs! +1. [fuzzywuzzy](https://github.com/sphericalkat/dart-fuzzywuzzy) - An implementation of the popular fuzzywuzzy package in Dart, to suit all your fuzzy string matching/searching needs! 1. [google_fonts](https://pub.dev/packages/google_fonts) - A Flutter package to use fonts from fonts.google.com. Supports HTTP fetching, caching, and asset bundling. 1. [go_router](https://pub.dev/packages/go_router) - A declarative router for Flutter based on Navigation 2 supporting deep linking, data-driven routes and more 1. [hive](https://github.com/hivedb/hive/tree/master/hive) - Lightweight and blazing fast key-value database written in pure Dart. Strongly encrypted using AES-256. @@ -244,10 +251,10 @@ If you are concerned, you can [read the reason of choosing this license](https:/ 1. [media_kit_libs_audio](https://github.com/media-kit/media-kit.git) - package:media_kit audio (only) playback native libraries for all platforms. 1. [metadata_god](https://github.com/KRTirtho/metadata_god) - Plugin for retrieving and writing audio tags/metadata from audio files 1. [mime](https://pub.dev/packages/mime) - Utilities for handling media (MIME) types, including determining a type from a file extension and file contents. -1. [package_info_plus](https://plus.fluttercommunity.dev/) - Flutter plugin for querying information about the application package, such as CFBundleVersion on iOS or versionCode on Android. +1. [package_info_plus](https://plus.fluttercommunity.dev/) - Flutter plugin for querying information about the application package, such as CFBundleVersion on iOS or versionCode on Android. 1. [palette_generator](https://pub.dev/packages/palette_generator) - Flutter package for generating palette colors from a source image. 1. [path](https://pub.dev/packages/path) - A string-based path manipulation library. All of the path operations you know and love, with solid support for Windows, POSIX (Linux and Mac OS X), and the web. -1. [path_provider](https://pub.dev/packages/path_provider) - Flutter plugin for getting commonly used locations on host platform file systems, such as the temp and app data directories. +1. [path_provider](https://pub.dev/packages/path_provider) - Flutter plugin for getting commonly used locations on host platform file systems, such as the temp and app data directories. 1. [permission_handler](https://pub.dev/packages/permission_handler) - Permission plugin for Flutter. This plugin provides a cross-platform (iOS, Android) API to request and check permissions. 1. [piped_client](https://github.com/KRTirtho/piped_client) - API Client for piped.video 1. [popover](https://github.com/minikin/popover) - A popover is a transient view that appears above other content onscreen when you tap a control or in an area. @@ -258,7 +265,6 @@ If you are concerned, you can [read the reason of choosing this license](https:/ 1. [smtc_windows](https://github.com/KRTirtho/smtc_windows) - Windows `SystemMediaTransportControls` implementation for Flutter giving access to Windows OS Media Control applet. 1. [spotify](https://github.com/rinukkusu/spotify-dart) - An incomplete dart library for interfacing with the Spotify Web API. 1. [stroke_text](https://github.com/MohamedAbd0/stroke_text) - A Simple Flutter plugin for applying stroke (border) style to a text widget -1. [supabase](https://supabase.com) - A dart client for Supabase. This client makes it simple for developers to build secure and scalable products. 1. [system_theme](https://pub.dev/packages/system_theme) - A plugin to get the current system theme info. Supports Android, Web, Windows, Linux and macOS 1. [titlebar_buttons](https://github.com/gtk-flutter/titlebar_buttons) - A package which provides most of the titlebar buttons from windows, linux and macos. 1. [url_launcher](https://pub.dev/packages/url_launcher) - Flutter plugin for launching a URL. Supports web, phone, SMS, and email schemes. @@ -269,6 +275,13 @@ If you are concerned, you can [read the reason of choosing this license](https:/ 1. [youtube_explode_dart](https://github.com/Hexer10/youtube_explode_dart) - A port in dart of the youtube explode library. Supports several API functions without the need of Youtube API Key. 1. [simple_icons](https://jlnrrg.github.io/) - The Simple Icon pack available as Flutter Icons. Provides over 1500 Free SVG icons for popular brands. 1. [audio_service_mpris](https://github.com/bdrazhzhov/audio-service-mpris) - audio_service platform interface supporting Media Player Remote Interfacing Specification. +1. [file_picker](https://github.com/miguelpruivo/plugins_flutter_file_picker) - A package that allows you to use a native file explorer to pick single or multiple absolute file paths, with extension filtering support. +1. [jiosaavn](https://github.com/KRTirtho/jiosaavn) - Unofficial API client for jiosaavn.com +1. [very_good_infinite_list](https://github.com/VeryGoodOpenSource/very_good_infinite_list) - A library for easily displaying paginated data, created by Very Good Ventures. Great for activity feeds, news feeds, and more. +1. [gap](https://github.com/letsar/gap) - Flutter widgets for easily adding gaps inside Flex widgets such as Columns and Rows or scrolling views. +1. [sliver_tools](https://github.com/Kavantix) - A set of useful sliver tools that are missing from the flutter framework +1. [html_unescape](https://github.com/filiph/html_unescape) - A small library for un-escaping HTML. Supports all Named Character References, Decimal Character References and Hexadecimal Character References. +1. [wikipedia_api](https://github.com/KRTirtho/wikipedia_api) - Wikipedia API for dart and flutter 1. [build_runner](https://pub.dev/packages/build_runner) - A build system for Dart code generation and modular compilation. 1. [envied_generator](https://github.com/petercinibulk/envied) - Generator for the Envied package. See https://pub.dev/packages/envied. 1. [flutter_distributor](https://distributor.leanflutter.org) - A complete tool for packaging and publishing your Flutter apps. @@ -279,12 +292,11 @@ If you are concerned, you can [read the reason of choosing this license](https:/ 1. [json_serializable](https://pub.dev/packages/json_serializable) - Automatically generate code for converting to and from JSON by annotating Dart classes. 1. [pub_api_client](https://github.com/leoafarias/pub_api_client) - An API Client for Pub to interact with public package information. 1. [pubspec_parse](https://pub.dev/packages/pubspec_parse) - Simple package for parsing pubspec.yaml files with a type-safe API and rich error reporting. -1. [fl_query](https://fl-query.vercel.app) - Asynchronous data caching, refetching & invalidation library for Flutter -1. [fl_query_hooks](https://fl-query.vercel.app) - Elite flutter_hooks compatible library for fl_query, the Asynchronous data caching, refetching & invalidation library for Flutter -1. [fl_query_devtools](https://fl-query.vercel.app) - Devtools support for Fl-Query 1. [flutter_desktop_tools](https://github.com/KRTirtho/flutter_desktop_tools) - Essential collection of tools for flutter desktop app development 1. [scrobblenaut](https://github.com/Nebulino/Scrobblenaut) - A deadly simple LastFM API Wrapper for Dart. So deadly simple that it's gonna hit the mark. 1. [window_size](https://github.com/google/flutter-desktop-embedding.git) - Allows resizing and repositioning the window containing Flutter. +1. [draggable_scrollbar](https://github.com/fluttercommunity/flutter-draggable-scrollbar) - A scrollbar that can be dragged for quickly navigation through a vertical list. Additional option is showing label next to scrollthumb with information about current item. +1. [dart_discord_rpc](https://github.com/alexmercerind/dart_discord_rpc) - Discord Rich Presence for Flutter & Dart apps & games.

© Copyright Spotube 2023

diff --git a/bin/gen-credits.dart b/bin/gen-credits.dart index 43e1e53d..f8975335 100644 --- a/bin/gen-credits.dart +++ b/bin/gen-credits.dart @@ -1,7 +1,7 @@ +import 'dart:developer'; import 'dart:io'; import 'package:collection/collection.dart'; -import 'package:path/path.dart'; import 'package:http/http.dart'; import 'package:html/parser.dart'; import 'package:pub_api_client/pub_api_client.dart'; @@ -33,15 +33,20 @@ void main() async { final gitDeps = gitDepsList.map( (d) { + final uri = Uri.parse( + d.value.url.toString().replaceAll('.git', ''), + ); return MapEntry( d.key, - join( - d.value.url.toString().replaceAll('.git', ''), - 'raw', - d.value.ref ?? 'main', - d.value.path ?? '', - 'pubspec.yaml', - ), + uri.replace( + pathSegments: [ + ...uri.pathSegments, + 'raw', + d.value.ref ?? 'main', + d.value.path ?? '', + 'pubspec.yaml', + ], + ).toString(), ); }, ).toList(); @@ -55,7 +60,10 @@ void main() async { } catch (e) { final document = parse(res.body); final pre = document.querySelector('pre'); - if (pre == null) rethrow; + if (pre == null) { + log(d.toString()); + rethrow; + } return Pubspec.parse(pre.text); } } diff --git a/pubspec.yaml b/pubspec.yaml index 1ad8fd9f..ba758cbf 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -3,7 +3,7 @@ description: Open source Spotify client that doesn't require Premium nor uses El publish_to: "none" -version: 3.2.0+25 +version: 3.3.0+26 homepage: https://spotube.krtirtho.dev repository: https://github.com/KRTirtho/spotube From 96021e1a49d22bd25fd052c122f49f439c2bea43 Mon Sep 17 00:00:00 2001 From: Kingkor Roy Tirtho Date: Mon, 27 Nov 2023 20:38:50 +0600 Subject: [PATCH 043/195] fix: "Add () to Playlist" option not showing in favorited playlists #904 --- .../dialogs/playlist_add_track_dialog.dart | 8 +++++-- .../shared/track_tile/track_options.dart | 6 ++++- .../sections/body/track_view_body.dart | 3 +-- .../body/track_view_body_headers.dart | 24 ++++++++----------- .../sections/body/track_view_options.dart | 22 +++++++---------- lib/main.dart | 2 +- .../playlist_generate_result.dart | 1 + lib/themes/theme.dart | 3 +++ 8 files changed, 35 insertions(+), 34 deletions(-) diff --git a/lib/components/shared/dialogs/playlist_add_track_dialog.dart b/lib/components/shared/dialogs/playlist_add_track_dialog.dart index aadcd9d6..1c8e5aaa 100644 --- a/lib/components/shared/dialogs/playlist_add_track_dialog.dart +++ b/lib/components/shared/dialogs/playlist_add_track_dialog.dart @@ -11,9 +11,12 @@ import 'package:spotube/services/queries/queries.dart'; import 'package:spotube/utils/type_conversion_utils.dart'; class PlaylistAddTrackDialog extends HookConsumerWidget { + /// The id of the playlist this dialog was opened from + final String? openFromPlaylist; final List tracks; const PlaylistAddTrackDialog({ required this.tracks, + required this.openFromPlaylist, Key? key, }) : super(key: key); @@ -30,11 +33,12 @@ class PlaylistAddTrackDialog extends HookConsumerWidget { ?.where( (playlist) => playlist.owner?.id != null && - playlist.owner!.id == me.data?.id, + playlist.owner!.id == me.data?.id && + playlist.id != openFromPlaylist, ) .toList() ?? [], - [userPlaylists.data, me.data?.id], + [userPlaylists.data, me.data?.id, openFromPlaylist], ); final playlistsCheck = useState({}); diff --git a/lib/components/shared/track_tile/track_options.dart b/lib/components/shared/track_tile/track_options.dart index b0633d34..9a587be6 100644 --- a/lib/components/shared/track_tile/track_options.dart +++ b/lib/components/shared/track_tile/track_options.dart @@ -64,11 +64,15 @@ class TrackOptions extends HookConsumerWidget { }); } - void actionAddToPlaylist(BuildContext context, Track track) { + void actionAddToPlaylist( + BuildContext context, + Track track, + ) { showDialog( context: context, builder: (context) => PlaylistAddTrackDialog( tracks: [track], + openFromPlaylist: playlistId, ), ); } diff --git a/lib/components/shared/tracks_view/sections/body/track_view_body.dart b/lib/components/shared/tracks_view/sections/body/track_view_body.dart index 1c3ba3fb..d77a3e6f 100644 --- a/lib/components/shared/tracks_view/sections/body/track_view_body.dart +++ b/lib/components/shared/tracks_view/sections/body/track_view_body.dart @@ -24,6 +24,7 @@ class TrackViewBodySection extends HookConsumerWidget { final playlist = ref.watch(ProxyPlaylistNotifier.provider); final playlistNotifier = ref.watch(ProxyPlaylistNotifier.notifier); final props = InheritedTrackView.of(context); + final trackViewState = ref.watch(trackViewProvider(props.tracks)); final searchController = useTextEditingController(); final searchFocus = useFocusNode(); @@ -38,8 +39,6 @@ class TrackViewBodySection extends HookConsumerWidget { return props.tracks.where((e) => trackIds.remove(e.id)).toList(); }, [props.tracks]); - final trackViewState = ref.watch(trackViewProvider(uniqTracks)); - final tracks = useMemoized(() { List filteredTracks; if (searchQuery.isEmpty) { diff --git a/lib/components/shared/tracks_view/sections/body/track_view_body_headers.dart b/lib/components/shared/tracks_view/sections/body/track_view_body_headers.dart index 57d8b296..7e4522a0 100644 --- a/lib/components/shared/tracks_view/sections/body/track_view_body_headers.dart +++ b/lib/components/shared/tracks_view/sections/body/track_view_body_headers.dart @@ -38,20 +38,16 @@ class TrackViewBodyHeaders extends HookConsumerWidget { ), ); }, - child: trackViewState.isSelecting - ? Checkbox( - value: trackViewState.hasSelectedAll, - onChanged: (checked) { - if (checked == true) { - trackViewState.selectAll(); - } else { - trackViewState.deselectAll(); - } - }, - ) - : constrains.mdAndUp - ? const SizedBox(width: 32) - : const SizedBox(width: 16), + child: Checkbox( + value: trackViewState.hasSelectedAll, + onChanged: (checked) { + if (checked == true) { + trackViewState.selectAll(); + } else { + trackViewState.deselectAll(); + } + }, + ), ), Expanded( flex: 7, diff --git a/lib/components/shared/tracks_view/sections/body/track_view_options.dart b/lib/components/shared/tracks_view/sections/body/track_view_options.dart index 4fcd0a59..583c9107 100644 --- a/lib/components/shared/tracks_view/sections/body/track_view_options.dart +++ b/lib/components/shared/tracks_view/sections/body/track_view_options.dart @@ -11,7 +11,6 @@ import 'package:spotube/provider/download_manager_provider.dart'; import 'package:spotube/provider/proxy_playlist/proxy_playlist_provider.dart'; import 'package:spotube/provider/user_preferences/user_preferences_provider.dart'; import 'package:spotube/provider/user_preferences/user_preferences_state.dart'; -import 'package:spotube/services/queries/queries.dart'; class TrackViewBodyOptions extends HookConsumerWidget { const TrackViewBodyOptions({Key? key}) : super(key: key); @@ -30,11 +29,6 @@ class TrackViewBodyOptions extends HookConsumerWidget { final trackViewState = ref.watch(trackViewProvider(props.tracks)); final selectedTracks = trackViewState.selectedTracks; - final userPlaylists = useQueries.playlist.ofMineAll(ref); - - final isUserPlaylist = - userPlaylists.data?.any((e) => e.id == props.collectionId) ?? false; - return AdaptivePopSheetList( tooltip: context.l10n.more_actions, headings: [ @@ -66,6 +60,7 @@ class TrackViewBodyOptions extends HookConsumerWidget { context: context, builder: (context) { return PlaylistAddTrackDialog( + openFromPlaylist: props.collectionId, tracks: selectedTracks.toList(), ); }, @@ -100,15 +95,14 @@ class TrackViewBodyOptions extends HookConsumerWidget { context.l10n.download_count(selectedTracks.length), ), ), - if (!isUserPlaylist) - PopSheetEntry( - value: "add-to-playlist", - leading: const Icon(SpotubeIcons.playlistAdd), - enabled: selectedTracks.isNotEmpty, - title: Text( - context.l10n.add_count_to_playlist(selectedTracks.length), - ), + PopSheetEntry( + value: "add-to-playlist", + leading: const Icon(SpotubeIcons.playlistAdd), + enabled: selectedTracks.isNotEmpty, + title: Text( + context.l10n.add_count_to_playlist(selectedTracks.length), ), + ), PopSheetEntry( enabled: selectedTracks.isNotEmpty, value: "add-to-queue", diff --git a/lib/main.dart b/lib/main.dart index 7bb96543..c68b6bc6 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -201,7 +201,7 @@ class SpotubeState extends ConsumerState { Brightness.dark, isAmoledTheme, ), - [paletteColor, accentMaterialColor, isAmoledTheme], + ); return MaterialApp.router( diff --git a/lib/pages/library/playlist_generate/playlist_generate_result.dart b/lib/pages/library/playlist_generate/playlist_generate_result.dart index 015685f1..f751b65b 100644 --- a/lib/pages/library/playlist_generate/playlist_generate_result.dart +++ b/lib/pages/library/playlist_generate/playlist_generate_result.dart @@ -163,6 +163,7 @@ class PlaylistGenerateResultPage extends HookConsumerWidget { context: context, builder: (context) => PlaylistAddTrackDialog( + openFromPlaylist: null, tracks: selectedTracks.value .map( (e) => generatedPlaylist.data! diff --git a/lib/themes/theme.dart b/lib/themes/theme.dart index 8c968e1b..9a5e473f 100644 --- a/lib/themes/theme.dart +++ b/lib/themes/theme.dart @@ -71,5 +71,8 @@ ThemeData theme(Color seed, Brightness brightness, bool isAmoled) { scrollbarTheme: const ScrollbarThemeData( thickness: MaterialStatePropertyAll(14), ), + checkboxTheme: CheckboxThemeData( + shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(20)), + ), ); } From cdd94529969bfc647f55bb85313ac20ff7358c77 Mon Sep 17 00:00:00 2001 From: Kingkor Roy Tirtho Date: Mon, 27 Nov 2023 20:41:14 +0600 Subject: [PATCH 044/195] chore: update CHANGELOG --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index dbdf1326..1544f055 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -18,6 +18,7 @@ All notable changes to this project will be documented in this file. See [standa ### Bug Fixes +* "Add () to Playlist" option not showing in favorited playlists [#904](https://github.com/KRTirtho/spotube/issues/904) ([96021e1](https://github.com/KRTirtho/spotube/commit/96021e1a49d22bd25fd052c122f49f439c2bea43)) * 0:00 media duration in queue after application restart [#782](https://github.com/KRTirtho/spotube/issues/782) ([83c0b49](https://github.com/KRTirtho/spotube/commit/83c0b49da962d9f3d40de9525f90f0b320e8f7b8)) * Add to Playlist Dialog memory leak [#817](https://github.com/KRTirtho/spotube/issues/817) ([fed36ec](https://github.com/KRTirtho/spotube/commit/fed36ecdd81e8a0f8358693eff0a6233dea32e5d)) * **album_card:** show loading state during adding track to queue/play ([5633367](https://github.com/KRTirtho/spotube/commit/5633367397812148f6d712d06e97a4f84033f968)) From a7b9398708ede865dc2c25fb791c8e98eeff7a38 Mon Sep 17 00:00:00 2001 From: Kingkor Roy Tirtho Date: Sat, 2 Dec 2023 21:57:05 +0600 Subject: [PATCH 045/195] fix: metadata not getting added for YouTube tracks #916 and Wrong duration of downloaded tracks #912 --- lib/provider/download_manager_provider.dart | 2 +- lib/utils/type_conversion_utils.dart | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/provider/download_manager_provider.dart b/lib/provider/download_manager_provider.dart index 691a1385..dc538938 100644 --- a/lib/provider/download_manager_provider.dart +++ b/lib/provider/download_manager_provider.dart @@ -25,7 +25,7 @@ class DownloadManagerProvider extends ChangeNotifier { final (:request, :status) = event; final track = $history.firstWhereOrNull( - (element) => element.url == request.url, + (element) => element.getUrlOfCodec(downloadCodec) == request.url, ); if (track == null) return; diff --git a/lib/utils/type_conversion_utils.dart b/lib/utils/type_conversion_utils.dart index a805272c..662b611c 100644 --- a/lib/utils/type_conversion_utils.dart +++ b/lib/utils/type_conversion_utils.dart @@ -147,7 +147,7 @@ abstract class TypeConversionUtils { track.name = metadata?.title ?? basenameWithoutExtension(file.path); track.type = "track"; track.uri = file.path; - track.durationMs = (metadata?.durationMs?.toInt() ?? 0) * 1000; + track.durationMs = (metadata?.durationMs?.toInt() ?? 0); return track; } From 840e014f2b18f193d040baef0e0cd595088a4a84 Mon Sep 17 00:00:00 2001 From: Kingkor Roy Tirtho Date: Sat, 2 Dec 2023 22:05:35 +0600 Subject: [PATCH 046/195] fix: amoled mode and color scheme can't be changed --- lib/main.dart | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/lib/main.dart b/lib/main.dart index c68b6bc6..24ba81b4 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -184,7 +184,6 @@ class SpotubeState extends ConsumerState { /// For enabling hot reload for audio player if (!kDebugMode) return; audioPlayer.dispose(); - // youtube.close(); }; }, []); @@ -201,7 +200,7 @@ class SpotubeState extends ConsumerState { Brightness.dark, isAmoledTheme, ), - + [paletteColor, accentMaterialColor, isAmoledTheme], ); return MaterialApp.router( From 2a87a0fe281fde9e99ae8b4c79d6f1ac23703dd0 Mon Sep 17 00:00:00 2001 From: Kingkor Roy Tirtho Date: Sat, 2 Dec 2023 22:17:53 +0600 Subject: [PATCH 047/195] chore: change API Type to Audio Source --- lib/l10n/app_ar.arb | 2 +- lib/l10n/app_bn.arb | 2 +- lib/l10n/app_ca.arb | 2 +- lib/l10n/app_de.arb | 2 +- lib/l10n/app_en.arb | 2 +- lib/l10n/app_es.arb | 2 +- lib/l10n/app_fa.arb | 2 +- lib/l10n/app_fr.arb | 2 +- lib/l10n/app_hi.arb | 2 +- lib/l10n/app_ja.arb | 2 +- lib/l10n/app_pl.arb | 2 +- lib/l10n/app_pt.arb | 2 +- lib/l10n/app_ru.arb | 2 +- lib/l10n/app_tr.arb | 2 +- lib/l10n/app_uk.arb | 2 +- lib/l10n/app_zh.arb | 2 +- lib/pages/settings/sections/playback.dart | 2 +- lib/provider/proxy_playlist/proxy_playlist_provider.dart | 6 ++++-- 18 files changed, 21 insertions(+), 19 deletions(-) diff --git a/lib/l10n/app_ar.arb b/lib/l10n/app_ar.arb index f587710c..b74564a4 100644 --- a/lib/l10n/app_ar.arb +++ b/lib/l10n/app_ar.arb @@ -251,7 +251,7 @@ "developers": "المطورون", "not_logged_in": "لم تقم بتسجيل الدخول", "search_mode": "وضع البحث", - "youtube_api_type": "نوع الـAPI", + "audio_source": "مصدر الصوت", "ok": "حسسناً", "failed_to_encrypt": "فشل في التشفير", "encryption_failed_warning": "يستخدم Spotube التشفير لتخزين بياناتك بشكل آمن. لكنها فشلت في القيام بذلك. لذلك سيعود الأمر إلى التخزين غير الآمن\nإذا كنت تستخدم Linux، فيرجى التأكد من تثبيت أي خدمة سرية (gnome-keyring، kde-wallet، keepassxc، إلخ)", diff --git a/lib/l10n/app_bn.arb b/lib/l10n/app_bn.arb index 02402179..59985b24 100644 --- a/lib/l10n/app_bn.arb +++ b/lib/l10n/app_bn.arb @@ -249,7 +249,7 @@ "developers": "ডেভেলপার", "not_logged_in": "আপনি লগইন করা নেই", "search_mode": "অনুসন্ধান মোড", - "youtube_api_type": "API প্রকার", + "audio_source": "অডিও উৎস", "ok": "ঠিক আছে", "failed_to_encrypt": "এনক্রিপ্ট করা ব্যর্থ হয়েছে", "encryption_failed_warning": "Spotube আপনার তথ্যগুলি নিরাপদভাবে স্টোর করতে এনক্রিপশন ব্যবহার করে। কিন্তু এটি ব্যর্থ হয়েছে। তাই এটি অনিরাপদ স্টোরে ফলফল হবে\nযদি আপনি Linux ব্যবহার করেন, তবে দয়া করে নিশ্চিত হউন যে আপনার কোনও সিক্রেট-সার্ভিস gnome-keyring, kde-wallet, keepassxc ইত্যাদি ইনস্টল করা আছে", diff --git a/lib/l10n/app_ca.arb b/lib/l10n/app_ca.arb index 81a11082..1d1bb5e4 100644 --- a/lib/l10n/app_ca.arb +++ b/lib/l10n/app_ca.arb @@ -249,7 +249,7 @@ "developers": "Desenvolupadors", "not_logged_in": "No ha iniciat sesió", "search_mode": "Mode de cerca", - "youtube_api_type": "Tipus d'API de YouTube", + "audio_source": "Font d'àudio", "ok": "OK", "failed_to_encrypt": "Error al xifrar", "encryption_failed_warning": "Spotube utilitza el xifrado per emmagatzemar les seves dades de forma segura. Però ha fallat. Per tant, tornarà a un emmagatzament no segur\nSi estè utilizant Linux, asseguri's de tenir instal·lats els serveis secrets com gnome-keyring, kde-wallet i keepassxc", diff --git a/lib/l10n/app_de.arb b/lib/l10n/app_de.arb index 339a8d65..8b7b2593 100644 --- a/lib/l10n/app_de.arb +++ b/lib/l10n/app_de.arb @@ -249,7 +249,7 @@ "developers": "Entwickler", "not_logged_in": "Sie sind nicht angemeldet", "search_mode": "Suchmodus", - "youtube_api_type": "API-Typ", + "audio_source": "Audioquelle", "ok": "OK", "failed_to_encrypt": "Verschlüsselung fehlgeschlagen", "encryption_failed_warning": "Spotube verwendet Verschlüsselung, um Ihre Daten sicher zu speichern. Dies ist jedoch fehlgeschlagen. Daher wird es auf unsichere Speicherung zurückgreifen\nWenn Sie Linux verwenden, stellen Sie bitte sicher, dass Sie Secret-Services wie gnome-keyring, kde-wallet und keepassxc installiert haben", diff --git a/lib/l10n/app_en.arb b/lib/l10n/app_en.arb index 730f51ea..2ce5b8ca 100644 --- a/lib/l10n/app_en.arb +++ b/lib/l10n/app_en.arb @@ -251,7 +251,7 @@ "developers": "Developers", "not_logged_in": "You're not logged in", "search_mode": "Search Mode", - "youtube_api_type": "API Type", + "audio_source": "Audio Source", "ok": "Ok", "failed_to_encrypt": "Failed to encrypt", "encryption_failed_warning": "Spotube uses encryption to securely store your data. But failed to do so. So it'll fallback to insecure storage\nIf you're using linux, please make sure you've any secret-service (gnome-keyring, kde-wallet, keepassxc etc) installed", diff --git a/lib/l10n/app_es.arb b/lib/l10n/app_es.arb index f617705e..d90ec972 100644 --- a/lib/l10n/app_es.arb +++ b/lib/l10n/app_es.arb @@ -249,7 +249,7 @@ "developers": "Desarrolladores", "not_logged_in": "No has iniciado sesión", "search_mode": "Modo de búsqueda", - "youtube_api_type": "Tipo de API de YouTube", + "audio_source": "Fuente de audio", "ok": "OK", "failed_to_encrypt": "Error al cifrar", "encryption_failed_warning": "Spotube utiliza el cifrado para almacenar sus datos de forma segura. Pero ha fallado. Por lo tanto, volverá a un almacenamiento no seguro\nSi está utilizando Linux, asegúrese de tener instalados servicios secretos como gnome-keyring, kde-wallet y keepassxc", diff --git a/lib/l10n/app_fa.arb b/lib/l10n/app_fa.arb index 5454b13b..a8bb9f8c 100644 --- a/lib/l10n/app_fa.arb +++ b/lib/l10n/app_fa.arb @@ -251,7 +251,7 @@ "developers": "توسعه دهنده ها", "not_logged_in": "شما وارد نشده اید ", "search_mode": "حالت جستجو", - "youtube_api_type": "API نوع", + "audio_source": "منبع صدا", "ok": "باشد", "failed_to_encrypt": "رمز گذاری نشده", "encryption_failed_warning": "Spotube از رمزگذاری برای ذخیره ایمن داده های شما استفاده می کند. اما موفق به انجام این کار نشد. بنابراین به فضای ذخیره‌سازی ناامن تبدیل می‌شود\nاگر از لینوکس استفاده می‌کنید، لطفاً مطمئن شوید که سرویس مخفی (gnome-keyring، kde-wallet، keepassxc و غیره) را نصب کرده‌اید.", diff --git a/lib/l10n/app_fr.arb b/lib/l10n/app_fr.arb index fbe5c335..06015964 100644 --- a/lib/l10n/app_fr.arb +++ b/lib/l10n/app_fr.arb @@ -249,7 +249,7 @@ "developers": "Développeurs", "not_logged_in": "Vous n'êtes pas connecté(e)", "search_mode": "Mode de recherche", - "youtube_api_type": "Type d'API", + "audio_source": "Source audio", "ok": "OK", "failed_to_encrypt": "Échec de la cryptage", "encryption_failed_warning": "Spotube utilise le cryptage pour stocker vos données en toute sécurité. Mais cela a échoué. Il basculera donc vers un stockage non sécurisé\nSi vous utilisez Linux, assurez-vous d'avoir installé des services secrets tels que gnome-keyring, kde-wallet et keepassxc", diff --git a/lib/l10n/app_hi.arb b/lib/l10n/app_hi.arb index d33f41dc..adbc6c06 100644 --- a/lib/l10n/app_hi.arb +++ b/lib/l10n/app_hi.arb @@ -249,7 +249,7 @@ "developers": "डेवलपर्स", "not_logged_in": "आप लॉग इन नहीं हैं", "search_mode": "खोज मोड", - "youtube_api_type": "API प्रकार", + "audio_source": "ऑडियो स्रोत", "ok": "ठीक है", "failed_to_encrypt": "एन्क्रिप्ट करने में विफल रहा", "encryption_failed_warning": "Spotube आपके डेटा को सुरक्षित रूप से स्टोर करने के लिए एन्क्रिप्शन का उपयोग करता है। लेकिन इसमें विफल रहा। इसलिए, यह असुरक्षित स्टोरेज पर फॉलबैक करेगा\nयदि आप Linux का उपयोग कर रहे हैं, तो कृपया सुनिश्चित करें कि आपके पास gnome-keyring, kde-wallet, keepassxc आदि जैसी कोई सीक्रेट-सर्विस इंस्टॉल की गई है", diff --git a/lib/l10n/app_ja.arb b/lib/l10n/app_ja.arb index 50c9369f..a288cf0e 100644 --- a/lib/l10n/app_ja.arb +++ b/lib/l10n/app_ja.arb @@ -249,7 +249,7 @@ "developers": "開発", "not_logged_in": "ログインしていません", "search_mode": "検索モード", - "youtube_api_type": "APIの種類", + "audio_source": "音声ソース", "ok": "分かりました", "failed_to_encrypt": "暗号化に失敗しました", "encryption_failed_warning": "Spotubeはデータを安全に保存するために暗号化を使用しています。しかし、失敗しました。したがって、安全でないストレージにフォールバックします\nLinuxを使用している場合は、gnome-keyring、kde-wallet、keepassxcなどのシークレットサービスがインストールされていることを確認してください", diff --git a/lib/l10n/app_pl.arb b/lib/l10n/app_pl.arb index 1a946615..8c6147ad 100644 --- a/lib/l10n/app_pl.arb +++ b/lib/l10n/app_pl.arb @@ -249,7 +249,7 @@ "developers": "Developerzy", "not_logged_in": "Nie jesteś zalogowany", "search_mode": "Tryb szukania", - "youtube_api_type": "Typ API", + "audio_source": "Źródło dźwięku", "ok": "Ok", "failed_to_encrypt": "Nie można zaszyfrować :(", "encryption_failed_warning": "Spotube używa szyfrowania do bezpiecznego przechowywania danych. Ale nie udało się tego zrobić. Więc powróci do niezabezpieczonego przechowywania\nJeśli używasz Linuksa, upewnij się, że masz zainstalowane jakieś usługi do szyfrowania (gnome-keyring, kde-wallet, keepassxc itp.)", diff --git a/lib/l10n/app_pt.arb b/lib/l10n/app_pt.arb index 97df3db3..46c0a88e 100644 --- a/lib/l10n/app_pt.arb +++ b/lib/l10n/app_pt.arb @@ -249,7 +249,7 @@ "developers": "Desenvolvedores", "not_logged_in": "Você não está logado", "search_mode": "Modo de Busca", - "youtube_api_type": "Tipo de API", + "audio_source": "Fonte de Áudio", "ok": "Ok", "failed_to_encrypt": "Falha ao criptografar", "encryption_failed_warning": "O Spotube usa criptografia para armazenar seus dados com segurança, mas falhou em fazê-lo. Portanto, ele voltará para o armazenamento não seguro.\nSe você estiver usando o Linux, certifique-se de ter algum serviço secreto (gnome-keyring, kde-wallet, keepassxc, etc.) instalado", diff --git a/lib/l10n/app_ru.arb b/lib/l10n/app_ru.arb index 098e73c7..b1964f5f 100644 --- a/lib/l10n/app_ru.arb +++ b/lib/l10n/app_ru.arb @@ -249,7 +249,7 @@ "developers": "Разработчики", "not_logged_in": "Вы не выполнили вход", "search_mode": "Режим поиска", - "youtube_api_type": "Тип API", + "audio_source": "Источник аудио", "ok": "Ок", "failed_to_encrypt": "Не удалось зашифровать", "encryption_failed_warning": "Spotube использует шифрование для безопасного хранения ваших данных. Однако в этом случае произошла ошибка. Поэтому будет использовано небезопасное хранилище.\nЕсли вы используете Linux, убедитесь, что у вас установлен какой-либо инструмент для работы с секретами (gnome-keyring, kde-wallet, keepassxc и т.д.)", diff --git a/lib/l10n/app_tr.arb b/lib/l10n/app_tr.arb index 1d72ec85..fa0ea587 100644 --- a/lib/l10n/app_tr.arb +++ b/lib/l10n/app_tr.arb @@ -251,7 +251,7 @@ "developers": "Geliştiriciler", "not_logged_in": "Giriş yapmadınız", "search_mode": "Arama Modu", - "youtube_api_type": "API Türü", + "audio_source": "Ses Kaynağı", "ok": "Tamam", "failed_to_encrypt": "Şifreleme başarısız oldu", "encryption_failed_warning": "Spotube, verilerinizi güvenli bir şekilde depolamak için şifreleme kullanır. Ancak bunu başaramadı. Bu nedenle güvensiz bir depolamaya geri dönecektir. Linux kullanıyorsanız, lütfen gnome-keyring, kde-wallet, keepassxc vb. gibi bir güvenlik hizmetinizin kurulu olduğundan emin olun.", diff --git a/lib/l10n/app_uk.arb b/lib/l10n/app_uk.arb index fa0877d1..22fc341e 100644 --- a/lib/l10n/app_uk.arb +++ b/lib/l10n/app_uk.arb @@ -251,7 +251,7 @@ "developers": "Розробники", "not_logged_in": "Ви не ввійшли в обліковий запис", "search_mode": "Режим пошуку", - "youtube_api_type": "Тип API", + "audio_source": "Джерело аудіо", "ok": "Гаразд", "failed_to_encrypt": "Не вдалося зашифрувати", "encryption_failed_warning": "Spotube використовує шифрування для безпечного зберігання ваших даних. Але не вдалося цього зробити. Тому він перейде до небезпечного зберігання\nЯкщо ви використовуєте Linux, переконайтеся, що у вас встановлено будь-який секретний сервіс (gnome-keyring, kde-wallet, keepassxc тощо)", diff --git a/lib/l10n/app_zh.arb b/lib/l10n/app_zh.arb index 9936c812..325216fa 100644 --- a/lib/l10n/app_zh.arb +++ b/lib/l10n/app_zh.arb @@ -249,7 +249,7 @@ "developers": "开发者", "not_logged_in": "你尚未登录", "search_mode": "搜索模式", - "youtube_api_type": "API 类型", + "audio_source": "音频源", "ok": "确定", "failed_to_encrypt": "加密失败", "encryption_failed_warning": "Spotube使用加密来安全地存储您的数据。但是失败了。因此,它将回退到不安全的存储\n如果您使用Linux,请确保已安装gnome-keyring、kde-wallet和keepassxc等秘密服务", diff --git a/lib/pages/settings/sections/playback.dart b/lib/pages/settings/sections/playback.dart index a0316b33..d36e0713 100644 --- a/lib/pages/settings/sections/playback.dart +++ b/lib/pages/settings/sections/playback.dart @@ -51,7 +51,7 @@ class SettingsPlaybackSection extends HookConsumerWidget { ), AdaptiveSelectTile( secondary: const Icon(SpotubeIcons.api), - title: Text(context.l10n.youtube_api_type), + title: Text(context.l10n.audio_source), value: preferences.audioSource, options: AudioSource.values .map((e) => DropdownMenuItem( diff --git a/lib/provider/proxy_playlist/proxy_playlist_provider.dart b/lib/provider/proxy_playlist/proxy_playlist_provider.dart index 89bb8a6c..84943993 100644 --- a/lib/provider/proxy_playlist/proxy_playlist_provider.dart +++ b/lib/provider/proxy_playlist/proxy_playlist_provider.dart @@ -28,6 +28,8 @@ import 'package:spotube/services/discord/discord.dart'; import 'package:spotube/services/sourced_track/exceptions.dart'; import 'package:spotube/services/sourced_track/models/source_info.dart'; import 'package:spotube/services/sourced_track/sourced_track.dart'; +import 'package:spotube/services/sourced_track/sources/piped.dart'; +import 'package:spotube/services/sourced_track/sources/youtube.dart'; import 'package:spotube/utils/persisted_state_notifier.dart'; import 'package:spotube/utils/type_conversion_utils.dart'; @@ -161,8 +163,8 @@ class ProxyPlaylistNotifier extends PersistedStateNotifier return; } try { - final isNotYTMode = preferences.audioSource != AudioSource.youtube || - (preferences.audioSource == AudioSource.piped && + final isNotYTMode = state.activeTrack is! YoutubeSourcedTrack && + (state.activeTrack is PipedSourcedTrack && preferences.searchMode == SearchMode.youtubeMusic); if (isNotYTMode || !preferences.skipNonMusic) return; From f86d5449168068e338f769d7f504d2146b86dc79 Mon Sep 17 00:00:00 2001 From: Kingkor Roy Tirtho Date: Sat, 2 Dec 2023 22:20:22 +0600 Subject: [PATCH 048/195] fix: Incorrect "Artist" label/heading on Search Results Page #920 --- lib/pages/search/sections/artists.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/pages/search/sections/artists.dart b/lib/pages/search/sections/artists.dart index b736bf13..fe4459d6 100644 --- a/lib/pages/search/sections/artists.dart +++ b/lib/pages/search/sections/artists.dart @@ -32,7 +32,7 @@ class SearchArtistsSection extends HookConsumerWidget { hasNextPage: query.hasNextPage, items: artists, onFetchMore: query.fetchNext, - title: Text(context.l10n.albums), + title: Text(context.l10n.artists), ); } } From b0beeca0cbaf810fae27832cff98cfda95715050 Mon Sep 17 00:00:00 2001 From: Kingkor Roy Tirtho Date: Sat, 2 Dec 2023 22:41:52 +0600 Subject: [PATCH 049/195] feat: Add Go to Album option in track option #917 --- .../shared/track_tile/track_options.dart | 21 ++++++- lib/l10n/app_en.arb | 3 +- untranslated_messages.json | 62 ++++++++++++++++++- 3 files changed, 83 insertions(+), 3 deletions(-) diff --git a/lib/components/shared/track_tile/track_options.dart b/lib/components/shared/track_tile/track_options.dart index 9a587be6..8405d6ea 100644 --- a/lib/components/shared/track_tile/track_options.dart +++ b/lib/components/shared/track_tile/track_options.dart @@ -3,6 +3,7 @@ import 'dart:io'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:flutter_hooks/flutter_hooks.dart'; +import 'package:go_router/go_router.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:spotify/spotify.dart'; import 'package:spotube/collections/spotube_icons.dart'; @@ -12,6 +13,7 @@ import 'package:spotube/components/shared/dialogs/playlist_add_track_dialog.dart import 'package:spotube/components/shared/dialogs/track_details_dialog.dart'; import 'package:spotube/components/shared/heart_button.dart'; import 'package:spotube/components/shared/image/universal_image.dart'; +import 'package:spotube/extensions/constrains.dart'; import 'package:spotube/extensions/context.dart'; import 'package:spotube/models/local_track.dart'; import 'package:spotube/provider/authentication_provider.dart'; @@ -22,6 +24,7 @@ import 'package:spotube/services/mutations/mutations.dart'; import 'package:spotube/utils/type_conversion_utils.dart'; enum TrackOptionValue { + album, share, addToPlaylist, addToQueue, @@ -79,9 +82,12 @@ class TrackOptions extends HookConsumerWidget { @override Widget build(BuildContext context, ref) { + final scaffoldMessenger = ScaffoldMessenger.of(context); + final mediaQuery = MediaQuery.of(context); + final router = GoRouter.of(context); + final playlist = ref.watch(ProxyPlaylistNotifier.provider); final playback = ref.watch(ProxyPlaylistNotifier.notifier); - final scaffoldMessenger = ScaffoldMessenger.of(context); final auth = ref.watch(AuthenticationNotifier.provider); ref.watch(downloadManagerProvider); final downloadManager = ref.watch(downloadManagerProvider.notifier); @@ -122,6 +128,12 @@ class TrackOptions extends HookConsumerWidget { final adaptivePopSheetList = AdaptivePopSheetList( onSelected: (value) async { switch (value) { + case TrackOptionValue.album: + await router.push( + '/album/${track.album!.id}', + extra: track.album!, + ); + break; case TrackOptionValue.delete: await File((track as LocalTrack).path).delete(); ref.refresh(localTracksProvider); @@ -233,6 +245,13 @@ class TrackOptions extends HookConsumerWidget { ) ], _ => [ + if (mediaQuery.smAndDown) + PopSheetEntry( + value: TrackOptionValue.album, + leading: const Icon(SpotubeIcons.album), + title: Text(context.l10n.go_to_album), + subtitle: Text(track.album!.name!), + ), if (!playlist.containsTrack(track)) ...[ PopSheetEntry( value: TrackOptionValue.addToQueue, diff --git a/lib/l10n/app_en.arb b/lib/l10n/app_en.arb index 2ce5b8ca..5aded7d5 100644 --- a/lib/l10n/app_en.arb +++ b/lib/l10n/app_en.arb @@ -279,5 +279,6 @@ "password": "Password", "login": "Login", "login_with_your_lastfm": "Login with your Last.fm account", - "scrobble_to_lastfm": "Scrobble to Last.fm" + "scrobble_to_lastfm": "Scrobble to Last.fm", + "go_to_album": "Go to Album" } \ No newline at end of file diff --git a/untranslated_messages.json b/untranslated_messages.json index 9e26dfee..0130c162 100644 --- a/untranslated_messages.json +++ b/untranslated_messages.json @@ -1 +1,61 @@ -{} \ No newline at end of file +{ + "ar": [ + "go_to_album" + ], + + "bn": [ + "go_to_album" + ], + + "ca": [ + "go_to_album" + ], + + "de": [ + "go_to_album" + ], + + "es": [ + "go_to_album" + ], + + "fa": [ + "go_to_album" + ], + + "fr": [ + "go_to_album" + ], + + "hi": [ + "go_to_album" + ], + + "ja": [ + "go_to_album" + ], + + "pl": [ + "go_to_album" + ], + + "pt": [ + "go_to_album" + ], + + "ru": [ + "go_to_album" + ], + + "tr": [ + "go_to_album" + ], + + "uk": [ + "go_to_album" + ], + + "zh": [ + "go_to_album" + ] +} From 5f1df5a87d8fb7980b52cf57b7b6bedea57a1269 Mon Sep 17 00:00:00 2001 From: Kingkor Roy Tirtho Date: Sat, 2 Dec 2023 22:49:29 +0600 Subject: [PATCH 050/195] fix: Playlist refresh not working #915 --- .../shared/tracks_view/track_view.dart | 23 +++++++++++-------- .../shared/tracks_view/track_view_props.dart | 9 ++++++-- lib/pages/playlist/liked_playlist.dart | 3 +++ 3 files changed, 23 insertions(+), 12 deletions(-) diff --git a/lib/components/shared/tracks_view/track_view.dart b/lib/components/shared/tracks_view/track_view.dart index a65bcff1..217aaed4 100644 --- a/lib/components/shared/tracks_view/track_view.dart +++ b/lib/components/shared/tracks_view/track_view.dart @@ -28,16 +28,19 @@ class TrackView extends HookConsumerWidget { ) : null, extendBodyBehindAppBar: true, - body: CustomScrollView( - slivers: [ - const TrackViewFlexHeader(), - SliverAnimatedSwitcher( - duration: const Duration(milliseconds: 500), - child: props.tracks.isEmpty - ? const ShimmerTrackTileGroup() - : const TrackViewBodySection(), - ), - ], + body: RefreshIndicator( + onRefresh: props.pagination.onRefresh, + child: CustomScrollView( + slivers: [ + const TrackViewFlexHeader(), + SliverAnimatedSwitcher( + duration: const Duration(milliseconds: 500), + child: props.tracks.isEmpty + ? const ShimmerTrackTileGroup() + : const TrackViewBodySection(), + ), + ], + ), ), ); } diff --git a/lib/components/shared/tracks_view/track_view_props.dart b/lib/components/shared/tracks_view/track_view_props.dart index 59c05db2..1c6c7647 100644 --- a/lib/components/shared/tracks_view/track_view_props.dart +++ b/lib/components/shared/tracks_view/track_view_props.dart @@ -6,6 +6,7 @@ class PaginationProps { final bool hasNextPage; final bool isLoading; final VoidCallback onFetchMore; + final Future Function() onRefresh; final Future> Function() onFetchAll; const PaginationProps({ @@ -13,6 +14,7 @@ class PaginationProps { required this.isLoading, required this.onFetchMore, required this.onFetchAll, + required this.onRefresh, }); factory PaginationProps.fromQuery( @@ -24,6 +26,7 @@ class PaginationProps { isLoading: query.isLoadingNextPage, onFetchMore: query.fetchNext, onFetchAll: onFetchAll, + onRefresh: query.refreshAll, ); } @@ -33,7 +36,8 @@ class PaginationProps { other.hasNextPage == hasNextPage && other.isLoading == isLoading && other.onFetchMore == onFetchMore && - other.onFetchAll == onFetchAll; + other.onFetchAll == onFetchAll && + other.onRefresh == onRefresh; } @override @@ -42,7 +46,8 @@ class PaginationProps { hasNextPage.hashCode ^ isLoading.hashCode ^ onFetchMore.hashCode ^ - onFetchAll.hashCode; + onFetchAll.hashCode ^ + onRefresh.hashCode; } class InheritedTrackView extends InheritedWidget { diff --git a/lib/pages/playlist/liked_playlist.dart b/lib/pages/playlist/liked_playlist.dart index 1f252ed4..5972a303 100644 --- a/lib/pages/playlist/liked_playlist.dart +++ b/lib/pages/playlist/liked_playlist.dart @@ -31,6 +31,9 @@ class LikedPlaylistPage extends HookConsumerWidget { onFetchAll: () async { return tracks.toList(); }, + onRefresh: () async { + await likedTracks.refresh(); + }, ), title: playlist.name!, description: playlist.description, From bb8f250f5f351c1a353791b77b25b9de7586191f Mon Sep 17 00:00:00 2001 From: Kingkor Roy Tirtho Date: Sat, 2 Dec 2023 23:18:07 +0600 Subject: [PATCH 051/195] fix: doesn't minimize to tray when system title bar close button is used #866 --- .../shared/page_window_title_bar.dart | 17 +- .../configurators/use_close_behavior.dart | 32 +++ .../configurators/use_window_listener.dart | 197 ++++++++++++++++++ lib/main.dart | 6 + 4 files changed, 236 insertions(+), 16 deletions(-) create mode 100644 lib/hooks/configurators/use_close_behavior.dart create mode 100644 lib/hooks/configurators/use_window_listener.dart diff --git a/lib/components/shared/page_window_title_bar.dart b/lib/components/shared/page_window_title_bar.dart index 43435f7d..d8e20184 100644 --- a/lib/components/shared/page_window_title_bar.dart +++ b/lib/components/shared/page_window_title_bar.dart @@ -11,16 +11,6 @@ import 'dart:io' show Platform, exit; import 'package:flutter_desktop_tools/flutter_desktop_tools.dart'; import 'package:local_notifier/local_notifier.dart'; -final closeNotification = DesktopTools.createNotification( - title: 'Spotube', - message: 'Running in background. Minimized to System Tray', - actions: [ - LocalNotificationAction(text: 'Close The App'), - ], -)?..onClickAction = (value) { - exit(0); - }; - class PageWindowTitleBar extends StatefulHookConsumerWidget implements PreferredSizeWidget { final Widget? leading; @@ -113,12 +103,7 @@ class WindowTitleBarButtons extends HookConsumerWidget { const type = ThemeType.auto; Future onClose() async { - if (preferences.closeBehavior == CloseBehavior.close) { - exit(0); - } else { - await DesktopTools.window.hide(); - await closeNotification?.show(); - } + await DesktopTools.window.close(); } useEffect(() { diff --git a/lib/hooks/configurators/use_close_behavior.dart b/lib/hooks/configurators/use_close_behavior.dart new file mode 100644 index 00000000..05c03fff --- /dev/null +++ b/lib/hooks/configurators/use_close_behavior.dart @@ -0,0 +1,32 @@ +import 'dart:io'; + +import 'package:flutter_desktop_tools/flutter_desktop_tools.dart'; +import 'package:hooks_riverpod/hooks_riverpod.dart'; +import 'package:spotube/hooks/configurators/use_window_listener.dart'; +import 'package:spotube/provider/user_preferences/user_preferences_provider.dart'; +import 'package:spotube/provider/user_preferences/user_preferences_state.dart'; +import 'package:local_notifier/local_notifier.dart'; + +final closeNotification = DesktopTools.createNotification( + title: 'Spotube', + message: 'Running in background. Minimized to System Tray', + actions: [ + LocalNotificationAction(text: 'Close The App'), + ], +)?..onClickAction = (value) { + exit(0); + }; + +void useCloseBehavior(WidgetRef ref) { + useWindowListener( + onWindowClose: () async { + final preferences = ref.read(userPreferencesProvider); + if (preferences.closeBehavior == CloseBehavior.minimizeToTray) { + await DesktopTools.window.hide(); + closeNotification?.show(); + } else { + exit(0); + } + }, + ); +} diff --git a/lib/hooks/configurators/use_window_listener.dart b/lib/hooks/configurators/use_window_listener.dart new file mode 100644 index 00000000..b91ad413 --- /dev/null +++ b/lib/hooks/configurators/use_window_listener.dart @@ -0,0 +1,197 @@ +import 'package:flutter/widgets.dart'; +import 'package:flutter_desktop_tools/flutter_desktop_tools.dart'; +import 'package:flutter_hooks/flutter_hooks.dart'; + +class CallbackWindowListener implements WindowListener { + final VoidCallback? _onWindowClose; + final VoidCallback? _onWindowFocus; + final VoidCallback? _onWindowBlur; + final VoidCallback? _onWindowMaximize; + final VoidCallback? _onWindowUnmaximize; + final VoidCallback? _onWindowMinimize; + final VoidCallback? _onWindowRestore; + final VoidCallback? _onWindowResize; + final VoidCallback? _onWindowResized; + final VoidCallback? _onWindowMove; + final VoidCallback? _onWindowMoved; + final VoidCallback? _onWindowEnterFullScreen; + final VoidCallback? _onWindowLeaveFullScreen; + final VoidCallback? _onWindowDocked; + final VoidCallback? _onWindowUndocked; + final VoidCallback? _onWindowEvent; + + const CallbackWindowListener({ + VoidCallback? onWindowClose, + VoidCallback? onWindowFocus, + VoidCallback? onWindowBlur, + VoidCallback? onWindowMaximize, + VoidCallback? onWindowUnmaximize, + VoidCallback? onWindowMinimize, + VoidCallback? onWindowRestore, + VoidCallback? onWindowResize, + VoidCallback? onWindowResized, + VoidCallback? onWindowMove, + VoidCallback? onWindowMoved, + VoidCallback? onWindowEnterFullScreen, + VoidCallback? onWindowLeaveFullScreen, + VoidCallback? onWindowDocked, + VoidCallback? onWindowUndocked, + VoidCallback? onWindowEvent, + }) : _onWindowClose = onWindowClose, + _onWindowFocus = onWindowFocus, + _onWindowBlur = onWindowBlur, + _onWindowMaximize = onWindowMaximize, + _onWindowUnmaximize = onWindowUnmaximize, + _onWindowMinimize = onWindowMinimize, + _onWindowRestore = onWindowRestore, + _onWindowResize = onWindowResize, + _onWindowResized = onWindowResized, + _onWindowMove = onWindowMove, + _onWindowMoved = onWindowMoved, + _onWindowEnterFullScreen = onWindowEnterFullScreen, + _onWindowLeaveFullScreen = onWindowLeaveFullScreen, + _onWindowDocked = onWindowDocked, + _onWindowUndocked = onWindowUndocked, + _onWindowEvent = onWindowEvent; + + @override + void onWindowBlur() { + return _onWindowBlur?.call(); + } + + @override + void onWindowClose() { + return _onWindowClose?.call(); + } + + @override + void onWindowDocked() { + return _onWindowDocked?.call(); + } + + @override + void onWindowEnterFullScreen() { + return _onWindowEnterFullScreen?.call(); + } + + @override + void onWindowEvent(String eventName) { + return _onWindowEvent?.call(); + } + + @override + void onWindowFocus() { + return _onWindowFocus?.call(); + } + + @override + void onWindowLeaveFullScreen() { + return _onWindowLeaveFullScreen?.call(); + } + + @override + void onWindowMaximize() { + return _onWindowMaximize?.call(); + } + + @override + void onWindowMinimize() { + return _onWindowMinimize?.call(); + } + + @override + void onWindowMove() { + return _onWindowMove?.call(); + } + + @override + void onWindowMoved() { + return _onWindowMoved?.call(); + } + + @override + void onWindowResize() { + return _onWindowResize?.call(); + } + + @override + void onWindowResized() { + return _onWindowResized?.call(); + } + + @override + void onWindowRestore() { + return _onWindowRestore?.call(); + } + + @override + void onWindowUndocked() { + return _onWindowUndocked?.call(); + } + + @override + void onWindowUnmaximize() { + return _onWindowUnmaximize?.call(); + } +} + +void useWindowListener({ + VoidCallback? onWindowClose, + VoidCallback? onWindowFocus, + VoidCallback? onWindowBlur, + VoidCallback? onWindowMaximize, + VoidCallback? onWindowUnmaximize, + VoidCallback? onWindowMinimize, + VoidCallback? onWindowRestore, + VoidCallback? onWindowResize, + VoidCallback? onWindowResized, + VoidCallback? onWindowMove, + VoidCallback? onWindowMoved, + VoidCallback? onWindowEnterFullScreen, + VoidCallback? onWindowLeaveFullScreen, + VoidCallback? onWindowDocked, + VoidCallback? onWindowUndocked, + VoidCallback? onWindowEvent, +}) { + useEffect(() { + final listener = CallbackWindowListener( + onWindowClose: onWindowClose, + onWindowFocus: onWindowFocus, + onWindowBlur: onWindowBlur, + onWindowMaximize: onWindowMaximize, + onWindowUnmaximize: onWindowUnmaximize, + onWindowMinimize: onWindowMinimize, + onWindowRestore: onWindowRestore, + onWindowResize: onWindowResize, + onWindowResized: onWindowResized, + onWindowMove: onWindowMove, + onWindowMoved: onWindowMoved, + onWindowEnterFullScreen: onWindowEnterFullScreen, + onWindowLeaveFullScreen: onWindowLeaveFullScreen, + onWindowDocked: onWindowDocked, + onWindowUndocked: onWindowUndocked, + onWindowEvent: onWindowEvent, + ); + DesktopTools.window.addListener(listener); + return () { + DesktopTools.window.removeListener(listener); + }; + }, [ + onWindowClose, + onWindowFocus, + onWindowBlur, + onWindowMaximize, + onWindowUnmaximize, + onWindowMinimize, + onWindowRestore, + onWindowResize, + onWindowResized, + onWindowMove, + onWindowMoved, + onWindowEnterFullScreen, + onWindowLeaveFullScreen, + onWindowDocked, + onWindowUndocked, + onWindowEvent, + ]); +} diff --git a/lib/main.dart b/lib/main.dart index 24ba81b4..91ec789d 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -15,6 +15,7 @@ import 'package:metadata_god/metadata_god.dart'; import 'package:shared_preferences/shared_preferences.dart'; import 'package:spotube/collections/routes.dart'; import 'package:spotube/collections/intents.dart'; +import 'package:spotube/hooks/configurators/use_close_behavior.dart'; import 'package:spotube/hooks/configurators/use_disable_battery_optimizations.dart'; import 'package:spotube/hooks/configurators/use_get_storage_perms.dart'; import 'package:spotube/l10n/l10n.dart'; @@ -49,6 +50,10 @@ Future main(List rawArgs) async { await FlutterDisplayMode.setHighRefreshRate(); } + if (DesktopTools.platform.isDesktop) { + await DesktopTools.window.setPreventClose(true); + } + await DesktopTools.ensureInitialized( DesktopWindowOptions( hideTitleBar: true, @@ -177,6 +182,7 @@ class SpotubeState extends ConsumerState { ref.watch(paletteProvider.select((s) => s?.dominantColor?.color)); useInitSysTray(ref); + useCloseBehavior(ref); useEffect(() { FlutterNativeSplash.remove(); From 5b659ce8c974f611fc04509b4cc45329bd8f1120 Mon Sep 17 00:00:00 2001 From: Kingkor Roy Tirtho Date: Sat, 2 Dec 2023 23:27:33 +0600 Subject: [PATCH 052/195] cd: upgrade flutter_distributor --- .github/workflows/spotube-release-binary.yml | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/.github/workflows/spotube-release-binary.yml b/.github/workflows/spotube-release-binary.yml index d57cc0e8..e4d2e860 100644 --- a/.github/workflows/spotube-release-binary.yml +++ b/.github/workflows/spotube-release-binary.yml @@ -33,11 +33,6 @@ jobs: runs-on: windows-latest steps: - uses: actions/checkout@v4 - - uses: actions/checkout@v4 - with: - repository: KRTirtho/flutter_distributor - path: flutter_distributor - ref: fix-windows-build - uses: subosito/flutter-action@v2.10.0 with: cache: true @@ -79,10 +74,9 @@ jobs: - name: Build Windows Executable run: | - dart pub global activate melos - cd flutter_distributor && melos bs && cd .. + dart pub global activate flutter_distributor make innoinstall - dart run ./flutter_distributor/packages/flutter_distributor/bin/main.dart package --platform=windows --targets=exe --skip-clean + flutter_distributor package --platform=windows --targets=exe --skip-clean mv dist/**/spotube-*-windows-setup.exe dist/Spotube-windows-x86_64-setup.exe - name: Create Chocolatey Package and set hash From 2ceb6a8e53d68c32d97d5b195add03cd6e1334a2 Mon Sep 17 00:00:00 2001 From: Kingkor Roy Tirtho Date: Sun, 3 Dec 2023 23:00:25 +0600 Subject: [PATCH 053/195] cd: remove appimage --- .github/workflows/spotube-release-binary.yml | 3 --- 1 file changed, 3 deletions(-) diff --git a/.github/workflows/spotube-release-binary.yml b/.github/workflows/spotube-release-binary.yml index e4d2e860..f5cc65ee 100644 --- a/.github/workflows/spotube-release-binary.yml +++ b/.github/workflows/spotube-release-binary.yml @@ -163,7 +163,6 @@ jobs: dart pub global activate flutter_distributor alias dpkg-deb="dpkg-deb --Zxz" flutter_distributor package --platform=linux --targets=deb - flutter_distributor package --platform=linux --targets=appimage flutter_distributor package --platform=linux --targets=rpm - name: Create tar.xz (stable) @@ -179,7 +178,6 @@ jobs: mv build/spotube-linux-*-x86_64.tar.xz dist/ mv dist/**/spotube-*-linux.deb dist/Spotube-linux-x86_64.deb mv dist/**/spotube-*-linux.rpm dist/Spotube-linux-x86_64.rpm - mv dist/**/spotube-*-linux.AppImage dist/Spotube-linux-x86_64.AppImage - uses: actions/upload-artifact@v3 @@ -187,7 +185,6 @@ jobs: if-no-files-found: error name: Spotube-Release-Binaries path: | - dist/Spotube-linux-x86_64.AppImage dist/Spotube-linux-x86_64.deb dist/Spotube-linux-x86_64.rpm dist/spotube-linux-${{ env.BUILD_VERSION }}-x86_64.tar.xz From b92583d0df7b8dee0d121cd2bb666b14c77d8c86 Mon Sep 17 00:00:00 2001 From: Kingkor Roy Tirtho Date: Mon, 4 Dec 2023 22:20:47 +0600 Subject: [PATCH 054/195] feat: improve loading animations --- lib/collections/fake.dart | 161 ++++++++++++++ lib/components/artist/artist_card.dart | 15 +- lib/components/library/user_albums.dart | 53 ++--- lib/components/library/user_artists.dart | 21 +- lib/components/library/user_local_tracks.dart | 61 +++-- lib/components/library/user_playlists.dart | 18 +- .../horizontal_playbutton_card_view.dart | 60 +++-- lib/components/shared/playbutton_card.dart | 37 ++-- .../shimmers/shimmer_artist_profile.dart | 57 ----- .../shared/shimmers/shimmer_categories.dart | 53 ----- .../shared/shimmers/shimmer_lyrics.dart | 81 +++---- .../shimmers/shimmer_playbutton_card.dart | 119 ---------- .../shared/shimmers/shimmer_track_tile.dart | 123 ----------- .../sections/body/track_view_body.dart | 20 +- .../shared/tracks_view/track_view.dart | 11 +- lib/pages/artist/artist.dart | 67 +++--- lib/pages/artist/section/header.dart | 208 +++++++++--------- lib/pages/artist/section/top_tracks.dart | 19 +- lib/pages/home/genres.dart | 32 ++- lib/pages/home/personalized.dart | 52 ++--- lib/pages/lyrics/synced_lyrics.dart | 6 +- pubspec.lock | 8 + pubspec.yaml | 1 + 23 files changed, 583 insertions(+), 700 deletions(-) create mode 100644 lib/collections/fake.dart delete mode 100644 lib/components/shared/shimmers/shimmer_artist_profile.dart delete mode 100644 lib/components/shared/shimmers/shimmer_categories.dart delete mode 100644 lib/components/shared/shimmers/shimmer_playbutton_card.dart delete mode 100644 lib/components/shared/shimmers/shimmer_track_tile.dart diff --git a/lib/collections/fake.dart b/lib/collections/fake.dart new file mode 100644 index 00000000..a02e8587 --- /dev/null +++ b/lib/collections/fake.dart @@ -0,0 +1,161 @@ +import 'package:spotify/spotify.dart'; +import 'package:spotube/extensions/track.dart'; + +abstract class FakeData { + static final Image image = Image() + ..height = 1 + ..width = 1 + ..url = "url"; + + static final Followers followers = Followers() + ..href = "text" + ..total = 1; + + static final Artist artist = Artist() + ..id = "1" + ..name = "Wow artist Good!" + ..images = [image] + ..popularity = 1 + ..type = "type" + ..uri = "uri" + ..externalUrls = externalUrls + ..genres = ["genre"] + ..href = "text" + ..followers = followers; + + static final externalIds = ExternalIds() + ..isrc = "text" + ..ean = "text" + ..upc = "text"; + + static final externalUrls = ExternalUrls()..spotify = "text"; + + static final Album album = Album() + ..id = "1" + ..genres = ["genre"] + ..label = "label" + ..popularity = 1 + ..albumType = AlbumType.album + ..artists = [artist] + ..availableMarkets = [Market.BD] + ..externalUrls = externalUrls + ..href = "text" + ..images = [image] + ..name = "Another good album" + ..releaseDate = "2021-01-01" + ..releaseDatePrecision = DatePrecision.day + ..tracks = [track] + ..type = "type" + ..uri = "uri" + ..externalIds = externalIds + ..copyrights = [ + Copyright() + ..type = CopyrightType.C + ..text = "text", + ]; + + static final ArtistSimple artistSimple = ArtistSimple() + ..id = "1" + ..name = "What an artist" + ..type = "type" + ..uri = "uri" + ..externalUrls = externalUrls; + + static final AlbumSimple albumSimple = AlbumSimple() + ..id = "1" + ..albumType = AlbumType.album + ..artists = [artistSimple] + ..availableMarkets = [Market.BD] + ..externalUrls = externalUrls + ..href = "text" + ..images = [image] + ..name = "A good album" + ..releaseDate = "2021-01-01" + ..releaseDatePrecision = DatePrecision.day + ..type = "type" + ..uri = "uri"; + + static final Track track = Track() + ..id = "1" + ..artists = [artist, artist, artist] + ..album = albumSimple + ..availableMarkets = [Market.BD] + ..discNumber = 1 + ..durationMs = 50000 + ..explicit = false + ..externalUrls = externalUrls + ..href = "text" + ..name = "A Track Name" + ..popularity = 1 + ..previewUrl = "url" + ..trackNumber = 1 + ..type = "type" + ..uri = "uri" + ..isPlayable = true + ..explicit = false + ..linkedFrom = trackLink; + + static final TrackLink trackLink = TrackLink() + ..id = "1" + ..type = "type" + ..uri = "uri" + ..externalUrls = {"spotify": "text"} + ..href = "text"; + + static final Paging paging = Paging() + ..href = "text" + ..itemsNative = [track.toJson()] + ..limit = 1 + ..next = "text" + ..offset = 1 + ..previous = "text" + ..total = 1; + + static final User user = User() + ..id = "1" + ..displayName = "Your Name" + ..birthdate = "2021-01-01" + ..country = Market.BD + ..email = "test@email.com" + ..followers = followers + ..href = "text" + ..images = [image] + ..type = "type" + ..uri = "uri"; + + static final TracksLink tracksLink = TracksLink() + ..href = "text" + ..total = 1; + + static final Playlist playlist = Playlist() + ..id = "1" + ..collaborative = false + ..description = "A very good playlist description" + ..externalUrls = externalUrls + ..followers = followers + ..href = "text" + ..images = [image] + ..name = "A good playlist" + ..owner = user + ..public = true + ..snapshotId = "text" + ..tracks = paging + ..tracksLink = tracksLink + ..type = "type" + ..uri = "uri"; + + static final PlaylistSimple playlistSimple = PlaylistSimple() + ..id = "1" + ..collaborative = false + ..externalUrls = externalUrls + ..href = "text" + ..images = [image] + ..name = "A good playlist" + ..owner = user + ..public = true + ..snapshotId = "text" + ..tracksLink = tracksLink + ..type = "type" + ..description = "A very good playlist description" + ..uri = "uri"; +} diff --git a/lib/components/artist/artist_card.dart b/lib/components/artist/artist_card.dart index 434b90ad..3526e88f 100644 --- a/lib/components/artist/artist_card.dart +++ b/lib/components/artist/artist_card.dart @@ -1,6 +1,7 @@ import 'package:auto_size_text/auto_size_text.dart'; import 'package:flutter/material.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; +import 'package:skeletonizer/skeletonizer.dart'; import 'package:spotify/spotify.dart'; import 'package:spotube/components/shared/image/universal_image.dart'; @@ -91,12 +92,14 @@ class ArtistCard extends HookConsumerWidget { decoration: BoxDecoration( color: Colors.blue, borderRadius: BorderRadius.circular(50)), - child: Text( - context.l10n.artist, - style: const TextStyle( - color: Colors.white, - fontSize: 12, - fontWeight: FontWeight.bold, + child: Skeleton.ignore( + child: Text( + context.l10n.artist, + style: const TextStyle( + color: Colors.white, + fontSize: 12, + fontWeight: FontWeight.bold, + ), ), ), ), diff --git a/lib/components/library/user_albums.dart b/lib/components/library/user_albums.dart index ccde43f9..49243870 100644 --- a/lib/components/library/user_albums.dart +++ b/lib/components/library/user_albums.dart @@ -3,12 +3,13 @@ import 'package:flutter_hooks/flutter_hooks.dart'; import 'package:collection/collection.dart'; import 'package:fuzzywuzzy/fuzzywuzzy.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; +import 'package:skeletonizer/skeletonizer.dart'; import 'package:spotify/spotify.dart'; +import 'package:spotube/collections/fake.dart'; import 'package:spotube/collections/spotube_icons.dart'; import 'package:spotube/components/album/album_card.dart'; import 'package:spotube/components/shared/inter_scrollbar/inter_scrollbar.dart'; -import 'package:spotube/components/shared/shimmers/shimmer_playbutton_card.dart'; import 'package:spotube/components/shared/fallbacks/anonymous_fallback.dart'; import 'package:spotube/components/shared/waypoint.dart'; import 'package:spotube/extensions/context.dart'; @@ -82,30 +83,32 @@ class UserAlbums extends HookConsumerWidget { child: SingleChildScrollView( padding: const EdgeInsets.all(8.0), controller: controller, - child: Wrap( - runSpacing: 20, - alignment: WrapAlignment.center, - runAlignment: WrapAlignment.center, - crossAxisAlignment: WrapCrossAlignment.center, - children: [ - if (albums.isEmpty) - Container( - alignment: Alignment.topLeft, - padding: const EdgeInsets.all(16.0), - child: const ShimmerPlaybuttonCard(count: 4), - ), - for (final album in albums) - AlbumCard( - TypeConversionUtils.simpleAlbum_X_Album(album), - ), - if (albumsQuery.hasNextPage) - Waypoint( - controller: controller, - isGrid: true, - onTouchEdge: albumsQuery.fetchNext, - child: const ShimmerPlaybuttonCard(count: 1), - ) - ], + child: Skeletonizer( + enabled: albums.isEmpty, + child: Wrap( + runSpacing: 20, + alignment: WrapAlignment.center, + runAlignment: WrapAlignment.center, + crossAxisAlignment: WrapCrossAlignment.center, + children: [ + if (albums.isEmpty) + ...List.generate( + 10, + (index) => AlbumCard(FakeData.album), + ), + for (final album in albums) + AlbumCard( + TypeConversionUtils.simpleAlbum_X_Album(album), + ), + if (albums.isNotEmpty && albumsQuery.hasNextPage) + Waypoint( + controller: controller, + isGrid: true, + onTouchEdge: albumsQuery.fetchNext, + child: AlbumCard(FakeData.album), + ) + ], + ), ), ), ), diff --git a/lib/components/library/user_artists.dart b/lib/components/library/user_artists.dart index 881451b0..7269d7eb 100644 --- a/lib/components/library/user_artists.dart +++ b/lib/components/library/user_artists.dart @@ -3,6 +3,8 @@ import 'package:flutter_hooks/flutter_hooks.dart'; import 'package:collection/collection.dart'; import 'package:fuzzywuzzy/fuzzywuzzy.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; +import 'package:skeletonizer/skeletonizer.dart'; +import 'package:spotube/collections/fake.dart'; import 'package:spotube/collections/spotube_icons.dart'; import 'package:spotube/components/shared/fallbacks/anonymous_fallback.dart'; @@ -87,12 +89,19 @@ class UserArtists extends HookConsumerWidget { width: double.infinity, child: SafeArea( child: Center( - child: Wrap( - spacing: 15, - runSpacing: 5, - children: filteredArtists - .mapIndexed((index, artist) => ArtistCard(artist)) - .toList(), + child: Skeletonizer( + enabled: artistQuery.isLoading, + child: Wrap( + spacing: 15, + runSpacing: 5, + children: artistQuery.isLoading + ? List.generate( + 10, (index) => ArtistCard(FakeData.artist)) + : filteredArtists + .mapIndexed( + (index, artist) => ArtistCard(artist)) + .toList(), + ), ), ), ), diff --git a/lib/components/library/user_local_tracks.dart b/lib/components/library/user_local_tracks.dart index cc8b10cf..fcaada9e 100644 --- a/lib/components/library/user_local_tracks.dart +++ b/lib/components/library/user_local_tracks.dart @@ -11,12 +11,13 @@ import 'package:metadata_god/metadata_god.dart'; import 'package:mime/mime.dart'; import 'package:path/path.dart'; import 'package:path_provider/path_provider.dart'; +import 'package:skeletonizer/skeletonizer.dart'; import 'package:spotify/spotify.dart'; +import 'package:spotube/collections/fake.dart'; import 'package:spotube/collections/spotube_icons.dart'; import 'package:spotube/components/shared/expandable_search/expandable_search.dart'; import 'package:spotube/components/shared/inter_scrollbar/inter_scrollbar.dart'; -import 'package:spotube/components/shared/shimmers/shimmer_track_tile.dart'; import 'package:spotube/components/shared/sort_tracks_dropdown.dart'; import 'package:spotube/components/shared/track_tile/track_tile.dart'; import 'package:spotube/extensions/context.dart'; @@ -261,32 +262,48 @@ class UserLocalTracks extends HookConsumerWidget { }, child: InterScrollbar( controller: controller, - child: ListView.builder( - controller: controller, - physics: const AlwaysScrollableScrollPhysics(), - itemCount: filteredTracks.length, - itemBuilder: (context, index) { - final track = filteredTracks[index]; - return TrackTile( - index: index, - track: track, - userPlaylist: false, - onTap: () async { - await playLocalTracks( - ref, - sortedTracks, - currentTrack: track, - ); - }, - ); - }, + child: Skeletonizer( + enabled: trackSnapshot.isLoading, + child: ListView.builder( + controller: controller, + physics: const AlwaysScrollableScrollPhysics(), + itemCount: + trackSnapshot.isLoading ? 5 : filteredTracks.length, + itemBuilder: (context, index) { + if (trackSnapshot.isLoading) { + return TrackTile(track: FakeData.track, index: index); + } + + final track = filteredTracks[index]; + return TrackTile( + index: index, + track: track, + userPlaylist: false, + onTap: () async { + await playLocalTracks( + ref, + sortedTracks, + currentTrack: track, + ); + }, + ); + }, + ), ), ), ), ); }, - loading: () => - const Expanded(child: ShimmerTrackTileGroup(noSliver: true)), + loading: () => Expanded( + child: Skeletonizer( + enabled: true, + child: ListView.builder( + itemCount: 5, + itemBuilder: (context, index) => + TrackTile(track: FakeData.track, index: index), + ), + ), + ), error: (error, stackTrace) => Text(error.toString() + stackTrace.toString()), ) diff --git a/lib/components/library/user_playlists.dart b/lib/components/library/user_playlists.dart index f7736ca7..a65c6d0e 100644 --- a/lib/components/library/user_playlists.dart +++ b/lib/components/library/user_playlists.dart @@ -1,16 +1,16 @@ import 'package:flutter/material.dart' hide Image; -import 'package:flutter_desktop_tools/flutter_desktop_tools.dart'; import 'package:flutter_hooks/flutter_hooks.dart'; import 'package:fuzzywuzzy/fuzzywuzzy.dart'; import 'package:collection/collection.dart'; import 'package:go_router/go_router.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; +import 'package:skeletonizer/skeletonizer.dart'; import 'package:spotify/spotify.dart'; +import 'package:spotube/collections/fake.dart'; import 'package:spotube/collections/spotube_icons.dart'; import 'package:spotube/components/playlist/playlist_create_dialog.dart'; import 'package:spotube/components/shared/inter_scrollbar/inter_scrollbar.dart'; -import 'package:spotube/components/shared/shimmers/shimmer_playbutton_card.dart'; import 'package:spotube/components/shared/fallbacks/anonymous_fallback.dart'; import 'package:spotube/components/playlist/playlist_card.dart'; import 'package:spotube/components/shared/waypoint.dart'; @@ -123,7 +123,7 @@ class UserPlaylists extends HookConsumerWidget { ), SliverLayoutBuilder(builder: (context, constrains) { return SliverGrid.builder( - itemCount: playlists.length + 1, + itemCount: playlists.isEmpty ? 6 : playlists.length + 1, gridDelegate: SliverGridDelegateWithMaxCrossAxisExtent( maxCrossAxisExtent: 200, mainAxisExtent: constrains.smAndDown ? 225 : 250, @@ -131,7 +131,7 @@ class UserPlaylists extends HookConsumerWidget { mainAxisSpacing: 8, ), itemBuilder: (context, index) { - if (index == playlists.length) { + if (playlists.isNotEmpty && index == playlists.length) { if (!playlistsQuery.hasNextPage) { return const SizedBox.shrink(); } @@ -140,11 +140,17 @@ class UserPlaylists extends HookConsumerWidget { controller: controller, isGrid: true, onTouchEdge: playlistsQuery.fetchNext, - child: const ShimmerPlaybuttonCard(count: 1), + child: Skeletonizer( + enabled: true, + child: PlaylistCard(FakeData.playlistSimple), + ), ); } - return PlaylistCard(playlists[index]); + return PlaylistCard( + playlists.elementAtOrNull(index) ?? + FakeData.playlistSimple, + ); }, ); }) diff --git a/lib/components/shared/horizontal_playbutton_card_view/horizontal_playbutton_card_view.dart b/lib/components/shared/horizontal_playbutton_card_view/horizontal_playbutton_card_view.dart index dca77233..d00e5c4b 100644 --- a/lib/components/shared/horizontal_playbutton_card_view/horizontal_playbutton_card_view.dart +++ b/lib/components/shared/horizontal_playbutton_card_view/horizontal_playbutton_card_view.dart @@ -2,11 +2,12 @@ import 'dart:ui'; import 'package:flutter/material.dart'; import 'package:flutter_hooks/flutter_hooks.dart'; +import 'package:skeletonizer/skeletonizer.dart'; import 'package:spotify/spotify.dart'; +import 'package:spotube/collections/fake.dart'; import 'package:spotube/components/album/album_card.dart'; import 'package:spotube/components/artist/artist_card.dart'; import 'package:spotube/components/playlist/playlist_card.dart'; -import 'package:spotube/components/shared/shimmers/shimmer_playbutton_card.dart'; import 'package:spotube/hooks/utils/use_breakpoint_value.dart'; import 'package:very_good_infinite_list/very_good_infinite_list.dart'; @@ -61,30 +62,41 @@ class HorizontalPlaybuttonCardView extends HookWidget { PointerDeviceKind.mouse, }, ), - child: InfiniteList( - scrollController: scrollController, - scrollDirection: Axis.horizontal, - padding: const EdgeInsets.symmetric(vertical: 8.0), - itemCount: items.length, - onFetchData: onFetchMore, - loadingBuilder: (context) => const ShimmerPlaybuttonCard(), - emptyBuilder: (context) => - const ShimmerPlaybuttonCard(count: 5), - isLoading: isLoadingNextPage, - hasReachedMax: !hasNextPage, - itemBuilder: (context, index) { - final item = items[index]; + child: items.isEmpty + ? ListView.builder( + scrollDirection: Axis.horizontal, + itemCount: 5, + itemBuilder: (context, index) { + return AlbumCard(FakeData.albumSimple); + }, + ) + : InfiniteList( + scrollController: scrollController, + scrollDirection: Axis.horizontal, + padding: const EdgeInsets.symmetric(vertical: 8.0), + itemCount: items.length, + onFetchData: onFetchMore, + loadingBuilder: (context) => Skeletonizer( + enabled: true, + child: AlbumCard(FakeData.albumSimple), + ), + isLoading: isLoadingNextPage, + hasReachedMax: !hasNextPage, + itemBuilder: (context, index) { + final item = items[index]; - return switch (item.runtimeType) { - PlaylistSimple => PlaylistCard(item as PlaylistSimple), - Album => AlbumCard(item as Album), - Artist => Padding( - padding: const EdgeInsets.symmetric(horizontal: 12.0), - child: ArtistCard(item as Artist), - ), - _ => const SizedBox.shrink(), - }; - }), + return switch (item.runtimeType) { + PlaylistSimple => + PlaylistCard(item as PlaylistSimple), + Album => AlbumCard(item as Album), + Artist => Padding( + padding: + const EdgeInsets.symmetric(horizontal: 12.0), + child: ArtistCard(item as Artist), + ), + _ => const SizedBox.shrink(), + }; + }), ), ), ], diff --git a/lib/components/shared/playbutton_card.dart b/lib/components/shared/playbutton_card.dart index d9c48640..60db648b 100644 --- a/lib/components/shared/playbutton_card.dart +++ b/lib/components/shared/playbutton_card.dart @@ -1,6 +1,7 @@ import 'package:auto_size_text/auto_size_text.dart'; import 'package:flutter/material.dart'; import 'package:flutter_hooks/flutter_hooks.dart'; +import 'package:skeletonizer/skeletonizer.dart'; import 'package:spotube/collections/assets.gen.dart'; import 'package:spotube/collections/spotube_icons.dart'; @@ -146,14 +147,16 @@ class PlaybuttonCard extends HookWidget { mainAxisSize: MainAxisSize.min, children: [ if (!isPlaying) - IconButton( - style: IconButton.styleFrom( - backgroundColor: theme.colorScheme.background, - foregroundColor: theme.colorScheme.primary, - minimumSize: const Size.square(10), + Skeleton.keep( + child: IconButton( + style: IconButton.styleFrom( + backgroundColor: theme.colorScheme.background, + foregroundColor: theme.colorScheme.primary, + minimumSize: const Size.square(10), + ), + icon: const Icon(SpotubeIcons.queueAdd), + onPressed: isLoading ? null : onAddToQueuePressed, ), - icon: const Icon(SpotubeIcons.queueAdd), - onPressed: isLoading ? null : onAddToQueuePressed, ), const SizedBox(height: 5), IconButton( @@ -162,15 +165,17 @@ class PlaybuttonCard extends HookWidget { foregroundColor: theme.colorScheme.primary, minimumSize: const Size.square(10), ), - icon: isLoading - ? SizedBox.fromSize( - size: const Size.square(15), - child: const CircularProgressIndicator( - strokeWidth: 2), - ) - : isPlaying - ? const Icon(SpotubeIcons.pause) - : const Icon(SpotubeIcons.play), + icon: Skeleton.keep( + child: isLoading + ? SizedBox.fromSize( + size: const Size.square(15), + child: const CircularProgressIndicator( + strokeWidth: 2), + ) + : isPlaying + ? const Icon(SpotubeIcons.pause) + : const Icon(SpotubeIcons.play), + ), onPressed: isLoading ? null : onPlaybuttonPressed, ), ], diff --git a/lib/components/shared/shimmers/shimmer_artist_profile.dart b/lib/components/shared/shimmers/shimmer_artist_profile.dart deleted file mode 100644 index 75e50cd0..00000000 --- a/lib/components/shared/shimmers/shimmer_artist_profile.dart +++ /dev/null @@ -1,57 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:flutter_hooks/flutter_hooks.dart'; - -import 'package:skeleton_text/skeleton_text.dart'; -import 'package:spotube/components/shared/shimmers/shimmer_track_tile.dart'; -import 'package:spotube/extensions/theme.dart'; -import 'package:spotube/hooks/utils/use_breakpoint_value.dart'; - -class ShimmerArtistProfile extends HookWidget { - const ShimmerArtistProfile({Key? key}) : super(key: key); - - @override - Widget build(BuildContext context) { - final isDark = Theme.of(context).brightness == Brightness.dark; - final shimmerTheme = ShimmerColorTheme( - shimmerBackgroundColor: isDark ? Colors.grey[700] : Colors.grey[200], - shimmerColor: isDark ? Colors.grey[800] : Colors.grey[300], - ); - final shimmerColor = shimmerTheme.shimmerColor ?? Colors.white; - final shimmerBackgroundColor = - shimmerTheme.shimmerBackgroundColor ?? Colors.grey; - - final avatarWidth = useBreakpointValue( - xs: MediaQuery.of(context).size.width * 0.80, - sm: MediaQuery.of(context).size.width * 0.80, - md: MediaQuery.of(context).size.width * 0.50, - lg: MediaQuery.of(context).size.width * 0.30, - xl: MediaQuery.of(context).size.width * 0.30, - xxl: MediaQuery.of(context).size.width * 0.30, - ) ?? - 0; - - return Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Padding( - padding: const EdgeInsets.all(20), - child: SkeletonAnimation( - shimmerColor: shimmerColor, - borderRadius: BorderRadius.circular(avatarWidth), - shimmerDuration: 1000, - child: Container( - width: avatarWidth, - height: avatarWidth, - decoration: BoxDecoration( - color: shimmerBackgroundColor, - borderRadius: BorderRadius.circular(avatarWidth), - ), - ), - ), - ), - const SizedBox(width: 10), - const Flexible(child: ShimmerTrackTileGroup(noSliver: true)), - ], - ); - } -} diff --git a/lib/components/shared/shimmers/shimmer_categories.dart b/lib/components/shared/shimmers/shimmer_categories.dart deleted file mode 100644 index 9bc773da..00000000 --- a/lib/components/shared/shimmers/shimmer_categories.dart +++ /dev/null @@ -1,53 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:flutter_hooks/flutter_hooks.dart'; - -import 'package:spotube/components/shared/shimmers/shimmer_playbutton_card.dart'; -import 'package:spotube/extensions/theme.dart'; -import 'package:spotube/hooks/utils/use_breakpoint_value.dart'; - -class ShimmerCategories extends HookWidget { - const ShimmerCategories({Key? key}) : super(key: key); - - @override - Widget build(BuildContext context) { - final isDark = Theme.of(context).brightness == Brightness.dark; - final shimmerTheme = ShimmerColorTheme( - shimmerBackgroundColor: isDark ? Colors.grey[700] : Colors.grey[200], - ); - final shimmerBackgroundColor = - shimmerTheme.shimmerBackgroundColor ?? Colors.grey; - - final shimmerCount = useBreakpointValue( - xs: 2, - sm: 2, - md: 3, - lg: 3, - xl: 6, - xxl: 8, - ); - - return Padding( - padding: const EdgeInsets.all(16), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - mainAxisAlignment: MainAxisAlignment.start, - children: [ - Container( - padding: const EdgeInsets.only(left: 15), - height: 10, - width: 100, - decoration: BoxDecoration( - color: shimmerBackgroundColor, - borderRadius: BorderRadius.circular(10), - ), - ), - const SizedBox(height: 10), - Align( - alignment: Alignment.topLeft, - child: ShimmerPlaybuttonCard(count: shimmerCount), - ), - ], - ), - ); - } -} diff --git a/lib/components/shared/shimmers/shimmer_lyrics.dart b/lib/components/shared/shimmers/shimmer_lyrics.dart index b0fba340..b225c008 100644 --- a/lib/components/shared/shimmers/shimmer_lyrics.dart +++ b/lib/components/shared/shimmers/shimmer_lyrics.dart @@ -1,69 +1,38 @@ import 'package:flutter/material.dart'; import 'package:flutter_hooks/flutter_hooks.dart'; +import 'package:gap/gap.dart'; -import 'package:skeleton_text/skeleton_text.dart'; -import 'package:spotube/extensions/constrains.dart'; -import 'package:spotube/extensions/theme.dart'; - -const widths = [20, 56, 89, 60, 25, 69]; +import 'package:skeletonizer/skeletonizer.dart'; class ShimmerLyrics extends HookWidget { const ShimmerLyrics({Key? key}) : super(key: key); @override Widget build(BuildContext context) { - final isDark = Theme.of(context).brightness == Brightness.dark; - final shimmerTheme = ShimmerColorTheme( - shimmerBackgroundColor: isDark ? Colors.grey[700] : Colors.grey[200], - shimmerColor: isDark ? Colors.grey[800] : Colors.grey[300], - ); - final shimmerColor = shimmerTheme.shimmerColor ?? Colors.white; - final shimmerBackgroundColor = - shimmerTheme.shimmerBackgroundColor ?? Colors.grey; - - final mediaQuery = MediaQuery.of(context); - - return ListView.builder( - itemCount: 20, - shrinkWrap: true, - physics: const NeverScrollableScrollPhysics(), - itemBuilder: (context, index) { - final widthsCp = [...widths]; - if (mediaQuery.isMd) { - widthsCp.removeLast(); - } - if (mediaQuery.smAndDown) { - widthsCp.removeLast(); - widthsCp.removeLast(); - } - widthsCp.shuffle(); - return Container( - margin: const EdgeInsets.symmetric(vertical: 5), - child: Row( + return Skeletonizer( + enabled: true, + child: ListView.builder( + itemCount: 30, + physics: const NeverScrollableScrollPhysics(), + shrinkWrap: true, + itemBuilder: (context, index) { + final texts = [ + "Lorem ipsum", + "consectetur.", + "Sed", + "Sed non risus", + ]..shuffle(); + return Row( mainAxisAlignment: MainAxisAlignment.center, - children: widthsCp.map( - (width) { - return Padding( - padding: const EdgeInsets.symmetric(horizontal: 8.0), - child: SkeletonAnimation( - shimmerColor: shimmerColor, - shimmerDuration: 1000, - child: Container( - height: 10, - width: width.toDouble(), - decoration: BoxDecoration( - color: shimmerBackgroundColor, - borderRadius: BorderRadius.circular(10), - ), - margin: const EdgeInsets.only(top: 10), - ), - ), - ); - }, - ).toList(), - ), - ); - }, + children: [ + for (final text in texts) ...[ + Text(text), + if (text != texts.last) const Gap(10), + ], + ], + ); + }, + ), ); } } diff --git a/lib/components/shared/shimmers/shimmer_playbutton_card.dart b/lib/components/shared/shimmers/shimmer_playbutton_card.dart deleted file mode 100644 index 2259c9b0..00000000 --- a/lib/components/shared/shimmers/shimmer_playbutton_card.dart +++ /dev/null @@ -1,119 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:flutter_hooks/flutter_hooks.dart'; - -import 'package:spotube/hooks/utils/use_breakpoint_value.dart'; - -class ShimmerPlaybuttonCardPainter extends CustomPainter { - final Color background; - final Color foreground; - ShimmerPlaybuttonCardPainter({ - required this.background, - required this.foreground, - }); - - @override - void paint(Canvas canvas, Size size) { - const radius = Radius.circular(15); - - canvas.drawRRect( - RRect.fromRectAndRadius( - Rect.fromLTWH(0, 0, size.width, size.height), - radius, - ), - Paint()..color = background, - ); - - canvas.drawRRect( - RRect.fromRectAndRadius( - Rect.fromLTWH(8, 8, size.width - 16, size.height - 90), - radius, - ), - Paint()..color = foreground, - ); - - canvas.drawRRect( - RRect.fromRectAndRadius( - Rect.fromLTWH(12, size.height - 67, size.width / 2, 10), - radius, - ), - Paint()..color = foreground, - ); - - canvas.drawRRect( - RRect.fromRectAndRadius( - Rect.fromLTWH(12, size.height - 45, size.width - 24, 8), - radius, - ), - Paint()..color = foreground, - ); - - canvas.drawRRect( - RRect.fromRectAndRadius( - Rect.fromLTWH(12, size.height - 30, size.width * .4, 8), - radius, - ), - Paint()..color = foreground, - ); - - canvas.drawCircle( - Offset(size.width * .85, size.height * .50), - 17, - Paint()..color = background, - ); - - canvas.drawCircle( - Offset(size.width * .85, size.height * .67), - 17, - Paint()..color = background, - ); - } - - @override - bool shouldRepaint(covariant CustomPainter oldDelegate) { - return false; - } -} - -class ShimmerPlaybuttonCard extends HookWidget { - final int count; - - const ShimmerPlaybuttonCard({ - Key? key, - this.count = 1, - }) : super(key: key); - - @override - Widget build(BuildContext context) { - final theme = Theme.of(context); - final Size size = useBreakpointValue( - xs: const Size(130, 200), - sm: const Size(130, 200), - md: const Size(150, 220), - others: const Size(170, 240), - ); - - final isDark = theme.brightness == Brightness.dark; - final bgColor = theme.colorScheme.surfaceVariant.withOpacity(.2); - final fgColor = Color.lerp( - theme.colorScheme.surfaceVariant, - isDark ? Colors.black : Colors.white, - .4, - ); - - return Wrap( - spacing: 20, - runSpacing: 20, - children: [ - for (var i = 0; i < count; i++) ...[ - CustomPaint( - size: size, - painter: ShimmerPlaybuttonCardPainter( - background: bgColor, - foreground: fgColor!, - ), - ), - ] - ], - ); - } -} diff --git a/lib/components/shared/shimmers/shimmer_track_tile.dart b/lib/components/shared/shimmers/shimmer_track_tile.dart deleted file mode 100644 index dcb634ed..00000000 --- a/lib/components/shared/shimmers/shimmer_track_tile.dart +++ /dev/null @@ -1,123 +0,0 @@ -import 'package:flutter/material.dart'; - -import 'package:spotube/extensions/theme.dart'; - -class ShimmerTrackTilePainter extends CustomPainter { - final Color background; - final Color foreground; - ShimmerTrackTilePainter({ - required this.background, - required this.foreground, - }); - - @override - void paint(Canvas canvas, Size size) { - final paint = Paint() - ..color = background - ..style = PaintingStyle.fill; - - canvas.drawRRect( - RRect.fromRectAndRadius( - Rect.fromLTWH(0, 0, size.width, size.height), - const Radius.circular(5), - ), - paint, - ); - - canvas.drawRRect( - RRect.fromRectAndRadius( - Rect.fromLTWH(0, 0, size.height, size.height), - const Radius.circular(5), - ), - Paint()..color = foreground, - ); - - canvas.drawRRect( - RRect.fromRectAndRadius( - const Rect.fromLTWH(70, 10, 100, 10), - const Radius.circular(5), - ), - Paint()..color = foreground, - ); - - // draw Icons.play - const icon = Icons.play_arrow_outlined; - TextPainter textPainter = TextPainter(textDirection: TextDirection.rtl); - textPainter.text = TextSpan( - text: String.fromCharCode(icon.codePoint), - style: TextStyle( - fontSize: 40.0, - fontFamily: icon.fontFamily, - color: background, - ), - ); - textPainter.layout(); - textPainter.paint(canvas, const Offset(10, 10)); - - canvas.drawRRect( - RRect.fromRectAndRadius( - const Rect.fromLTWH(70, 30, 170, 7), - const Radius.circular(5), - ), - Paint()..color = foreground, - ); - } - - @override - bool shouldRepaint(CustomPainter oldDelegate) { - return false; - } -} - -class ShimmerTrackTile extends StatelessWidget { - const ShimmerTrackTile({super.key}); - - @override - Widget build(BuildContext context) { - final theme = Theme.of(context); - final isDark = theme.brightness == Brightness.dark; - final shimmerTheme = ShimmerColorTheme( - shimmerBackgroundColor: isDark ? Colors.grey[700] : Colors.grey[200], - shimmerColor: isDark ? Colors.grey[800] : Colors.grey[300], - ); - - return Padding( - padding: const EdgeInsets.only(bottom: 8.0, left: 8, right: 8), - child: CustomPaint( - size: const Size(double.infinity, 60), - painter: ShimmerTrackTilePainter( - background: shimmerTheme.shimmerBackgroundColor ?? - theme.scaffoldBackgroundColor, - foreground: shimmerTheme.shimmerColor ?? theme.cardColor, - ), - ), - ); - } -} - -class ShimmerTrackTileGroup extends StatelessWidget { - final bool noSliver; - final int count; - const ShimmerTrackTileGroup({ - super.key, - this.noSliver = false, - this.count = 5, - }); - - @override - Widget build(BuildContext context) { - if (noSliver) { - return ListView.builder( - itemCount: 5, - itemBuilder: (context, index) => const ShimmerTrackTile(), - ); - } - - return SliverList( - delegate: SliverChildBuilderDelegate( - (BuildContext context, int index) => const ShimmerTrackTile(), - childCount: count, - ), - ); - } -} diff --git a/lib/components/shared/tracks_view/sections/body/track_view_body.dart b/lib/components/shared/tracks_view/sections/body/track_view_body.dart index d77a3e6f..b7149cc2 100644 --- a/lib/components/shared/tracks_view/sections/body/track_view_body.dart +++ b/lib/components/shared/tracks_view/sections/body/track_view_body.dart @@ -4,9 +4,10 @@ import 'package:flutter_hooks/flutter_hooks.dart'; import 'package:fuzzywuzzy/fuzzywuzzy.dart'; import 'package:gap/gap.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; +import 'package:skeletonizer/skeletonizer.dart'; import 'package:spotify/spotify.dart'; +import 'package:spotube/collections/fake.dart'; import 'package:spotube/components/shared/expandable_search/expandable_search.dart'; -import 'package:spotube/components/shared/shimmers/shimmer_track_tile.dart'; import 'package:spotube/components/shared/track_tile/track_tile.dart'; import 'package:spotube/components/shared/tracks_view/sections/body/track_view_body_headers.dart'; import 'package:spotube/components/shared/tracks_view/sections/body/use_is_user_playlist.dart'; @@ -84,7 +85,22 @@ class TrackViewBodySection extends HookConsumerWidget { onFetchData: props.pagination.onFetchMore, isLoading: props.pagination.isLoading, hasReachedMax: !props.pagination.hasNextPage, - loadingBuilder: (context) => const ShimmerTrackTile(), + loadingBuilder: (context) => Skeletonizer( + enabled: true, + child: TrackTile( + track: FakeData.track, + index: 0, + ), + ), + emptyBuilder: (context) => Skeletonizer( + enabled: true, + child: Column( + children: List.generate( + 10, + (index) => TrackTile(track: FakeData.track, index: index), + ), + ), + ), itemBuilder: (context, index) { final track = tracks[index]; return TrackTile( diff --git a/lib/components/shared/tracks_view/track_view.dart b/lib/components/shared/tracks_view/track_view.dart index 217aaed4..a1a2d48b 100644 --- a/lib/components/shared/tracks_view/track_view.dart +++ b/lib/components/shared/tracks_view/track_view.dart @@ -3,7 +3,6 @@ import 'package:flutter_desktop_tools/flutter_desktop_tools.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:sliver_tools/sliver_tools.dart'; import 'package:spotube/components/shared/page_window_title_bar.dart'; -import 'package:spotube/components/shared/shimmers/shimmer_track_tile.dart'; import 'package:spotube/components/shared/tracks_view/sections/header/flexible_header.dart'; import 'package:spotube/components/shared/tracks_view/sections/body/track_view_body.dart'; import 'package:spotube/components/shared/tracks_view/track_view_props.dart'; @@ -30,14 +29,12 @@ class TrackView extends HookConsumerWidget { extendBodyBehindAppBar: true, body: RefreshIndicator( onRefresh: props.pagination.onRefresh, - child: CustomScrollView( + child: const CustomScrollView( slivers: [ - const TrackViewFlexHeader(), + TrackViewFlexHeader(), SliverAnimatedSwitcher( - duration: const Duration(milliseconds: 500), - child: props.tracks.isEmpty - ? const ShimmerTrackTileGroup() - : const TrackViewBodySection(), + duration: Duration(milliseconds: 500), + child: TrackViewBodySection(), ), ], ), diff --git a/lib/pages/artist/artist.dart b/lib/pages/artist/artist.dart index 693e825b..92470397 100644 --- a/lib/pages/artist/artist.dart +++ b/lib/pages/artist/artist.dart @@ -2,10 +2,10 @@ import 'package:flutter/material.dart'; import 'package:flutter_hooks/flutter_hooks.dart'; import 'package:gap/gap.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; +import 'package:skeletonizer/skeletonizer.dart'; import 'package:spotube/components/shared/page_window_title_bar.dart'; import 'package:spotube/components/artist/artist_album_list.dart'; -import 'package:spotube/components/shared/shimmers/shimmer_artist_profile.dart'; import 'package:spotube/extensions/context.dart'; import 'package:spotube/models/logger.dart'; import 'package:spotube/pages/artist/section/footer.dart'; @@ -35,45 +35,46 @@ class ArtistPage extends HookConsumerWidget { ), extendBodyBehindAppBar: true, body: Builder(builder: (context) { - if (artistQuery.isLoading || !artistQuery.hasData) { - const ShimmerArtistProfile(); - } else if (artistQuery.hasError) { + if (artistQuery.hasError) { return Center(child: Text(artistQuery.error.toString())); } - return CustomScrollView( - controller: scrollController, - slivers: [ - SliverToBoxAdapter( - child: SafeArea( - bottom: false, - child: ArtistPageHeader(artistId: artistId), - ), - ), - const SliverGap(50), - ArtistPageTopTracks(artistId: artistId), - const SliverGap(50), - SliverToBoxAdapter(child: ArtistAlbumList(artistId)), - const SliverGap(20), - SliverPadding( - padding: const EdgeInsets.all(8.0), - sliver: SliverToBoxAdapter( - child: Text( - context.l10n.fans_also_like, - style: theme.textTheme.headlineSmall, + return Skeletonizer( + enabled: artistQuery.isLoading, + child: CustomScrollView( + controller: scrollController, + slivers: [ + SliverToBoxAdapter( + child: SafeArea( + bottom: false, + child: ArtistPageHeader(artistId: artistId), ), ), - ), - SliverSafeArea( - sliver: ArtistPageRelatedArtists(artistId: artistId), - ), - if (artistQuery.data != null) - SliverSafeArea( - top: false, + const SliverGap(50), + ArtistPageTopTracks(artistId: artistId), + const SliverGap(50), + SliverToBoxAdapter(child: ArtistAlbumList(artistId)), + const SliverGap(20), + SliverPadding( + padding: const EdgeInsets.all(8.0), sliver: SliverToBoxAdapter( - child: ArtistPageFooter(artist: artistQuery.data!), + child: Text( + context.l10n.fans_also_like, + style: theme.textTheme.headlineSmall, + ), ), ), - ], + SliverSafeArea( + sliver: ArtistPageRelatedArtists(artistId: artistId), + ), + if (artistQuery.data != null) + SliverSafeArea( + top: false, + sliver: SliverToBoxAdapter( + child: ArtistPageFooter(artist: artistQuery.data!), + ), + ), + ], + ), ); }), ), diff --git a/lib/pages/artist/section/header.dart b/lib/pages/artist/section/header.dart index 9fc9d78e..7cee7a01 100644 --- a/lib/pages/artist/section/header.dart +++ b/lib/pages/artist/section/header.dart @@ -4,7 +4,9 @@ import 'package:flutter/services.dart'; import 'package:flutter_hooks/flutter_hooks.dart'; import 'package:gap/gap.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; +import 'package:skeletonizer/skeletonizer.dart'; import 'package:spotify/spotify.dart'; +import 'package:spotube/collections/fake.dart'; import 'package:spotube/collections/spotube_icons.dart'; import 'package:spotube/components/shared/image/universal_image.dart'; import 'package:spotube/extensions/constrains.dart'; @@ -25,7 +27,7 @@ class ArtistPageHeader extends HookConsumerWidget { Widget build(BuildContext context, ref) { final queryClient = useQueryClient(); final artistQuery = useQueries.artist.get(ref, artistId); - final artist = artistQuery.data; + final artist = artistQuery.data ?? FakeData.artist; final scaffoldMessenger = ScaffoldMessenger.of(context); final mediaQuery = MediaQuery.of(context); @@ -41,10 +43,6 @@ class ArtistPageHeader extends HookConsumerWidget { xxl: textTheme.titleMedium, ); - if (artist == null) { - return const SizedBox.shrink(); - } - final spotify = ref.read(spotifyProvider); final auth = ref.watch(AuthenticationNotifier.provider); final blacklist = ref.watch(BlackListNotifier.provider); @@ -96,10 +94,12 @@ class ArtistPageHeader extends HookConsumerWidget { decoration: BoxDecoration( color: Colors.blue, borderRadius: BorderRadius.circular(50)), - child: Text( - artist.type!.toUpperCase(), - style: chipTextVariant.copyWith( - color: Colors.white, + child: Skeleton.keep( + child: Text( + artist.type!.toUpperCase(), + style: chipTextVariant.copyWith( + color: Colors.white, + ), ), ), ), @@ -138,113 +138,115 @@ class ArtistPageHeader extends HookConsumerWidget { ), ), const Gap(20), - Row( - mainAxisSize: MainAxisSize.min, - children: [ - if (auth != null) - HookBuilder( - builder: (context) { - final isFollowingQuery = - useQueries.artist.doIFollow(ref, artistId); + Skeleton.keep( + child: Row( + mainAxisSize: MainAxisSize.min, + children: [ + if (auth != null) + HookBuilder( + builder: (context) { + final isFollowingQuery = + useQueries.artist.doIFollow(ref, artistId); - final followUnfollow = useCallback(() async { - try { - isFollowingQuery.data! - ? await spotify.me.unfollow( - FollowingType.artist, - [artistId], - ) - : await spotify.me.follow( - FollowingType.artist, - [artistId], - ); - await isFollowingQuery.refresh(); + final followUnfollow = useCallback(() async { + try { + isFollowingQuery.data! + ? await spotify.me.unfollow( + FollowingType.artist, + [artistId], + ) + : await spotify.me.follow( + FollowingType.artist, + [artistId], + ); + await isFollowingQuery.refresh(); - queryClient.refreshInfiniteQueryAllPages( - "user-following-artists"); - } finally { - queryClient.refreshQuery( - "user-follows-artists-query/$artistId", + queryClient.refreshInfiniteQueryAllPages( + "user-following-artists"); + } finally { + queryClient.refreshQuery( + "user-follows-artists-query/$artistId", + ); + } + }, [isFollowingQuery]); + + if (isFollowingQuery.isLoading || + !isFollowingQuery.hasData) { + return const SizedBox( + height: 20, + width: 20, + child: CircularProgressIndicator(), ); } - }, [isFollowingQuery]); - if (isFollowingQuery.isLoading || - !isFollowingQuery.hasData) { - return const SizedBox( - height: 20, - width: 20, - child: CircularProgressIndicator(), - ); - } + if (isFollowingQuery.data!) { + return OutlinedButton( + onPressed: followUnfollow, + child: Text(context.l10n.following), + ); + } - if (isFollowingQuery.data!) { - return OutlinedButton( + return FilledButton( onPressed: followUnfollow, - child: Text(context.l10n.following), + child: Text(context.l10n.follow), ); + }, + ), + const SizedBox(width: 5), + IconButton( + tooltip: context.l10n.add_artist_to_blacklist, + icon: Icon( + SpotubeIcons.userRemove, + color: + !isBlackListed ? Colors.red[400] : Colors.white, + ), + style: IconButton.styleFrom( + backgroundColor: + isBlackListed ? Colors.red[400] : null, + ), + onPressed: () async { + if (isBlackListed) { + ref + .read(BlackListNotifier.provider.notifier) + .remove( + BlacklistedElement.artist( + artist.id!, artist.name!), + ); + } else { + ref.read(BlackListNotifier.provider.notifier).add( + BlacklistedElement.artist( + artist.id!, artist.name!), + ); } - - return FilledButton( - onPressed: followUnfollow, - child: Text(context.l10n.follow), - ); }, ), - const SizedBox(width: 5), - IconButton( - tooltip: context.l10n.add_artist_to_blacklist, - icon: Icon( - SpotubeIcons.userRemove, - color: - !isBlackListed ? Colors.red[400] : Colors.white, - ), - style: IconButton.styleFrom( - backgroundColor: - isBlackListed ? Colors.red[400] : null, - ), - onPressed: () async { - if (isBlackListed) { - ref - .read(BlackListNotifier.provider.notifier) - .remove( - BlacklistedElement.artist( - artist.id!, artist.name!), - ); - } else { - ref.read(BlackListNotifier.provider.notifier).add( - BlacklistedElement.artist( - artist.id!, artist.name!), - ); - } - }, - ), - IconButton( - icon: const Icon(SpotubeIcons.share), - onPressed: () async { - if (artist.externalUrls?.spotify != null) { - await Clipboard.setData( - ClipboardData( - text: artist.externalUrls!.spotify!, + IconButton( + icon: const Icon(SpotubeIcons.share), + onPressed: () async { + if (artist.externalUrls?.spotify != null) { + await Clipboard.setData( + ClipboardData( + text: artist.externalUrls!.spotify!, + ), + ); + } + + if (!context.mounted) return; + + scaffoldMessenger.showSnackBar( + SnackBar( + width: 300, + behavior: SnackBarBehavior.floating, + content: Text( + context.l10n.artist_url_copied, + textAlign: TextAlign.center, + ), ), ); - } - - if (!context.mounted) return; - - scaffoldMessenger.showSnackBar( - SnackBar( - width: 300, - behavior: SnackBarBehavior.floating, - content: Text( - context.l10n.artist_url_copied, - textAlign: TextAlign.center, - ), - ), - ); - }, - ) - ], + }, + ) + ], + ), ) ], ), diff --git a/lib/pages/artist/section/top_tracks.dart b/lib/pages/artist/section/top_tracks.dart index 9e3e4054..771757b9 100644 --- a/lib/pages/artist/section/top_tracks.dart +++ b/lib/pages/artist/section/top_tracks.dart @@ -1,6 +1,8 @@ import 'package:flutter/material.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; +import 'package:skeletonizer/skeletonizer.dart'; import 'package:spotify/spotify.dart'; +import 'package:spotube/collections/fake.dart'; import 'package:spotube/collections/spotube_icons.dart'; import 'package:spotube/components/shared/track_tile/track_tile.dart'; import 'package:spotube/extensions/context.dart'; @@ -28,11 +30,7 @@ class ArtistPageTopTracks extends HookConsumerWidget { topTracksQuery.data ?? [], ); - if (topTracksQuery.isLoading || !topTracksQuery.hasData) { - return const SliverToBoxAdapter( - child: Center(child: CircularProgressIndicator()), - ); - } else if (topTracksQuery.hasError) { + if (topTracksQuery.hasError) { return SliverToBoxAdapter( child: Center( child: Text(topTracksQuery.error.toString()), @@ -40,7 +38,8 @@ class ArtistPageTopTracks extends HookConsumerWidget { ); } - final topTracks = topTracksQuery.data!; + final topTracks = + topTracksQuery.data ?? List.generate(10, (index) => FakeData.track); void playPlaylist(List tracks, {Track? currentTrack}) async { currentTrack ??= tracks.first; @@ -92,9 +91,11 @@ class ArtistPageTopTracks extends HookConsumerWidget { ), const SizedBox(width: 5), IconButton( - icon: Icon( - isPlaylistPlaying ? SpotubeIcons.stop : SpotubeIcons.play, - color: Colors.white, + icon: Skeleton.keep( + child: Icon( + isPlaylistPlaying ? SpotubeIcons.stop : SpotubeIcons.play, + color: Colors.white, + ), ), style: IconButton.styleFrom( backgroundColor: theme.colorScheme.primary, diff --git a/lib/pages/home/genres.dart b/lib/pages/home/genres.dart index 54fb6786..88eaef70 100644 --- a/lib/pages/home/genres.dart +++ b/lib/pages/home/genres.dart @@ -3,11 +3,12 @@ import 'package:flutter_hooks/flutter_hooks.dart'; import 'package:collection/collection.dart'; import 'package:fuzzywuzzy/fuzzywuzzy.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; +import 'package:skeletonizer/skeletonizer.dart'; import 'package:spotify/spotify.dart'; import 'package:spotube/collections/spotube_icons.dart'; import 'package:spotube/components/genre/category_card.dart'; import 'package:spotube/components/shared/expandable_search/expandable_search.dart'; -import 'package:spotube/components/shared/shimmers/shimmer_categories.dart'; +import 'package:spotube/components/shared/horizontal_playbutton_card_view/horizontal_playbutton_card_view.dart'; import 'package:spotube/components/shared/waypoint.dart'; import 'package:spotube/provider/user_preferences/user_preferences_provider.dart'; @@ -77,7 +78,23 @@ class GenrePage extends HookConsumerWidget { ), if (!categoriesQuery.hasPageData && !categoriesQuery.isLoadingNextPage) - const ShimmerCategories() + Expanded( + child: Skeletonizer( + enabled: true, + child: ListView.builder( + itemCount: 5, + itemBuilder: (context, index) { + return HorizontalPlaybuttonCardView( + title: const Text("Loading"), + items: const [], + hasNextPage: true, + isLoadingNextPage: false, + onFetchMore: () {}, + ); + }, + ), + ), + ) else Expanded( child: InfiniteList( @@ -86,7 +103,16 @@ class GenrePage extends HookConsumerWidget { onFetchData: categoriesQuery.fetchNext, isLoading: categoriesQuery.isLoadingNextPage, hasReachedMax: !categoriesQuery.hasNextPage, - loadingBuilder: (context) => const ShimmerCategories(), + loadingBuilder: (context) => Skeletonizer( + enabled: true, + child: HorizontalPlaybuttonCardView( + title: const Text("Loading"), + items: const [], + hasNextPage: true, + isLoadingNextPage: false, + onFetchMore: () {}, + ), + ), itemBuilder: (context, index) { return CategoryCard(categories[index]); }, diff --git a/lib/pages/home/personalized.dart b/lib/pages/home/personalized.dart index 7fbd27ae..22224c39 100644 --- a/lib/pages/home/personalized.dart +++ b/lib/pages/home/personalized.dart @@ -4,11 +4,11 @@ import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:spotify/spotify.dart'; import 'package:spotube/components/shared/horizontal_playbutton_card_view/horizontal_playbutton_card_view.dart'; -import 'package:spotube/components/shared/shimmers/shimmer_categories.dart'; import 'package:spotube/extensions/context.dart'; import 'package:spotube/provider/authentication_provider.dart'; import 'package:spotube/services/queries/queries.dart'; import 'package:spotube/utils/type_conversion_utils.dart'; +import 'package:skeletonizer/skeletonizer.dart'; class PersonalizedPage extends HookConsumerWidget { const PersonalizedPage({Key? key}) : super(key: key); @@ -46,39 +46,35 @@ class PersonalizedPage extends HookConsumerWidget { [newReleases.pages], ); + final hasNewReleases = newReleases.hasPageData && + userArtistsQuery.hasData && + !newReleases.isLoadingNextPage; + + final isLoadingFeaturedPlaylists = !featuredPlaylistsQuery.hasPageData && + !featuredPlaylistsQuery.isLoadingNextPage; + return CustomScrollView( controller: controller, slivers: [ SliverList.list( children: [ - AnimatedSwitcher( - duration: const Duration(milliseconds: 300), - child: !featuredPlaylistsQuery.hasPageData && - !featuredPlaylistsQuery.isLoadingNextPage - ? const ShimmerCategories() - : HorizontalPlaybuttonCardView( - items: playlists.toList(), - title: Text(context.l10n.featured), - isLoadingNextPage: - featuredPlaylistsQuery.isLoadingNextPage, - hasNextPage: featuredPlaylistsQuery.hasNextPage, - onFetchMore: featuredPlaylistsQuery.fetchNext, - ), + Skeletonizer( + enabled: isLoadingFeaturedPlaylists, + child: HorizontalPlaybuttonCardView( + items: playlists.toList(), + title: Text(context.l10n.featured), + isLoadingNextPage: featuredPlaylistsQuery.isLoadingNextPage, + hasNextPage: featuredPlaylistsQuery.hasNextPage, + onFetchMore: featuredPlaylistsQuery.fetchNext, + ), ), - if (auth != null) - AnimatedSwitcher( - duration: const Duration(milliseconds: 300), - child: newReleases.hasPageData && - userArtistsQuery.hasData && - !newReleases.isLoadingNextPage - ? HorizontalPlaybuttonCardView( - items: albums, - title: Text(context.l10n.new_releases), - isLoadingNextPage: newReleases.isLoadingNextPage, - hasNextPage: newReleases.hasNextPage, - onFetchMore: newReleases.fetchNext, - ) - : const ShimmerCategories(), + if (auth != null || hasNewReleases) + HorizontalPlaybuttonCardView( + items: albums, + title: Text(context.l10n.new_releases), + isLoadingNextPage: newReleases.isLoadingNextPage, + hasNextPage: newReleases.hasNextPage, + onFetchMore: newReleases.fetchNext, ), ], ), diff --git a/lib/pages/lyrics/synced_lyrics.dart b/lib/pages/lyrics/synced_lyrics.dart index 36a9f316..9af71d94 100644 --- a/lib/pages/lyrics/synced_lyrics.dart +++ b/lib/pages/lyrics/synced_lyrics.dart @@ -77,7 +77,7 @@ class SyncedLyrics extends HookConsumerWidget { : textTheme.headlineMedium?.copyWith(fontSize: 25)) ?.copyWith(color: palette.titleTextColor); - var bodyTextTheme = textTheme.bodyLarge?.copyWith( + final bodyTextTheme = textTheme.bodyLarge?.copyWith( color: palette.bodyTextColor, ); return Stack( @@ -184,7 +184,9 @@ class SyncedLyrics extends HookConsumerWidget { ), if (playlist.activeTrack != null && (timedLyricsQuery.isLoading || timedLyricsQuery.isRefreshing)) - const Expanded(child: ShimmerLyrics()) + const Expanded( + child: ShimmerLyrics(), + ) else if (playlist.activeTrack != null && (timedLyricsQuery.hasError)) Text( diff --git a/pubspec.lock b/pubspec.lock index 06ca8202..8921f8a7 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -1832,6 +1832,14 @@ packages: url: "https://pub.dev" source: hosted version: "3.0.1" + skeletonizer: + dependency: "direct main" + description: + name: skeletonizer + sha256: ff4c36e826efd5288d7a84e7619a6e9be8185d3064cecf101a9133762f3b401b + url: "https://pub.dev" + source: hosted + version: "0.8.0" sky_engine: dependency: transitive description: flutter diff --git a/pubspec.yaml b/pubspec.yaml index ba758cbf..77a26911 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -118,6 +118,7 @@ dependencies: url: https://github.com/Tommypop2/dart_discord_rpc.git html_unescape: ^2.0.0 wikipedia_api: ^0.1.0 + skeletonizer: ^0.8.0 dev_dependencies: build_runner: ^2.3.2 From b59bea16f071aede5bf8a46ae730bddfdfaa151d Mon Sep 17 00:00:00 2001 From: Ashirbad Sahu <130544212+ashirbadsahu@users.noreply.github.com> Date: Mon, 4 Dec 2023 22:05:05 +0530 Subject: [PATCH 055/195] website: dynamic copyright year in footer (#923) * Update copyright year in footer to 2023 * Update copyright year to be dynamic --- website/components/Footer.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/website/components/Footer.tsx b/website/components/Footer.tsx index b940815d..a51cf0a2 100644 --- a/website/components/Footer.tsx +++ b/website/components/Footer.tsx @@ -49,7 +49,7 @@ const Footer = () => { color: "white", }} > - © 2022, Spotube. All rights reserved + © {new Date().getFullYear()}, Spotube. All rights reserved From 66d492b4b3d0f9ee8e8798bc325e452f723ef2b1 Mon Sep 17 00:00:00 2001 From: Alex Stan <90788596+Ultra980@users.noreply.github.com> Date: Fri, 8 Dec 2023 07:20:22 +0200 Subject: [PATCH 056/195] Fix a typo in lib/pages/lyrics/synced_lyrics.dart (#933) "Synced lyrics is not ..." -> "Synced lyrics are not ..." --- lib/pages/lyrics/synced_lyrics.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/pages/lyrics/synced_lyrics.dart b/lib/pages/lyrics/synced_lyrics.dart index 36a9f316..28239539 100644 --- a/lib/pages/lyrics/synced_lyrics.dart +++ b/lib/pages/lyrics/synced_lyrics.dart @@ -201,7 +201,7 @@ class SyncedLyrics extends HookConsumerWidget { children: [ const TextSpan( text: - "Synced lyrics is not available for this song. Please use the", + "Synced lyrics are not available for this song. Please use the", ), TextSpan( text: " Plain Lyrics ", From e4eb0e2596ade2bb5195e183f03af42742fc8486 Mon Sep 17 00:00:00 2001 From: Henrik Sozzi Date: Fri, 8 Dec 2023 06:23:53 +0100 Subject: [PATCH 057/195] feat: add Italian language translations (#818) * Italian language added Created and added the Italian language * Corrections and new textes Corrected the wrong TAB in i10n.dart and added translations of new text items * Fix it const name was lowercase * Merged suggestions from PR #676, added credits Added suggestions as in comments of PR #676 and added credits to @ncvescera and @OpenCode --- lib/collections/language_codes.dart | 8 +- lib/l10n/app_it.arb | 283 ++++++++++++++++++++++++++++ lib/l10n/l10n.dart | 2 + 3 files changed, 289 insertions(+), 4 deletions(-) create mode 100644 lib/l10n/app_it.arb diff --git a/lib/collections/language_codes.dart b/lib/collections/language_codes.dart index 0518363e..d89e1a2a 100644 --- a/lib/collections/language_codes.dart +++ b/lib/collections/language_codes.dart @@ -288,10 +288,10 @@ abstract class LanguageLocals { // name: "Icelandic", // nativeName: "Íslenska", // ), - // "it": const ISOLanguageName( - // name: "Italian", - // nativeName: "Italiano", - // ), + "it": const ISOLanguageName( + name: "Italian", + nativeName: "Italiano", + ), // "iu": const ISOLanguageName( // name: "Inuktitut", // nativeName: "ᐃᓄᒃᑎᑐᑦ", diff --git a/lib/l10n/app_it.arb b/lib/l10n/app_it.arb new file mode 100644 index 00000000..d8f0ae88 --- /dev/null +++ b/lib/l10n/app_it.arb @@ -0,0 +1,283 @@ +{ + "guest": "Ospite", + "browse": "Sfoglia", + "search": "Cerca", + "library": "Libreria", + "lyrics": "Testi", + "settings": "Impostazioni", + "genre_categories_filter": "Filtra categorie e generi...", + "genre": "Genere", + "personalized": "Personalizzato", + "featured": "In evidenza", + "new_releases": "Novità", + "songs": "Canzoni", + "playing_track": "Riproduzione {track}", + "queue_clear_alert": "Questo cancellerà la coda corrente. {track_length} tracce saranno rimosse\nVuoi continuare?", + "load_more": "Carica altro", + "playlists": "Playlist", + "artists": "Artisti", + "albums": "Album", + "tracks": "Tracce", + "downloads": "Downloads", + "filter_playlists": "Filtra le tue playlist...", + "liked_tracks": "Tracce piaciute", + "liked_tracks_description": "Tutte le tracce piaciute", + "create_playlist": "Crea Playlist", + "create_a_playlist": "Crea una playlist", + "update_playlist": "Aggiorna playlist", + "create": "Crea", + "cancel": "Annulla", + "update": "Aggiorna", + "playlist_name": "Nome Playlist", + "name_of_playlist": "Nome della playlist", + "description": "Descrizione", + "public": "Pubblico", + "collaborative": "Collaborativo", + "search_local_tracks": "Cerca tracce locali...", + "play": "Riproduci", + "delete": "Cancella", + "none": "Nessuno", + "sort_a_z": "Ordina dalla A-Z", + "sort_z_a": "Ordina dalla Z-A", + "sort_artist": "Ordina per Artista", + "sort_album": "Ordina per Album", + "sort_tracks": "Ordina tracce", + "currently_downloading": "Attualmente in Download ({tracks_length})", + "cancel_all": "Annulla Tutto", + "filter_artist": "Filtra artisti...", + "followers": "{followers} Seguaci", + "add_artist_to_blacklist": "Aggiungi artista alla lista nera", + "top_tracks": "Tracce Top", + "fans_also_like": "Ai fan piace anche", + "loading": "Caricamento...", + "artist": "Artista", + "blacklisted": "In lista nera", + "following": "Seguendo", + "follow": "Segui", + "artist_url_copied": "URL artista copiato negli appunti", + "added_to_queue": "Aggiunto {tracks} tracce alla coda", + "filter_albums": "Filtra album...", + "synced": "Sincronizzato", + "plain": "Semplice", + "shuffle": "Casuale", + "search_tracks": "Cerca tracce...", + "released": "Rilasciato", + "error": "Errore {error}", + "title": "Titolo", + "time": "Durata", + "more_actions": "Più azioni", + "download_count": "Scaricato ({count})", + "add_count_to_playlist": "Aggiungi ({count}) alla playlist", + "add_count_to_queue": "Aggiungi ({count}) alla Coda", + "play_count_next": "Riproduci ({count}) prossime", + "album": "Album", + "copied_to_clipboard": "Copiato {data} negli appunti", + "add_to_following_playlists": "Aggiungi {track} nelle seguenti Playlist", + "add": "Aggiungi", + "added_track_to_queue": "Aggiunto {track} alla coda", + "add_to_queue": "Aggiungi alla coda", + "track_will_play_next": "in seguito sarà riprodotta {track}", + "play_next": "Riproduci prossimo", + "removed_track_from_queue": "Rimosso {track} dalla coda", + "remove_from_queue": "Rimuovi dalla coda", + "remove_from_favorites": "Rimuovi dai preferiti", + "save_as_favorite": "Salva come preferito", + "add_to_playlist": "Aggiungi alla playlist", + "remove_from_playlist": "Rimuovi dalla playlist", + "add_to_blacklist": "Aggiungi alla blacklist", + "remove_from_blacklist": "Rimuovi dalla blacklist", + "share": "Condividi", + "mini_player": "Mini Riproduttore", + "slide_to_seek": "Scorri per cercare avanti o indietro", + "shuffle_playlist": "Playlist casuale", + "unshuffle_playlist": "Ordina playlist", + "previous_track": "Traccia precedente", + "next_track": "Traccia successiva", + "pause_playback": "Pausa Playback", + "resume_playback": "Riprendi Playback", + "loop_track": "Cicla traccia", + "repeat_playlist": "Ripeti playlist", + "queue": "Coda", + "alternative_track_sources": "Sorgenti traccia alternative", + "download_track": "Scarica traccia", + "tracks_in_queue": "{tracks} tracce in coda", + "clear_all": "Cancella tutto", + "show_hide_ui_on_hover": "Mostra/Nascondi UI al passaggio", + "always_on_top": "Sempre in cima", + "exit_mini_player": "Esci da Mini player", + "download_location": "Cartella di scarico", + "account": "Account", + "login_with_spotify": "Login con il tuo account Spotify", + "connect_with_spotify": "Connetti con Spotify", + "logout": "Esci", + "logout_of_this_account": "Esci da questo account", + "language_region": "Lingua & Regione", + "language": "Lingua", + "system_default": "Default sistema", + "market_place_region": "Regione del mercato", + "recommendation_country": "Paese Raccomandato", + "appearance": "Aspetto", + "layout_mode": "Modalità Layout", + "override_layout_settings": "Sovrascrivi le impostazioni del layout responsivo", + "adaptive": "Adattiva", + "compact": "Compatta", + "extended": "Estesa", + "theme": "Tema", + "dark": "Scuro", + "light": "Chiaro", + "system": "Sistema", + "accent_color": "Colore accento", + "sync_album_color": "Syncronizza colore album", + "sync_album_color_description": "Usa il colore dominante della copertina dell'album come colore accento", + "playback": "Riproduzione", + "audio_quality": "Qualità Audio", + "high": "Alta", + "low": "Bassa", + "pre_download_play": "Pre-scarica e riproduci", + "pre_download_play_description": "Anzi che effettuare lo stream dell'audio, scarica invece i byte e li riproduce (raccomandato per gli utenti con banda più alta)", + "skip_non_music": "Salta i segmenti non di musica (SponsorBlock)", + "blacklist_description": "Tracce e artisti in blacklist", + "wait_for_download_to_finish": "Prego attendere che lo scaricamento corrente finisca", + "desktop": "Desktop", + "close_behavior": "Comportamento Chiusura", + "close": "Chiudi", + "minimize_to_tray": "Minimizza in tray", + "show_tray_icon": "Mostra icona in tray di sistema", + "about": "A proposito di", + "u_love_spotube": "Sappiamo che ami Spotube", + "check_for_updates": "Controlla aggiornamenti", + "about_spotube": "A proposito di Spotube", + "blacklist": "Blacklist", + "please_sponsor": "Per favore sponsorizza/dona", + "spotube_description": "Spotube, un client spotify gratis per tutti, multipiattaforma e leggero", + "version": "Versione", + "build_number": "Numero Build", + "founder": "Fondatore", + "repository": "Repository", + "bug_issues": "Bug+Problemi", + "made_with": "Fatto con ❤️ in Bangladesh🇧🇩", + "kingkor_roy_tirtho": "Kingkor Roy Tirtho", + "copyright": "© 2021-{current_year} Kingkor Roy Tirtho", + "license": "Licenza", + "add_spotify_credentials": "Aggiungi le tue credenziali spotify per iniziare", + "credentials_will_not_be_shared_disclaimer": "Non ti preoccupare, le tue credenziali non saranno inviate o condivise con nessuno", + "know_how_to_login": "Non sai come farlo?", + "follow_step_by_step_guide": "Segui la guida passo-passo", + "spotify_cookie": "Cookie Spotify {name}", + "cookie_name_cookie": "Cookie {name}", + "fill_in_all_fields": "Inserire tutti i campi", + "submit": "Invia", + "exit": "Esci", + "previous": "Precedente", + "next": "Prossimo", + "done": "Finito", + "step_1": "Passo 1", + "first_go_to": "Prim, vai a", + "login_if_not_logged_in": "ed effettua il login o iscrizione se non sei già acceduto", + "step_2": "Passo 2", + "step_2_steps": "1. Quando sei acceduto premi F12 o premi il tasto destro del Mouse > Ispeziona per aprire gli strumenti di sviluppo del browser.\n2. Vai quindi nel tab \"Applicazione\" (Chrome, Edge, Brave etc..) o tab \"Archiviazione\" (Firefox, Palemoon etc..)\n3. Vai nella sezione \"Cookies\" quindi nella sezione \"https://accounts.spotify.com\"", + "step_3": "Passo 3", + "step_3_steps": "Copia il valore dei cookie \"sp_dc\" e \"sp_key\" (o sp_gaid)", + "success_emoji": "Successo🥳", + "success_message": "Ora hai correttamente effettuato il login al tuo account Spotify. Bel lavoro, amico!", + "step_4": "Passo 4", + "step_4_steps": "Incolla i valori copiati di \"sp_dc\" e \"sp_key\" (o sp_gaid) nei campi rispettivi", + "something_went_wrong": "Qualcosa è andato storto", + "piped_instance": "Istanza Server Piped", + "piped_description": "L'istanza server Piped da usare per il match della tracccia", + "piped_warning": "Alcune di queste non funzioneranno benen. Usa quindi a tuo rischio", + "generate_playlist": "Genera Playlist", + "track_exists": "La traccia {track} esiste già", + "replace_downloaded_tracks": "Sostituisci tutte le tracce scaricate", + "skip_download_tracks": "Salta lo scaricamento di tutte le tracce scaricate", + "do_you_want_to_replace": "Vuoi sovrascrivere la traccia esistente??", + "replace": "Sovrascrivi", + "skip": "Salta", + "select_up_to_count_type": "Seleziona fino a {count} {type}", + "select_genres": "Seleziona Generi", + "add_genres": "Aggiungi Generi", + "country": "Paese", + "number_of_tracks_generate": "Nnumero di tracce da generare", + "acousticness": "Acustica", + "danceability": "Ballabilità", + "energy": "Energia", + "instrumentalness": "Strumentalità", + "liveness": "Vitalità", + "loudness": "Sonorità", + "speechiness": "Loquacità", + "valence": "Valenza", + "popularity": "Popolarità", + "key": "Chiave", + "duration": "Durata (s)", + "tempo": "Tempo (BPM)", + "mode": "Modo", + "time_signature": "Indicazione di tempo", + "short": "Corta", + "medium": "Media", + "long": "Lunga", + "min": "Min", + "max": "Max", + "target": "Obiettivo", + "moderate": "Moderato", + "deselect_all": "Deseleziona Tutto", + "select_all": "Seleziona Tutto", + "are_you_sure": "Sei certo?", + "generating_playlist": "Generazione delle tue playlist custom...", + "selected_count_tracks": "{count} tracce selezionate", + "download_warning": "Se scarichi tutte le Tracce in massa stai chiaramente piratando Musica e causando un danno alla società creativa della Musica. Spero che tu sia cosciente di questo. Cerca di rispettare e supportare sempre il duro lavoro degli Artisti", + "download_ip_ban_warning": "A proposito, il tuo IP può essere bloccato da YouTube per il numero di richieste di download eccessive rispetto la norma. Il blocco IP significa che non puoi usare YoutTube (anche hai effettuato l'accesso) per almeno 2-3 mesi dal dispositivo con questo IP. Spotube non ha responsabilità se questo dovesse accadere", + "by_clicking_accept_terms": "Cliccando su 'accetta' concordi con i seguenti termini:", + "download_agreement_1": "So che sto piratando Musica. Sono cattivo", + "download_agreement_2": "Supporterò l'Artista come potrò e sto facendo questo solo perchè non ho denaro per acquistare il suo prodotto dell'ingegno", + "download_agreement_3": "Sono completamente cosciente che il mio IP può essere bloccato da YouTube & non riterrò responsabili Spotube o i suoi autori/contributori per ogni inconveniente causato dalla mia azione corrente", + "decline": "Declino", + "accept": "Accetto", + "details": "Dettagli", + "youtube": "YouTube", + "channel": "Canale", + "likes": "Mi Piace", + "dislikes": "Non Mi Piace", + "views": "Viste", + "streamUrl": "URL dello streaming", + "stop": "Stop", + "sort_newest": "Ordina per nuovi aggiunti", + "sort_oldest": "Ordina per aggiunta più vecchia", + "sleep_timer": "Timer Dormire", + "mins": "{minutes} Minuti", + "hours": "{hours} Ore", + "hour": "{hours} Ora", + "custom_hours": "Orari Personalizzati", + "logs": "Log", + "developers": "Sviluppatori", + "not_logged_in": "Non hai effettuato l'accesso", + "search_mode": "Modalità Ricerca", + "youtube_api_type": "Tipo API", + "ok": "Ok", + "failed_to_encrypt": "Criptazione fallita", + "encryption_failed_warning": "Spotube usa la criptazione per memorizzare in modo sicuro i dati. Ma ha fallito a farlo. Passerà quindi in ripiego alla memorizzazione non siscura\nSe stai usando Linux assicurati di avere un servizio di segretezza installato (gnome-keyring, kde-wallet, keepassxc etc)", + "querying_info": "Richiesta informazioni...", + "piped_api_down": "Le Piped API non funzionano", + "piped_down_error_instructions": "L'istanza di Piped {pipedInstance} è correntemente offline\n\nCambia istanza o cambia 'Tipo API' alle API ufficiali YouTube\n\nAssicurati di riavviare l'app dopo il cambio", + "you_are_offline": "Sei correntemente offline", + "connection_restored": "Connessione ad internet ripristinata", + "use_system_title_bar": "Usa la barra del titolo di sistema", + "crunching_results": "Elaborazione risultati...", + "search_to_get_results": "Cerca per ottenere risultati" + "use_amoled_mode": "Usa modalità AMOLED", + "pitch_dark_theme": "Tema nero profondo", + "normalize_audio": "Normalizza audio", + "change_cover": "Cambia copertina", + "add_cover": "Aggiungi copertina", + "restore_defaults": "Ripristina default", + "download_music_codec": "Codec musicale scaricamento", + "streaming_music_codec": "Codec musicale streaming", + "login_with_lastfm": "Accesso a Last.fm", + "connect": "Connetti", + "disconnect_lastfm": "Disconnetti Last.fm", + "disconnect": "Disconnetti", + "username": "Nome utente", + "password": "Password", + "login": "Accesso", + "login_with_your_lastfm": "Accedi con il tuo account Last.fm", + "scrobble_to_lastfm": "Invia a Last.fm" +} \ No newline at end of file diff --git a/lib/l10n/l10n.dart b/lib/l10n/l10n.dart index 61a6d097..d6cf3e37 100644 --- a/lib/l10n/l10n.dart +++ b/lib/l10n/l10n.dart @@ -6,6 +6,7 @@ /// iceyear@github => Simplified Chinese /// TexturedPolak@github => Polish /// yuri-val@github => Ukrainian +/// energywave@github, ncvescera@github, OpenCode@github => Italian /// mdksec@github => Turkish import 'package:flutter/material.dart'; @@ -20,6 +21,7 @@ class L10n { const Locale("fa", "IR"), const Locale('fr', 'FR'), const Locale('hi', 'IN'), + const Locale('it', 'IT'), const Locale('ja', 'JP'), const Locale('pl', 'PL'), const Locale('pt', 'PT'), From 24a2294512bb0c4aff77bc8dcad9b4de3e8b45c6 Mon Sep 17 00:00:00 2001 From: Kingkor Roy Tirtho Date: Fri, 8 Dec 2023 13:27:31 +0600 Subject: [PATCH 058/195] feat: toggle for discord rpc --- lib/collections/spotube_icons.dart | 1 + lib/l10n/app_en.arb | 3 +- lib/pages/settings/sections/desktop.dart | 8 +++ lib/provider/discord_provider.dart | 70 +++++++++++++++++++ .../proxy_playlist_provider.dart | 3 +- .../user_preferences_provider.dart | 4 ++ .../user_preferences_state.dart | 6 ++ .../user_preferences_state.g.dart | 2 + lib/services/discord/discord.dart | 44 ------------ untranslated_messages.json | 45 ++++++++---- 10 files changed, 125 insertions(+), 61 deletions(-) create mode 100644 lib/provider/discord_provider.dart delete mode 100644 lib/services/discord/discord.dart diff --git a/lib/collections/spotube_icons.dart b/lib/collections/spotube_icons.dart index d00775c7..00010aae 100644 --- a/lib/collections/spotube_icons.dart +++ b/lib/collections/spotube_icons.dart @@ -108,4 +108,5 @@ abstract class SpotubeIcons { static const noEye = FeatherIcons.eyeOff; static const normalize = FeatherIcons.barChart2; static const wikipedia = SimpleIcons.wikipedia; + static const discord = SimpleIcons.discord; } diff --git a/lib/l10n/app_en.arb b/lib/l10n/app_en.arb index 5aded7d5..85900012 100644 --- a/lib/l10n/app_en.arb +++ b/lib/l10n/app_en.arb @@ -280,5 +280,6 @@ "login": "Login", "login_with_your_lastfm": "Login with your Last.fm account", "scrobble_to_lastfm": "Scrobble to Last.fm", - "go_to_album": "Go to Album" + "go_to_album": "Go to Album", + "discord_rich_presence": "Discord Rich Presence" } \ No newline at end of file diff --git a/lib/pages/settings/sections/desktop.dart b/lib/pages/settings/sections/desktop.dart index 41d6d61e..ae721fc4 100644 --- a/lib/pages/settings/sections/desktop.dart +++ b/lib/pages/settings/sections/desktop.dart @@ -1,4 +1,5 @@ import 'package:flutter/material.dart'; +import 'package:flutter_desktop_tools/flutter_desktop_tools.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:spotube/collections/spotube_icons.dart'; import 'package:spotube/components/settings/section_card_with_heading.dart'; @@ -50,6 +51,13 @@ class SettingsDesktopSection extends HookConsumerWidget { value: preferences.systemTitleBar, onChanged: preferencesNotifier.setSystemTitleBar, ), + if (!DesktopTools.platform.isMacOS) + SwitchListTile( + secondary: const Icon(SpotubeIcons.discord), + title: Text(context.l10n.discord_rich_presence), + value: preferences.discordPresence, + onChanged: preferencesNotifier.setDiscordPresence, + ), ], ); } diff --git a/lib/provider/discord_provider.dart b/lib/provider/discord_provider.dart new file mode 100644 index 00000000..3aa547a9 --- /dev/null +++ b/lib/provider/discord_provider.dart @@ -0,0 +1,70 @@ +import 'package:dart_discord_rpc/dart_discord_rpc.dart'; +import 'package:flutter/foundation.dart'; +import 'package:flutter_desktop_tools/flutter_desktop_tools.dart'; +import 'package:hooks_riverpod/hooks_riverpod.dart'; +import 'package:spotify/spotify.dart'; +import 'package:spotube/collections/env.dart'; +import 'package:spotube/provider/proxy_playlist/proxy_playlist_provider.dart'; +import 'package:spotube/provider/user_preferences/user_preferences_provider.dart'; +import 'package:spotube/utils/type_conversion_utils.dart'; + +class Discord extends ChangeNotifier { + final DiscordRPC? discordRPC; + final bool isEnabled; + + Discord(this.isEnabled) + : discordRPC = (DesktopTools.platform.isWindows || + DesktopTools.platform.isLinux) && + isEnabled + ? DiscordRPC(applicationId: Env.discordAppId) + : null { + discordRPC?.start(autoRegister: true); + } + + void updatePresence(Track track) { + clear(); + final artistNames = + TypeConversionUtils.artists_X_String(track.artists ?? []); + discordRPC?.updatePresence( + DiscordPresence( + details: "Song: ${track.name} by $artistNames", + state: "Vibing in Music", + startTimeStamp: DateTime.now().millisecondsSinceEpoch, + largeImageKey: "spotube-logo-foreground", + largeImageText: "Spotube", + smallImageKey: "spotube-logo-foreground", + smallImageText: "Spotube", + ), + ); + } + + void clear() { + discordRPC?.clearPresence(); + } + + void shutdown() { + discordRPC?.shutDown(); + } + + @override + void dispose() { + clear(); + shutdown(); + super.dispose(); + } +} + +final discordProvider = ChangeNotifierProvider( + (ref) { + final isEnabled = + ref.watch(userPreferencesProvider.select((s) => s.discordPresence)); + final playback = ref.read(ProxyPlaylistNotifier.provider); + final discord = Discord(isEnabled); + + if (playback.activeTrack != null) { + discord.updatePresence(playback.activeTrack!); + } + + return discord; + }, +); diff --git a/lib/provider/proxy_playlist/proxy_playlist_provider.dart b/lib/provider/proxy_playlist/proxy_playlist_provider.dart index 84943993..ca0fb308 100644 --- a/lib/provider/proxy_playlist/proxy_playlist_provider.dart +++ b/lib/provider/proxy_playlist/proxy_playlist_provider.dart @@ -24,7 +24,7 @@ import 'package:spotube/provider/user_preferences/user_preferences_provider.dart import 'package:spotube/provider/user_preferences/user_preferences_state.dart'; import 'package:spotube/services/audio_player/audio_player.dart'; import 'package:spotube/services/audio_services/audio_services.dart'; -import 'package:spotube/services/discord/discord.dart'; +import 'package:spotube/provider/discord_provider.dart'; import 'package:spotube/services/sourced_track/exceptions.dart'; import 'package:spotube/services/sourced_track/models/source_info.dart'; import 'package:spotube/services/sourced_track/sourced_track.dart'; @@ -64,6 +64,7 @@ class ProxyPlaylistNotifier extends PersistedStateNotifier ProxyPlaylist get playlist => state; BlackListNotifier get blacklist => ref.read(BlackListNotifier.provider.notifier); + Discord get discord => ref.read(discordProvider); static final provider = StateNotifierProvider( diff --git a/lib/provider/user_preferences/user_preferences_provider.dart b/lib/provider/user_preferences/user_preferences_provider.dart index 88a0df2e..46569269 100644 --- a/lib/provider/user_preferences/user_preferences_provider.dart +++ b/lib/provider/user_preferences/user_preferences_provider.dart @@ -110,6 +110,10 @@ class UserPreferencesNotifier extends PersistedStateNotifier { } } + void setDiscordPresence(bool discordPresence) { + state = state.copyWith(discordPresence: discordPresence); + } + void setAmoledDarkTheme(bool isAmoled) { state = state.copyWith(amoledDarkTheme: isAmoled); } diff --git a/lib/provider/user_preferences/user_preferences_state.dart b/lib/provider/user_preferences/user_preferences_state.dart index b3d7fe8a..4244ca67 100644 --- a/lib/provider/user_preferences/user_preferences_state.dart +++ b/lib/provider/user_preferences/user_preferences_state.dart @@ -198,6 +198,9 @@ final class UserPreferences { ) final SourceCodecs downloadMusicCodec; + @JsonKey(defaultValue: true) + final bool discordPresence; + UserPreferences({ required this.audioQuality, required this.albumColorSync, @@ -219,6 +222,7 @@ final class UserPreferences { required this.audioSource, required this.streamMusicCodec, required this.downloadMusicCodec, + required this.discordPresence, }); factory UserPreferences.withDefaults() { @@ -255,6 +259,7 @@ final class UserPreferences { SourceCodecs? downloadMusicCodec, SourceCodecs? streamMusicCodec, bool? systemTitleBar, + bool? discordPresence, }) { return UserPreferences( themeMode: themeMode ?? this.themeMode, @@ -277,6 +282,7 @@ final class UserPreferences { normalizeAudio: normalizeAudio ?? this.normalizeAudio, streamMusicCodec: streamMusicCodec ?? this.streamMusicCodec, systemTitleBar: systemTitleBar ?? this.systemTitleBar, + discordPresence: discordPresence ?? this.discordPresence, ); } } diff --git a/lib/provider/user_preferences/user_preferences_state.g.dart b/lib/provider/user_preferences/user_preferences_state.g.dart index 54cd3aa2..59043601 100644 --- a/lib/provider/user_preferences/user_preferences_state.g.dart +++ b/lib/provider/user_preferences/user_preferences_state.g.dart @@ -63,6 +63,7 @@ UserPreferences _$UserPreferencesFromJson(Map json) => _$SourceCodecsEnumMap, json['downloadMusicCodec'], unknownValue: SourceCodecs.m4a) ?? SourceCodecs.m4a, + discordPresence: json['discordPresence'] as bool? ?? true, ); Map _$UserPreferencesToJson(UserPreferences instance) => @@ -88,6 +89,7 @@ Map _$UserPreferencesToJson(UserPreferences instance) => 'audioSource': _$AudioSourceEnumMap[instance.audioSource]!, 'streamMusicCodec': _$SourceCodecsEnumMap[instance.streamMusicCodec]!, 'downloadMusicCodec': _$SourceCodecsEnumMap[instance.downloadMusicCodec]!, + 'discordPresence': instance.discordPresence, }; const _$SourceQualitiesEnumMap = { diff --git a/lib/services/discord/discord.dart b/lib/services/discord/discord.dart deleted file mode 100644 index 2a40e388..00000000 --- a/lib/services/discord/discord.dart +++ /dev/null @@ -1,44 +0,0 @@ -import 'package:dart_discord_rpc/dart_discord_rpc.dart'; -import 'package:flutter_desktop_tools/flutter_desktop_tools.dart'; -import 'package:spotify/spotify.dart'; -import 'package:spotube/collections/env.dart'; -import 'package:spotube/utils/type_conversion_utils.dart'; - -class Discord { - final DiscordRPC? discordRPC; - - Discord() - : discordRPC = - DesktopTools.platform.isWindows || DesktopTools.platform.isLinux - ? DiscordRPC(applicationId: Env.discordAppId) - : null { - discordRPC?.start(autoRegister: true); - } - - void updatePresence(Track track) { - clear(); - final artistNames = - TypeConversionUtils.artists_X_String(track.artists ?? []); - discordRPC?.updatePresence( - DiscordPresence( - details: "Song: ${track.name} by $artistNames", - state: "Vibing in Music", - startTimeStamp: DateTime.now().millisecondsSinceEpoch, - largeImageKey: "spotube-logo-foreground", - largeImageText: "Spotube", - smallImageKey: "spotube-logo-foreground", - smallImageText: "Spotube", - ), - ); - } - - void clear() { - discordRPC?.clearPresence(); - } - - void shutdown() { - discordRPC?.shutDown(); - } -} - -final discord = Discord(); diff --git a/untranslated_messages.json b/untranslated_messages.json index 0130c162..e3bdc047 100644 --- a/untranslated_messages.json +++ b/untranslated_messages.json @@ -1,61 +1,76 @@ { "ar": [ - "go_to_album" + "go_to_album", + "discord_rich_presence" ], "bn": [ - "go_to_album" + "go_to_album", + "discord_rich_presence" ], "ca": [ - "go_to_album" + "go_to_album", + "discord_rich_presence" ], "de": [ - "go_to_album" + "go_to_album", + "discord_rich_presence" ], "es": [ - "go_to_album" + "go_to_album", + "discord_rich_presence" ], "fa": [ - "go_to_album" + "go_to_album", + "discord_rich_presence" ], "fr": [ - "go_to_album" + "go_to_album", + "discord_rich_presence" ], "hi": [ - "go_to_album" + "go_to_album", + "discord_rich_presence" ], "ja": [ - "go_to_album" + "go_to_album", + "discord_rich_presence" ], "pl": [ - "go_to_album" + "go_to_album", + "discord_rich_presence" ], "pt": [ - "go_to_album" + "go_to_album", + "discord_rich_presence" ], "ru": [ - "go_to_album" + "go_to_album", + "discord_rich_presence" ], "tr": [ - "go_to_album" + "go_to_album", + "discord_rich_presence" ], "uk": [ - "go_to_album" + "go_to_album", + "discord_rich_presence" ], "zh": [ - "go_to_album" + "go_to_album", + "discord_rich_presence" ] } From 581b241f995712805baafa67c4f56f0e9e29b7cd Mon Sep 17 00:00:00 2001 From: Kingkor Roy Tirtho Date: Fri, 8 Dec 2023 13:58:12 +0600 Subject: [PATCH 059/195] chore: add not found for empty lists --- lib/components/library/user_albums.dart | 56 +++++++++++-------- lib/components/library/user_artists.dart | 19 +++++-- lib/components/library/user_local_tracks.dart | 10 ++++ .../sections/body/track_view_body.dart | 12 ++-- lib/themes/theme.dart | 1 + 5 files changed, 62 insertions(+), 36 deletions(-) diff --git a/lib/components/library/user_albums.dart b/lib/components/library/user_albums.dart index 49243870..04ab5b63 100644 --- a/lib/components/library/user_albums.dart +++ b/lib/components/library/user_albums.dart @@ -9,6 +9,7 @@ import 'package:spotube/collections/fake.dart'; import 'package:spotube/collections/spotube_icons.dart'; import 'package:spotube/components/album/album_card.dart'; +import 'package:spotube/components/shared/fallbacks/not_found.dart'; import 'package:spotube/components/shared/inter_scrollbar/inter_scrollbar.dart'; import 'package:spotube/components/shared/fallbacks/anonymous_fallback.dart'; import 'package:spotube/components/shared/waypoint.dart'; @@ -84,30 +85,37 @@ class UserAlbums extends HookConsumerWidget { padding: const EdgeInsets.all(8.0), controller: controller, child: Skeletonizer( - enabled: albums.isEmpty, - child: Wrap( - runSpacing: 20, - alignment: WrapAlignment.center, - runAlignment: WrapAlignment.center, - crossAxisAlignment: WrapCrossAlignment.center, - children: [ - if (albums.isEmpty) - ...List.generate( - 10, - (index) => AlbumCard(FakeData.album), - ), - for (final album in albums) - AlbumCard( - TypeConversionUtils.simpleAlbum_X_Album(album), - ), - if (albums.isNotEmpty && albumsQuery.hasNextPage) - Waypoint( - controller: controller, - isGrid: true, - onTouchEdge: albumsQuery.fetchNext, - child: AlbumCard(FakeData.album), - ) - ], + enabled: albums.isEmpty && albumsQuery.isLoadingNextPage, + child: Center( + child: Wrap( + runSpacing: 20, + alignment: WrapAlignment.center, + runAlignment: WrapAlignment.center, + crossAxisAlignment: WrapCrossAlignment.center, + children: [ + if (albums.isEmpty && albumsQuery.isLoadingNextPage) + ...List.generate( + 10, + (index) => AlbumCard(FakeData.album), + ) + else if (albums.isEmpty) + const Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [NotFound()], + ), + for (final album in albums) + AlbumCard( + TypeConversionUtils.simpleAlbum_X_Album(album), + ), + if (albums.isNotEmpty && albumsQuery.hasNextPage) + Waypoint( + controller: controller, + isGrid: true, + onTouchEdge: albumsQuery.fetchNext, + child: AlbumCard(FakeData.album), + ) + ], + ), ), ), ), diff --git a/lib/components/library/user_artists.dart b/lib/components/library/user_artists.dart index 7269d7eb..36b8528e 100644 --- a/lib/components/library/user_artists.dart +++ b/lib/components/library/user_artists.dart @@ -9,6 +9,7 @@ import 'package:spotube/collections/fake.dart'; import 'package:spotube/collections/spotube_icons.dart'; import 'package:spotube/components/shared/fallbacks/anonymous_fallback.dart'; import 'package:spotube/components/artist/artist_card.dart'; +import 'package:spotube/components/shared/fallbacks/not_found.dart'; import 'package:spotube/components/shared/inter_scrollbar/inter_scrollbar.dart'; import 'package:spotube/extensions/context.dart'; import 'package:spotube/provider/authentication_provider.dart'; @@ -97,10 +98,20 @@ class UserArtists extends HookConsumerWidget { children: artistQuery.isLoading ? List.generate( 10, (index) => ArtistCard(FakeData.artist)) - : filteredArtists - .mapIndexed( - (index, artist) => ArtistCard(artist)) - .toList(), + : filteredArtists.isEmpty + ? [ + const Row( + mainAxisAlignment: + MainAxisAlignment.center, + children: [ + NotFound(), + ], + ) + ] + : filteredArtists + .mapIndexed((index, artist) => + ArtistCard(artist)) + .toList(), ), ), ), diff --git a/lib/components/library/user_local_tracks.dart b/lib/components/library/user_local_tracks.dart index fcaada9e..f4e782d9 100644 --- a/lib/components/library/user_local_tracks.dart +++ b/lib/components/library/user_local_tracks.dart @@ -17,6 +17,7 @@ import 'package:spotify/spotify.dart'; import 'package:spotube/collections/fake.dart'; import 'package:spotube/collections/spotube_icons.dart'; import 'package:spotube/components/shared/expandable_search/expandable_search.dart'; +import 'package:spotube/components/shared/fallbacks/not_found.dart'; import 'package:spotube/components/shared/inter_scrollbar/inter_scrollbar.dart'; import 'package:spotube/components/shared/sort_tracks_dropdown.dart'; import 'package:spotube/components/shared/track_tile/track_tile.dart'; @@ -255,6 +256,15 @@ class UserLocalTracks extends HookConsumerWidget { .toList(); }, [searchController.text, sortedTracks]); + if (!trackSnapshot.isLoading && filteredTracks.isEmpty) { + return const Expanded( + child: Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [NotFound()], + ), + ); + } + return Expanded( child: RefreshIndicator( onRefresh: () async { diff --git a/lib/components/shared/tracks_view/sections/body/track_view_body.dart b/lib/components/shared/tracks_view/sections/body/track_view_body.dart index b7149cc2..2ad1dc9b 100644 --- a/lib/components/shared/tracks_view/sections/body/track_view_body.dart +++ b/lib/components/shared/tracks_view/sections/body/track_view_body.dart @@ -8,6 +8,7 @@ import 'package:skeletonizer/skeletonizer.dart'; import 'package:spotify/spotify.dart'; import 'package:spotube/collections/fake.dart'; import 'package:spotube/components/shared/expandable_search/expandable_search.dart'; +import 'package:spotube/components/shared/fallbacks/not_found.dart'; import 'package:spotube/components/shared/track_tile/track_tile.dart'; import 'package:spotube/components/shared/tracks_view/sections/body/track_view_body_headers.dart'; import 'package:spotube/components/shared/tracks_view/sections/body/use_is_user_playlist.dart'; @@ -92,14 +93,9 @@ class TrackViewBodySection extends HookConsumerWidget { index: 0, ), ), - emptyBuilder: (context) => Skeletonizer( - enabled: true, - child: Column( - children: List.generate( - 10, - (index) => TrackTile(track: FakeData.track, index: index), - ), - ), + emptyBuilder: (context) => const Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [NotFound()], ), itemBuilder: (context, index) { final track = tracks[index]; diff --git a/lib/themes/theme.dart b/lib/themes/theme.dart index 9a5e473f..51e98269 100644 --- a/lib/themes/theme.dart +++ b/lib/themes/theme.dart @@ -52,6 +52,7 @@ ThemeData theme(Color seed, Brightness brightness, bool isAmoled) { ), sliderTheme: SliderThemeData(overlayShape: SliderComponentShape.noOverlay), searchBarTheme: SearchBarThemeData( + textStyle: const MaterialStatePropertyAll(TextStyle(fontSize: 15)), constraints: const BoxConstraints(maxWidth: double.infinity), padding: const MaterialStatePropertyAll(EdgeInsets.all(8)), backgroundColor: MaterialStatePropertyAll( From b04d8849e7169824ec5b980236b5d61b2629f56e Mon Sep 17 00:00:00 2001 From: Kingkor Roy Tirtho Date: Fri, 8 Dec 2023 14:46:27 +0600 Subject: [PATCH 060/195] fix: track view header title overflow and player view drag glitch --- lib/components/player/player.dart | 103 ++++++++++-------- lib/components/player/player_overlay.dart | 9 +- lib/components/shared/playbutton_card.dart | 4 +- .../shared/track_tile/track_tile.dart | 43 ++++---- .../sections/body/track_view_body.dart | 11 +- .../sections/header/flexible_header.dart | 102 ++++++++++------- 6 files changed, 156 insertions(+), 116 deletions(-) diff --git a/lib/components/player/player.dart b/lib/components/player/player.dart index 889b7c5c..3957cc65 100644 --- a/lib/components/player/player.dart +++ b/lib/components/player/player.dart @@ -28,9 +28,11 @@ import 'package:spotube/utils/type_conversion_utils.dart'; class PlayerView extends HookConsumerWidget { final PanelController panelController; + final ScrollController scrollController; const PlayerView({ Key? key, required this.panelController, + required this.scrollController, }) : super(key: key); @override @@ -119,40 +121,43 @@ class PlayerView extends HookConsumerWidget { preferredSize: Size.fromHeight( kToolbarHeight + topPadding, ), - child: Padding( - padding: EdgeInsets.only(top: topPadding), - child: PageWindowTitleBar( - backgroundColor: Colors.transparent, - foregroundColor: titleTextColor, - toolbarOpacity: 1, - leading: IconButton( - icon: const Icon(SpotubeIcons.angleDown, size: 18), - onPressed: panelController.close, + child: ForceDraggableWidget( + child: Padding( + padding: EdgeInsets.only(top: topPadding), + child: PageWindowTitleBar( + backgroundColor: Colors.transparent, + foregroundColor: titleTextColor, + toolbarOpacity: 1, + leading: IconButton( + icon: const Icon(SpotubeIcons.angleDown, size: 18), + onPressed: panelController.close, + ), + actions: [ + IconButton( + icon: const Icon(SpotubeIcons.info, size: 18), + tooltip: context.l10n.details, + style: IconButton.styleFrom( + foregroundColor: bodyTextColor), + onPressed: currentTrack == null + ? null + : () { + showDialog( + context: context, + builder: (context) { + return TrackDetailsDialog( + track: currentTrack, + ); + }); + }, + ) + ], ), - actions: [ - IconButton( - icon: const Icon(SpotubeIcons.info, size: 18), - tooltip: context.l10n.details, - style: - IconButton.styleFrom(foregroundColor: bodyTextColor), - onPressed: currentTrack == null - ? null - : () { - showDialog( - context: context, - builder: (context) { - return TrackDetailsDialog( - track: currentTrack, - ); - }); - }, - ) - ], ), ), ), extendBodyBehindAppBar: true, body: SingleChildScrollView( + controller: scrollController, child: Container( alignment: Alignment.center, width: double.infinity, @@ -163,27 +168,29 @@ class PlayerView extends HookConsumerWidget { padding: const EdgeInsets.all(8.0), child: Column( children: [ - Container( - margin: const EdgeInsets.all(8), - constraints: const BoxConstraints( - maxHeight: 300, maxWidth: 300), - decoration: BoxDecoration( - borderRadius: BorderRadius.circular(20), - boxShadow: const [ - BoxShadow( - color: Colors.black26, - spreadRadius: 2, - blurRadius: 10, - offset: Offset(0, 0), + ForceDraggableWidget( + child: Container( + margin: const EdgeInsets.all(8), + constraints: const BoxConstraints( + maxHeight: 300, maxWidth: 300), + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(20), + boxShadow: const [ + BoxShadow( + color: Colors.black26, + spreadRadius: 2, + blurRadius: 10, + offset: Offset(0, 0), + ), + ], + ), + child: ClipRRect( + borderRadius: BorderRadius.circular(20), + child: UniversalImage( + path: albumArt, + placeholder: Assets.albumPlaceholder.path, + fit: BoxFit.cover, ), - ], - ), - child: ClipRRect( - borderRadius: BorderRadius.circular(20), - child: UniversalImage( - path: albumArt, - placeholder: Assets.albumPlaceholder.path, - fit: BoxFit.cover, ), ), ), diff --git a/lib/components/player/player_overlay.dart b/lib/components/player/player_overlay.dart index 4869a0fa..2d63811e 100644 --- a/lib/components/player/player_overlay.dart +++ b/lib/components/player/player_overlay.dart @@ -43,6 +43,7 @@ class PlayerOverlay extends HookConsumerWidget { final mediaQuery = MediaQuery.of(context); final panelController = useMemoized(() => PanelController(), []); + final scrollController = useScrollController(); useEffect(() { return () { @@ -174,6 +175,7 @@ class PlayerOverlay extends HookConsumerWidget { ), ), ), + scrollController: scrollController, panelBuilder: (position) { // this is the reason we're getting an update final navigationHeight = ref.watch(navigationPanelHeight); @@ -188,8 +190,11 @@ class PlayerOverlay extends HookConsumerWidget { decoration: navigationHeight == 0 ? const BoxDecoration(borderRadius: BorderRadius.zero) : const BoxDecoration(borderRadius: radius), - child: HorizontalScrollableWidget( - child: PlayerView(panelController: panelController), + child: IgnoreDraggableWidget( + child: PlayerView( + panelController: panelController, + scrollController: scrollController, + ), ), ), ); diff --git a/lib/components/shared/playbutton_card.dart b/lib/components/shared/playbutton_card.dart index 60db648b..d6226716 100644 --- a/lib/components/shared/playbutton_card.dart +++ b/lib/components/shared/playbutton_card.dart @@ -90,17 +90,19 @@ class PlaybuttonCard extends HookWidget { Stack( clipBehavior: Clip.none, children: [ - Padding( + Container( padding: const EdgeInsets.only( left: 8, right: 8, top: 8, ), + constraints: BoxConstraints(maxHeight: size), child: ClipRRect( borderRadius: radius, child: UniversalImage( path: imageUrl, placeholder: Assets.albumPlaceholder.path, + fit: BoxFit.cover, ), ), ), diff --git a/lib/components/shared/track_tile/track_tile.dart b/lib/components/shared/track_tile/track_tile.dart index 6d4e236a..961f29c9 100644 --- a/lib/components/shared/track_tile/track_tile.dart +++ b/lib/components/shared/track_tile/track_tile.dart @@ -4,6 +4,7 @@ import 'package:flutter/gestures.dart'; import 'package:flutter/material.dart'; import 'package:flutter_hooks/flutter_hooks.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; +import 'package:skeletonizer/skeletonizer.dart'; import 'package:spotify/spotify.dart'; import 'package:spotube/collections/spotube_icons.dart'; import 'package:spotube/components/shared/hover_builder.dart'; @@ -158,26 +159,28 @@ class TrackTile extends HookConsumerWidget { child: IconTheme( data: theme.iconTheme .copyWith(size: 26, color: Colors.white), - child: AnimatedSwitcher( - duration: const Duration(milliseconds: 300), - child: (isPlaying && playlist.isFetching) || - isLoading.value - ? const SizedBox( - width: 26, - height: 26, - child: CircularProgressIndicator( - strokeWidth: 1.5, - color: Colors.white, - ), - ) - : isPlaying - ? Icon( - SpotubeIcons.pause, - color: theme.colorScheme.primary, - ) - : !isHovering - ? const SizedBox.shrink() - : const Icon(SpotubeIcons.play), + child: Skeleton.ignore( + child: AnimatedSwitcher( + duration: const Duration(milliseconds: 300), + child: (isPlaying && playlist.isFetching) || + isLoading.value + ? const SizedBox( + width: 26, + height: 26, + child: CircularProgressIndicator( + strokeWidth: 1.5, + color: Colors.white, + ), + ) + : isPlaying + ? Icon( + SpotubeIcons.pause, + color: theme.colorScheme.primary, + ) + : !isHovering + ? const SizedBox.shrink() + : const Icon(SpotubeIcons.play), + ), ), ), ), diff --git a/lib/components/shared/tracks_view/sections/body/track_view_body.dart b/lib/components/shared/tracks_view/sections/body/track_view_body.dart index 2ad1dc9b..20caf4f1 100644 --- a/lib/components/shared/tracks_view/sections/body/track_view_body.dart +++ b/lib/components/shared/tracks_view/sections/body/track_view_body.dart @@ -93,9 +93,14 @@ class TrackViewBodySection extends HookConsumerWidget { index: 0, ), ), - emptyBuilder: (context) => const Row( - mainAxisAlignment: MainAxisAlignment.center, - children: [NotFound()], + emptyBuilder: (context) => Skeletonizer( + enabled: true, + child: Column( + children: List.generate( + 10, + (index) => TrackTile(track: FakeData.track, index: index), + ), + ), ), itemBuilder: (context, index) { final track = tracks[index]; diff --git a/lib/components/shared/tracks_view/sections/header/flexible_header.dart b/lib/components/shared/tracks_view/sections/header/flexible_header.dart index 7c469654..e16ccbff 100644 --- a/lib/components/shared/tracks_view/sections/header/flexible_header.dart +++ b/lib/components/shared/tracks_view/sections/header/flexible_header.dart @@ -88,50 +88,68 @@ class TrackViewFlexHeader extends HookConsumerWidget { mainAxisAlignment: MainAxisAlignment.center, crossAxisAlignment: CrossAxisAlignment.center, children: [ - Flex( - direction: mediaQuery.mdAndDown - ? Axis.vertical - : Axis.horizontal, - mainAxisSize: MainAxisSize.min, - children: [ - ClipRRect( - borderRadius: BorderRadius.circular(10), - child: UniversalImage( - path: props.image, - width: 200, - height: 200, - placeholder: Assets.albumPlaceholder.path, + ConstrainedBox( + constraints: BoxConstraints( + maxWidth: mediaQuery.mdAndDown + ? mediaQuery.size.width + : 800, + ), + child: Flex( + direction: mediaQuery.mdAndDown + ? Axis.vertical + : Axis.horizontal, + mainAxisSize: MainAxisSize.min, + children: [ + ClipRRect( + borderRadius: BorderRadius.circular(10), + child: UniversalImage( + path: props.image, + width: 200, + height: 200, + placeholder: Assets.albumPlaceholder.path, + ), ), - ), - const Gap(20), - Column( - mainAxisSize: MainAxisSize.min, - crossAxisAlignment: mediaQuery.mdAndDown - ? CrossAxisAlignment.center - : CrossAxisAlignment.start, - children: [ - Text(props.title, style: headingStyle), - const SizedBox(height: 10), - if (description != null && - description.isNotEmpty) - Text( - description, - style: defaultTextStyle.style.copyWith( - color: palette.bodyTextColor, + const Gap(20), + Flexible( + child: Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: mediaQuery.mdAndDown + ? CrossAxisAlignment.center + : CrossAxisAlignment.start, + children: [ + Text( + props.title, + style: headingStyle, + textAlign: mediaQuery.mdAndDown + ? TextAlign.center + : TextAlign.start, + maxLines: 2, + overflow: TextOverflow.ellipsis, ), - textAlign: mediaQuery.mdAndDown - ? TextAlign.center - : TextAlign.start, - maxLines: 2, - overflow: TextOverflow.ellipsis, - ), - const Gap(10), - const TrackViewHeaderActions(), - const Gap(10), - TrackViewHeaderButtons(color: palette), - ], - ), - ], + const SizedBox(height: 10), + if (description != null && + description.isNotEmpty) + Text( + description, + style: + defaultTextStyle.style.copyWith( + color: palette.bodyTextColor, + ), + textAlign: mediaQuery.mdAndDown + ? TextAlign.center + : TextAlign.start, + maxLines: 2, + overflow: TextOverflow.ellipsis, + ), + const Gap(10), + const TrackViewHeaderActions(), + const Gap(10), + TrackViewHeaderButtons(color: palette), + ], + ), + ), + ], + ), ), ], ), From c592cff1eea9660f906aa95a6854152bfbbb41f9 Mon Sep 17 00:00:00 2001 From: Kingkor Roy Tirtho Date: Fri, 8 Dec 2023 18:41:57 +0600 Subject: [PATCH 061/195] chore: fix padding issues --- lib/components/library/user_albums.dart | 4 ++-- lib/components/shared/playbutton_card.dart | 7 ++++--- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/lib/components/library/user_albums.dart b/lib/components/library/user_albums.dart index 04ab5b63..200d1c59 100644 --- a/lib/components/library/user_albums.dart +++ b/lib/components/library/user_albums.dart @@ -85,7 +85,7 @@ class UserAlbums extends HookConsumerWidget { padding: const EdgeInsets.all(8.0), controller: controller, child: Skeletonizer( - enabled: albums.isEmpty && albumsQuery.isLoadingNextPage, + enabled: albumsQuery.pages.isEmpty, child: Center( child: Wrap( runSpacing: 20, @@ -93,7 +93,7 @@ class UserAlbums extends HookConsumerWidget { runAlignment: WrapAlignment.center, crossAxisAlignment: WrapCrossAlignment.center, children: [ - if (albums.isEmpty && albumsQuery.isLoadingNextPage) + if (albumsQuery.pages.isEmpty) ...List.generate( 10, (index) => AlbumCard(FakeData.album), diff --git a/lib/components/shared/playbutton_card.dart b/lib/components/shared/playbutton_card.dart index d6226716..94751f8e 100644 --- a/lib/components/shared/playbutton_card.dart +++ b/lib/components/shared/playbutton_card.dart @@ -1,6 +1,7 @@ import 'package:auto_size_text/auto_size_text.dart'; import 'package:flutter/material.dart'; import 'package:flutter_hooks/flutter_hooks.dart'; +import 'package:gap/gap.dart'; import 'package:skeletonizer/skeletonizer.dart'; import 'package:spotube/collections/assets.gen.dart'; @@ -59,8 +60,8 @@ class PlaybuttonCard extends HookWidget { ); final end = useBreakpointValue( - xs: 10, - sm: 10, + xs: 7, + sm: 7, others: 15, ); @@ -160,7 +161,7 @@ class PlaybuttonCard extends HookWidget { onPressed: isLoading ? null : onAddToQueuePressed, ), ), - const SizedBox(height: 5), + const Gap(5), IconButton( style: IconButton.styleFrom( backgroundColor: theme.colorScheme.primaryContainer, From 82ed5e90576b57ef32e61a65015e04862ab15461 Mon Sep 17 00:00:00 2001 From: Kingkor Roy Tirtho Date: Fri, 8 Dec 2023 22:18:18 +0600 Subject: [PATCH 062/195] feat: compact genre view in home page --- lib/collections/fake.dart | 6 + lib/collections/gradients.dart | 232 ++++++++++++++++++ lib/collections/routes.dart | 19 +- lib/components/genre/category_card.dart | 51 ---- lib/components/home/sections/featured.dart | 36 +++ lib/components/home/sections/genres.dart | 154 ++++++++++++ .../home/sections/made_for_user.dart | 35 +++ .../home/sections/new_releases.dart | 51 ++++ lib/components/shared/playbutton_card.dart | 19 +- lib/pages/home/genres.dart | 151 ------------ lib/pages/home/genres/genre_playlists.dart | 165 +++++++++++++ lib/pages/home/genres/genres.dart | 89 +++++++ lib/pages/home/home.dart | 40 ++- lib/pages/home/personalized.dart | 106 -------- lib/services/queries/category.dart | 23 ++ 15 files changed, 840 insertions(+), 337 deletions(-) create mode 100644 lib/collections/gradients.dart delete mode 100644 lib/components/genre/category_card.dart create mode 100644 lib/components/home/sections/featured.dart create mode 100644 lib/components/home/sections/genres.dart create mode 100644 lib/components/home/sections/made_for_user.dart create mode 100644 lib/components/home/sections/new_releases.dart delete mode 100644 lib/pages/home/genres.dart create mode 100644 lib/pages/home/genres/genre_playlists.dart create mode 100644 lib/pages/home/genres/genres.dart delete mode 100644 lib/pages/home/personalized.dart diff --git a/lib/collections/fake.dart b/lib/collections/fake.dart index a02e8587..10cf2819 100644 --- a/lib/collections/fake.dart +++ b/lib/collections/fake.dart @@ -158,4 +158,10 @@ abstract class FakeData { ..type = "type" ..description = "A very good playlist description" ..uri = "uri"; + + static final Category category = Category() + ..href = "text" + ..icons = [image] + ..id = "1" + ..name = "category"; } diff --git a/lib/collections/gradients.dart b/lib/collections/gradients.dart new file mode 100644 index 00000000..e861dde7 --- /dev/null +++ b/lib/collections/gradients.dart @@ -0,0 +1,232 @@ +import 'package:flutter/material.dart'; + +const gradients = [ + LinearGradient(colors: [ + Color.fromRGBO(123, 102, 255, 1), + Color.fromRGBO(95, 189, 255, 1), + Color.fromRGBO(150, 239, 255, 1), + Color.fromRGBO(197, 255, 248, 1) + ]), + LinearGradient(colors: [ + Color.fromRGBO(245, 204, 160, 1), + Color.fromRGBO(228, 143, 69, 1), + Color.fromRGBO(153, 77, 28, 1), + Color.fromRGBO(107, 36, 12, 1) + ]), + LinearGradient(colors: [ + Color.fromRGBO(243, 243, 243, 1), + Color.fromRGBO(197, 232, 152, 1), + Color.fromRGBO(41, 173, 178, 1), + Color.fromRGBO(7, 102, 173, 1) + ]), + LinearGradient(colors: [ + Color.fromRGBO(240, 89, 65, 1), + Color.fromRGBO(190, 49, 68, 1), + Color.fromRGBO(135, 35, 65, 1), + Color.fromRGBO(34, 9, 44, 1) + ]), + LinearGradient(colors: [ + Color.fromRGBO(119, 107, 93, 1), + Color.fromRGBO(176, 166, 149, 1), + Color.fromRGBO(235, 227, 213, 1), + Color.fromRGBO(243, 238, 234, 1) + ]), + LinearGradient(colors: [ + Color.fromRGBO(208, 162, 247, 1), + Color.fromRGBO(220, 191, 255, 1), + Color.fromRGBO(229, 212, 255, 1), + Color.fromRGBO(241, 234, 255, 1) + ]), + LinearGradient(colors: [ + Color.fromRGBO(221, 242, 253, 1), + Color.fromRGBO(155, 190, 200, 1), + Color.fromRGBO(66, 125, 157, 1), + Color.fromRGBO(22, 72, 99, 1) + ]), + LinearGradient(colors: [ + Color.fromRGBO(119, 67, 219, 1), + Color.fromRGBO(195, 172, 208, 1), + Color.fromRGBO(247, 239, 229, 1), + Color.fromRGBO(255, 251, 245, 1) + ]), + LinearGradient(colors: [ + Color.fromRGBO(194, 217, 255, 1), + Color.fromRGBO(142, 143, 250, 1), + Color.fromRGBO(119, 82, 254, 1), + Color.fromRGBO(25, 4, 130, 1) + ]), + LinearGradient(colors: [ + Color.fromRGBO(104, 126, 255, 1), + Color.fromRGBO(128, 179, 255, 1), + Color.fromRGBO(152, 228, 255, 1), + Color.fromRGBO(182, 255, 250, 1) + ]), + LinearGradient(colors: [ + Color.fromRGBO(176, 87, 141, 1), + Color.fromRGBO(217, 136, 185, 1), + Color.fromRGBO(250, 203, 234, 1), + Color.fromRGBO(255, 228, 214, 1) + ]), + LinearGradient(colors: [ + Color.fromRGBO(190, 255, 247, 1), + Color.fromRGBO(166, 246, 255, 1), + Color.fromRGBO(158, 221, 255, 1), + Color.fromRGBO(100, 153, 233, 1) + ]), + LinearGradient(colors: [ + Color.fromRGBO(245, 252, 205, 1), + Color.fromRGBO(120, 214, 198, 1), + Color.fromRGBO(65, 145, 151, 1), + Color.fromRGBO(18, 72, 107, 1) + ]), + LinearGradient(colors: [ + Color.fromRGBO(229, 207, 247, 1), + Color.fromRGBO(157, 118, 193, 1), + Color.fromRGBO(113, 58, 190, 1), + Color.fromRGBO(91, 8, 136, 1) + ]), + LinearGradient(colors: [ + Color.fromRGBO(249, 222, 201, 1), + Color.fromRGBO(247, 140, 162, 1), + Color.fromRGBO(216, 0, 50, 1), + Color.fromRGBO(61, 12, 17, 1) + ]), + LinearGradient(colors: [ + Color.fromRGBO(242, 247, 161, 1), + Color.fromRGBO(53, 162, 159, 1), + Color.fromRGBO(8, 131, 149, 1), + Color.fromRGBO(7, 25, 82, 1) + ]), + LinearGradient(colors: [ + Color.fromRGBO(243, 159, 90, 1), + Color.fromRGBO(174, 68, 90, 1), + Color.fromRGBO(102, 37, 73, 1), + Color.fromRGBO(69, 25, 82, 1) + ]), + LinearGradient(colors: [ + Color.fromRGBO(255, 200, 200, 1), + Color.fromRGBO(255, 155, 130, 1), + Color.fromRGBO(255, 63, 164, 1), + Color.fromRGBO(87, 55, 93, 1) + ]), + LinearGradient(colors: [ + Color.fromRGBO(238, 238, 238, 1), + Color.fromRGBO(100, 204, 197, 1), + Color.fromRGBO(23, 107, 135, 1), + Color.fromRGBO(5, 59, 80, 1) + ]), + LinearGradient(colors: [ + Color.fromRGBO(198, 61, 47, 1), + Color.fromRGBO(226, 94, 62, 1), + Color.fromRGBO(255, 155, 80, 1), + Color.fromRGBO(255, 187, 92, 1) + ]), + LinearGradient(colors: [ + Color.fromRGBO(236, 83, 176, 1), + Color.fromRGBO(157, 68, 192, 1), + Color.fromRGBO(77, 45, 183, 1), + Color.fromRGBO(14, 33, 160, 1) + ]), + LinearGradient(colors: [ + Color.fromRGBO(242, 236, 190, 1), + Color.fromRGBO(226, 199, 153, 1), + Color.fromRGBO(192, 130, 97, 1), + Color.fromRGBO(154, 59, 59, 1) + ]), + LinearGradient(colors: [ + Color.fromRGBO(255, 253, 140, 1), + Color.fromRGBO(151, 255, 244, 1), + Color.fromRGBO(112, 145, 245, 1), + Color.fromRGBO(121, 63, 223, 1) + ]), + LinearGradient(colors: [ + Color.fromRGBO(67, 83, 52, 1), + Color.fromRGBO(158, 179, 132, 1), + Color.fromRGBO(206, 222, 189, 1), + Color.fromRGBO(250, 241, 228, 1) + ]), + LinearGradient(colors: [ + Color.fromRGBO(250, 240, 230, 1), + Color.fromRGBO(185, 180, 199, 1), + Color.fromRGBO(92, 84, 112, 1), + Color.fromRGBO(53, 47, 68, 1) + ]), + LinearGradient(colors: [ + Color.fromRGBO(255, 186, 134, 1), + Color.fromRGBO(246, 99, 92, 1), + Color.fromRGBO(194, 51, 115, 1), + Color.fromRGBO(121, 21, 91, 1) + ]), + LinearGradient(colors: [ + Color.fromRGBO(213, 255, 208, 1), + Color.fromRGBO(64, 248, 255, 1), + Color.fromRGBO(39, 158, 255, 1), + Color.fromRGBO(12, 53, 106, 1) + ]), + LinearGradient(colors: [ + Color.fromRGBO(131, 96, 150, 1), + Color.fromRGBO(237, 123, 123, 1), + Color.fromRGBO(240, 184, 110, 1), + Color.fromRGBO(235, 231, 108, 1) + ]), + LinearGradient(colors: [ + Color.fromRGBO(63, 29, 56, 1), + Color.fromRGBO(77, 60, 119, 1), + Color.fromRGBO(162, 103, 138, 1), + Color.fromRGBO(225, 152, 152, 1) + ]), + LinearGradient(colors: [ + Color.fromRGBO(254, 123, 229, 1), + Color.fromRGBO(151, 78, 195, 1), + Color.fromRGBO(80, 64, 153, 1), + Color.fromRGBO(49, 56, 102, 1) + ]), + LinearGradient(colors: [ + Color.fromRGBO(248, 222, 34, 1), + Color.fromRGBO(249, 76, 16, 1), + Color.fromRGBO(199, 0, 57, 1), + Color.fromRGBO(144, 12, 63, 1) + ]), + LinearGradient(colors: [ + Color.fromRGBO(101, 69, 31, 1), + Color.fromRGBO(118, 88, 39, 1), + Color.fromRGBO(200, 174, 125, 1), + Color.fromRGBO(234, 198, 150, 1) + ]), + LinearGradient(colors: [ + Color.fromRGBO(255, 246, 224, 1), + Color.fromRGBO(216, 217, 218, 1), + Color.fromRGBO(97, 103, 122, 1), + Color.fromRGBO(39, 40, 41, 1) + ]), + LinearGradient(colors: [ + Color.fromRGBO(145, 109, 179, 1), + Color.fromRGBO(228, 133, 134, 1), + Color.fromRGBO(252, 186, 173, 1), + Color.fromRGBO(253, 229, 236, 1) + ]), + LinearGradient(colors: [ + Color.fromRGBO(124, 115, 192, 1), + Color.fromRGBO(148, 173, 215, 1), + Color.fromRGBO(172, 250, 223, 1), + Color.fromRGBO(232, 255, 206, 1) + ]), + LinearGradient(colors: [ + Color.fromRGBO(174, 216, 204, 1), + Color.fromRGBO(205, 102, 136, 1), + Color.fromRGBO(122, 49, 111, 1), + Color.fromRGBO(70, 25, 89, 1) + ]), + LinearGradient(colors: [ + Color.fromRGBO(237, 228, 255, 1), + Color.fromRGBO(215, 187, 245, 1), + Color.fromRGBO(160, 118, 249, 1), + Color.fromRGBO(101, 40, 247, 1) + ]), + LinearGradient(colors: [ + Color.fromRGBO(255, 236, 175, 1), + Color.fromRGBO(255, 176, 127, 1), + Color.fromRGBO(255, 82, 162, 1), + Color.fromRGBO(243, 21, 89, 1) + ]), +]; diff --git a/lib/collections/routes.dart b/lib/collections/routes.dart index 82597ddb..7816f204 100644 --- a/lib/collections/routes.dart +++ b/lib/collections/routes.dart @@ -1,9 +1,11 @@ import 'package:catcher_2/catcher_2.dart'; -import 'package:flutter/foundation.dart'; +import 'package:flutter/foundation.dart' hide Category; import 'package:flutter/widgets.dart'; import 'package:go_router/go_router.dart'; import 'package:spotify/spotify.dart' hide Search; import 'package:spotube/pages/album/album.dart'; +import 'package:spotube/pages/home/genres/genre_playlists.dart'; +import 'package:spotube/pages/home/genres/genres.dart'; import 'package:spotube/pages/home/home.dart'; import 'package:spotube/pages/lastfm_login/lastfm_login.dart'; import 'package:spotube/pages/library/playlist_generate/playlist_generate.dart'; @@ -38,6 +40,21 @@ final router = GoRouter( GoRoute( path: "/", pageBuilder: (context, state) => const SpotubePage(child: HomePage()), + routes: [ + GoRoute( + path: "genres", + pageBuilder: (context, state) => + const SpotubePage(child: GenrePage()), + ), + GoRoute( + path: "genre/:categoryId", + pageBuilder: (context, state) => SpotubePage( + child: GenrePlaylistsPage( + category: state.extra as Category, + ), + ), + ), + ], ), GoRoute( path: "/search", diff --git a/lib/components/genre/category_card.dart b/lib/components/genre/category_card.dart deleted file mode 100644 index 7f580157..00000000 --- a/lib/components/genre/category_card.dart +++ /dev/null @@ -1,51 +0,0 @@ -import 'package:collection/collection.dart'; -import 'package:flutter/material.dart' hide Page; -import 'package:flutter_hooks/flutter_hooks.dart'; -import 'package:hooks_riverpod/hooks_riverpod.dart'; - -import 'package:spotify/spotify.dart'; -import 'package:spotube/components/shared/horizontal_playbutton_card_view/horizontal_playbutton_card_view.dart'; -import 'package:spotube/models/logger.dart'; -import 'package:spotube/services/queries/queries.dart'; - -class CategoryCard extends HookConsumerWidget { - final Category category; - CategoryCard( - this.category, { - Key? key, - }) : super(key: key); - - final logger = getLogger(CategoryCard); - - @override - Widget build(BuildContext context, ref) { - final playlistQuery = useQueries.category.playlistsOf( - ref, - category.id!, - ); - - final playlists = useMemoized( - () => playlistQuery.pages.expand( - (page) { - return page.items?.whereNotNull() ?? - const Iterable.empty(); - }, - ).toList(), - [playlistQuery.pages], - ); - - if (playlistQuery.hasErrors && - !playlistQuery.hasPageData && - !playlistQuery.isLoadingNextPage) { - return const SizedBox.shrink(); - } - - return HorizontalPlaybuttonCardView( - title: Text(category.name!), - isLoadingNextPage: playlistQuery.isLoadingNextPage, - hasNextPage: playlistQuery.hasNextPage, - items: playlists, - onFetchMore: playlistQuery.fetchNext, - ); - } -} diff --git a/lib/components/home/sections/featured.dart b/lib/components/home/sections/featured.dart new file mode 100644 index 00000000..8a7c2c95 --- /dev/null +++ b/lib/components/home/sections/featured.dart @@ -0,0 +1,36 @@ +import 'package:flutter/material.dart' hide Page; +import 'package:flutter_hooks/flutter_hooks.dart'; +import 'package:hooks_riverpod/hooks_riverpod.dart'; +import 'package:skeletonizer/skeletonizer.dart'; +import 'package:spotify/spotify.dart'; +import 'package:spotube/components/shared/horizontal_playbutton_card_view/horizontal_playbutton_card_view.dart'; +import 'package:spotube/extensions/context.dart'; +import 'package:spotube/services/queries/queries.dart'; + +class HomeFeaturedSection extends HookConsumerWidget { + const HomeFeaturedSection({Key? key}) : super(key: key); + + @override + Widget build(BuildContext context, ref) { + final featuredPlaylistsQuery = useQueries.playlist.featured(ref); + final playlists = useMemoized( + () => featuredPlaylistsQuery.pages + .whereType>() + .expand((page) => page.items ?? const []), + [featuredPlaylistsQuery.pages], + ); + final isLoadingFeaturedPlaylists = !featuredPlaylistsQuery.hasPageData && + !featuredPlaylistsQuery.isLoadingNextPage; + + return Skeletonizer( + enabled: isLoadingFeaturedPlaylists, + child: HorizontalPlaybuttonCardView( + items: playlists.toList(), + title: Text(context.l10n.featured), + isLoadingNextPage: featuredPlaylistsQuery.isLoadingNextPage, + hasNextPage: featuredPlaylistsQuery.hasNextPage, + onFetchMore: featuredPlaylistsQuery.fetchNext, + ), + ); + } +} diff --git a/lib/components/home/sections/genres.dart b/lib/components/home/sections/genres.dart new file mode 100644 index 00000000..52467b28 --- /dev/null +++ b/lib/components/home/sections/genres.dart @@ -0,0 +1,154 @@ +import 'dart:math'; + +import 'package:flutter/material.dart'; +import 'package:flutter_hooks/flutter_hooks.dart'; +import 'package:gap/gap.dart'; +import 'package:go_router/go_router.dart'; +import 'package:hooks_riverpod/hooks_riverpod.dart'; +import 'package:skeletonizer/skeletonizer.dart'; +import 'package:spotify/spotify.dart'; +import 'package:spotube/collections/fake.dart'; +import 'package:spotube/collections/gradients.dart'; +import 'package:spotube/collections/spotube_icons.dart'; +import 'package:spotube/components/shared/image/universal_image.dart'; +import 'package:spotube/extensions/constrains.dart'; +import 'package:spotube/extensions/context.dart'; +import 'package:spotube/provider/user_preferences/user_preferences_provider.dart'; +import 'package:spotube/services/queries/queries.dart'; + +class HomeGenresSection extends HookConsumerWidget { + const HomeGenresSection({Key? key}) : super(key: key); + + @override + Widget build(BuildContext context, ref) { + final ThemeData(:textTheme, :colorScheme) = Theme.of(context); + final mediaQuery = MediaQuery.of(context); + + final recommendationMarket = ref.watch( + userPreferencesProvider.select((s) => s.recommendationMarket), + ); + final categoriesQuery = + useQueries.category.listAll(ref, recommendationMarket); + + final categories = categoriesQuery.data + ?.where((c) => (c.icons?.length ?? 0) > 0) + .take(mediaQuery.mdAndDown ? 6 : 10) + .toList() ?? + []; + + return SliverMainAxisGroup( + slivers: [ + SliverToBoxAdapter( + child: Padding( + padding: const EdgeInsets.symmetric(horizontal: 8), + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Text( + context.l10n.genre, + style: textTheme.headlineSmall, + ), + Directionality( + textDirection: TextDirection.rtl, + child: TextButton.icon( + onPressed: () { + context.push('/genres'); + }, + icon: const Icon(SpotubeIcons.angleRight), + label: Text( + "Browse All", + style: textTheme.bodyMedium?.copyWith( + color: colorScheme.secondary, + ), + ), + ), + ), + ], + ), + ), + ), + const SliverGap(8), + SliverPadding( + padding: const EdgeInsets.symmetric(horizontal: 16), + sliver: Skeletonizer.sliver( + enabled: categoriesQuery.isLoading, + child: SliverGrid.builder( + gridDelegate: SliverGridDelegateWithMaxCrossAxisExtent( + maxCrossAxisExtent: mediaQuery.mdAndDown ? 200 : 250, + mainAxisExtent: 50, + crossAxisSpacing: 16, + mainAxisSpacing: 16, + ), + itemCount: categoriesQuery.isLoading + ? mediaQuery.mdAndDown + ? 6 + : 10 + : categories.length, + itemBuilder: (context, index) { + final category = + categories.elementAtOrNull(index) ?? FakeData.category; + + return HookBuilder(builder: (context) { + final (:gradient, :textColor) = useMemoized( + () { + final gradient = + gradients[Random().nextInt(gradients.length)]; + final text = gradient.colors + .take(2) + .any((c) => c.computeLuminance() > 0.5) + ? Colors.grey[900] + : Colors.white; + return ( + gradient: LinearGradient( + colors: gradient.colors + .map((c) => c.withOpacity(0.8)) + .toList(), + ), + textColor: text + ); + }, + [], + ); + + return InkWell( + onTap: () { + context.push('/genre/${category.id}', extra: category); + }, + borderRadius: BorderRadius.circular(8), + child: Ink( + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(6), + image: DecorationImage( + image: UniversalImage.imageProvider( + category.icons!.first.url!, + ), + fit: BoxFit.cover, + ), + ), + child: Ink( + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(8), + color: colorScheme.surfaceVariant, + gradient: categoriesQuery.isLoading ? null : gradient, + ), + padding: const EdgeInsets.symmetric(horizontal: 16), + child: Align( + alignment: Alignment.centerLeft, + child: Text( + category.name!, + style: textTheme.titleMedium + ?.copyWith(color: textColor), + ), + ), + ), + ), + ); + }); + }, + ), + ), + ), + ], + ); + } +} diff --git a/lib/components/home/sections/made_for_user.dart b/lib/components/home/sections/made_for_user.dart new file mode 100644 index 00000000..a3f96899 --- /dev/null +++ b/lib/components/home/sections/made_for_user.dart @@ -0,0 +1,35 @@ +import 'package:flutter/widgets.dart'; +import 'package:hooks_riverpod/hooks_riverpod.dart'; +import 'package:spotify/spotify.dart'; +import 'package:spotube/components/shared/horizontal_playbutton_card_view/horizontal_playbutton_card_view.dart'; +import 'package:spotube/services/queries/queries.dart'; + +class HomeMadeForUserSection extends HookConsumerWidget { + const HomeMadeForUserSection({Key? key}) : super(key: key); + + @override + Widget build(BuildContext context, ref) { + final madeForUser = useQueries.views.get(ref, "made-for-x-hub"); + + return SliverList.builder( + itemCount: madeForUser.data?["content"]?["items"]?.length ?? 0, + itemBuilder: (context, index) { + final item = madeForUser.data?["content"]?["items"]?[index]; + final playlists = item["content"]?["items"] + ?.where((itemL2) => itemL2["type"] == "playlist") + .map((itemL2) => PlaylistSimple.fromJson(itemL2)) + .toList() + .cast() ?? + []; + if (playlists.isEmpty) return const SizedBox.shrink(); + return HorizontalPlaybuttonCardView( + items: playlists, + title: Text(item["name"] ?? ""), + hasNextPage: false, + isLoadingNextPage: false, + onFetchMore: () {}, + ); + }, + ); + } +} diff --git a/lib/components/home/sections/new_releases.dart b/lib/components/home/sections/new_releases.dart new file mode 100644 index 00000000..77481de1 --- /dev/null +++ b/lib/components/home/sections/new_releases.dart @@ -0,0 +1,51 @@ +import 'package:flutter/material.dart' hide Page; +import 'package:flutter_hooks/flutter_hooks.dart'; +import 'package:hooks_riverpod/hooks_riverpod.dart'; +import 'package:spotify/spotify.dart'; +import 'package:spotube/components/shared/horizontal_playbutton_card_view/horizontal_playbutton_card_view.dart'; +import 'package:spotube/extensions/context.dart'; +import 'package:spotube/provider/authentication_provider.dart'; +import 'package:spotube/services/queries/queries.dart'; +import 'package:spotube/utils/type_conversion_utils.dart'; + +class HomeNewReleasesSection extends HookConsumerWidget { + const HomeNewReleasesSection({Key? key}) : super(key: key); + + @override + Widget build(BuildContext context, ref) { + final auth = ref.watch(AuthenticationNotifier.provider); + + final newReleases = useQueries.album.newReleases(ref); + final userArtistsQuery = useQueries.artist.followedByMeAll(ref); + final userArtists = + userArtistsQuery.data?.map((s) => s.id!).toList() ?? const []; + + final albums = useMemoized( + () => newReleases.pages + .whereType>() + .expand((page) => page.items ?? const []) + .where((album) { + return album.artists + ?.any((artist) => userArtists.contains(artist.id!)) == + true; + }) + .map((album) => TypeConversionUtils.simpleAlbum_X_Album(album)) + .toList(), + [newReleases.pages], + ); + + final hasNewReleases = newReleases.hasPageData && + userArtistsQuery.hasData && + !newReleases.isLoadingNextPage; + + if (auth == null || !hasNewReleases) return const SizedBox.shrink(); + + return HorizontalPlaybuttonCardView( + items: albums, + title: Text(context.l10n.new_releases), + isLoadingNextPage: newReleases.isLoadingNextPage, + hasNextPage: newReleases.hasNextPage, + onFetchMore: newReleases.fetchNext, + ); + } +} diff --git a/lib/components/shared/playbutton_card.dart b/lib/components/shared/playbutton_card.dart index 94751f8e..a8a75d30 100644 --- a/lib/components/shared/playbutton_card.dart +++ b/lib/components/shared/playbutton_card.dart @@ -4,10 +4,10 @@ import 'package:flutter_hooks/flutter_hooks.dart'; import 'package:gap/gap.dart'; import 'package:skeletonizer/skeletonizer.dart'; -import 'package:spotube/collections/assets.gen.dart'; import 'package:spotube/collections/spotube_icons.dart'; import 'package:spotube/components/shared/hover_builder.dart'; import 'package:spotube/components/shared/image/universal_image.dart'; +import 'package:spotube/extensions/constrains.dart'; import 'package:spotube/hooks/utils/use_breakpoint_value.dart'; import 'package:spotube/hooks/utils/use_brightness_value.dart'; @@ -50,6 +50,7 @@ class PlaybuttonCard extends HookWidget { Widget build(BuildContext context) { final textsKey = useMemoized(() => GlobalKey(), []); final theme = Theme.of(context); + final mediaQuery = MediaQuery.of(context); final radius = BorderRadius.circular(15); final double size = useBreakpointValue( @@ -86,23 +87,27 @@ class PlaybuttonCard extends HookWidget { splashFactory: theme.splashFactory, child: Column( mainAxisSize: MainAxisSize.min, - crossAxisAlignment: CrossAxisAlignment.start, + crossAxisAlignment: CrossAxisAlignment.stretch, children: [ Stack( clipBehavior: Clip.none, children: [ Container( + margin: const EdgeInsets.fromLTRB(8, 8, 8, 0), padding: const EdgeInsets.only( left: 8, right: 8, top: 8, ), - constraints: BoxConstraints(maxHeight: size), - child: ClipRRect( + height: mediaQuery.smAndDown + ? 120 + : mediaQuery.mdAndDown + ? 130 + : 150, + decoration: BoxDecoration( borderRadius: radius, - child: UniversalImage( - path: imageUrl, - placeholder: Assets.albumPlaceholder.path, + image: DecorationImage( + image: UniversalImage.imageProvider(imageUrl), fit: BoxFit.cover, ), ), diff --git a/lib/pages/home/genres.dart b/lib/pages/home/genres.dart deleted file mode 100644 index 88eaef70..00000000 --- a/lib/pages/home/genres.dart +++ /dev/null @@ -1,151 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:flutter_hooks/flutter_hooks.dart'; -import 'package:collection/collection.dart'; -import 'package:fuzzywuzzy/fuzzywuzzy.dart'; -import 'package:hooks_riverpod/hooks_riverpod.dart'; -import 'package:skeletonizer/skeletonizer.dart'; -import 'package:spotify/spotify.dart'; -import 'package:spotube/collections/spotube_icons.dart'; -import 'package:spotube/components/genre/category_card.dart'; -import 'package:spotube/components/shared/expandable_search/expandable_search.dart'; -import 'package:spotube/components/shared/horizontal_playbutton_card_view/horizontal_playbutton_card_view.dart'; -import 'package:spotube/components/shared/waypoint.dart'; - -import 'package:spotube/provider/user_preferences/user_preferences_provider.dart'; -import 'package:spotube/services/queries/queries.dart'; -import 'package:very_good_infinite_list/very_good_infinite_list.dart'; - -class GenrePage extends HookConsumerWidget { - const GenrePage({Key? key}) : super(key: key); - - @override - Widget build(BuildContext context, ref) { - final scrollController = useScrollController(); - final recommendationMarket = ref.watch( - userPreferencesProvider.select((s) => s.recommendationMarket), - ); - final categoriesQuery = useQueries.category.list(ref, recommendationMarket); - final isFiltering = useState(false); - - final isMounted = useIsMounted(); - - final searchController = useTextEditingController(); - final searchFocus = useFocusNode(); - - useValueListenable(searchController); - - final categories = useMemoized( - () { - final categories = categoriesQuery.pages - .expand( - (page) => page.items ?? const Iterable.empty(), - ) - .toList(); - if (searchController.text.isEmpty) { - return categories; - } - return categories - .map((e) => ( - weightedRatio(e.name!, searchController.text), - e, - )) - .sorted((a, b) => b.$1.compareTo(a.$1)) - .where((e) => e.$1 > 50) - .map((e) => e.$2) - .toList(); - }, - [categoriesQuery.pages, searchController.text], - ); - - final list = RefreshIndicator( - onRefresh: () async { - await categoriesQuery.refreshAll(); - }, - child: Waypoint( - onTouchEdge: () async { - if (categoriesQuery.hasNextPage && isMounted()) { - await categoriesQuery.fetchNext(); - } - }, - controller: scrollController, - child: Column( - children: [ - ExpandableSearchField( - isFiltering: isFiltering.value, - onChangeFiltering: (value) => isFiltering.value = value, - searchController: searchController, - searchFocus: searchFocus, - ), - if (!categoriesQuery.hasPageData && - !categoriesQuery.isLoadingNextPage) - Expanded( - child: Skeletonizer( - enabled: true, - child: ListView.builder( - itemCount: 5, - itemBuilder: (context, index) { - return HorizontalPlaybuttonCardView( - title: const Text("Loading"), - items: const [], - hasNextPage: true, - isLoadingNextPage: false, - onFetchMore: () {}, - ); - }, - ), - ), - ) - else - Expanded( - child: InfiniteList( - scrollController: scrollController, - itemCount: categories.length, - onFetchData: categoriesQuery.fetchNext, - isLoading: categoriesQuery.isLoadingNextPage, - hasReachedMax: !categoriesQuery.hasNextPage, - loadingBuilder: (context) => Skeletonizer( - enabled: true, - child: HorizontalPlaybuttonCardView( - title: const Text("Loading"), - items: const [], - hasNextPage: true, - isLoadingNextPage: false, - onFetchMore: () {}, - ), - ), - itemBuilder: (context, index) { - return CategoryCard(categories[index]); - }, - ), - ), - ], - ), - ), - ); - - return Stack( - children: [ - Positioned.fill(child: list), - Positioned( - top: 0, - right: 10, - child: ExpandableSearchButton( - isFiltering: isFiltering.value, - searchFocus: searchFocus, - icon: const Icon(SpotubeIcons.search), - onPressed: (value) { - isFiltering.value = value; - if (isFiltering.value) { - scrollController.animateTo( - 0, - duration: const Duration(milliseconds: 300), - curve: Curves.easeInOut, - ); - } - }, - ), - ), - ], - ); - } -} diff --git a/lib/pages/home/genres/genre_playlists.dart b/lib/pages/home/genres/genre_playlists.dart new file mode 100644 index 00000000..600880e0 --- /dev/null +++ b/lib/pages/home/genres/genre_playlists.dart @@ -0,0 +1,165 @@ +import 'dart:ui'; + +import 'package:flutter/material.dart'; +import 'package:flutter_hooks/flutter_hooks.dart'; +import 'package:gap/gap.dart'; +import 'package:hooks_riverpod/hooks_riverpod.dart'; +import 'package:skeletonizer/skeletonizer.dart'; +import 'package:spotify/spotify.dart' hide Offset; +import 'package:spotube/collections/fake.dart'; +import 'package:spotube/components/playlist/playlist_card.dart'; +import 'package:spotube/components/shared/image/universal_image.dart'; +import 'package:spotube/components/shared/page_window_title_bar.dart'; +import 'package:spotube/components/shared/waypoint.dart'; +import 'package:spotube/extensions/constrains.dart'; +import 'package:spotube/services/queries/queries.dart'; +import 'package:collection/collection.dart'; + +class GenrePlaylistsPage extends HookConsumerWidget { + final Category category; + const GenrePlaylistsPage({Key? key, required this.category}) + : super(key: key); + + @override + Widget build(BuildContext context, ref) { + final playlistsQuery = useQueries.category.playlistsOf( + ref, + category.id!, + ); + + final playlists = useMemoized( + () => playlistsQuery.pages.expand( + (page) { + return page.items?.whereNotNull() ?? + const Iterable.empty(); + }, + ).toList(), + [playlistsQuery.pages], + ); + + final mediaQuery = MediaQuery.of(context); + + final scrollController = useScrollController(); + + return Scaffold( + appBar: const PageWindowTitleBar( + automaticallyImplyLeading: true, + backgroundColor: Colors.transparent, + ), + extendBodyBehindAppBar: true, + body: CustomScrollView( + controller: scrollController, + slivers: [ + SliverAppBar( + automaticallyImplyLeading: false, + expandedHeight: mediaQuery.mdAndDown ? 200 : 250, + flexibleSpace: FlexibleSpaceBar( + stretchModes: const [ + StretchMode.zoomBackground, + StretchMode.blurBackground, + ], + background: DecoratedBox( + decoration: BoxDecoration( + image: DecorationImage( + image: UniversalImage.imageProvider( + category.icons!.first.url!, + ), + fit: BoxFit.cover, + ), + ), + child: BackdropFilter( + filter: ImageFilter.blur(sigmaX: 10, sigmaY: 10), + child: const ColoredBox(color: Colors.transparent), + ), + ), + centerTitle: true, + title: Text( + category.name!, + style: Theme.of(context).textTheme.headlineMedium?.copyWith( + letterSpacing: 3, + shadows: [ + const Shadow( + offset: Offset(-1.5, -1.5), + color: Colors.black54, + ), + const Shadow( + offset: Offset(1.5, -1.5), + color: Colors.black54, + ), + const Shadow( + offset: Offset(1.5, 1.5), + color: Colors.black54, + ), + const Shadow( + offset: Offset(-1.5, 1.5), + color: Colors.black54, + ), + ], + ), + ), + collapseMode: CollapseMode.parallax, + ), + ), + const SliverGap(20), + SliverSafeArea( + top: false, + sliver: SliverPadding( + padding: EdgeInsets.symmetric( + horizontal: mediaQuery.mdAndDown ? 12 : 24, + ), + sliver: playlists.isEmpty + ? Skeletonizer.sliver( + child: SliverToBoxAdapter( + child: Wrap( + spacing: 12, + runSpacing: 12, + children: List.generate( + 6, + (index) => PlaylistCard(FakeData.playlist), + ), + ), + ), + ) + : SliverGrid.builder( + gridDelegate: SliverGridDelegateWithMaxCrossAxisExtent( + maxCrossAxisExtent: 190, + mainAxisExtent: mediaQuery.mdAndDown ? 225 : 250, + crossAxisSpacing: 12, + mainAxisSpacing: 12, + ), + itemCount: playlists.length + 1, + itemBuilder: (context, index) { + final playlist = playlists.elementAtOrNull(index); + + if (playlist == null) { + if (!playlistsQuery.hasNextPage) { + return const SizedBox.shrink(); + } + return Skeletonizer( + enabled: true, + child: Waypoint( + controller: scrollController, + isGrid: true, + onTouchEdge: () async { + if (playlistsQuery.hasNextPage) { + await playlistsQuery.fetchNext(); + } + }, + child: PlaylistCard(FakeData.playlist), + ), + ); + } + + return Skeleton.keep( + child: PlaylistCard(playlist), + ); + }, + ), + ), + ), + const SliverGap(20), + ], + ), + ); + } +} diff --git a/lib/pages/home/genres/genres.dart b/lib/pages/home/genres/genres.dart new file mode 100644 index 00000000..0ab43e83 --- /dev/null +++ b/lib/pages/home/genres/genres.dart @@ -0,0 +1,89 @@ +import 'package:auto_size_text/auto_size_text.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_hooks/flutter_hooks.dart'; +import 'package:go_router/go_router.dart'; +import 'package:hooks_riverpod/hooks_riverpod.dart'; +import 'package:skeletonizer/skeletonizer.dart'; +import 'package:spotify/spotify.dart' hide Offset; +import 'package:spotube/components/shared/page_window_title_bar.dart'; +import 'package:spotube/extensions/constrains.dart'; + +import 'package:spotube/provider/user_preferences/user_preferences_provider.dart'; +import 'package:spotube/services/queries/queries.dart'; + +class GenrePage extends HookConsumerWidget { + const GenrePage({Key? key}) : super(key: key); + + @override + Widget build(BuildContext context, ref) { + final ThemeData(:textTheme) = Theme.of(context); + final scrollController = useScrollController(); + final recommendationMarket = ref.watch( + userPreferencesProvider.select((s) => s.recommendationMarket), + ); + final categoriesQuery = + useQueries.category.listAll(ref, recommendationMarket); + + final categories = categoriesQuery.data ?? []; + + final mediaQuery = MediaQuery.of(context); + + return Scaffold( + appBar: const PageWindowTitleBar(automaticallyImplyLeading: true), + body: SafeArea( + top: false, + child: GridView.builder( + padding: const EdgeInsets.all(12), + controller: scrollController, + gridDelegate: SliverGridDelegateWithMaxCrossAxisExtent( + childAspectRatio: 9 / 18, + maxCrossAxisExtent: mediaQuery.smAndDown ? 200 : 300, + mainAxisExtent: 200, + crossAxisSpacing: 12, + mainAxisSpacing: 12, + ), + itemCount: categories.length, + itemBuilder: (context, index) { + final category = categories[index]; + return InkWell( + borderRadius: BorderRadius.circular(8), + onTap: () { + context.push("/genre/${category.id}", extra: category); + }, + child: Ink( + padding: const EdgeInsets.all(8), + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(8), + image: DecorationImage( + image: NetworkImage(category.icons!.first.url!), + fit: BoxFit.cover, + ), + ), + child: Align( + alignment: Alignment.bottomCenter, + child: AutoSizeText( + category.name!, + style: textTheme.titleLarge?.copyWith( + shadows: [ + // stroke shadow + const Shadow( + color: Colors.black, + offset: Offset(1, 1), + blurRadius: 2, + ), + ], + ), + maxLines: 1, + textAlign: TextAlign.center, + maxFontSize: textTheme.titleLarge!.fontSize!, + minFontSize: textTheme.titleMedium!.fontSize!, + ), + ), + ), + ); + }, + ), + ), + ); + } +} diff --git a/lib/pages/home/home.dart b/lib/pages/home/home.dart index 34f136b6..0a8a0aac 100644 --- a/lib/pages/home/home.dart +++ b/lib/pages/home/home.dart @@ -1,35 +1,33 @@ import 'package:flutter/material.dart'; +import 'package:flutter_hooks/flutter_hooks.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; +import 'package:spotube/components/home/sections/featured.dart'; +import 'package:spotube/components/home/sections/genres.dart'; +import 'package:spotube/components/home/sections/made_for_user.dart'; +import 'package:spotube/components/home/sections/new_releases.dart'; import 'package:spotube/components/shared/page_window_title_bar.dart'; -import 'package:spotube/components/shared/themed_button_tab_bar.dart'; -import 'package:spotube/extensions/context.dart'; -import 'package:spotube/pages/home/genres.dart'; -import 'package:spotube/pages/home/personalized.dart'; class HomePage extends HookConsumerWidget { const HomePage({Key? key}) : super(key: key); @override Widget build(BuildContext context, ref) { - return DefaultTabController( - length: 2, - child: Scaffold( - appBar: PageWindowTitleBar( - centerTitle: true, - leadingWidth: double.infinity, - leading: ThemedButtonsTabBar( - tabs: [ - Tab(text: " ${context.l10n.personalized} "), - Tab(text: " ${context.l10n.genre} "), + final controller = useScrollController(); + + return Scaffold( + appBar: const PageWindowTitleBar(), + body: CustomScrollView( + controller: controller, + slivers: [ + const HomeGenresSection(), + SliverList.list( + children: const [ + HomeFeaturedSection(), + HomeNewReleasesSection(), ], ), - ), - body: const TabBarView( - children: [ - PersonalizedPage(), - GenrePage(), - ], - ), + const SliverSafeArea(sliver: HomeMadeForUserSection()), + ], ), ); } diff --git a/lib/pages/home/personalized.dart b/lib/pages/home/personalized.dart deleted file mode 100644 index 22224c39..00000000 --- a/lib/pages/home/personalized.dart +++ /dev/null @@ -1,106 +0,0 @@ -import 'package:flutter/material.dart' hide Page; -import 'package:flutter_hooks/flutter_hooks.dart'; -import 'package:hooks_riverpod/hooks_riverpod.dart'; - -import 'package:spotify/spotify.dart'; -import 'package:spotube/components/shared/horizontal_playbutton_card_view/horizontal_playbutton_card_view.dart'; -import 'package:spotube/extensions/context.dart'; -import 'package:spotube/provider/authentication_provider.dart'; -import 'package:spotube/services/queries/queries.dart'; -import 'package:spotube/utils/type_conversion_utils.dart'; -import 'package:skeletonizer/skeletonizer.dart'; - -class PersonalizedPage extends HookConsumerWidget { - const PersonalizedPage({Key? key}) : super(key: key); - - @override - Widget build(BuildContext context, ref) { - final controller = useScrollController(); - final auth = ref.watch(AuthenticationNotifier.provider); - final featuredPlaylistsQuery = useQueries.playlist.featured(ref); - final playlists = useMemoized( - () => featuredPlaylistsQuery.pages - .whereType>() - .expand((page) => page.items ?? const []), - [featuredPlaylistsQuery.pages], - ); - - final madeForUser = useQueries.views.get(ref, "made-for-x-hub"); - - final newReleases = useQueries.album.newReleases(ref); - final userArtistsQuery = useQueries.artist.followedByMeAll(ref); - final userArtists = - userArtistsQuery.data?.map((s) => s.id!).toList() ?? const []; - - final albums = useMemoized( - () => newReleases.pages - .whereType>() - .expand((page) => page.items ?? const []) - .where((album) { - return album.artists - ?.any((artist) => userArtists.contains(artist.id!)) == - true; - }) - .map((album) => TypeConversionUtils.simpleAlbum_X_Album(album)) - .toList(), - [newReleases.pages], - ); - - final hasNewReleases = newReleases.hasPageData && - userArtistsQuery.hasData && - !newReleases.isLoadingNextPage; - - final isLoadingFeaturedPlaylists = !featuredPlaylistsQuery.hasPageData && - !featuredPlaylistsQuery.isLoadingNextPage; - - return CustomScrollView( - controller: controller, - slivers: [ - SliverList.list( - children: [ - Skeletonizer( - enabled: isLoadingFeaturedPlaylists, - child: HorizontalPlaybuttonCardView( - items: playlists.toList(), - title: Text(context.l10n.featured), - isLoadingNextPage: featuredPlaylistsQuery.isLoadingNextPage, - hasNextPage: featuredPlaylistsQuery.hasNextPage, - onFetchMore: featuredPlaylistsQuery.fetchNext, - ), - ), - if (auth != null || hasNewReleases) - HorizontalPlaybuttonCardView( - items: albums, - title: Text(context.l10n.new_releases), - isLoadingNextPage: newReleases.isLoadingNextPage, - hasNextPage: newReleases.hasNextPage, - onFetchMore: newReleases.fetchNext, - ), - ], - ), - SliverSafeArea( - sliver: SliverList.builder( - itemCount: madeForUser.data?["content"]?["items"]?.length ?? 0, - itemBuilder: (context, index) { - final item = madeForUser.data?["content"]?["items"]?[index]; - final playlists = item["content"]?["items"] - ?.where((itemL2) => itemL2["type"] == "playlist") - .map((itemL2) => PlaylistSimple.fromJson(itemL2)) - .toList() - .cast() ?? - []; - if (playlists.isEmpty) return const SizedBox.shrink(); - return HorizontalPlaybuttonCardView( - items: playlists, - title: Text(item["name"] ?? ""), - hasNextPage: false, - isLoadingNextPage: false, - onFetchMore: () {}, - ); - }, - ), - ), - ], - ); - } -} diff --git a/lib/services/queries/category.dart b/lib/services/queries/category.dart index 960b5702..6a4b196e 100644 --- a/lib/services/queries/category.dart +++ b/lib/services/queries/category.dart @@ -5,12 +5,35 @@ import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:spotify/spotify.dart'; import 'package:spotube/extensions/context.dart'; import 'package:spotube/hooks/spotify/use_spotify_infinite_query.dart'; +import 'package:spotube/hooks/spotify/use_spotify_query.dart'; import 'package:spotube/provider/custom_spotify_endpoint_provider.dart'; import 'package:spotube/provider/user_preferences/user_preferences_provider.dart'; class CategoryQueries { const CategoryQueries(); + Query, dynamic> listAll( + WidgetRef ref, Market recommendationMarket) { + ref.watch(userPreferencesProvider.select((s) => s.locale)); + final locale = useContext().l10n.localeName; + final query = useSpotifyQuery, dynamic>( + "category-playlists", + (spotify) async { + final categories = await spotify.categories + .list( + country: recommendationMarket, + locale: locale, + ) + .all(); + + return categories.toList(); + }, + ref: ref, + ); + + return query; + } + InfiniteQuery, dynamic, int> list( WidgetRef ref, Market recommendationMarket, From 956f4b198b103aab65844a067cff9a3906266a31 Mon Sep 17 00:00:00 2001 From: Kingkor Roy Tirtho Date: Fri, 8 Dec 2023 22:37:56 +0600 Subject: [PATCH 063/195] chore: fix translations issues --- lib/components/home/sections/genres.dart | 2 +- lib/l10n/app_en.arb | 4 +- lib/pages/home/home.dart | 4 +- untranslated_messages.json | 60 ++++++++++++++++++------ 4 files changed, 52 insertions(+), 18 deletions(-) diff --git a/lib/components/home/sections/genres.dart b/lib/components/home/sections/genres.dart index 52467b28..190f24f7 100644 --- a/lib/components/home/sections/genres.dart +++ b/lib/components/home/sections/genres.dart @@ -45,7 +45,7 @@ class HomeGenresSection extends HookConsumerWidget { mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Text( - context.l10n.genre, + context.l10n.genres, style: textTheme.headlineSmall, ), Directionality( diff --git a/lib/l10n/app_en.arb b/lib/l10n/app_en.arb index 85900012..ccb95160 100644 --- a/lib/l10n/app_en.arb +++ b/lib/l10n/app_en.arb @@ -281,5 +281,7 @@ "login_with_your_lastfm": "Login with your Last.fm account", "scrobble_to_lastfm": "Scrobble to Last.fm", "go_to_album": "Go to Album", - "discord_rich_presence": "Discord Rich Presence" + "discord_rich_presence": "Discord Rich Presence", + "browse_all": "Browse All", + "genres": "Genres" } \ No newline at end of file diff --git a/lib/pages/home/home.dart b/lib/pages/home/home.dart index 0a8a0aac..2970cb62 100644 --- a/lib/pages/home/home.dart +++ b/lib/pages/home/home.dart @@ -1,4 +1,5 @@ import 'package:flutter/material.dart'; +import 'package:flutter_desktop_tools/flutter_desktop_tools.dart'; import 'package:flutter_hooks/flutter_hooks.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:spotube/components/home/sections/featured.dart'; @@ -15,7 +16,8 @@ class HomePage extends HookConsumerWidget { final controller = useScrollController(); return Scaffold( - appBar: const PageWindowTitleBar(), + appBar: + DesktopTools.platform.isMobile ? null : const PageWindowTitleBar(), body: CustomScrollView( controller: controller, slivers: [ diff --git a/untranslated_messages.json b/untranslated_messages.json index e3bdc047..7ec3886a 100644 --- a/untranslated_messages.json +++ b/untranslated_messages.json @@ -1,76 +1,106 @@ { "ar": [ "go_to_album", - "discord_rich_presence" + "discord_rich_presence", + "browse_all", + "genres" ], "bn": [ "go_to_album", - "discord_rich_presence" + "discord_rich_presence", + "browse_all", + "genres" ], "ca": [ "go_to_album", - "discord_rich_presence" + "discord_rich_presence", + "browse_all", + "genres" ], "de": [ "go_to_album", - "discord_rich_presence" + "discord_rich_presence", + "browse_all", + "genres" ], "es": [ "go_to_album", - "discord_rich_presence" + "discord_rich_presence", + "browse_all", + "genres" ], "fa": [ "go_to_album", - "discord_rich_presence" + "discord_rich_presence", + "browse_all", + "genres" ], "fr": [ "go_to_album", - "discord_rich_presence" + "discord_rich_presence", + "browse_all", + "genres" ], "hi": [ "go_to_album", - "discord_rich_presence" + "discord_rich_presence", + "browse_all", + "genres" ], "ja": [ "go_to_album", - "discord_rich_presence" + "discord_rich_presence", + "browse_all", + "genres" ], "pl": [ "go_to_album", - "discord_rich_presence" + "discord_rich_presence", + "browse_all", + "genres" ], "pt": [ "go_to_album", - "discord_rich_presence" + "discord_rich_presence", + "browse_all", + "genres" ], "ru": [ "go_to_album", - "discord_rich_presence" + "discord_rich_presence", + "browse_all", + "genres" ], "tr": [ "go_to_album", - "discord_rich_presence" + "discord_rich_presence", + "browse_all", + "genres" ], "uk": [ "go_to_album", - "discord_rich_presence" + "discord_rich_presence", + "browse_all", + "genres" ], "zh": [ "go_to_album", - "discord_rich_presence" + "discord_rich_presence", + "browse_all", + "genres" ] } From 9ee60677f6d50df7468e12dc6653ecedefa2494f Mon Sep 17 00:00:00 2001 From: Kingkor Roy Tirtho Date: Fri, 8 Dec 2023 23:31:20 +0600 Subject: [PATCH 064/195] fix: add safe area in home --- lib/pages/home/home.dart | 33 ++++++++++++++++++--------------- 1 file changed, 18 insertions(+), 15 deletions(-) diff --git a/lib/pages/home/home.dart b/lib/pages/home/home.dart index 2970cb62..9b33a66c 100644 --- a/lib/pages/home/home.dart +++ b/lib/pages/home/home.dart @@ -15,22 +15,25 @@ class HomePage extends HookConsumerWidget { Widget build(BuildContext context, ref) { final controller = useScrollController(); - return Scaffold( - appBar: - DesktopTools.platform.isMobile ? null : const PageWindowTitleBar(), - body: CustomScrollView( - controller: controller, - slivers: [ - const HomeGenresSection(), - SliverList.list( - children: const [ - HomeFeaturedSection(), - HomeNewReleasesSection(), + return SafeArea( + bottom: false, + child: Scaffold( + appBar: DesktopTools.platform.isMobile + ? null + : const PageWindowTitleBar(), + body: CustomScrollView( + controller: controller, + slivers: [ + const HomeGenresSection(), + SliverList.list( + children: const [ + HomeFeaturedSection(), + HomeNewReleasesSection(), + ], + ), + const SliverSafeArea(sliver: HomeMadeForUserSection()), ], ), - const SliverSafeArea(sliver: HomeMadeForUserSection()), - ], - ), - ); + )); } } From 781dfdd7c9fa9a85e96be3182bf899921393d0b9 Mon Sep 17 00:00:00 2001 From: Kingkor Roy Tirtho Date: Sun, 10 Dec 2023 16:51:38 +0600 Subject: [PATCH 065/195] cd: upgrade flutter version to 3.16.0 --- .github/workflows/spotube-release-binary.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/spotube-release-binary.yml b/.github/workflows/spotube-release-binary.yml index f5cc65ee..d4f15664 100644 --- a/.github/workflows/spotube-release-binary.yml +++ b/.github/workflows/spotube-release-binary.yml @@ -26,7 +26,7 @@ on: default: true env: - FLUTTER_VERSION: '3.16.0' + FLUTTER_VERSION: '3.16.3' jobs: windows: From 0def714af29f05bbfde348e0494eea019ad6032b Mon Sep 17 00:00:00 2001 From: Gorom <1423386+Go-rom@users.noreply.github.com> Date: Mon, 11 Dec 2023 15:33:21 +0100 Subject: [PATCH 066/195] fix(android): wrong app name for the french version #830 (#944) --- android/app/build.gradle | 6 +++--- android/app/src/main/AndroidManifest.xml | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/android/app/build.gradle b/android/app/build.gradle index cd6bc457..df13c9f4 100644 --- a/android/app/build.gradle +++ b/android/app/build.gradle @@ -78,19 +78,19 @@ android { productFlavors { nightly { dimension "default" - resValue "string", "app_name", "Spotube Nightly" + resValue "string", "app_name_en", "Spotube Nightly" applicationIdSuffix ".nightly" versionNameSuffix "-nightly" } dev { dimension "default" - resValue "string", "app_name", "Spotube Dev" + resValue "string", "app_name_en", "Spotube Dev" applicationIdSuffix ".dev" versionNameSuffix "-dev" } stable { dimension "default" - resValue "string", "app_name", "Spotube" + resValue "string", "app_name_en", "Spotube" } } diff --git a/android/app/src/main/AndroidManifest.xml b/android/app/src/main/AndroidManifest.xml index bfb51226..a3f1390a 100644 --- a/android/app/src/main/AndroidManifest.xml +++ b/android/app/src/main/AndroidManifest.xml @@ -18,7 +18,7 @@ Date: Mon, 11 Dec 2023 20:35:48 +0600 Subject: [PATCH 067/195] chore: fix italian translation format error --- lib/l10n/app_it.arb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/l10n/app_it.arb b/lib/l10n/app_it.arb index d8f0ae88..ada9f1f6 100644 --- a/lib/l10n/app_it.arb +++ b/lib/l10n/app_it.arb @@ -262,7 +262,7 @@ "connection_restored": "Connessione ad internet ripristinata", "use_system_title_bar": "Usa la barra del titolo di sistema", "crunching_results": "Elaborazione risultati...", - "search_to_get_results": "Cerca per ottenere risultati" + "search_to_get_results": "Cerca per ottenere risultati", "use_amoled_mode": "Usa modalità AMOLED", "pitch_dark_theme": "Tema nero profondo", "normalize_audio": "Normalizza audio", @@ -280,4 +280,4 @@ "login": "Accesso", "login_with_your_lastfm": "Accedi con il tuo account Last.fm", "scrobble_to_lastfm": "Invia a Last.fm" -} \ No newline at end of file +} From e74d880bac39204bb523a3e5981d1cd8f7521785 Mon Sep 17 00:00:00 2001 From: Kingkor Roy Tirtho Date: Mon, 11 Dec 2023 23:34:28 +0600 Subject: [PATCH 068/195] cd: add pr-lint workflow --- .github/workflows/pr-lint.yml | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) create mode 100644 .github/workflows/pr-lint.yml diff --git a/.github/workflows/pr-lint.yml b/.github/workflows/pr-lint.yml new file mode 100644 index 00000000..72495b98 --- /dev/null +++ b/.github/workflows/pr-lint.yml @@ -0,0 +1,26 @@ +name: Lint + +on: + pull_request: + +env: + FLUTTER_VERSION: '3.16.0' + +jobs: + lint: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + - uses: subosito/flutter-action@v2 + with: + flutter-version: ${{ env.FLUTTER_VERSION }} + + - name: Lint Dart files + run: | + flutter pub get + flutter analyze . + + - name: Lint translations & config files + run: | + jsonlint -q -D --enforce-double-quotes ./lib/l10n/*.arb + jsonlint -q -D --enforce-double-quotes -T .vscode/*.json \ No newline at end of file From 11949b39ffbaa1f8c9c61ea980463a530edb63de Mon Sep 17 00:00:00 2001 From: Kingkor Roy Tirtho Date: Mon, 11 Dec 2023 23:39:05 +0600 Subject: [PATCH 069/195] cd: lint ignore warnings --- .github/workflows/pr-lint.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/pr-lint.yml b/.github/workflows/pr-lint.yml index 72495b98..d4130c0f 100644 --- a/.github/workflows/pr-lint.yml +++ b/.github/workflows/pr-lint.yml @@ -18,7 +18,7 @@ jobs: - name: Lint Dart files run: | flutter pub get - flutter analyze . + flutter analyze --no-fatal-infos --no-fatal-warnings - name: Lint translations & config files run: | From d4a2e5c3278d06c17cac08271ef68a7e0a69bb55 Mon Sep 17 00:00:00 2001 From: Kingkor Roy Tirtho Date: Mon, 11 Dec 2023 23:48:13 +0600 Subject: [PATCH 070/195] cd: fix secrets not being generated for lint --- .github/workflows/pr-lint.yml | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/.github/workflows/pr-lint.yml b/.github/workflows/pr-lint.yml index d4130c0f..490cb82a 100644 --- a/.github/workflows/pr-lint.yml +++ b/.github/workflows/pr-lint.yml @@ -10,14 +10,19 @@ jobs: lint: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - uses: subosito/flutter-action@v2 with: flutter-version: ${{ env.FLUTTER_VERSION }} - - name: Lint Dart files + - name: Configure repo run: | flutter pub get + echo '${{ secrets.DOTENV_NIGHTLY }}' > .env + dart run build_runner build --delete-conflicting-outputs + + - name: Lint Dart files + run: | flutter analyze --no-fatal-infos --no-fatal-warnings - name: Lint translations & config files From 69396e64657ea29d88209bad4078647357924e94 Mon Sep 17 00:00:00 2001 From: Kingkor Roy Tirtho Date: Mon, 11 Dec 2023 23:59:25 +0600 Subject: [PATCH 071/195] cd: no fatal lint warnings --- .github/workflows/pr-lint.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/pr-lint.yml b/.github/workflows/pr-lint.yml index 490cb82a..b6087c95 100644 --- a/.github/workflows/pr-lint.yml +++ b/.github/workflows/pr-lint.yml @@ -23,7 +23,7 @@ jobs: - name: Lint Dart files run: | - flutter analyze --no-fatal-infos --no-fatal-warnings + dart analyze --no-fatal-warnings - name: Lint translations & config files run: | From 2b0d17e9cad742a6e651bc48752ff7cfd2782c32 Mon Sep 17 00:00:00 2001 From: Kingkor Roy Tirtho Date: Tue, 12 Dec 2023 00:01:27 +0600 Subject: [PATCH 072/195] cd: fix json lint --- .github/workflows/pr-lint.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/pr-lint.yml b/.github/workflows/pr-lint.yml index b6087c95..e4fb55c5 100644 --- a/.github/workflows/pr-lint.yml +++ b/.github/workflows/pr-lint.yml @@ -27,5 +27,6 @@ jobs: - name: Lint translations & config files run: | + npm install -g @prantlf/jsonlint jsonlint -q -D --enforce-double-quotes ./lib/l10n/*.arb jsonlint -q -D --enforce-double-quotes -T .vscode/*.json \ No newline at end of file From 2fb16e64e9cdfca54d633cdf287b0544ecdda3b6 Mon Sep 17 00:00:00 2001 From: Kingkor Roy Tirtho Date: Tue, 12 Dec 2023 21:27:14 +0600 Subject: [PATCH 073/195] fix: genre border issues --- lib/components/home/sections/genres.dart | 4 +- lib/l10n/app_en.arb | 3 +- lib/pages/home/genres/genre_playlists.dart | 10 +++- lib/pages/home/genres/genres.dart | 13 +++++- lib/services/queries/category.dart | 6 ++- untranslated_messages.json | 54 ++++++++++++++++------ 6 files changed, 66 insertions(+), 24 deletions(-) diff --git a/lib/components/home/sections/genres.dart b/lib/components/home/sections/genres.dart index 190f24f7..41ba235c 100644 --- a/lib/components/home/sections/genres.dart +++ b/lib/components/home/sections/genres.dart @@ -117,7 +117,7 @@ class HomeGenresSection extends HookConsumerWidget { borderRadius: BorderRadius.circular(8), child: Ink( decoration: BoxDecoration( - borderRadius: BorderRadius.circular(6), + borderRadius: BorderRadius.circular(8), image: DecorationImage( image: UniversalImage.imageProvider( category.icons!.first.url!, @@ -127,7 +127,7 @@ class HomeGenresSection extends HookConsumerWidget { ), child: Ink( decoration: BoxDecoration( - borderRadius: BorderRadius.circular(8), + borderRadius: BorderRadius.circular(5), color: colorScheme.surfaceVariant, gradient: categoriesQuery.isLoading ? null : gradient, ), diff --git a/lib/l10n/app_en.arb b/lib/l10n/app_en.arb index ccb95160..bebfafac 100644 --- a/lib/l10n/app_en.arb +++ b/lib/l10n/app_en.arb @@ -283,5 +283,6 @@ "go_to_album": "Go to Album", "discord_rich_presence": "Discord Rich Presence", "browse_all": "Browse All", - "genres": "Genres" + "genres": "Genres", + "explore_genres": "Explore Genres" } \ No newline at end of file diff --git a/lib/pages/home/genres/genre_playlists.dart b/lib/pages/home/genres/genre_playlists.dart index 600880e0..19f98c7f 100644 --- a/lib/pages/home/genres/genre_playlists.dart +++ b/lib/pages/home/genres/genre_playlists.dart @@ -43,8 +43,9 @@ class GenrePlaylistsPage extends HookConsumerWidget { return Scaffold( appBar: const PageWindowTitleBar( - automaticallyImplyLeading: true, + leading: BackButton(color: Colors.white), backgroundColor: Colors.transparent, + foregroundColor: Colors.white, ), extendBodyBehindAppBar: true, body: CustomScrollView( @@ -52,7 +53,11 @@ class GenrePlaylistsPage extends HookConsumerWidget { slivers: [ SliverAppBar( automaticallyImplyLeading: false, - expandedHeight: mediaQuery.mdAndDown ? 200 : 250, + expandedHeight: mediaQuery.mdAndDown ? 200 : 150, + pinned: true, + floating: false, + title: const Text(""), + backgroundColor: Colors.brown.withOpacity(0.7), flexibleSpace: FlexibleSpaceBar( stretchModes: const [ StretchMode.zoomBackground, @@ -76,6 +81,7 @@ class GenrePlaylistsPage extends HookConsumerWidget { title: Text( category.name!, style: Theme.of(context).textTheme.headlineMedium?.copyWith( + color: Colors.white, letterSpacing: 3, shadows: [ const Shadow( diff --git a/lib/pages/home/genres/genres.dart b/lib/pages/home/genres/genres.dart index 0ab43e83..dc165fe4 100644 --- a/lib/pages/home/genres/genres.dart +++ b/lib/pages/home/genres/genres.dart @@ -1,12 +1,15 @@ +import 'dart:math'; + import 'package:auto_size_text/auto_size_text.dart'; import 'package:flutter/material.dart'; import 'package:flutter_hooks/flutter_hooks.dart'; import 'package:go_router/go_router.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; -import 'package:skeletonizer/skeletonizer.dart'; import 'package:spotify/spotify.dart' hide Offset; +import 'package:spotube/collections/gradients.dart'; import 'package:spotube/components/shared/page_window_title_bar.dart'; import 'package:spotube/extensions/constrains.dart'; +import 'package:spotube/extensions/context.dart'; import 'package:spotube/provider/user_preferences/user_preferences_provider.dart'; import 'package:spotube/services/queries/queries.dart'; @@ -29,7 +32,10 @@ class GenrePage extends HookConsumerWidget { final mediaQuery = MediaQuery.of(context); return Scaffold( - appBar: const PageWindowTitleBar(automaticallyImplyLeading: true), + appBar: PageWindowTitleBar( + title: Text(context.l10n.explore_genres), + automaticallyImplyLeading: true, + ), body: SafeArea( top: false, child: GridView.builder( @@ -45,6 +51,7 @@ class GenrePage extends HookConsumerWidget { itemCount: categories.length, itemBuilder: (context, index) { final category = categories[index]; + final gradient = gradients[Random().nextInt(gradients.length)]; return InkWell( borderRadius: BorderRadius.circular(8), onTap: () { @@ -58,12 +65,14 @@ class GenrePage extends HookConsumerWidget { image: NetworkImage(category.icons!.first.url!), fit: BoxFit.cover, ), + gradient: gradient, ), child: Align( alignment: Alignment.bottomCenter, child: AutoSizeText( category.name!, style: textTheme.titleLarge?.copyWith( + color: Colors.white, shadows: [ // stroke shadow const Shadow( diff --git a/lib/services/queries/category.dart b/lib/services/queries/category.dart index 6a4b196e..d520b909 100644 --- a/lib/services/queries/category.dart +++ b/lib/services/queries/category.dart @@ -13,7 +13,9 @@ class CategoryQueries { const CategoryQueries(); Query, dynamic> listAll( - WidgetRef ref, Market recommendationMarket) { + WidgetRef ref, + Market recommendationMarket, + ) { ref.watch(userPreferencesProvider.select((s) => s.locale)); final locale = useContext().l10n.localeName; final query = useSpotifyQuery, dynamic>( @@ -26,7 +28,7 @@ class CategoryQueries { ) .all(); - return categories.toList(); + return categories.toList()..shuffle(); }, ref: ref, ); diff --git a/untranslated_messages.json b/untranslated_messages.json index 7ec3886a..66d8c7b2 100644 --- a/untranslated_messages.json +++ b/untranslated_messages.json @@ -3,104 +3,128 @@ "go_to_album", "discord_rich_presence", "browse_all", - "genres" + "genres", + "explore_genres" ], "bn": [ "go_to_album", "discord_rich_presence", "browse_all", - "genres" + "genres", + "explore_genres" ], "ca": [ "go_to_album", "discord_rich_presence", "browse_all", - "genres" + "genres", + "explore_genres" ], "de": [ "go_to_album", "discord_rich_presence", "browse_all", - "genres" + "genres", + "explore_genres" ], "es": [ "go_to_album", "discord_rich_presence", "browse_all", - "genres" + "genres", + "explore_genres" ], "fa": [ "go_to_album", "discord_rich_presence", "browse_all", - "genres" + "genres", + "explore_genres" ], "fr": [ "go_to_album", "discord_rich_presence", "browse_all", - "genres" + "genres", + "explore_genres" ], "hi": [ "go_to_album", "discord_rich_presence", "browse_all", - "genres" + "genres", + "explore_genres" + ], + + "it": [ + "audio_source", + "go_to_album", + "discord_rich_presence", + "browse_all", + "genres", + "explore_genres" ], "ja": [ "go_to_album", "discord_rich_presence", "browse_all", - "genres" + "genres", + "explore_genres" ], "pl": [ "go_to_album", "discord_rich_presence", "browse_all", - "genres" + "genres", + "explore_genres" ], "pt": [ "go_to_album", "discord_rich_presence", "browse_all", - "genres" + "genres", + "explore_genres" ], "ru": [ "go_to_album", "discord_rich_presence", "browse_all", - "genres" + "genres", + "explore_genres" ], "tr": [ "go_to_album", "discord_rich_presence", "browse_all", - "genres" + "genres", + "explore_genres" ], "uk": [ "go_to_album", "discord_rich_presence", "browse_all", - "genres" + "genres", + "explore_genres" ], "zh": [ "go_to_album", "discord_rich_presence", "browse_all", - "genres" + "genres", + "explore_genres" ] } From 4050f556400aaec5515231578512cf1a6b990110 Mon Sep 17 00:00:00 2001 From: Kingkor Roy Tirtho Date: Mon, 18 Dec 2023 22:12:16 +0600 Subject: [PATCH 074/195] feat: Deep link support (#950) * feat: add deep link support * feat(android): add intent share support * chore: untranslated msg for it locale --- android/app/src/main/AndroidManifest.xml | 26 +++++- lib/collections/initializers.dart | 25 +++++ lib/hooks/configurators/use_deep_linking.dart | 93 +++++++++++++++++++ lib/main.dart | 10 +- linux/flutter/generated_plugin_registrant.cc | 4 + linux/flutter/generated_plugins.cmake | 1 + linux/my_application.cc | 13 ++- linux/packaging/appimage/make_config.yaml | 3 + linux/packaging/deb/make_config.yaml | 3 + linux/packaging/rpm/make_config.yaml | 3 + macos/Flutter/GeneratedPluginRegistrant.swift | 2 + macos/Runner/Info.plist | 13 +++ pubspec.lock | 30 +++++- pubspec.yaml | 3 + untranslated_messages.json | 6 ++ .../flutter/generated_plugin_registrant.cc | 3 + windows/flutter/generated_plugins.cmake | 1 + windows/runner/win32_window.cpp | 40 ++++++++ windows/runner/win32_window.h | 4 + 19 files changed, 273 insertions(+), 10 deletions(-) create mode 100644 lib/collections/initializers.dart create mode 100644 lib/hooks/configurators/use_deep_linking.dart diff --git a/android/app/src/main/AndroidManifest.xml b/android/app/src/main/AndroidManifest.xml index a3f1390a..5ab7a0b5 100644 --- a/android/app/src/main/AndroidManifest.xml +++ b/android/app/src/main/AndroidManifest.xml @@ -27,7 +27,7 @@ + + + + + + + + + + + + + + + + + + + + + diff --git a/lib/collections/initializers.dart b/lib/collections/initializers.dart new file mode 100644 index 00000000..9627de1c --- /dev/null +++ b/lib/collections/initializers.dart @@ -0,0 +1,25 @@ +import 'dart:io'; +import 'package:flutter_desktop_tools/flutter_desktop_tools.dart'; +import 'package:win32_registry/win32_registry.dart'; + +Future registerWindowsScheme(String scheme) async { + if (!DesktopTools.platform.isWindows) return; + String appPath = Platform.resolvedExecutable; + + String protocolRegKey = 'Software\\Classes\\$scheme'; + RegistryValue protocolRegValue = const RegistryValue( + 'URL Protocol', + RegistryValueType.string, + '', + ); + String protocolCmdRegKey = 'shell\\open\\command'; + RegistryValue protocolCmdRegValue = RegistryValue( + '', + RegistryValueType.string, + '"$appPath" "%1"', + ); + + final regKey = Registry.currentUser.createKey(protocolRegKey); + regKey.createValue(protocolRegValue); + regKey.createKey(protocolCmdRegKey).createValue(protocolCmdRegValue); +} diff --git a/lib/hooks/configurators/use_deep_linking.dart b/lib/hooks/configurators/use_deep_linking.dart new file mode 100644 index 00000000..546ab2e8 --- /dev/null +++ b/lib/hooks/configurators/use_deep_linking.dart @@ -0,0 +1,93 @@ +import 'package:app_links/app_links.dart'; +import 'package:fl_query_hooks/fl_query_hooks.dart'; +import 'package:flutter_hooks/flutter_hooks.dart'; +import 'package:hooks_riverpod/hooks_riverpod.dart'; +import 'package:spotify/spotify.dart'; +import 'package:spotube/collections/routes.dart'; +import 'package:spotube/provider/spotify_provider.dart'; +import 'package:flutter_sharing_intent/flutter_sharing_intent.dart'; +import 'package:flutter_sharing_intent/model/sharing_file.dart'; + +void useDeepLinking(WidgetRef ref) { + // single instance no worries + final appLinks = AppLinks(); + final spotify = ref.watch(spotifyProvider); + final queryClient = useQueryClient(); + + useEffect(() { + void uriListener(List files) async { + for (final file in files) { + if (file.type != SharedMediaType.URL) continue; + final url = Uri.parse(file.value!); + if (url.pathSegments.length != 2) continue; + + switch (url.pathSegments.first) { + case "album": + router.push( + "/album/${url.pathSegments.last}", + extra: await queryClient.fetchQuery( + "album/${url.pathSegments.last}", + () => spotify.albums.get(url.pathSegments.last), + ), + ); + break; + case "artist": + router.push("/artist/${url.pathSegments.last}"); + break; + case "playlist": + router.push( + "/playlist/${url.pathSegments.last}", + extra: await queryClient.fetchQuery( + "playlist/${url.pathSegments.last}", + () => spotify.playlists.get(url.pathSegments.last), + ), + ); + break; + default: + break; + } + } + } + + FlutterSharingIntent.instance.getInitialSharing().then(uriListener); + + final mediaStream = + FlutterSharingIntent.instance.getMediaStream().listen(uriListener); + + final subscription = appLinks.allStringLinkStream.listen((uri) async { + final startSegment = uri.split(":").take(2).join(":"); + final endSegment = uri.split(":").last; + + switch (startSegment) { + case "spotify:album": + await router.push( + "/album/$endSegment", + extra: await queryClient.fetchQuery( + "album/$endSegment", + () => spotify.albums.get(endSegment), + ), + ); + break; + case "spotify:artist": + await router.push("/artist/$endSegment"); + break; + case "spotify:playlist": + await router.push( + "/playlist/$endSegment", + extra: await queryClient.fetchQuery( + "playlist/$endSegment", + () => spotify.playlists.get(endSegment), + ), + ); + break; + default: + break; + } + }); + + return () { + mediaStream.cancel(); + subscription.cancel(); + }; + }, [spotify, queryClient]); +} diff --git a/lib/main.dart b/lib/main.dart index 91ec789d..052e6809 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -13,9 +13,11 @@ import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:media_kit/media_kit.dart'; import 'package:metadata_god/metadata_god.dart'; import 'package:shared_preferences/shared_preferences.dart'; +import 'package:spotube/collections/initializers.dart'; import 'package:spotube/collections/routes.dart'; import 'package:spotube/collections/intents.dart'; import 'package:spotube/hooks/configurators/use_close_behavior.dart'; +import 'package:spotube/hooks/configurators/use_deep_linking.dart'; import 'package:spotube/hooks/configurators/use_disable_battery_optimizations.dart'; import 'package:spotube/hooks/configurators/use_get_storage_perms.dart'; import 'package:spotube/l10n/l10n.dart'; @@ -41,6 +43,8 @@ Future main(List rawArgs) async { final widgetsBinding = WidgetsFlutterBinding.ensureInitialized(); + await registerWindowsScheme("spotify"); + FlutterNativeSplash.preserve(widgetsBinding: widgetsBinding); MediaKit.ensureInitialized(); @@ -181,8 +185,11 @@ class SpotubeState extends ConsumerState { final paletteColor = ref.watch(paletteProvider.select((s) => s?.dominantColor?.color)); + useDisableBatteryOptimizations(); useInitSysTray(ref); + useDeepLinking(ref); useCloseBehavior(ref); + useGetStoragePermissions(ref); useEffect(() { FlutterNativeSplash.remove(); @@ -193,9 +200,6 @@ class SpotubeState extends ConsumerState { }; }, []); - useDisableBatteryOptimizations(); - useGetStoragePermissions(ref); - final lightTheme = useMemoized( () => theme(paletteColor ?? accentMaterialColor, Brightness.light, false), [paletteColor, accentMaterialColor], diff --git a/linux/flutter/generated_plugin_registrant.cc b/linux/flutter/generated_plugin_registrant.cc index a07f7f9b..c69c17c0 100644 --- a/linux/flutter/generated_plugin_registrant.cc +++ b/linux/flutter/generated_plugin_registrant.cc @@ -9,6 +9,7 @@ #include #include #include +#include #include #include #include @@ -28,6 +29,9 @@ void fl_register_plugins(FlPluginRegistry* registry) { g_autoptr(FlPluginRegistrar) flutter_secure_storage_linux_registrar = fl_plugin_registry_get_registrar_for_plugin(registry, "FlutterSecureStorageLinuxPlugin"); flutter_secure_storage_linux_plugin_register_with_registrar(flutter_secure_storage_linux_registrar); + g_autoptr(FlPluginRegistrar) gtk_registrar = + fl_plugin_registry_get_registrar_for_plugin(registry, "GtkPlugin"); + gtk_plugin_register_with_registrar(gtk_registrar); g_autoptr(FlPluginRegistrar) local_notifier_registrar = fl_plugin_registry_get_registrar_for_plugin(registry, "LocalNotifierPlugin"); local_notifier_plugin_register_with_registrar(local_notifier_registrar); diff --git a/linux/flutter/generated_plugins.cmake b/linux/flutter/generated_plugins.cmake index 97d541b3..a4487f4d 100644 --- a/linux/flutter/generated_plugins.cmake +++ b/linux/flutter/generated_plugins.cmake @@ -6,6 +6,7 @@ list(APPEND FLUTTER_PLUGIN_LIST dart_discord_rpc file_selector_linux flutter_secure_storage_linux + gtk local_notifier media_kit_libs_linux screen_retriever diff --git a/linux/my_application.cc b/linux/my_application.cc index 759285af..d1ac5d12 100644 --- a/linux/my_application.cc +++ b/linux/my_application.cc @@ -17,6 +17,13 @@ G_DEFINE_TYPE(MyApplication, my_application, GTK_TYPE_APPLICATION) // Implements GApplication::activate. static void my_application_activate(GApplication* application) { MyApplication* self = MY_APPLICATION(application); + + GList* windows = gtk_application_get_windows(GTK_APPLICATION(application)); + if (windows) { + gtk_window_present(GTK_WINDOW(windows->data)); + return; + } + GtkWindow* window = GTK_WINDOW(gtk_application_window_new(GTK_APPLICATION(application))); @@ -78,7 +85,7 @@ static gboolean my_application_local_command_line(GApplication* application, gch g_application_activate(application); *exit_status = 0; - return TRUE; + return FALSE; } // Implements GObject::dispose. @@ -98,7 +105,7 @@ static void my_application_init(MyApplication* self) {} MyApplication* my_application_new() { return MY_APPLICATION(g_object_new(my_application_get_type(), - "application-id", APPLICATION_ID, - "flags", G_APPLICATION_NON_UNIQUE, + "com.github.KRTirtho.Spotube", APPLICATION_ID, + "flags", G_APPLICATION_HANDLES_COMMAND_LINE | G_APPLICATION_HANDLES_OPEN, nullptr)); } diff --git a/linux/packaging/appimage/make_config.yaml b/linux/packaging/appimage/make_config.yaml index 68e36df7..c7332ea2 100644 --- a/linux/packaging/appimage/make_config.yaml +++ b/linux/packaging/appimage/make_config.yaml @@ -11,3 +11,6 @@ keywords: generic_name: Music Streaming Application categories: - Music + +supported_mime_type: + - x-scheme-handler/spotify diff --git a/linux/packaging/deb/make_config.yaml b/linux/packaging/deb/make_config.yaml index 46493122..f4c279b4 100644 --- a/linux/packaging/deb/make_config.yaml +++ b/linux/packaging/deb/make_config.yaml @@ -32,3 +32,6 @@ keywords: generic_name: Music Streaming Application categories: - Music + +supported_mime_type: + - x-scheme-handler/spotify diff --git a/linux/packaging/rpm/make_config.yaml b/linux/packaging/rpm/make_config.yaml index 00f4c20e..1f952d0e 100644 --- a/linux/packaging/rpm/make_config.yaml +++ b/linux/packaging/rpm/make_config.yaml @@ -28,3 +28,6 @@ categories: - Music startup_notify: true + +supported_mime_type: + - x-scheme-handler/spotify diff --git a/macos/Flutter/GeneratedPluginRegistrant.swift b/macos/Flutter/GeneratedPluginRegistrant.swift index 270e6261..a7965e14 100644 --- a/macos/Flutter/GeneratedPluginRegistrant.swift +++ b/macos/Flutter/GeneratedPluginRegistrant.swift @@ -5,6 +5,7 @@ import FlutterMacOS import Foundation +import app_links import audio_service import audio_session import device_info_plus @@ -24,6 +25,7 @@ import window_manager import window_size func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) { + AppLinksMacosPlugin.register(with: registry.registrar(forPlugin: "AppLinksMacosPlugin")) AudioServicePlugin.register(with: registry.registrar(forPlugin: "AudioServicePlugin")) AudioSessionPlugin.register(with: registry.registrar(forPlugin: "AudioSessionPlugin")) DeviceInfoPlusMacosPlugin.register(with: registry.registrar(forPlugin: "DeviceInfoPlusMacosPlugin")) diff --git a/macos/Runner/Info.plist b/macos/Runner/Info.plist index 19f1c02a..1a8bb655 100644 --- a/macos/Runner/Info.plist +++ b/macos/Runner/Info.plist @@ -2,6 +2,19 @@ + CFBundleURLTypes + + + CFBundleURLName + + Spotify + CFBundleURLSchemes + + + spotify + + + CFBundleDevelopmentRegion $(DEVELOPMENT_LANGUAGE) CFBundleExecutable diff --git a/pubspec.lock b/pubspec.lock index 8921f8a7..526898d5 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -17,6 +17,14 @@ packages: url: "https://pub.dev" source: hosted version: "5.13.0" + app_links: + dependency: "direct main" + description: + name: app_links + sha256: "4e392b5eba997df356ca6021f28431ce1cfeb16758699553a94b13add874a3bb" + url: "https://pub.dev" + source: hosted + version: "3.5.0" app_package_maker: dependency: transitive description: @@ -907,6 +915,14 @@ packages: url: "https://pub.dev" source: hosted version: "3.0.0" + flutter_sharing_intent: + dependency: "direct main" + description: + name: flutter_sharing_intent + sha256: "6eb896e6523b735e8230eeb206fd3b9f220f11ce879c2400a90b443147036ff9" + url: "https://pub.dev" + source: hosted + version: "1.1.0" flutter_svg: dependency: "direct main" description: @@ -1018,6 +1034,14 @@ packages: url: "https://pub.dev" source: hosted version: "0.2.8" + gtk: + dependency: transitive + description: + name: gtk + sha256: e8ce9ca4b1df106e4d72dad201d345ea1a036cc12c360f1a7d5a758f78ffa42c + url: "https://pub.dev" + source: hosted + version: "2.1.0" hive: dependency: "direct main" description: @@ -2246,13 +2270,13 @@ packages: source: hosted version: "5.0.7" win32_registry: - dependency: transitive + dependency: "direct main" description: name: win32_registry - sha256: e4506d60b7244251bc59df15656a3093501c37fb5af02105a944d73eb95be4c9 + sha256: "41fd8a189940d8696b1b810efb9abcf60827b6cbfab90b0c43e8439e3a39d85a" url: "https://pub.dev" source: hosted - version: "1.1.1" + version: "1.1.2" window_manager: dependency: "direct main" description: diff --git a/pubspec.yaml b/pubspec.yaml index 77a26911..267ab17f 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -119,6 +119,9 @@ dependencies: html_unescape: ^2.0.0 wikipedia_api: ^0.1.0 skeletonizer: ^0.8.0 + app_links: ^3.5.0 + win32_registry: ^1.1.2 + flutter_sharing_intent: ^1.1.0 dev_dependencies: build_runner: ^2.3.2 diff --git a/untranslated_messages.json b/untranslated_messages.json index e3bdc047..438ad6b3 100644 --- a/untranslated_messages.json +++ b/untranslated_messages.json @@ -39,6 +39,12 @@ "discord_rich_presence" ], + "it": [ + "audio_source", + "go_to_album", + "discord_rich_presence" + ], + "ja": [ "go_to_album", "discord_rich_presence" diff --git a/windows/flutter/generated_plugin_registrant.cc b/windows/flutter/generated_plugin_registrant.cc index b9c6a481..fcf9927e 100644 --- a/windows/flutter/generated_plugin_registrant.cc +++ b/windows/flutter/generated_plugin_registrant.cc @@ -6,6 +6,7 @@ #include "generated_plugin_registrant.h" +#include #include #include #include @@ -20,6 +21,8 @@ #include void RegisterPlugins(flutter::PluginRegistry* registry) { + AppLinksPluginCApiRegisterWithRegistrar( + registry->GetRegistrarForPlugin("AppLinksPluginCApi")); DartDiscordRpcPluginRegisterWithRegistrar( registry->GetRegistrarForPlugin("DartDiscordRpcPlugin")); FileSelectorWindowsRegisterWithRegistrar( diff --git a/windows/flutter/generated_plugins.cmake b/windows/flutter/generated_plugins.cmake index 5cd55ff3..0fe6e076 100644 --- a/windows/flutter/generated_plugins.cmake +++ b/windows/flutter/generated_plugins.cmake @@ -3,6 +3,7 @@ # list(APPEND FLUTTER_PLUGIN_LIST + app_links dart_discord_rpc file_selector_windows flutter_secure_storage_windows diff --git a/windows/runner/win32_window.cpp b/windows/runner/win32_window.cpp index d5c04f23..9823151c 100644 --- a/windows/runner/win32_window.cpp +++ b/windows/runner/win32_window.cpp @@ -3,6 +3,7 @@ #include #include "resource.h" +#include "app_links/app_links_plugin_c_api.h" namespace { @@ -105,6 +106,9 @@ Win32Window::~Win32Window() { bool Win32Window::CreateAndShow(const std::wstring& title, const Point& origin, const Size& size) { + if (SendAppLinkToInstance(title)) { + return false; + } Destroy(); const wchar_t* window_class = @@ -244,3 +248,39 @@ bool Win32Window::OnCreate() { void Win32Window::OnDestroy() { // No-op; provided for subclasses. } + +// app_links +bool Win32Window::SendAppLinkToInstance(const std::wstring& title) { + // Find our exact window + HWND hwnd = ::FindWindow(kWindowClassName, title.c_str()); + + if (hwnd) { + // Dispatch new link to current window + SendAppLink(hwnd); + + // (Optional) Restore our window to front in same state + WINDOWPLACEMENT place = { sizeof(WINDOWPLACEMENT) }; + GetWindowPlacement(hwnd, &place); + + switch(place.showCmd) { + case SW_SHOWMAXIMIZED: + ShowWindow(hwnd, SW_SHOWMAXIMIZED); + break; + case SW_SHOWMINIMIZED: + ShowWindow(hwnd, SW_RESTORE); + break; + default: + ShowWindow(hwnd, SW_NORMAL); + break; + } + + SetWindowPos(0, HWND_TOP, 0, 0, 0, 0, SWP_SHOWWINDOW | SWP_NOSIZE | SWP_NOMOVE); + SetForegroundWindow(hwnd); + // END Restore + + // Window has been found, don't create another one. + return true; + } + + return false; +} \ No newline at end of file diff --git a/windows/runner/win32_window.h b/windows/runner/win32_window.h index 17ba4311..1d817bd2 100644 --- a/windows/runner/win32_window.h +++ b/windows/runner/win32_window.h @@ -93,6 +93,10 @@ class Win32Window { // window handle for hosted content. HWND child_content_ = nullptr; + // Dispatches link if any. + // This method enables our app to be with a single instance too. + // This is mandatory if you want to catch further links in same app. + bool SendAppLinkToInstance(const std::wstring& title); }; #endif // RUNNER_WIN32_WINDOW_H_ From dcbe7294b742d43fbff4e89ab4c4825e94421dd9 Mon Sep 17 00:00:00 2001 From: Kingkor Roy Tirtho Date: Wed, 27 Dec 2023 21:57:18 +0600 Subject: [PATCH 075/195] fix: wrong artist name sent while scrobbling #958 --- lib/provider/scrobbler_provider.dart | 2 +- untranslated_messages.json | 6 ------ 2 files changed, 1 insertion(+), 7 deletions(-) diff --git a/lib/provider/scrobbler_provider.dart b/lib/provider/scrobbler_provider.dart index 5ac3c5a1..4ff4cce7 100644 --- a/lib/provider/scrobbler_provider.dart +++ b/lib/provider/scrobbler_provider.dart @@ -43,7 +43,7 @@ class ScrobblerNotifier extends PersistedStateNotifier { _scrobbleController.stream.listen((track) async { try { await state?.scrobblenaut.track.scrobble( - artist: TypeConversionUtils.artists_X_String(track.artists!), + artist: track.artists.first.name!, track: track.name!, album: track.album!.name!, chosenByUser: true, diff --git a/untranslated_messages.json b/untranslated_messages.json index 84d6b95f..66d8c7b2 100644 --- a/untranslated_messages.json +++ b/untranslated_messages.json @@ -72,12 +72,6 @@ "explore_genres" ], - "it": [ - "audio_source", - "go_to_album", - "discord_rich_presence" - ], - "ja": [ "go_to_album", "discord_rich_presence", From 3ad7ba66b56e93e69d2181d47029b7549ed225fc Mon Sep 17 00:00:00 2001 From: SecularSteve <33793273+SecularSteve@users.noreply.github.com> Date: Fri, 29 Dec 2023 13:12:39 +0100 Subject: [PATCH 076/195] feat(translations): add Dutch Language (#969) * Update language_codes.dart Added Dutch * Added Dutch language * Added Dutch my contribution credentials included * Added Dutch Language * fixed a mistake "Vlaams" is a very specific term to describe the Belgian Dutch dialect. "Nederland" is the correct way. * fixed a mistake "Nederlands" actually, got mixed up a bit --- lib/collections/language_codes.dart | 8 +- lib/l10n/app_nl.arb | 284 ++++++++++++++++++++++++++++ lib/l10n/l10n.dart | 2 + 3 files changed, 290 insertions(+), 4 deletions(-) create mode 100644 lib/l10n/app_nl.arb diff --git a/lib/collections/language_codes.dart b/lib/collections/language_codes.dart index d89e1a2a..de6f6d1c 100644 --- a/lib/collections/language_codes.dart +++ b/lib/collections/language_codes.dart @@ -164,10 +164,10 @@ abstract class LanguageLocals { // name: "Maldivian;", // nativeName: "ދިވެހި", // ), - // "nl": const ISOLanguageName( - // name: "Dutch", - // nativeName: "Vlaams", - // ), + "nl": const ISOLanguageName( + name: "Dutch", + nativeName: "Nederlands", + ), "en": const ISOLanguageName( name: "English", nativeName: "English", diff --git a/lib/l10n/app_nl.arb b/lib/l10n/app_nl.arb new file mode 100644 index 00000000..306d63c4 --- /dev/null +++ b/lib/l10n/app_nl.arb @@ -0,0 +1,284 @@ +{ + "guest": "Gast", + "browse": "Bladeren", + "search": "Zoek op", + "library": "Bibliotheek", + "lyrics": "Liedteksten", + "settings": "Instellingen", + "genre_categories_filter": "Categorieën of genres filteren...", + "genre": "Genre", + "personalized": "Gepersonaliseerd", + "featured": "Aanbevolen", + "new_releases": "Nieuwe uitgaves", + "songs": "Liedjes", + "playing_track": "{track} afspelen", + "queue_clear_alert": "Dit zal de huidige wachtrij wissen. {track_length} tracks worden verwijderd\nWilt u doorgaan?", + "load_more": "Meer laden", + "playlists": "Afspeellijsten", + "artists": "Kunstenaars", + "albums": "Albums", + "tracks": "Nummers", + "downloads": "Downloads", + "filter_playlists": "Filter uw afspeellijsten...", + "liked_tracks": "Geliefde tracks", + "liked_tracks_description": "Al je favoriete nummers", + "create_playlist": "Afspeellijst maken", + "create_a_playlist": "Een afspeellijst maken", + "update_playlist": "Afspeellijst bijwerken", + "create": "Maak", + "cancel": "Annuleren", + "update": "Bijwerken", + "playlist_name": "Afspeellijstnaam", + "name_of_playlist": "Naam van de afspeellijst", + "description": "Beschrijving", + "public": "Openbaar", + "collaborative": "Samenwerkend", + "search_local_tracks": "Lokale nummers zoeken...", + "play": "Speel", + "delete": "Wissen", + "none": "Geen", + "sort_a_z": "Sorteren op A-Z", + "sort_z_a": "Sorteren op Z-A", + "sort_artist": "Sorteren op kunstenaar", + "sort_album": "Sorteren op album", + "sort_tracks": "Nummers sorteren", + "currently_downloading": "Momenteel aan het downloaden ({tracks_length})", + "cancel_all": "Alle annuleren", + "filter_artist": "Kunstenaars filteren...", + "followers": "{followers} volgers", + "add_artist_to_blacklist": "Kunstenaar toevoegen aan zwarte lijst", + "top_tracks": "Topsporen", + "fans_also_like": "Liefhebbers willen ook", + "loading": "Aan het laden...", + "artist": "Kunstenaar", + "blacklisted": "Op de zwarte lijst", + "following": "Op volg", + "follow": "Volgen", + "artist_url_copied": "URL artiest gekopieerd naar klembord", + "added_to_queue": "{tracks} tracks toegevoegd aan wachtrij", + "filter_albums": "Albums filteren...", + "synced": "Gesynchroniseerd", + "plain": "Eenvoudig", + "shuffle": "Schuifelen", + "search_tracks": "Zoek nummers...", + "released": "Vrijgegeven", + "error": "Fout {error}", + "title": "Titel", + "time": "Tijd", + "more_actions": "Meer acties", + "download_count": "({count}) downloads", + "add_count_to_playlist": "Voeg ({count}) toe aan afspeellijst", + "add_count_to_queue": "Voeg ({count}) toe aan wachtrij", + "play_count_next": "Speel ({count}) volgende", + "album": "Album", + "copied_to_clipboard": "{data} naar klembord gekopieerd", + "add_to_following_playlists": "Voeg {track} toe aan volgende afspeellijsten", + "add": "Toevoegen", + "added_track_to_queue": "{track} toegevoegd aan wachtrij", + "add_to_queue": "Toevoegen aan wachtrij", + "track_will_play_next": "{track} zal hierna spelen", + "play_next": "Volgende afspelen", + "removed_track_from_queue": "{track} uit wachtrij verwijderd", + "remove_from_queue": "Verwijderen uit wachtrij", + "remove_from_favorites": "Verwijderen uit favorieten", + "save_as_favorite": "Opslaan als favoriet", + "add_to_playlist": "Toevoegen aan afspeellijst", + "remove_from_playlist": "Verwijderen uit afspeellijst", + "add_to_blacklist": "Toevoegen aan zwarte lijst", + "remove_from_blacklist": "Verwijderen uit zwarte lijst", + "share": "Delen", + "mini_player": "Minispeler", + "slide_to_seek": "Schuif om vooruit of achteruit te zoeken", + "shuffle_playlist": "Afspeellijst schuifelen", + "unshuffle_playlist": "Afspeellijst onschuifelen", + "previous_track": "Vorige nummer", + "next_track": "Volgende nummer", + "pause_playback": "Weergave pauzeren", + "resume_playback": "Weergave hervatten", + "loop_track": "Nummer loopen", + "repeat_playlist": "Afspeellijst herhalen", + "queue": "Wachtrij", + "alternative_track_sources": "Alternatieve nummerbronnen", + "download_track": "Nummer downloaden", + "tracks_in_queue": "{tracks} tracks in wachtrij", + "clear_all": "Wis alles", + "show_hide_ui_on_hover": "UI tonen/verbergen bij zweven", + "always_on_top": "Altijd bovenaan", + "exit_mini_player": "Minispeler afsluiten", + "download_location": "Downloadlocatie", + "account": "Account", + "login_with_spotify": "Inloggen met je Spotify-account", + "connect_with_spotify": "Verbinden met Spotify", + "logout": "Afmelden", + "logout_of_this_account": "Afmelden van dit account", + "language_region": "Taal & Regio", + "language": "Taal", + "system_default": "Systeemstandaard", + "market_place_region": "Marktplaats-regio", + "recommendation_country": "Aanbeveling Land", + "appearance": "Uiterlijk", + "layout_mode": "Opmaakmodus", + "override_layout_settings": "Instellingen voor responsieve opmaakmodus opheffen", + "adaptive": "Aanpassingsgericht", + "compact": "Compact", + "extended": "Uitgebreide", + "theme": "Thema", + "dark": "Donker", + "light": "Licht", + "system": "Systeem", + "accent_color": "Accentkleur", + "sync_album_color": "Albumkleur synchroniseren", + "sync_album_color_description": "Gebruikt de overheersende kleur van het albumartikel als accentkleur", + "playback": "Weergave", + "audio_quality": "Audiokwaliteit", + "high": "Hoog", + "low": "Laag", + "pre_download_play": "Vooraf downloaden en spelen", + "pre_download_play_description": "In plaats van audio te streamen, kun je bytes downloaden en afspelen (aanbevolen voor gebruikers met een hogere bandbreedte)", + "skip_non_music": "Niet-muzieksegmenten overslaan (SponsorBlock)", + "blacklist_description": "Nummers en artiesten op de zwarte lijst", + "wait_for_download_to_finish": "Wacht tot de huidige download is voltooid", + "desktop": "Bureaublad", + "close_behavior": "Sluitgedrag", + "close": "Sluit af", + "minimize_to_tray": "Minimaliseren naar lade", + "show_tray_icon": "Systeemvakpictogram tonen", + "about": "Over", + "u_love_spotube": "We weten dat jullie van Spotube houden", + "check_for_updates": "Controleren op updates", + "about_spotube": "Over Spotube", + "blacklist": "Zwarte lijst", + "please_sponsor": "Sponsor/Doneer a.u.b.", + "spotube_description": "Spotube, een lichtgewicht, cross-platform, vrij-voor-alles Spotify-client", + "version": "Versie", + "build_number": "Beeldnummer", + "founder": "Stichter", + "repository": "Opslagplaats", + "bug_issues": "Bug+problemen", + "made_with": "Gemaakt met ❤️ in Bangladesh🇧🇩", + "kingkor_roy_tirtho": "Kingkor Roy Tirtho", + "copyright": "© 2021-{current_year} Kingkor Roy Tirtho", + "license": "Licentie", + "add_spotify_credentials": "Voeg je spotify-referenties toe om te beginnen", + "credentials_will_not_be_shared_disclaimer": "Maakt u geen zorgen, uw gegevens worden niet verzameld of gedeeld met anderen.", + "know_how_to_login": "Weet u niet hoe u dit moet doen?", + "follow_step_by_step_guide": "Volg de stap voor stap gids", + "spotify_cookie": "Spotify {name} Cookie", + "cookie_name_cookie": "{name} Cookie", + "fill_in_all_fields": "Vul alle velden in a.u.b.", + "submit": "Verzenden", + "exit": "Ga weg", + "previous": "Vorige", + "next": "Volgende", + "done": "Klaar", + "step_1": "Stap 1", + "first_go_to": "Ga eerst naar", + "login_if_not_logged_in": "en Inloggen/Aanmelden als u niet bent ingelogd", + "step_2": "Stap 2", + "step_2_steps": "1. Zodra je bent aangemeld, druk je op F12 of klik je met de rechtermuisknop > Inspect om de Browser devtools te openen.\n2. Ga vervolgens naar het tabblad \"Toepassing\" (Chrome, Edge, Brave enz..) of naar het tabblad \"Opslag\" (Firefox, Palemoon enz..).\n3. Ga naar de sectie \"Cookies\" en vervolgens naar de subsectie \"https://accounts.spotify.com\".", + "step_3": "Stap 3", + "step_3_steps": "Kopieer de waarden van \"sp_dc\" en \"sp_key\" (of sp_gaid) Cookies", + "success_emoji": "Succes🥳", + "success_message": "Je bent nu succesvol ingelogd met je Spotify account. Goed gedaan, maat!", + "step_4": "Stap 4", + "step_4_steps": "Plak de gekopieerde \"sp_dc\" en \"sp_key\" (of sp_gaid) waarden in de respectievelijke velden", + "something_went_wrong": "Er ging iets mis", + "piped_instance": "Piped-serverinstantie", + "piped_description": "De Piped-serverinstantie die moet worden gebruikt voor het matchen van sporen", + "piped_warning": "Sommige werken misschien niet goed. Dus gebruik ze op eigen risico", + "generate_playlist": "Afspeellijst genereren", + "track_exists": "Nummer {track} bestaat al", + "replace_downloaded_tracks": "Alle gedownloade nummers vervangen", + "skip_download_tracks": "Downloaden van alle gedownloade nummers overslaan", + "do_you_want_to_replace": "Wil je de bestaande nummer vervangen?", + "replace": "Vervangen", + "skip": "Overslaan", + "select_up_to_count_type": "Selecteer tot {count} {type}", + "select_genres": "Genres selecteren", + "add_genres": "Genres toevoegen", + "country": "Land", + "number_of_tracks_generate": "Aantal nummers om te genereren", + "acousticness": "Akoesticiteit", + "danceability": "Dansbaarheid", + "energy": "Energie", + "instrumentalness": "Instrumentaliteit", + "liveness": "Levendigheid", + "loudness": "Luidheid", + "speechiness": "Sprakeligheid", + "valence": "Valentie", + "popularity": "Populariteit", + "key": "Sleutel", + "duration": "Tijdsduur (s)", + "tempo": "Tempo (SPM)", + "mode": "Modus", + "time_signature": "Tijdsnotatie", + "short": "Kort", + "medium": "Middel", + "long": "Lang", + "min": "Min", + "max": "Max", + "target": "Doel", + "moderate": "Matig", + "deselect_all": "Alles deselecteren", + "select_all": "Alles selecteren", + "are_you_sure": "Weet je het zeker?", + "generating_playlist": "Je aangepaste afspeellijst genereren...", + "selected_count_tracks": "{count} nummers geselecteerd", + "download_warning": "Als je alle Tracks in bulk downloadt, ben je duidelijk bezig met muziekpiraterij en breng je schade toe aan de creatieve muziekmaatschappij. Ik hoop dat je je hiervan bewust bent. Probeer altijd het harde werk van artiesten te respecteren en te steunen.", + "download_ip_ban_warning": "BTW, je IP-adres kan worden geblokkeerd op YouTube als gevolg van buitensporige downloadverzoeken dan normaal. IP blokkering betekent dat je YouTube niet kunt gebruiken (zelfs als je ingelogd bent) voor tenminste 2-3 maanden vanaf dat IP apparaat. Spotube is niet verantwoordelijk als dit ooit gebeurt.", + "by_clicking_accept_terms": "Door op 'accepteren' te klikken ga je akkoord met de volgende voorwaarden:", + "download_agreement_1": "Ik weet dat ik muziek illegaal verveel. Ik ben en crimineel.", + "download_agreement_2": "Ik steun de kunstenaar waar ik kan en ik doe dit alleen omdat ik geen geld heb om hun kunst te kopen.", + "download_agreement_3": "Ik ben me er volledig van bewust dat mijn IP geblokkeerd kan worden op YouTube & ik houd Spotube of zijn eigenaars/contributeurs niet verantwoordelijk voor ongelukken die veroorzaakt worden door mijn huidige actie.", + "decline": "Weigeren", + "accept": "Accepteren", + "details": "Bijzonderheden", + "youtube": "YouTube", + "channel": "Kanaal", + "likes": "Liefs", + "dislikes": "Hekels", + "views": "Weergaven", + "streamUrl": "Stream-URL", + "stop": "Stoppen", + "sort_newest": "Sorteren op nieuwste toegevoegd", + "sort_oldest": "Sorteren op oudste toegevoegd", + "sleep_timer": "Slaaptimer", + "mins": "{minutes} minuten", + "hours": "{hours} uren", + "hour": "{hours} uur", + "custom_hours": "Aangepaste uren", + "logs": "Logboeken", + "developers": "Ontwikkelaars", + "not_logged_in": "U bent niet aangemeld", + "search_mode": "Zoekmodus", + "youtube_api_type": "API-type", + "ok": "Oké", + "failed_to_encrypt": "Versleuteling mislukt", + "encryption_failed_warning": "Spotube gebruikt encryptie om je gegevens veilig op te slaan. Maar dat is niet gelukt. Dus zal het terugvallen op onveilige opslag.\nAls je linux gebruikt, zorg er dan voor dat je een geheim-dienst (gnome-keyring, kde-wallet, keepassxc etc) hebt geïnstalleerd.", + "querying_info": "Info opvragen...", + "piped_api_down": "Piped API is uit", + "piped_down_error_instructions": "De Piped-instantie {pipedInstance} is momenteel uitgevallen\n\nVerander de instantie of verander het 'API-type' naar de officiële YouTube API.\n\nZorg ervoor dat u de app herstart na de wijziging", + "you_are_offline": "U bent momenteel offline", + "connection_restored": "Uw internetverbinding is hersteld", + "use_system_title_bar": "Systeemtitelbalk gebruiken", + "crunching_results": "Resultaten kraken...", + "search_to_get_results": "Zoek om resultaten te krijgen", + "use_amoled_mode": "Pikzwart donkerthema", + "pitch_dark_theme": "AMOLED-modus", + "normalize_audio": "Audio normaliseren", + "change_cover": "Dekking wijzigen", + "add_cover": "Dekking toevoegen", + "restore_defaults": "Standaardwaarden herstellen", + "download_music_codec": "Muziek-codec downloaden", + "streaming_music_codec": "Muziek-codec streamen", + "login_with_lastfm": "Aanmelden met Last.fm", + "connect": "Verbinden", + "disconnect_lastfm": "Last.fm verbreken", + "disconnect": "Ontkoppelen", + "username": "Gebruikersnaam", + "password": "Wachtwoord", + "login": "Inloggen", + "login_with_your_lastfm": "Inloggen met uw Last.fm account", + "scrobble_to_lastfm": "Scrobbel naar Last.fm", + "@@locale": "nl" +} diff --git a/lib/l10n/l10n.dart b/lib/l10n/l10n.dart index d6cf3e37..3434cf66 100644 --- a/lib/l10n/l10n.dart +++ b/lib/l10n/l10n.dart @@ -8,6 +8,7 @@ /// yuri-val@github => Ukrainian /// energywave@github, ncvescera@github, OpenCode@github => Italian /// mdksec@github => Turkish +/// SecularSteve@github => Dutch import 'package:flutter/material.dart'; class L10n { @@ -23,6 +24,7 @@ class L10n { const Locale('hi', 'IN'), const Locale('it', 'IT'), const Locale('ja', 'JP'), + const Locale('nl'. 'NL'), const Locale('pl', 'PL'), const Locale('pt', 'PT'), const Locale('ru', 'RU'), From b4999993bf51dbd8d07387620ce1844c44d3d527 Mon Sep 17 00:00:00 2001 From: Kingkor Roy Tirtho Date: Fri, 29 Dec 2023 18:28:25 +0600 Subject: [PATCH 077/195] fix: wrong artist name sent while scrobbling #958 --- lib/components/player/player.dart | 15 ++++++++++----- lib/provider/scrobbler_provider.dart | 2 +- 2 files changed, 11 insertions(+), 6 deletions(-) diff --git a/lib/components/player/player.dart b/lib/components/player/player.dart index 3957cc65..cd89d3e4 100644 --- a/lib/components/player/player.dart +++ b/lib/components/player/player.dart @@ -74,10 +74,14 @@ class PlayerView extends HookConsumerWidget { useMemoized(() => GlobalKey(), []); useEffect(() { - WidgetsBinding.instance.renderView.automaticSystemUiAdjustment = false; + for (final renderView in WidgetsBinding.instance.renderViews) { + renderView.automaticSystemUiAdjustment = false; + } return () { - WidgetsBinding.instance.renderView.automaticSystemUiAdjustment = true; + for (final renderView in WidgetsBinding.instance.renderViews) { + renderView.automaticSystemUiAdjustment = true; + } }; }, [panelController.isPanelOpen]); @@ -90,10 +94,11 @@ class PlayerView extends HookConsumerWidget { final topPadding = MediaQueryData.fromView(View.of(context)).padding.top; - return WillPopScope( - onWillPop: () async { + return PopScope( + canPop: panelController.isPanelOpen, + onPopInvoked: (canPop) async { + if (!canPop) return; panelController.close(); - return false; }, child: IconTheme( data: theme.iconTheme.copyWith(color: bodyTextColor), diff --git a/lib/provider/scrobbler_provider.dart b/lib/provider/scrobbler_provider.dart index 4ff4cce7..bf234e62 100644 --- a/lib/provider/scrobbler_provider.dart +++ b/lib/provider/scrobbler_provider.dart @@ -43,7 +43,7 @@ class ScrobblerNotifier extends PersistedStateNotifier { _scrobbleController.stream.listen((track) async { try { await state?.scrobblenaut.track.scrobble( - artist: track.artists.first.name!, + artist: track.artists!.first.name!, track: track.name!, album: track.album!.name!, chosenByUser: true, From 9877c6a3b0f403e84f5b224060123406fe188f04 Mon Sep 17 00:00:00 2001 From: Kingkor Roy Tirtho Date: Sat, 30 Dec 2023 19:21:56 +0600 Subject: [PATCH 078/195] chore: fix l10n error --- lib/l10n/l10n.dart | 2 +- untranslated_messages.json | 9 +++++++++ 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/lib/l10n/l10n.dart b/lib/l10n/l10n.dart index 3434cf66..47e5eb99 100644 --- a/lib/l10n/l10n.dart +++ b/lib/l10n/l10n.dart @@ -24,7 +24,7 @@ class L10n { const Locale('hi', 'IN'), const Locale('it', 'IT'), const Locale('ja', 'JP'), - const Locale('nl'. 'NL'), + const Locale('nl', 'NL'), const Locale('pl', 'PL'), const Locale('pt', 'PT'), const Locale('ru', 'RU'), diff --git a/untranslated_messages.json b/untranslated_messages.json index 66d8c7b2..5d165f85 100644 --- a/untranslated_messages.json +++ b/untranslated_messages.json @@ -80,6 +80,15 @@ "explore_genres" ], + "nl": [ + "audio_source", + "go_to_album", + "discord_rich_presence", + "browse_all", + "genres", + "explore_genres" + ], + "pl": [ "go_to_album", "discord_rich_presence", From d645f607ac673bfb7d1764b973fa87ca933e77f2 Mon Sep 17 00:00:00 2001 From: Kingkor Roy Tirtho Date: Sat, 30 Dec 2023 20:18:35 +0600 Subject: [PATCH 079/195] chore: platform check deep link for android --- lib/hooks/configurators/use_deep_linking.dart | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/lib/hooks/configurators/use_deep_linking.dart b/lib/hooks/configurators/use_deep_linking.dart index 546ab2e8..9431f04d 100644 --- a/lib/hooks/configurators/use_deep_linking.dart +++ b/lib/hooks/configurators/use_deep_linking.dart @@ -1,3 +1,5 @@ +import 'dart:async'; + import 'package:app_links/app_links.dart'; import 'package:fl_query_hooks/fl_query_hooks.dart'; import 'package:flutter_hooks/flutter_hooks.dart'; @@ -7,6 +9,7 @@ import 'package:spotube/collections/routes.dart'; import 'package:spotube/provider/spotify_provider.dart'; import 'package:flutter_sharing_intent/flutter_sharing_intent.dart'; import 'package:flutter_sharing_intent/model/sharing_file.dart'; +import 'package:flutter_desktop_tools/flutter_desktop_tools.dart'; void useDeepLinking(WidgetRef ref) { // single instance no worries @@ -49,10 +52,14 @@ void useDeepLinking(WidgetRef ref) { } } - FlutterSharingIntent.instance.getInitialSharing().then(uriListener); + StreamSubscription? mediaStream; - final mediaStream = - FlutterSharingIntent.instance.getMediaStream().listen(uriListener); + if (DesktopTools.platform.isMobile) { + FlutterSharingIntent.instance.getInitialSharing().then(uriListener); + + mediaStream = + FlutterSharingIntent.instance.getMediaStream().listen(uriListener); + } final subscription = appLinks.allStringLinkStream.listen((uri) async { final startSegment = uri.split(":").take(2).join(":"); @@ -86,7 +93,7 @@ void useDeepLinking(WidgetRef ref) { }); return () { - mediaStream.cancel(); + mediaStream?.cancel(); subscription.cancel(); }; }, [spotify, queryClient]); From 0f6d0a44eac8accfbef6c8940a83ea0c19c92d21 Mon Sep 17 00:00:00 2001 From: Kingkor Roy Tirtho Date: Sat, 30 Dec 2023 23:13:27 +0600 Subject: [PATCH 080/195] chore: fix not closing player --- lib/components/player/player.dart | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/lib/components/player/player.dart b/lib/components/player/player.dart index cd89d3e4..33283c3e 100644 --- a/lib/components/player/player.dart +++ b/lib/components/player/player.dart @@ -95,9 +95,8 @@ class PlayerView extends HookConsumerWidget { final topPadding = MediaQueryData.fromView(View.of(context)).padding.top; return PopScope( - canPop: panelController.isPanelOpen, - onPopInvoked: (canPop) async { - if (!canPop) return; + canPop: false, + onPopInvoked: (didPop) async { panelController.close(); }, child: IconTheme( From ec9d9d7d7e83a41aad2daab039734ef55f54bff0 Mon Sep 17 00:00:00 2001 From: Kingkor Roy Tirtho Date: Sat, 30 Dec 2023 23:25:29 +0600 Subject: [PATCH 081/195] chore: fix genre playlist title bar --- lib/pages/home/genres/genre_playlists.dart | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/lib/pages/home/genres/genre_playlists.dart b/lib/pages/home/genres/genre_playlists.dart index 19f98c7f..78f32245 100644 --- a/lib/pages/home/genres/genre_playlists.dart +++ b/lib/pages/home/genres/genre_playlists.dart @@ -14,6 +14,7 @@ import 'package:spotube/components/shared/waypoint.dart'; import 'package:spotube/extensions/constrains.dart'; import 'package:spotube/services/queries/queries.dart'; import 'package:collection/collection.dart'; +import 'package:flutter_desktop_tools/flutter_desktop_tools.dart'; class GenrePlaylistsPage extends HookConsumerWidget { final Category category; @@ -42,17 +43,19 @@ class GenrePlaylistsPage extends HookConsumerWidget { final scrollController = useScrollController(); return Scaffold( - appBar: const PageWindowTitleBar( - leading: BackButton(color: Colors.white), - backgroundColor: Colors.transparent, - foregroundColor: Colors.white, - ), + appBar: DesktopTools.platform.isDesktop + ? const PageWindowTitleBar( + leading: BackButton(color: Colors.white), + backgroundColor: Colors.transparent, + foregroundColor: Colors.white, + ) + : null, extendBodyBehindAppBar: true, body: CustomScrollView( controller: scrollController, slivers: [ SliverAppBar( - automaticallyImplyLeading: false, + automaticallyImplyLeading: DesktopTools.platform.isMobile, expandedHeight: mediaQuery.mdAndDown ? 200 : 150, pinned: true, floating: false, @@ -77,7 +80,7 @@ class GenrePlaylistsPage extends HookConsumerWidget { child: const ColoredBox(color: Colors.transparent), ), ), - centerTitle: true, + centerTitle: DesktopTools.platform.isDesktop, title: Text( category.name!, style: Theme.of(context).textTheme.headlineMedium?.copyWith( From ec7c952270caca55131ed6aba9467c975eab772a Mon Sep 17 00:00:00 2001 From: Kingkor Roy Tirtho Date: Sat, 30 Dec 2023 23:41:43 +0600 Subject: [PATCH 082/195] chore: generate changelogs and bump version to 3.4.4 --- .github/workflows/spotube-release-binary.yml | 2 +- CHANGELOG.md | 26 ++++ README.md | 19 ++- bin/untranslated_messages.dart | 5 + lib/l10n/app_ar.arb | 7 +- lib/l10n/app_bn.arb | 7 +- lib/l10n/app_ca.arb | 7 +- lib/l10n/app_de.arb | 7 +- lib/l10n/app_es.arb | 7 +- lib/l10n/app_fa.arb | 7 +- lib/l10n/app_fr.arb | 7 +- lib/l10n/app_hi.arb | 7 +- lib/l10n/app_it.arb | 10 +- lib/l10n/app_ja.arb | 7 +- lib/l10n/app_nl.arb | 9 +- lib/l10n/app_pl.arb | 7 +- lib/l10n/app_pt.arb | 7 +- lib/l10n/app_ru.arb | 7 +- lib/l10n/app_tr.arb | 7 +- lib/l10n/app_uk.arb | 7 +- lib/l10n/app_zh.arb | 7 +- pubspec.yaml | 2 +- untranslated_messages.json | 140 +------------------ 23 files changed, 151 insertions(+), 167 deletions(-) diff --git a/.github/workflows/spotube-release-binary.yml b/.github/workflows/spotube-release-binary.yml index d4f15664..caeb7238 100644 --- a/.github/workflows/spotube-release-binary.yml +++ b/.github/workflows/spotube-release-binary.yml @@ -4,7 +4,7 @@ on: inputs: version: description: Version to release (x.x.x) - default: 3.3.0 + default: 3.4.0 required: true channel: type: choice diff --git a/CHANGELOG.md b/CHANGELOG.md index 1544f055..ea429caa 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,32 @@ All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines. +## [3.4.0](https://github.com/KRTirtho/spotube/compare/v3.3.0...v3.4.0) (2023-12-30) + + +### Features + +* Add Go to Album option in track option [#917](https://github.com/KRTirtho/spotube/issues/917) ([b0beeca](https://github.com/KRTirtho/spotube/commit/b0beeca0cbaf810fae27832cff98cfda95715050)) +* **translations:** add Italian language translations ([#818](https://github.com/KRTirtho/spotube/issues/818)) ([e4eb0e2](https://github.com/KRTirtho/spotube/commit/e4eb0e2596ade2bb5195e183f03af42742fc8486)), closes [#676](https://github.com/KRTirtho/spotube/issues/676) [#676](https://github.com/KRTirtho/spotube/issues/676) +* compact genre view in home page ([82ed5e9](https://github.com/KRTirtho/spotube/commit/82ed5e90576b57ef32e61a65015e04862ab15461)) +* Deep link support ([#950](https://github.com/KRTirtho/spotube/issues/950)) ([4050f55](https://github.com/KRTirtho/spotube/commit/4050f556400aaec5515231578512cf1a6b990110)) +* improve loading animations ([b92583d](https://github.com/KRTirtho/spotube/commit/b92583d0df7b8dee0d121cd2bb666b14c77d8c86)) +* toggle for discord rpc ([24a2294](https://github.com/KRTirtho/spotube/commit/24a2294512bb0c4aff77bc8dcad9b4de3e8b45c6)) +* **translations:** add Dutch Language ([#969](https://github.com/KRTirtho/spotube/issues/969)) ([3ad7ba6](https://github.com/KRTirtho/spotube/commit/3ad7ba66b56e93e69d2181d47029b7549ed225fc)) + + +### Bug Fixes + +* add safe area in home ([9ee6067](https://github.com/KRTirtho/spotube/commit/9ee60677f6d50df7468e12dc6653ecedefa2494f)) +* amoled mode and color scheme can't be changed ([840e014](https://github.com/KRTirtho/spotube/commit/840e014f2b18f193d040baef0e0cd595088a4a84)) +* doesn't minimize to tray when system title bar close button is used [#866](https://github.com/KRTirtho/spotube/issues/866) ([bb8f250](https://github.com/KRTirtho/spotube/commit/bb8f250f5f351c1a353791b77b25b9de7586191f)) +* genre border issues ([2fb16e6](https://github.com/KRTirtho/spotube/commit/2fb16e64e9cdfca54d633cdf287b0544ecdda3b6)) +* Incorrect "Artist" label/heading on Search Results Page [#920](https://github.com/KRTirtho/spotube/issues/920) ([f86d544](https://github.com/KRTirtho/spotube/commit/f86d5449168068e338f769d7f504d2146b86dc79)) +* metadata not getting added for YouTube tracks [#916](https://github.com/KRTirtho/spotube/issues/916) and Wrong duration of downloaded tracks [#912](https://github.com/KRTirtho/spotube/issues/912) ([a7b9398](https://github.com/KRTirtho/spotube/commit/a7b9398708ede865dc2c25fb791c8e98eeff7a38)) +* Playlist refresh not working [#915](https://github.com/KRTirtho/spotube/issues/915) ([5f1df5a](https://github.com/KRTirtho/spotube/commit/5f1df5a87d8fb7980b52cf57b7b6bedea57a1269)) +* track view header title overflow and player view drag glitch ([b04d884](https://github.com/KRTirtho/spotube/commit/b04d8849e7169824ec5b980236b5d61b2629f56e)) +* wrong artist name sent while scrobbling [#958](https://github.com/KRTirtho/spotube/issues/958) ([dcbe729](https://github.com/KRTirtho/spotube/commit/dcbe7294b742d43fbff4e89ab4c4825e94421dd9)) + ## [3.3.0](https://github.com/KRTirtho/spotube/compare/v3.2.0...v3.3.0) (2023-11-27) diff --git a/README.md b/README.md index 498c45de..2736d1f1 100644 --- a/README.md +++ b/README.md @@ -199,6 +199,7 @@ If you are concerned, you can [read the reason of choosing this license](https:/ 1. [SponsorBlock](https://sponsor.ajay.app) - SponsorBlock is an open-source crowdsourced browser extension and open API for skipping sponsor segments in YouTube videos. 1. [Inno Setup](https://jrsoftware.org/isinfo.php) - Inno Setup is a free installer for Windows programs by Jordan Russell and Martijn Laan 1. [F-Droid](https://f-droid.org) - F-Droid is an installable catalogue of FOSS (Free and Open Source Software) applications for the Android platform. The client makes it easy to browse, install, and keep track of updates on your device +1. [LastFM](https://last.fm) - Last.fm is a music streaming and discovery platform that helps users discover and share new music. It tracks users' music listening habits across many devices and platforms. ### Dependencies 1. [args](https://pub.dev/packages/args) - Library for defining parsers for parsing raw command-line arguments into a set of options and values using GNU and POSIX style options. @@ -208,7 +209,7 @@ If you are concerned, you can [read the reason of choosing this license](https:/ 1. [auto_size_text](https://github.com/leisim/auto_size_text) - Flutter widget that automatically resizes text to fit perfectly within its bounds. 1. [buttons_tabbar](https://afonsoraposo.com) - A Flutter package that implements a TabBar where each label is a toggle button. 1. [cached_network_image](https://github.com/Baseflow/flutter_cached_network_image) - Flutter library to load and cache network images. Can also be used with placeholder and error widgets. -1. [catcher_2](https://github.com/ThexXTURBOXx/catcher_2) - Plugin for error catching which provides multiple handlers for dealing with errors when they are not caught by the developer. +1. [catcher_2](https://github.com/ThexXTURBOXx/catcher_2) - Plugin for error catching which provides multiple handlers for dealing with errors when they are not caught by the developer. 1. [collection](https://pub.dev/packages/collection) - Collections and utilities functions and classes related to collections. 1. [cupertino_icons](https://pub.dev/packages/cupertino_icons) - Default icons asset for Cupertino widgets based on Apple styled icons 1. [curved_navigation_bar](https://github.com/rafalbednarczuk/curved_navigation_bar) - Stunning Animating Curved Shape Navigation Bar. Adjustable color, background color, animation curve, animation duration. @@ -221,9 +222,9 @@ If you are concerned, you can [read the reason of choosing this license](https:/ 1. [envied](https://github.com/petercinibulk/envied) - Explicitly reads environment variables into a dart file from a .env file for more security and faster start up times. 1. [file_selector](https://pub.dev/packages/file_selector) - Flutter plugin for opening and saving files, or selecting directories, using native file selection UI. 1. [fl_query](https://fl-query.krtirtho.dev) - Asynchronous data caching, refetching & invalidation library for Flutter -1. [fl_query_hooks](https://fl-query.krtirtho.dev) - Elite flutter_hooks compatible library for fl_query, the Asynchronous data caching, refetching & invalidation library for Flutter +1. [fl_query_hooks](https://fl-query.krtirtho.dev) - Elite flutter_hooks compatible library for fl_query, the Asynchronous data caching, refetching & invalidation library for Flutter 1. [fl_query_devtools](https://fl-query.krtirtho.dev) - Devtools support for Fl-Query -1. [fluentui_system_icons](https://github.com/microsoft/fluentui-system-icons/tree/main) - Fluent UI System Icons are a collection of familiar, friendly and modern icons from Microsoft. +1. [fluentui_system_icons](https://github.com/microsoft/fluentui-system-icons/tree/main) - Fluent UI System Icons are a collection of familiar, friendly and modern icons from Microsoft. 1. [flutter_cache_manager](https://github.com/Baseflow/flutter_cache_manager/tree/develop/flutter_cache_manager) - Generic cache manager for flutter. Saves web files on the storages of the device and saves the cache info using sqflite. 1. [flutter_displaymode](https://github.com/ajinasokan/flutter_displaymode) - A Flutter plugin to set display mode (resolution, refresh rate) on Android platform. Allows to enable high refresh rate on supported devices. 1. [flutter_feather_icons](https://github.com/muj-programmer/flutter_feather_icons) - Feather is a collection of simply beautiful open source icons. Each icon is designed on a 24x24 grid with an emphasis on simplicity, consistency and usability. @@ -234,7 +235,7 @@ If you are concerned, you can [read the reason of choosing this license](https:/ 1. [flutter_secure_storage](https://pub.dev/packages/flutter_secure_storage) - Flutter Secure Storage provides API to store data in secure storage. Keychain is used in iOS, KeyStore based solution is used in Android. 1. [flutter_svg](https://pub.dev/packages/flutter_svg) - An SVG rendering and widget library for Flutter, which allows painting and displaying Scalable Vector Graphics 1.1 files. 1. [form_validator](https://github.com/TheMisir/form-validator) - Simplest form validation library for flutter's form field widgets -1. [fuzzywuzzy](https://github.com/sphericalkat/dart-fuzzywuzzy) - An implementation of the popular fuzzywuzzy package in Dart, to suit all your fuzzy string matching/searching needs! +1. [fuzzywuzzy](https://github.com/sphericalkat/dart-fuzzywuzzy) - An implementation of the popular fuzzywuzzy package in Dart, to suit all your fuzzy string matching/searching needs! 1. [google_fonts](https://pub.dev/packages/google_fonts) - A Flutter package to use fonts from fonts.google.com. Supports HTTP fetching, caching, and asset bundling. 1. [go_router](https://pub.dev/packages/go_router) - A declarative router for Flutter based on Navigation 2 supporting deep linking, data-driven routes and more 1. [hive](https://github.com/hivedb/hive/tree/master/hive) - Lightweight and blazing fast key-value database written in pure Dart. Strongly encrypted using AES-256. @@ -251,10 +252,10 @@ If you are concerned, you can [read the reason of choosing this license](https:/ 1. [media_kit_libs_audio](https://github.com/media-kit/media-kit.git) - package:media_kit audio (only) playback native libraries for all platforms. 1. [metadata_god](https://github.com/KRTirtho/metadata_god) - Plugin for retrieving and writing audio tags/metadata from audio files 1. [mime](https://pub.dev/packages/mime) - Utilities for handling media (MIME) types, including determining a type from a file extension and file contents. -1. [package_info_plus](https://plus.fluttercommunity.dev/) - Flutter plugin for querying information about the application package, such as CFBundleVersion on iOS or versionCode on Android. +1. [package_info_plus](https://plus.fluttercommunity.dev/) - Flutter plugin for querying information about the application package, such as CFBundleVersion on iOS or versionCode on Android. 1. [palette_generator](https://pub.dev/packages/palette_generator) - Flutter package for generating palette colors from a source image. 1. [path](https://pub.dev/packages/path) - A string-based path manipulation library. All of the path operations you know and love, with solid support for Windows, POSIX (Linux and Mac OS X), and the web. -1. [path_provider](https://pub.dev/packages/path_provider) - Flutter plugin for getting commonly used locations on host platform file systems, such as the temp and app data directories. +1. [path_provider](https://pub.dev/packages/path_provider) - Flutter plugin for getting commonly used locations on host platform file systems, such as the temp and app data directories. 1. [permission_handler](https://pub.dev/packages/permission_handler) - Permission plugin for Flutter. This plugin provides a cross-platform (iOS, Android) API to request and check permissions. 1. [piped_client](https://github.com/KRTirtho/piped_client) - API Client for piped.video 1. [popover](https://github.com/minikin/popover) - A popover is a transient view that appears above other content onscreen when you tap a control or in an area. @@ -273,7 +274,7 @@ If you are concerned, you can [read the reason of choosing this license](https:/ 1. [visibility_detector](https://pub.dev/packages/visibility_detector) - A widget that detects the visibility of its child and notifies a callback. 1. [window_manager](https://github.com/leanflutter/window_manager) - This plugin allows Flutter desktop apps to resizing and repositioning the window. 1. [youtube_explode_dart](https://github.com/Hexer10/youtube_explode_dart) - A port in dart of the youtube explode library. Supports several API functions without the need of Youtube API Key. -1. [simple_icons](https://jlnrrg.github.io/) - The Simple Icon pack available as Flutter Icons. Provides over 1500 Free SVG icons for popular brands. +1. [simple_icons](https://teavelopment.com/) - The Simple Icon pack available as Flutter Icons. Provides over 1500 Free SVG icons for popular brands. 1. [audio_service_mpris](https://github.com/bdrazhzhov/audio-service-mpris) - audio_service platform interface supporting Media Player Remote Interfacing Specification. 1. [file_picker](https://github.com/miguelpruivo/plugins_flutter_file_picker) - A package that allows you to use a native file explorer to pick single or multiple absolute file paths, with extension filtering support. 1. [jiosaavn](https://github.com/KRTirtho/jiosaavn) - Unofficial API client for jiosaavn.com @@ -282,6 +283,10 @@ If you are concerned, you can [read the reason of choosing this license](https:/ 1. [sliver_tools](https://github.com/Kavantix) - A set of useful sliver tools that are missing from the flutter framework 1. [html_unescape](https://github.com/filiph/html_unescape) - A small library for un-escaping HTML. Supports all Named Character References, Decimal Character References and Hexadecimal Character References. 1. [wikipedia_api](https://github.com/KRTirtho/wikipedia_api) - Wikipedia API for dart and flutter +1. [skeletonizer](https://github.com/Milad-Akarie/skeletonizer) - Converts already built widgets into skeleton loaders with no extra effort. +1. [app_links](https://github.com/llfbandit/app_links) - Android App Links, Deep Links, iOs Universal Links and Custom URL schemes handler for Flutter (desktop included). +1. [win32_registry](https://win32.pub) - A package that provides a friendly Dart API for accessing the Windows Registry. +1. [flutter_sharing_intent](https://github.com/bhagat-techind/flutter_sharing_intent.git) - A flutter plugin that allow flutter apps to receive photos, videos, text, urls or any other file types from another app. 1. [build_runner](https://pub.dev/packages/build_runner) - A build system for Dart code generation and modular compilation. 1. [envied_generator](https://github.com/petercinibulk/envied) - Generator for the Envied package. See https://pub.dev/packages/envied. 1. [flutter_distributor](https://distributor.leanflutter.org) - A complete tool for packaging and publishing your Flutter apps. diff --git a/bin/untranslated_messages.dart b/bin/untranslated_messages.dart index 172f218f..e19f9a07 100644 --- a/bin/untranslated_messages.dart +++ b/bin/untranslated_messages.dart @@ -35,6 +35,11 @@ void main(List args) { ); } + print( + "Prompt:\n" + "Translate following to their appropriate locale for flutter arb translations files." + " Put the respective new translations in a map of their corresponding locale.", + ); // ignore: avoid_print print( const JsonEncoder.withIndent(' ').convert( diff --git a/lib/l10n/app_ar.arb b/lib/l10n/app_ar.arb index b74564a4..2bdde72a 100644 --- a/lib/l10n/app_ar.arb +++ b/lib/l10n/app_ar.arb @@ -279,5 +279,10 @@ "password": "كلمة المرور", "login": "تسجيل الدخول", "login_with_your_lastfm": "تسجيل الدخول باستخدام حساب Last.fm الخاص بك", - "scrobble_to_lastfm": "تسجيل الاستماع على Last.fm" + "scrobble_to_lastfm": "تسجيل الاستماع على Last.fm", + "go_to_album": "الانتقال إلى الألبوم", + "discord_rich_presence": "وجود ديسكورد الغني", + "browse_all": "تصفح الكل", + "genres": "الأنواع الموسيقية", + "explore_genres": "استكشاف الأنواع" } \ No newline at end of file diff --git a/lib/l10n/app_bn.arb b/lib/l10n/app_bn.arb index 59985b24..39f8a1ee 100644 --- a/lib/l10n/app_bn.arb +++ b/lib/l10n/app_bn.arb @@ -279,5 +279,10 @@ "password": "পাসওয়ার্ড", "login": "লগইন", "login_with_your_lastfm": "আপনার Last.fm অ্যাকাউন্ট দিয়ে লগইন করুন", - "scrobble_to_lastfm": "Last.fm এ স্ক্রবল করুন" + "scrobble_to_lastfm": "Last.fm এ স্ক্রবল করুন", + "go_to_album": "الانتقال إلى الألبوم", + "discord_rich_presence": "وجود ديسكورد الغني", + "browse_all": "تصفح الكل", + "genres": "الأنواع الموسيقية", + "explore_genres": "استكشاف الأنواع" } \ No newline at end of file diff --git a/lib/l10n/app_ca.arb b/lib/l10n/app_ca.arb index 1d1bb5e4..15ca9e31 100644 --- a/lib/l10n/app_ca.arb +++ b/lib/l10n/app_ca.arb @@ -279,5 +279,10 @@ "password": "Contrasenya", "login": "Inicia la sessió", "login_with_your_lastfm": "Inicia la sessió amb el teu compte de Last.fm", - "scrobble_to_lastfm": "Scrobble a Last.fm" + "scrobble_to_lastfm": "Scrobble a Last.fm", + "go_to_album": "Anar a l'àlbum", + "discord_rich_presence": "Presència rica de Discord", + "browse_all": "Navega per tot", + "genres": "Gèneres", + "explore_genres": "Explora els gèneres" } \ No newline at end of file diff --git a/lib/l10n/app_de.arb b/lib/l10n/app_de.arb index 8b7b2593..1a13e4a1 100644 --- a/lib/l10n/app_de.arb +++ b/lib/l10n/app_de.arb @@ -279,5 +279,10 @@ "password": "Passwort", "login": "Anmelden", "login_with_your_lastfm": "Mit Ihrem Last.fm-Konto anmelden", - "scrobble_to_lastfm": "Auf Last.fm scrobbeln" + "scrobble_to_lastfm": "Auf Last.fm scrobbeln", + "go_to_album": "Zum Album gehen", + "discord_rich_presence": "Discord Rich Presence", + "browse_all": "Alles durchsuchen", + "genres": "Genres", + "explore_genres": "Genres erkunden" } \ No newline at end of file diff --git a/lib/l10n/app_es.arb b/lib/l10n/app_es.arb index d90ec972..2fecd8f1 100644 --- a/lib/l10n/app_es.arb +++ b/lib/l10n/app_es.arb @@ -279,5 +279,10 @@ "password": "Contraseña", "login": "Iniciar sesión", "login_with_your_lastfm": "Iniciar sesión con tu cuenta de Last.fm", - "scrobble_to_lastfm": "Scrobble a Last.fm" + "scrobble_to_lastfm": "Scrobble a Last.fm", + "go_to_album": "Ir al álbum", + "discord_rich_presence": "Presencia rica en Discord", + "browse_all": "Explorar todo", + "genres": "Géneros", + "explore_genres": "Explorar géneros" } \ No newline at end of file diff --git a/lib/l10n/app_fa.arb b/lib/l10n/app_fa.arb index a8bb9f8c..84b9b448 100644 --- a/lib/l10n/app_fa.arb +++ b/lib/l10n/app_fa.arb @@ -279,5 +279,10 @@ "password": "رمز عبور", "login": "ورود", "login_with_your_lastfm": "ورود با حساب کاربری Last.fm خود", - "scrobble_to_lastfm": "Scrobble به Last.fm" + "scrobble_to_lastfm": "Scrobble به Last.fm", + "go_to_album": "رفتن به آلبوم", + "discord_rich_presence": "حضور غنی دیسکورد", + "browse_all": "مرور همه", + "genres": "ژانرها", + "explore_genres": "استکشاف ژانرها" } \ No newline at end of file diff --git a/lib/l10n/app_fr.arb b/lib/l10n/app_fr.arb index 06015964..82997bad 100644 --- a/lib/l10n/app_fr.arb +++ b/lib/l10n/app_fr.arb @@ -279,5 +279,10 @@ "password": "Mot de passe", "login": "Se connecter", "login_with_your_lastfm": "Se connecter avec votre compte Last.fm", - "scrobble_to_lastfm": "Scrobble à Last.fm" + "scrobble_to_lastfm": "Scrobble à Last.fm", + "go_to_album": "Aller à l'album", + "discord_rich_presence": "Présence riche de Discord", + "browse_all": "Parcourir tout", + "genres": "Genres", + "explore_genres": "Explorer les genres" } \ No newline at end of file diff --git a/lib/l10n/app_hi.arb b/lib/l10n/app_hi.arb index adbc6c06..4bfff3da 100644 --- a/lib/l10n/app_hi.arb +++ b/lib/l10n/app_hi.arb @@ -279,5 +279,10 @@ "password": "पासवर्ड", "login": "लॉग इन करें", "login_with_your_lastfm": "अपने Last.fm अकाउंट से लॉगिन करें", - "scrobble_to_lastfm": "Last.fm पर स्क्रॉबल करें" + "scrobble_to_lastfm": "Last.fm पर स्क्रॉबल करें", + "go_to_album": "एल्बम पर जाएं", + "discord_rich_presence": "डिस्कॉर्ड रिच प्रेजेंस", + "browse_all": "सभी को ब्राउज़ करें", + "genres": "शैलियाँ", + "explore_genres": "शैलियों का अन्वेषण करें" } \ No newline at end of file diff --git a/lib/l10n/app_it.arb b/lib/l10n/app_it.arb index ada9f1f6..033bb516 100644 --- a/lib/l10n/app_it.arb +++ b/lib/l10n/app_it.arb @@ -279,5 +279,11 @@ "password": "Password", "login": "Accesso", "login_with_your_lastfm": "Accedi con il tuo account Last.fm", - "scrobble_to_lastfm": "Invia a Last.fm" -} + "scrobble_to_lastfm": "Invia a Last.fm", + "audio_source": "Fonte audio", + "go_to_album": "Vai all'album", + "discord_rich_presence": "Presenza ricca di Discord", + "browse_all": "Esplora tutto", + "genres": "Generi", + "explore_genres": "Esplora generi" +} \ No newline at end of file diff --git a/lib/l10n/app_ja.arb b/lib/l10n/app_ja.arb index a288cf0e..ac23728b 100644 --- a/lib/l10n/app_ja.arb +++ b/lib/l10n/app_ja.arb @@ -279,5 +279,10 @@ "password": "パスワード", "login": "ログインする", "login_with_your_lastfm": "あなたのLast.fmアカウントでログインする", - "scrobble_to_lastfm": "Last.fmにスクロブルする" + "scrobble_to_lastfm": "Last.fmにスクロブルする", + "go_to_album": "アルバムに移動", + "discord_rich_presence": "ディスコードリッチプレゼンス", + "browse_all": "すべてを閲覧", + "genres": "ジャンル", + "explore_genres": "ジャンルを探索" } \ No newline at end of file diff --git a/lib/l10n/app_nl.arb b/lib/l10n/app_nl.arb index 306d63c4..6e50c461 100644 --- a/lib/l10n/app_nl.arb +++ b/lib/l10n/app_nl.arb @@ -280,5 +280,10 @@ "login": "Inloggen", "login_with_your_lastfm": "Inloggen met uw Last.fm account", "scrobble_to_lastfm": "Scrobbel naar Last.fm", - "@@locale": "nl" -} + "audio_source": "Audiobron", + "go_to_album": "Ga naar album", + "discord_rich_presence": "Discord Rich Presence", + "browse_all": "Alles bekijken", + "genres": "Genres", + "explore_genres": "Verken genres" +} \ No newline at end of file diff --git a/lib/l10n/app_pl.arb b/lib/l10n/app_pl.arb index 8c6147ad..dd173a37 100644 --- a/lib/l10n/app_pl.arb +++ b/lib/l10n/app_pl.arb @@ -279,5 +279,10 @@ "password": "Hasło", "login": "Zaloguj", "login_with_your_lastfm": "Zaloguj się na swoje konto Last.fm", - "scrobble_to_lastfm": "Scrobbluj do Last.fm" + "scrobble_to_lastfm": "Scrobbluj do Last.fm", + "go_to_album": "Przejdź do albumu", + "discord_rich_presence": "Obecność na Discordzie", + "browse_all": "Przeglądaj wszystko", + "genres": "Gatunki muzyczne", + "explore_genres": "Eksploruj gatunki" } \ No newline at end of file diff --git a/lib/l10n/app_pt.arb b/lib/l10n/app_pt.arb index 46c0a88e..705217c1 100644 --- a/lib/l10n/app_pt.arb +++ b/lib/l10n/app_pt.arb @@ -279,5 +279,10 @@ "password": "Palavra-passe", "login": "Iniciar sessão", "login_with_your_lastfm": "Inicie sessão na sua conta Last.fm", - "scrobble_to_lastfm": "Scrobble para o Last.fm" + "scrobble_to_lastfm": "Scrobble para o Last.fm", + "go_to_album": "Ir para o álbum", + "discord_rich_presence": "Presença rica no Discord", + "browse_all": "Navegar por tudo", + "genres": "Gêneros", + "explore_genres": "Explorar gêneros" } \ No newline at end of file diff --git a/lib/l10n/app_ru.arb b/lib/l10n/app_ru.arb index b1964f5f..32415863 100644 --- a/lib/l10n/app_ru.arb +++ b/lib/l10n/app_ru.arb @@ -279,5 +279,10 @@ "password": "Пароль", "login": "Войти", "login_with_your_lastfm": "Войти в свою учетную запись Last.fm", - "scrobble_to_lastfm": "Скробблинг на Last.fm" + "scrobble_to_lastfm": "Скробблинг на Last.fm", + "go_to_album": "Перейти к альбому", + "discord_rich_presence": "Богатое присутствие в Discord", + "browse_all": "Просмотреть все", + "genres": "Жанры", + "explore_genres": "Исследовать жанры" } \ No newline at end of file diff --git a/lib/l10n/app_tr.arb b/lib/l10n/app_tr.arb index fa0ea587..63646af6 100644 --- a/lib/l10n/app_tr.arb +++ b/lib/l10n/app_tr.arb @@ -279,5 +279,10 @@ "password": "Şifre", "login": "Giriş Yap", "login_with_your_lastfm": "Last.fm hesabınız ile giriş yapın", - "scrobble_to_lastfm": "Last.fm için Scrobble" + "scrobble_to_lastfm": "Last.fm için Scrobble", + "go_to_album": "Albüme Git", + "discord_rich_presence": "Discord Zengin Varlık", + "browse_all": "Tümünü Gözat", + "genres": "Müzik Türleri", + "explore_genres": "Türleri Keşfet" } \ No newline at end of file diff --git a/lib/l10n/app_uk.arb b/lib/l10n/app_uk.arb index 22fc341e..2ae29237 100644 --- a/lib/l10n/app_uk.arb +++ b/lib/l10n/app_uk.arb @@ -279,5 +279,10 @@ "password": "Пароль", "login": "Увійти", "login_with_your_lastfm": "Увійти в свій обліковий запис Last.fm", - "scrobble_to_lastfm": "Скробблінг на Last.fm" + "scrobble_to_lastfm": "Скробблінг на Last.fm", + "go_to_album": "Перейти до альбому", + "discord_rich_presence": "Багата присутність у Discord", + "browse_all": "Переглянути все", + "genres": "Жанри", + "explore_genres": "Досліджувати жанри" } \ No newline at end of file diff --git a/lib/l10n/app_zh.arb b/lib/l10n/app_zh.arb index 325216fa..85b57724 100644 --- a/lib/l10n/app_zh.arb +++ b/lib/l10n/app_zh.arb @@ -279,5 +279,10 @@ "password": "密码", "login": "登录", "login_with_your_lastfm": "使用您的 Last.fm 帐户登录", - "scrobble_to_lastfm": "在 Last.fm 上记录播放" + "scrobble_to_lastfm": "在 Last.fm 上记录播放", + "go_to_album": "前往专辑", + "discord_rich_presence": "Discord 丰富展现", + "browse_all": "浏览全部", + "genres": "音乐类型", + "explore_genres": "探索音乐类型" } \ No newline at end of file diff --git a/pubspec.yaml b/pubspec.yaml index 267ab17f..16cdc2b6 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -3,7 +3,7 @@ description: Open source Spotify client that doesn't require Premium nor uses El publish_to: "none" -version: 3.3.0+26 +version: 3.4.0+27 homepage: https://spotube.krtirtho.dev repository: https://github.com/KRTirtho/spotube diff --git a/untranslated_messages.json b/untranslated_messages.json index 5d165f85..9e26dfee 100644 --- a/untranslated_messages.json +++ b/untranslated_messages.json @@ -1,139 +1 @@ -{ - "ar": [ - "go_to_album", - "discord_rich_presence", - "browse_all", - "genres", - "explore_genres" - ], - - "bn": [ - "go_to_album", - "discord_rich_presence", - "browse_all", - "genres", - "explore_genres" - ], - - "ca": [ - "go_to_album", - "discord_rich_presence", - "browse_all", - "genres", - "explore_genres" - ], - - "de": [ - "go_to_album", - "discord_rich_presence", - "browse_all", - "genres", - "explore_genres" - ], - - "es": [ - "go_to_album", - "discord_rich_presence", - "browse_all", - "genres", - "explore_genres" - ], - - "fa": [ - "go_to_album", - "discord_rich_presence", - "browse_all", - "genres", - "explore_genres" - ], - - "fr": [ - "go_to_album", - "discord_rich_presence", - "browse_all", - "genres", - "explore_genres" - ], - - "hi": [ - "go_to_album", - "discord_rich_presence", - "browse_all", - "genres", - "explore_genres" - ], - - "it": [ - "audio_source", - "go_to_album", - "discord_rich_presence", - "browse_all", - "genres", - "explore_genres" - ], - - "ja": [ - "go_to_album", - "discord_rich_presence", - "browse_all", - "genres", - "explore_genres" - ], - - "nl": [ - "audio_source", - "go_to_album", - "discord_rich_presence", - "browse_all", - "genres", - "explore_genres" - ], - - "pl": [ - "go_to_album", - "discord_rich_presence", - "browse_all", - "genres", - "explore_genres" - ], - - "pt": [ - "go_to_album", - "discord_rich_presence", - "browse_all", - "genres", - "explore_genres" - ], - - "ru": [ - "go_to_album", - "discord_rich_presence", - "browse_all", - "genres", - "explore_genres" - ], - - "tr": [ - "go_to_album", - "discord_rich_presence", - "browse_all", - "genres", - "explore_genres" - ], - - "uk": [ - "go_to_album", - "discord_rich_presence", - "browse_all", - "genres", - "explore_genres" - ], - - "zh": [ - "go_to_album", - "discord_rich_presence", - "browse_all", - "genres", - "explore_genres" - ] -} +{} \ No newline at end of file From 0dfd40153714b7a4b83ac30f0c56830bc0c05ffd Mon Sep 17 00:00:00 2001 From: Kingkor Roy Tirtho Date: Mon, 1 Jan 2024 21:01:21 +0600 Subject: [PATCH 083/195] fix(linux): crash after login --- lib/hooks/configurators/use_deep_linking.dart | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/lib/hooks/configurators/use_deep_linking.dart b/lib/hooks/configurators/use_deep_linking.dart index 9431f04d..be6facf9 100644 --- a/lib/hooks/configurators/use_deep_linking.dart +++ b/lib/hooks/configurators/use_deep_linking.dart @@ -11,9 +11,11 @@ import 'package:flutter_sharing_intent/flutter_sharing_intent.dart'; import 'package:flutter_sharing_intent/model/sharing_file.dart'; import 'package:flutter_desktop_tools/flutter_desktop_tools.dart'; +final appLinks = AppLinks(); +final linkStream = appLinks.allStringLinkStream.asBroadcastStream(); + void useDeepLinking(WidgetRef ref) { // single instance no worries - final appLinks = AppLinks(); final spotify = ref.watch(spotifyProvider); final queryClient = useQueryClient(); @@ -61,7 +63,7 @@ void useDeepLinking(WidgetRef ref) { FlutterSharingIntent.instance.getMediaStream().listen(uriListener); } - final subscription = appLinks.allStringLinkStream.listen((uri) async { + final subscription = linkStream.listen((uri) async { final startSegment = uri.split(":").take(2).join(":"); final endSegment = uri.split(":").last; From 7e1005dc62c99a6f0bd569fc8f293b334ba721f4 Mon Sep 17 00:00:00 2001 From: franchioping <43936644+franchioping@users.noreply.github.com> Date: Tue, 2 Jan 2024 16:08:51 +0000 Subject: [PATCH 084/195] docs: Update dev branch in CONTRIBUTION.md (#977) change development branch from main to dev --- CONTRIBUTION.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/CONTRIBUTION.md b/CONTRIBUTION.md index b2823e62..13996cea 100644 --- a/CONTRIBUTION.md +++ b/CONTRIBUTION.md @@ -145,7 +145,7 @@ Do the following: flutter run -d )> ``` -Do debugging/testing/build etc then submit to us with PR against the development branch (master) & we'll review your code +Do debugging/testing/build etc then submit to us with PR against the development branch (dev) & we'll review your code ### Submit Translations @@ -163,4 +163,4 @@ Make sure you're familiar with [Flutter localization](https://docs.flutter.dev/u - Now restart (hot restart if running already) the app in debug mode & go to "Settings" > "Language" & see if your locale shows up - If it does, select it & see if the app is translated properly - Now git commit the changes & push -- Finally, submit a PR against the development branch (dev) & we'll review your code \ No newline at end of file +- Finally, submit a PR against the development branch (dev) & we'll review your code From 02e44fc6b849a873adad382f5d46ed8caf32359f Mon Sep 17 00:00:00 2001 From: Piotr Rogowski Date: Tue, 2 Jan 2024 17:21:12 +0100 Subject: [PATCH 085/195] fix: Black window flash when starting the app (#1003) --- lib/main.dart | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/lib/main.dart b/lib/main.dart index 052e6809..f96920a1 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -58,15 +58,6 @@ Future main(List rawArgs) async { await DesktopTools.window.setPreventClose(true); } - await DesktopTools.ensureInitialized( - DesktopWindowOptions( - hideTitleBar: true, - title: "Spotube", - backgroundColor: Colors.transparent, - minimumSize: const Size(300, 700), - ), - ); - await SystemTheme.accentColor.load(); if (!kIsWeb) { @@ -107,6 +98,15 @@ Future main(List rawArgs) async { path: hiveCacheDir, ); + await DesktopTools.ensureInitialized( + DesktopWindowOptions( + hideTitleBar: true, + title: "Spotube", + backgroundColor: Colors.transparent, + minimumSize: const Size(300, 700), + ), + ); + Catcher2( enableLogger: arguments["verbose"], debugConfig: Catcher2Options( From ba4e11a40ab18308437a05333a46eace6f8eeb5a Mon Sep 17 00:00:00 2001 From: franchioping <43936644+franchioping@users.noreply.github.com> Date: Tue, 2 Jan 2024 16:37:51 +0000 Subject: [PATCH 086/195] fix: songs doesn't play when sources with preferred audio codec is empty (#976) * Fix song not playing when m4a or weba is not available (one is available but not the other) for that song * Update lib/services/sourced_track/sources/youtube.dart --------- Co-authored-by: Kingkor Roy Tirtho --- lib/services/sourced_track/sources/youtube.dart | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/lib/services/sourced_track/sources/youtube.dart b/lib/services/sourced_track/sources/youtube.dart index 096de2d4..2bcd6e3e 100644 --- a/lib/services/sourced_track/sources/youtube.dart +++ b/lib/services/sourced_track/sources/youtube.dart @@ -79,14 +79,17 @@ class YoutubeSourcedTrack extends SourcedTrack { } static SourceMap toSourceMap(StreamManifest manifest) { - final m4a = manifest.audioOnly + var m4a = manifest.audioOnly .where((audio) => audio.codec.mimeType == "audio/mp4") .sortByBitrate(); - final weba = manifest.audioOnly + var weba = manifest.audioOnly .where((audio) => audio.codec.mimeType == "audio/webm") .sortByBitrate(); + m4a = m4a.isEmpty ? weba.toList() : m4a; + weba = weba.isEmpty ? m4a.toList() : weba; + return SourceMap( m4a: SourceQualityMap( high: m4a.first.url.toString(), From 69559ba24285636e42b2f2231f956c31388c5cf3 Mon Sep 17 00:00:00 2001 From: Piotr Rogowski Date: Tue, 2 Jan 2024 17:41:03 +0100 Subject: [PATCH 087/195] fix(macos): Respect Minimize to tray option (#1001) --- macos/Runner/AppDelegate.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/macos/Runner/AppDelegate.swift b/macos/Runner/AppDelegate.swift index d53ef643..218f93e0 100644 --- a/macos/Runner/AppDelegate.swift +++ b/macos/Runner/AppDelegate.swift @@ -4,6 +4,6 @@ import FlutterMacOS @NSApplicationMain class AppDelegate: FlutterAppDelegate { override func applicationShouldTerminateAfterLastWindowClosed(_ sender: NSApplication) -> Bool { - return true + return false } } From b2ba6d9261319240877cbde3aa27d2459d9ee17e Mon Sep 17 00:00:00 2001 From: powen Date: Wed, 3 Jan 2024 02:40:50 +0800 Subject: [PATCH 088/195] cd: build iPA support for iOS (#971) * Create build-iPA.yml * Update build-iPA.yml * update-iOS - Set AppIcon(same as Android) - Set to correct app name(Sptube -> Spotube) - * update iOS flavors * Update build-iPA.yml * Update spotube-release-binary.yml * rename release-bin iPA filename * update appicon * Update dev-Info.plist --- .github/workflows/build-iPA.yml | 42 + .github/workflows/spotube-release-binary.yml | 44 +- flutter_launcher_icons-nightly.yaml | 1 + ios/Podfile | 21 + ios/Podfile.lock | 153 +- ios/Runner.xcodeproj/project.pbxproj | 2038 ++++++++++++++++- .../xcshareddata/xcschemes/Runner.xcscheme | 2 +- .../xcshareddata/xcschemes/dev.xcscheme | 77 + .../xcshareddata/xcschemes/nightly.xcscheme | 77 + .../xcshareddata/xcschemes/stable.xcscheme | 77 + .../AppIcon-nightly-1024x1024@1x.png | Bin 0 -> 296365 bytes .../AppIcon-nightly-20x20@1x.png | Bin 0 -> 1067 bytes .../AppIcon-nightly-20x20@2x.png | Bin 0 -> 3063 bytes .../AppIcon-nightly-20x20@3x.png | Bin 0 -> 5544 bytes .../AppIcon-nightly-29x29@1x.png | Bin 0 -> 1908 bytes .../AppIcon-nightly-29x29@2x.png | Bin 0 -> 5273 bytes .../AppIcon-nightly-29x29@3x.png | Bin 0 -> 9629 bytes .../AppIcon-nightly-40x40@1x.png | Bin 0 -> 3063 bytes .../AppIcon-nightly-40x40@2x.png | Bin 0 -> 8549 bytes .../AppIcon-nightly-40x40@3x.png | Bin 0 -> 15152 bytes .../AppIcon-nightly-50x50@1x.png | Bin 0 -> 4221 bytes .../AppIcon-nightly-50x50@2x.png | Bin 0 -> 11770 bytes .../AppIcon-nightly-57x57@1x.png | Bin 0 -> 5119 bytes .../AppIcon-nightly-57x57@2x.png | Bin 0 -> 14102 bytes .../AppIcon-nightly-60x60@2x.png | Bin 0 -> 15152 bytes .../AppIcon-nightly-60x60@3x.png | Bin 0 -> 27017 bytes .../AppIcon-nightly-72x72@1x.png | Bin 0 -> 7219 bytes .../AppIcon-nightly-72x72@2x.png | Bin 0 -> 19833 bytes .../AppIcon-nightly-76x76@1x.png | Bin 0 -> 7952 bytes .../AppIcon-nightly-76x76@2x.png | Bin 0 -> 21551 bytes .../AppIcon-nightly-83.5x83.5@2x.png | Bin 0 -> 24166 bytes .../AppIcon-nightly.appiconset/Contents.json | 1 + .../AppIcon-1024x1024@1x.png | Bin 0 -> 279220 bytes .../AppIcon.appiconset/AppIcon-20x20@1x.png | Bin 0 -> 1169 bytes .../AppIcon.appiconset/AppIcon-20x20@2x.png | Bin 0 -> 2967 bytes .../AppIcon.appiconset/AppIcon-20x20@3x.png | Bin 0 -> 5238 bytes .../AppIcon.appiconset/AppIcon-29x29@1x.png | Bin 0 -> 1903 bytes .../AppIcon.appiconset/AppIcon-29x29@2x.png | Bin 0 -> 4947 bytes .../AppIcon.appiconset/AppIcon-29x29@3x.png | Bin 0 -> 8997 bytes .../AppIcon.appiconset/AppIcon-40x40@1x.png | Bin 0 -> 2967 bytes .../AppIcon.appiconset/AppIcon-40x40@2x.png | Bin 0 -> 7960 bytes .../AppIcon.appiconset/AppIcon-40x40@3x.png | Bin 0 -> 14374 bytes .../AppIcon.appiconset/AppIcon-50x50@1x.png | Bin 0 -> 3996 bytes .../AppIcon.appiconset/AppIcon-50x50@2x.png | Bin 0 -> 10909 bytes .../AppIcon.appiconset/AppIcon-57x57@1x.png | Bin 0 -> 4900 bytes .../AppIcon.appiconset/AppIcon-57x57@2x.png | Bin 0 -> 13357 bytes .../AppIcon.appiconset/AppIcon-60x60@2x.png | Bin 0 -> 14374 bytes .../AppIcon.appiconset/AppIcon-60x60@3x.png | Bin 0 -> 25638 bytes .../AppIcon.appiconset/AppIcon-72x72@1x.png | Bin 0 -> 6770 bytes .../AppIcon.appiconset/AppIcon-72x72@2x.png | Bin 0 -> 18578 bytes .../AppIcon.appiconset/AppIcon-76x76@1x.png | Bin 0 -> 7415 bytes .../AppIcon.appiconset/AppIcon-76x76@2x.png | Bin 0 -> 20128 bytes .../AppIcon-83.5x83.5@2x.png | Bin 0 -> 22732 bytes .../AppIcon.appiconset/Contents.json | 123 +- .../Icon-App-1024x1024@1x.png | Bin 10932 -> 0 bytes .../AppIcon.appiconset/Icon-App-20x20@1x.png | Bin 564 -> 0 bytes .../AppIcon.appiconset/Icon-App-20x20@2x.png | Bin 1283 -> 0 bytes .../AppIcon.appiconset/Icon-App-20x20@3x.png | Bin 1588 -> 0 bytes .../AppIcon.appiconset/Icon-App-29x29@1x.png | Bin 1025 -> 0 bytes .../AppIcon.appiconset/Icon-App-29x29@2x.png | Bin 1716 -> 0 bytes .../AppIcon.appiconset/Icon-App-29x29@3x.png | Bin 1920 -> 0 bytes .../AppIcon.appiconset/Icon-App-40x40@1x.png | Bin 1283 -> 0 bytes .../AppIcon.appiconset/Icon-App-40x40@2x.png | Bin 1895 -> 0 bytes .../AppIcon.appiconset/Icon-App-40x40@3x.png | Bin 2665 -> 0 bytes .../AppIcon.appiconset/Icon-App-60x60@2x.png | Bin 2665 -> 0 bytes .../AppIcon.appiconset/Icon-App-60x60@3x.png | Bin 3831 -> 0 bytes .../AppIcon.appiconset/Icon-App-76x76@1x.png | Bin 1888 -> 0 bytes .../AppIcon.appiconset/Icon-App-76x76@2x.png | Bin 3294 -> 0 bytes .../Icon-App-83.5x83.5@2x.png | Bin 3612 -> 0 bytes ios/Runner/Assets.xcassets/Contents.json | 6 + ios/Runner/Info.plist | 6 +- ios/build/.last_build_id | 1 + ios/dev-Info.plist | 66 + ios/nightly-Info.plist | 66 + ios/stable-Info.plist | 66 + pubspec.yaml | 1 + 76 files changed, 2696 insertions(+), 172 deletions(-) create mode 100644 .github/workflows/build-iPA.yml create mode 100644 ios/Runner.xcodeproj/xcshareddata/xcschemes/dev.xcscheme create mode 100644 ios/Runner.xcodeproj/xcshareddata/xcschemes/nightly.xcscheme create mode 100644 ios/Runner.xcodeproj/xcshareddata/xcschemes/stable.xcscheme create mode 100644 ios/Runner/Assets.xcassets/AppIcon-nightly.appiconset/AppIcon-nightly-1024x1024@1x.png create mode 100644 ios/Runner/Assets.xcassets/AppIcon-nightly.appiconset/AppIcon-nightly-20x20@1x.png create mode 100644 ios/Runner/Assets.xcassets/AppIcon-nightly.appiconset/AppIcon-nightly-20x20@2x.png create mode 100644 ios/Runner/Assets.xcassets/AppIcon-nightly.appiconset/AppIcon-nightly-20x20@3x.png create mode 100644 ios/Runner/Assets.xcassets/AppIcon-nightly.appiconset/AppIcon-nightly-29x29@1x.png create mode 100644 ios/Runner/Assets.xcassets/AppIcon-nightly.appiconset/AppIcon-nightly-29x29@2x.png create mode 100644 ios/Runner/Assets.xcassets/AppIcon-nightly.appiconset/AppIcon-nightly-29x29@3x.png create mode 100644 ios/Runner/Assets.xcassets/AppIcon-nightly.appiconset/AppIcon-nightly-40x40@1x.png create mode 100644 ios/Runner/Assets.xcassets/AppIcon-nightly.appiconset/AppIcon-nightly-40x40@2x.png create mode 100644 ios/Runner/Assets.xcassets/AppIcon-nightly.appiconset/AppIcon-nightly-40x40@3x.png create mode 100644 ios/Runner/Assets.xcassets/AppIcon-nightly.appiconset/AppIcon-nightly-50x50@1x.png create mode 100644 ios/Runner/Assets.xcassets/AppIcon-nightly.appiconset/AppIcon-nightly-50x50@2x.png create mode 100644 ios/Runner/Assets.xcassets/AppIcon-nightly.appiconset/AppIcon-nightly-57x57@1x.png create mode 100644 ios/Runner/Assets.xcassets/AppIcon-nightly.appiconset/AppIcon-nightly-57x57@2x.png create mode 100644 ios/Runner/Assets.xcassets/AppIcon-nightly.appiconset/AppIcon-nightly-60x60@2x.png create mode 100644 ios/Runner/Assets.xcassets/AppIcon-nightly.appiconset/AppIcon-nightly-60x60@3x.png create mode 100644 ios/Runner/Assets.xcassets/AppIcon-nightly.appiconset/AppIcon-nightly-72x72@1x.png create mode 100644 ios/Runner/Assets.xcassets/AppIcon-nightly.appiconset/AppIcon-nightly-72x72@2x.png create mode 100644 ios/Runner/Assets.xcassets/AppIcon-nightly.appiconset/AppIcon-nightly-76x76@1x.png create mode 100644 ios/Runner/Assets.xcassets/AppIcon-nightly.appiconset/AppIcon-nightly-76x76@2x.png create mode 100644 ios/Runner/Assets.xcassets/AppIcon-nightly.appiconset/AppIcon-nightly-83.5x83.5@2x.png create mode 100644 ios/Runner/Assets.xcassets/AppIcon-nightly.appiconset/Contents.json create mode 100644 ios/Runner/Assets.xcassets/AppIcon.appiconset/AppIcon-1024x1024@1x.png create mode 100644 ios/Runner/Assets.xcassets/AppIcon.appiconset/AppIcon-20x20@1x.png create mode 100644 ios/Runner/Assets.xcassets/AppIcon.appiconset/AppIcon-20x20@2x.png create mode 100644 ios/Runner/Assets.xcassets/AppIcon.appiconset/AppIcon-20x20@3x.png create mode 100644 ios/Runner/Assets.xcassets/AppIcon.appiconset/AppIcon-29x29@1x.png create mode 100644 ios/Runner/Assets.xcassets/AppIcon.appiconset/AppIcon-29x29@2x.png create mode 100644 ios/Runner/Assets.xcassets/AppIcon.appiconset/AppIcon-29x29@3x.png create mode 100644 ios/Runner/Assets.xcassets/AppIcon.appiconset/AppIcon-40x40@1x.png create mode 100644 ios/Runner/Assets.xcassets/AppIcon.appiconset/AppIcon-40x40@2x.png create mode 100644 ios/Runner/Assets.xcassets/AppIcon.appiconset/AppIcon-40x40@3x.png create mode 100644 ios/Runner/Assets.xcassets/AppIcon.appiconset/AppIcon-50x50@1x.png create mode 100644 ios/Runner/Assets.xcassets/AppIcon.appiconset/AppIcon-50x50@2x.png create mode 100644 ios/Runner/Assets.xcassets/AppIcon.appiconset/AppIcon-57x57@1x.png create mode 100644 ios/Runner/Assets.xcassets/AppIcon.appiconset/AppIcon-57x57@2x.png create mode 100644 ios/Runner/Assets.xcassets/AppIcon.appiconset/AppIcon-60x60@2x.png create mode 100644 ios/Runner/Assets.xcassets/AppIcon.appiconset/AppIcon-60x60@3x.png create mode 100644 ios/Runner/Assets.xcassets/AppIcon.appiconset/AppIcon-72x72@1x.png create mode 100644 ios/Runner/Assets.xcassets/AppIcon.appiconset/AppIcon-72x72@2x.png create mode 100644 ios/Runner/Assets.xcassets/AppIcon.appiconset/AppIcon-76x76@1x.png create mode 100644 ios/Runner/Assets.xcassets/AppIcon.appiconset/AppIcon-76x76@2x.png create mode 100644 ios/Runner/Assets.xcassets/AppIcon.appiconset/AppIcon-83.5x83.5@2x.png delete mode 100644 ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png delete mode 100644 ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png delete mode 100644 ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png delete mode 100644 ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png delete mode 100644 ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png delete mode 100644 ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png delete mode 100644 ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png delete mode 100644 ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png delete mode 100644 ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png delete mode 100644 ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png delete mode 100644 ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png delete mode 100644 ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png delete mode 100644 ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png delete mode 100644 ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png delete mode 100644 ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png create mode 100644 ios/Runner/Assets.xcassets/Contents.json create mode 100644 ios/build/.last_build_id create mode 100644 ios/dev-Info.plist create mode 100644 ios/nightly-Info.plist create mode 100644 ios/stable-Info.plist diff --git a/.github/workflows/build-iPA.yml b/.github/workflows/build-iPA.yml new file mode 100644 index 00000000..72e68774 --- /dev/null +++ b/.github/workflows/build-iPA.yml @@ -0,0 +1,42 @@ +name: Build iPA +on: workflow_dispatch + +jobs: + build: + runs-on: macos-latest + steps: + - name: Checkout + uses: actions/checkout@master + - uses: actions/checkout@v4 + - name: submodules-init + uses: snickerbockers/submodules-init@v4 + - name: Set up Flutter + uses: subosito/flutter-action@v2 + with: + channel: 'stable' + - name: Build + run: | + cp .env.example .env + flutter pub get && dart run build_runner build --delete-conflicting-outputs --enable-experiment=records,patterns + flutter build ios --release --no-codesign --flavor dev + flutter build ios --release --no-codesign --flavor stable + flutter build ios --release --no-codesign --flavor nightly + ln -sf ./build/ios/iphoneos Payload + zip -r9 spotube-dev.ipa Payload/dev.app + zip -r9 spotube-stable.ipa Payload/stable.app + zip -r9 spotube-nightly.ipa Payload/nightly.app + - name: Upload spotube-dev.ipa + uses: actions/upload-artifact@v4 + with: + name: "spotube-dev.ipa" + path: "spotube-dev.ipa" + - name: Upload spotube-stable.ipa + uses: actions/upload-artifact@v4 + with: + name: "spotube-stable.ipa" + path: "spotube-stable.ipa" + - name: Upload spotube-nightly.ipa + uses: actions/upload-artifact@v4 + with: + name: "spotube-nightly.ipa" + path: "spotube-nightly.ipa" diff --git a/.github/workflows/spotube-release-binary.yml b/.github/workflows/spotube-release-binary.yml index caeb7238..b561bca8 100644 --- a/.github/workflows/spotube-release-binary.yml +++ b/.github/workflows/spotube-release-binary.yml @@ -321,13 +321,54 @@ jobs: mkdir -p build/${{ env.BUILD_VERSION }} appdmg appdmg.json build/Spotube-macos-universal.dmg + iOS: + + runs-on: macos-latest + steps: + - uses: actions/checkout@v4 + - uses: subosito/flutter-action@v2.10.0 + with: + cache: true + flutter-version: ${{ env.FLUTTER_VERSION }} + + - name: Replace pubspec version and BUILD_VERSION Env (nightly) + if: ${{ inputs.channel == 'nightly' }} + run: | + brew install yq + yq -i '.version |= sub("\+\d+", "+${{ inputs.channel }}.")' pubspec.yaml + yq -i '.version += strenv(GITHUB_RUN_NUMBER)' pubspec.yaml + echo "BUILD_VERSION=${{ inputs.version }}+${{ inputs.channel }}.${{ github.run_number }}" >> $GITHUB_ENV + + - name: BUILD_VERSION Env (stable) + if: ${{ inputs.channel == 'stable' }} + run: | + echo "BUILD_VERSION=${{ inputs.version }}" >> $GITHUB_ENV + + - name: Create Stable .env + if: ${{ inputs.channel == 'stable' }} + run: echo '${{ secrets.DOTENV_RELEASE }}' > .env + + - name: Create Nightly .env + if: ${{ inputs.channel == 'nightly' }} + run: echo '${{ secrets.DOTENV_NIGHTLY }}' > .env + + - name: Generate Secrets + run: | + flutter pub get + dart run build_runner build --delete-conflicting-outputs --enable-experiment=records,patterns + + - name: Build iOS iPA + run: | + flutter build ios --release --no-codesign --flavor ${{ inputs.channel }} + ln -sf ./build/ios/iphoneos Payload + zip -r9 Spotube-iOS.ipa Payload/${{ inputs.channel }}.app - uses: actions/upload-artifact@v3 with: if-no-files-found: error name: Spotube-Release-Binaries path: | - build/Spotube-macos-universal.dmg + Spotube-iOS.ipa - name: Debug With SSH When fails if: ${{ failure() && inputs.debug && inputs.channel == 'nightly' }} @@ -343,6 +384,7 @@ jobs: - linux - android - macos + - iOS steps: - uses: actions/download-artifact@v3 with: diff --git a/flutter_launcher_icons-nightly.yaml b/flutter_launcher_icons-nightly.yaml index e531efd4..c6892d4b 100644 --- a/flutter_launcher_icons-nightly.yaml +++ b/flutter_launcher_icons-nightly.yaml @@ -1,5 +1,6 @@ flutter_launcher_icons: android: true + ios: true image_path: "assets/spotube-nightly-logo.png" adaptive_icon_foreground: "assets/spotube-nightly-logo-foreground.jpg" adaptive_icon_background: "#242832" diff --git a/ios/Podfile b/ios/Podfile index cfd01b62..5b0d5a2c 100644 --- a/ios/Podfile +++ b/ios/Podfile @@ -34,6 +34,27 @@ target 'Runner' do flutter_install_all_ios_pods File.dirname(File.realpath(__FILE__)) end +target 'dev' do + use_frameworks! + use_modular_headers! + + flutter_install_all_ios_pods File.dirname(File.realpath(__FILE__)) +end + +target 'stable' do + use_frameworks! + use_modular_headers! + + flutter_install_all_ios_pods File.dirname(File.realpath(__FILE__)) +end + +target 'nightly' do + use_frameworks! + use_modular_headers! + + flutter_install_all_ios_pods File.dirname(File.realpath(__FILE__)) +end + post_install do |installer| installer.pods_project.targets.each do |target| flutter_additional_ios_build_settings(target) diff --git a/ios/Podfile.lock b/ios/Podfile.lock index 68fcdacc..35f3dc18 100644 --- a/ios/Podfile.lock +++ b/ios/Podfile.lock @@ -1,13 +1,12 @@ PODS: + - app_links (0.0.1): + - Flutter - audio_service (0.0.1): - Flutter - audio_session (0.0.1): - Flutter - - audioplayers_darwin (0.0.1): + - device_info_plus (0.0.1): - Flutter - - connectivity_plus (0.0.1): - - Flutter - - ReachabilitySwift - DKImagePickerController/Core (4.3.4): - DKImagePickerController/ImageDataManager - DKImagePickerController/Resource @@ -42,6 +41,8 @@ PODS: - file_picker (0.0.1): - DKImagePickerController/PhotoGallery - Flutter + - file_selector_ios (0.0.1): + - Flutter - Flutter (1.0.0) - flutter_inappwebview (0.0.1): - Flutter @@ -50,44 +51,77 @@ PODS: - flutter_inappwebview/Core (0.0.1): - Flutter - OrderedSet (~> 5.0) + - flutter_keyboard_visibility (0.0.1): + - Flutter + - flutter_mailer (0.0.1): + - Flutter + - flutter_native_splash (0.0.1): + - Flutter + - flutter_secure_storage (6.0.0): + - Flutter + - flutter_sharing_intent (0.0.1): + - Flutter + - fluttertoast (0.0.2): + - Flutter + - Toast - FMDB (2.7.5): - FMDB/standard (= 2.7.5) - FMDB/standard (2.7.5) - - metadata_god (0.0.1): + - image_picker_ios (0.0.1): - Flutter + - integration_test (0.0.1): + - Flutter + - media_kit_libs_ios_audio (1.0.4): + - Flutter + - media_kit_native_event_loop (1.0.0): + - Flutter + - metadata_god (0.0.1) - OrderedSet (5.0.0) - package_info_plus (0.4.5): - Flutter - - path_provider_ios (0.0.1): + - path_provider_foundation (0.0.1): - Flutter - - permission_handler_apple (9.0.4): + - FlutterMacOS + - permission_handler_apple (9.1.1): - Flutter - - ReachabilitySwift (5.0.0) - - SDWebImage (5.13.4): - - SDWebImage/Core (= 5.13.4) - - SDWebImage/Core (5.13.4) - - shared_preferences_ios (0.0.1): + - SDWebImage (5.18.8): + - SDWebImage/Core (= 5.18.8) + - SDWebImage/Core (5.18.8) + - shared_preferences_foundation (0.0.1): - Flutter - - sqflite (0.0.2): + - FlutterMacOS + - sqflite (0.0.3): - Flutter - FMDB (>= 2.7.5) - - SwiftyGif (5.4.3) + - SwiftyGif (5.4.4) + - Toast (4.0.0) - url_launcher_ios (0.0.1): - Flutter DEPENDENCIES: + - app_links (from `.symlinks/plugins/app_links/ios`) - audio_service (from `.symlinks/plugins/audio_service/ios`) - audio_session (from `.symlinks/plugins/audio_session/ios`) - - audioplayers_darwin (from `.symlinks/plugins/audioplayers_darwin/ios`) - - connectivity_plus (from `.symlinks/plugins/connectivity_plus/ios`) + - device_info_plus (from `.symlinks/plugins/device_info_plus/ios`) - file_picker (from `.symlinks/plugins/file_picker/ios`) + - file_selector_ios (from `.symlinks/plugins/file_selector_ios/ios`) - Flutter (from `Flutter`) - flutter_inappwebview (from `.symlinks/plugins/flutter_inappwebview/ios`) + - flutter_keyboard_visibility (from `.symlinks/plugins/flutter_keyboard_visibility/ios`) + - flutter_mailer (from `.symlinks/plugins/flutter_mailer/ios`) + - flutter_native_splash (from `.symlinks/plugins/flutter_native_splash/ios`) + - flutter_secure_storage (from `.symlinks/plugins/flutter_secure_storage/ios`) + - flutter_sharing_intent (from `.symlinks/plugins/flutter_sharing_intent/ios`) + - fluttertoast (from `.symlinks/plugins/fluttertoast/ios`) + - image_picker_ios (from `.symlinks/plugins/image_picker_ios/ios`) + - integration_test (from `.symlinks/plugins/integration_test/ios`) + - media_kit_libs_ios_audio (from `.symlinks/plugins/media_kit_libs_ios_audio/ios`) + - media_kit_native_event_loop (from `.symlinks/plugins/media_kit_native_event_loop/ios`) - metadata_god (from `.symlinks/plugins/metadata_god/ios`) - package_info_plus (from `.symlinks/plugins/package_info_plus/ios`) - - path_provider_ios (from `.symlinks/plugins/path_provider_ios/ios`) + - path_provider_foundation (from `.symlinks/plugins/path_provider_foundation/darwin`) - permission_handler_apple (from `.symlinks/plugins/permission_handler_apple/ios`) - - shared_preferences_ios (from `.symlinks/plugins/shared_preferences_ios/ios`) + - shared_preferences_foundation (from `.symlinks/plugins/shared_preferences_foundation/darwin`) - sqflite (from `.symlinks/plugins/sqflite/ios`) - url_launcher_ios (from `.symlinks/plugins/url_launcher_ios/ios`) @@ -97,63 +131,96 @@ SPEC REPOS: - DKPhotoGallery - FMDB - OrderedSet - - ReachabilitySwift - SDWebImage - SwiftyGif + - Toast EXTERNAL SOURCES: + app_links: + :path: ".symlinks/plugins/app_links/ios" audio_service: :path: ".symlinks/plugins/audio_service/ios" audio_session: :path: ".symlinks/plugins/audio_session/ios" - audioplayers_darwin: - :path: ".symlinks/plugins/audioplayers_darwin/ios" - connectivity_plus: - :path: ".symlinks/plugins/connectivity_plus/ios" + device_info_plus: + :path: ".symlinks/plugins/device_info_plus/ios" file_picker: :path: ".symlinks/plugins/file_picker/ios" + file_selector_ios: + :path: ".symlinks/plugins/file_selector_ios/ios" Flutter: :path: Flutter flutter_inappwebview: :path: ".symlinks/plugins/flutter_inappwebview/ios" + flutter_keyboard_visibility: + :path: ".symlinks/plugins/flutter_keyboard_visibility/ios" + flutter_mailer: + :path: ".symlinks/plugins/flutter_mailer/ios" + flutter_native_splash: + :path: ".symlinks/plugins/flutter_native_splash/ios" + flutter_secure_storage: + :path: ".symlinks/plugins/flutter_secure_storage/ios" + flutter_sharing_intent: + :path: ".symlinks/plugins/flutter_sharing_intent/ios" + fluttertoast: + :path: ".symlinks/plugins/fluttertoast/ios" + image_picker_ios: + :path: ".symlinks/plugins/image_picker_ios/ios" + integration_test: + :path: ".symlinks/plugins/integration_test/ios" + media_kit_libs_ios_audio: + :path: ".symlinks/plugins/media_kit_libs_ios_audio/ios" + media_kit_native_event_loop: + :path: ".symlinks/plugins/media_kit_native_event_loop/ios" metadata_god: :path: ".symlinks/plugins/metadata_god/ios" package_info_plus: :path: ".symlinks/plugins/package_info_plus/ios" - path_provider_ios: - :path: ".symlinks/plugins/path_provider_ios/ios" + path_provider_foundation: + :path: ".symlinks/plugins/path_provider_foundation/darwin" permission_handler_apple: :path: ".symlinks/plugins/permission_handler_apple/ios" - shared_preferences_ios: - :path: ".symlinks/plugins/shared_preferences_ios/ios" + shared_preferences_foundation: + :path: ".symlinks/plugins/shared_preferences_foundation/darwin" sqflite: :path: ".symlinks/plugins/sqflite/ios" url_launcher_ios: :path: ".symlinks/plugins/url_launcher_ios/ios" SPEC CHECKSUMS: + app_links: 5ef33d0d295a89d9d16bb81b0e3b0d5f70d6c875 audio_service: f509d65da41b9521a61f1c404dd58651f265a567 audio_session: 4f3e461722055d21515cf3261b64c973c062f345 - audioplayers_darwin: 387322cb364026a1782298c982693b1b6aa9fa1b - connectivity_plus: 413a8857dd5d9f1c399a39130850d02fe0feaf7e + device_info_plus: 7545d84d8d1b896cb16a4ff98c19f07ec4b298ea DKImagePickerController: b512c28220a2b8ac7419f21c491fc8534b7601ac DKPhotoGallery: fdfad5125a9fdda9cc57df834d49df790dbb4179 - file_picker: 817ab1d8cd2da9d2da412a417162deee3500fc95 + file_picker: 15fd9539e4eb735dc54bae8c0534a7a9511a03de + file_selector_ios: 8c25d700d625e1dcdd6599f2d927072f2254647b Flutter: f04841e97a9d0b0a8025694d0796dd46242b2854 - flutter_inappwebview: bfd58618f49dc62f2676de690fc6dcda1d6c3721 + flutter_inappwebview: acd4fc0f012cefd09015000c241137d82f01ba62 + flutter_keyboard_visibility: 0339d06371254c3eb25eeb90ba8d17dca8f9c069 + flutter_mailer: 2ef5a67087bc8c6c4cefd04a178bf1ae2c94cd83 + flutter_native_splash: 52501b97d1c0a5f898d687f1646226c1f93c56ef + flutter_secure_storage: 23fc622d89d073675f2eaa109381aefbcf5a49be + flutter_sharing_intent: e35380d0e1501d7111dbb7e46d5ac6339da6da98 + fluttertoast: 31b00dabfa7fb7bacd9e7dbee580d7a2ff4bf265 FMDB: 2ce00b547f966261cd18927a3ddb07cb6f3db82a - metadata_god: cebcc48708aca3e9d1ef60c74b23404ff3730d5e + image_picker_ios: 4a8aadfbb6dc30ad5141a2ce3832af9214a705b5 + integration_test: 13825b8a9334a850581300559b8839134b124670 + media_kit_libs_ios_audio: 8f39d96a9c630685dfb844c289bd1d114c486fb3 + media_kit_native_event_loop: 99111eded5acbdc9c2738021ea6550dd36ca8837 + metadata_god: eceae399d0020475069a5cebc35943ce8562b5d7 OrderedSet: aaeb196f7fef5a9edf55d89760da9176ad40b93c - package_info_plus: 6c92f08e1f853dc01228d6f553146438dafcd14e - path_provider_ios: 14f3d2fd28c4fdb42f44e0f751d12861c43cee02 - permission_handler_apple: 44366e37eaf29454a1e7b1b7d736c2cceaeb17ce - ReachabilitySwift: 985039c6f7b23a1da463388634119492ff86c825 - SDWebImage: e5cc87bf736e60f49592f307bdf9e157189298a3 - shared_preferences_ios: 548a61f8053b9b8a49ac19c1ffbc8b92c50d68ad - sqflite: 6d358c025f5b867b29ed92fc697fd34924e11904 - SwiftyGif: 6c3eafd0ce693cad58bb63d2b2fb9bacb8552780 - url_launcher_ios: 839c58cdb4279282219f5e248c3321761ff3c4de + package_info_plus: fd030dabf36271f146f1f3beacd48f564b0f17f7 + path_provider_foundation: 29f094ae23ebbca9d3d0cec13889cd9060c0e943 + permission_handler_apple: e76247795d700c14ea09e3a2d8855d41ee80a2e6 + SDWebImage: a81bbb3ba4ea5f810f4069c68727cb118467a04a + shared_preferences_foundation: 5b919d13b803cadd15ed2dc053125c68730e5126 + sqflite: 31f7eba61e3074736dff8807a9b41581e4f7f15a + SwiftyGif: 93a1cc87bf3a51916001cf8f3d63835fb64c819f + Toast: 91b396c56ee72a5790816f40d3a94dd357abc196 + url_launcher_ios: 08a3dfac5fb39e8759aeb0abbd5d9480f30fc8b4 -PODFILE CHECKSUM: e9ba2289804955e1370e293b204c6e8651354f4a +PODFILE CHECKSUM: e36c7ad9836dfd8d22934c7680185432a658e28f -COCOAPODS: 1.11.3 +COCOAPODS: 1.14.3 diff --git a/ios/Runner.xcodeproj/project.pbxproj b/ios/Runner.xcodeproj/project.pbxproj index d9cf2138..8b7c2b1e 100644 --- a/ios/Runner.xcodeproj/project.pbxproj +++ b/ios/Runner.xcodeproj/project.pbxproj @@ -3,17 +3,39 @@ archiveVersion = 1; classes = { }; - objectVersion = 50; + objectVersion = 54; objects = { /* Begin PBXBuildFile section */ + 051977801F58E8DBB6712352 /* Pods_Runner.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = F7E9EBDD27997A73A4D38EE1 /* Pods_Runner.framework */; }; 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */ = {isa = PBXBuildFile; fileRef = 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */; }; + 17438EB903776D8D0E926C9B /* Pods_nightly.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = BAC36FC304DBD4E8A8C00694 /* Pods_nightly.framework */; }; 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */ = {isa = PBXBuildFile; fileRef = 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */; }; 46249B26D47C5DB81A4F972E /* Pods_Runner.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = F7E9EBDD27997A73A4D38EE1 /* Pods_Runner.framework */; }; + 4E86E0C42011EDB42C34AF9A /* Pods_stable.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = B5F91A319C771EEC978B238A /* Pods_stable.framework */; }; 74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 74858FAE1ED2DC5600515810 /* AppDelegate.swift */; }; 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FA1CF9000F007C117D /* Main.storyboard */; }; 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FD1CF9000F007C117D /* Assets.xcassets */; }; 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */; }; + B536BD902B405DB1009B3CE4 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 74858FAE1ED2DC5600515810 /* AppDelegate.swift */; }; + B536BD912B405DB1009B3CE4 /* GeneratedPluginRegistrant.m in Sources */ = {isa = PBXBuildFile; fileRef = 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */; }; + B536BD952B405DB1009B3CE4 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */; }; + B536BD962B405DB1009B3CE4 /* AppFrameworkInfo.plist in Resources */ = {isa = PBXBuildFile; fileRef = 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */; }; + B536BD972B405DB1009B3CE4 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FD1CF9000F007C117D /* Assets.xcassets */; }; + B536BD982B405DB1009B3CE4 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FA1CF9000F007C117D /* Main.storyboard */; }; + B536BDAE2B405FDE009B3CE4 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 74858FAE1ED2DC5600515810 /* AppDelegate.swift */; }; + B536BDAF2B405FDE009B3CE4 /* GeneratedPluginRegistrant.m in Sources */ = {isa = PBXBuildFile; fileRef = 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */; }; + B536BDB22B405FDE009B3CE4 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */; }; + B536BDB32B405FDE009B3CE4 /* AppFrameworkInfo.plist in Resources */ = {isa = PBXBuildFile; fileRef = 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */; }; + B536BDB42B405FDE009B3CE4 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FD1CF9000F007C117D /* Assets.xcassets */; }; + B536BDB52B405FDE009B3CE4 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FA1CF9000F007C117D /* Main.storyboard */; }; + B536BDD02B4060B3009B3CE4 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 74858FAE1ED2DC5600515810 /* AppDelegate.swift */; }; + B536BDD12B4060B3009B3CE4 /* GeneratedPluginRegistrant.m in Sources */ = {isa = PBXBuildFile; fileRef = 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */; }; + B536BDD42B4060B3009B3CE4 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */; }; + B536BDD52B4060B3009B3CE4 /* AppFrameworkInfo.plist in Resources */ = {isa = PBXBuildFile; fileRef = 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */; }; + B536BDD62B4060B3009B3CE4 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FD1CF9000F007C117D /* Assets.xcassets */; }; + B536BDD72B4060B3009B3CE4 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FA1CF9000F007C117D /* Main.storyboard */; }; + C36A05AD330BBFAED75A62D5 /* Pods_dev.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4238A4985255EC9F93067739 /* Pods_dev.framework */; }; /* End PBXBuildFile section */ /* Begin PBXCopyFilesBuildPhase section */ @@ -27,17 +49,78 @@ name = "Embed Frameworks"; runOnlyForDeploymentPostprocessing = 0; }; + B536BD992B405DB1009B3CE4 /* Embed Frameworks */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 2147483647; + dstPath = ""; + dstSubfolderSpec = 10; + files = ( + ); + name = "Embed Frameworks"; + runOnlyForDeploymentPostprocessing = 0; + }; + B536BDB62B405FDE009B3CE4 /* Embed Frameworks */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 2147483647; + dstPath = ""; + dstSubfolderSpec = 10; + files = ( + ); + name = "Embed Frameworks"; + runOnlyForDeploymentPostprocessing = 0; + }; + B536BDD82B4060B3009B3CE4 /* Embed Frameworks */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 2147483647; + dstPath = ""; + dstSubfolderSpec = 10; + files = ( + ); + name = "Embed Frameworks"; + runOnlyForDeploymentPostprocessing = 0; + }; /* End PBXCopyFilesBuildPhase section */ /* Begin PBXFileReference section */ + 04C104D3779B4D1635D939BF /* Pods-Runner.profile-nightly.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.profile-nightly.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.profile-nightly.xcconfig"; sourceTree = ""; }; + 0F8FB58820FF492BD3CF9315 /* Pods-nightly.debug-stable.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-nightly.debug-stable.xcconfig"; path = "Target Support Files/Pods-nightly/Pods-nightly.debug-stable.xcconfig"; sourceTree = ""; }; + 126B91CED32FAD3C40A67A23 /* Pods-dev.debug-stable.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-dev.debug-stable.xcconfig"; path = "Target Support Files/Pods-dev/Pods-dev.debug-stable.xcconfig"; sourceTree = ""; }; 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GeneratedPluginRegistrant.h; sourceTree = ""; }; 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GeneratedPluginRegistrant.m; sourceTree = ""; }; 171073CFF94F5751BC2B78DD /* Pods-Runner.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.profile.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.profile.xcconfig"; sourceTree = ""; }; + 1C9810F8B3FD927ED8C94791 /* Pods-dev.profile-nightly.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-dev.profile-nightly.xcconfig"; path = "Target Support Files/Pods-dev/Pods-dev.profile-nightly.xcconfig"; sourceTree = ""; }; + 21C0B1DEE0F0BFD3F3651F79 /* Pods-stable.debug-nightly.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-stable.debug-nightly.xcconfig"; path = "Target Support Files/Pods-stable/Pods-stable.debug-nightly.xcconfig"; sourceTree = ""; }; + 261A31AC0DBA2D93BD1910D9 /* Pods-nightly.profile-nightly.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-nightly.profile-nightly.xcconfig"; path = "Target Support Files/Pods-nightly/Pods-nightly.profile-nightly.xcconfig"; sourceTree = ""; }; + 285DE2278D380EE2A6647CA9 /* Pods-nightly.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-nightly.debug.xcconfig"; path = "Target Support Files/Pods-nightly/Pods-nightly.debug.xcconfig"; sourceTree = ""; }; + 29304D1832AA30DE0C33E05C /* Pods-dev.profile-stable.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-dev.profile-stable.xcconfig"; path = "Target Support Files/Pods-dev/Pods-dev.profile-stable.xcconfig"; sourceTree = ""; }; + 2DA87118BE2AF25875B7C376 /* Pods-stable.release-stable.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-stable.release-stable.xcconfig"; path = "Target Support Files/Pods-stable/Pods-stable.release-stable.xcconfig"; sourceTree = ""; }; + 2F9AD76AF35FFC693C051CE1 /* Pods-dev.release-nightly.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-dev.release-nightly.xcconfig"; path = "Target Support Files/Pods-dev/Pods-dev.release-nightly.xcconfig"; sourceTree = ""; }; + 39E15EE1745C9266FDB59558 /* Pods-stable.debug-dev.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-stable.debug-dev.xcconfig"; path = "Target Support Files/Pods-stable/Pods-stable.debug-dev.xcconfig"; sourceTree = ""; }; 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = AppFrameworkInfo.plist; path = Flutter/AppFrameworkInfo.plist; sourceTree = ""; }; + 3E262038FF3BDA3B8A7BDAC3 /* Pods-Runner.release-dev.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.release-dev.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.release-dev.xcconfig"; sourceTree = ""; }; + 3F754C793C1BC0E8B8FFB5B7 /* Pods-stable.profile-stable.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-stable.profile-stable.xcconfig"; path = "Target Support Files/Pods-stable/Pods-stable.profile-stable.xcconfig"; sourceTree = ""; }; + 4238A4985255EC9F93067739 /* Pods_dev.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_dev.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + 46E04A5AA989356A32CD8E66 /* Pods-dev.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-dev.profile.xcconfig"; path = "Target Support Files/Pods-dev/Pods-dev.profile.xcconfig"; sourceTree = ""; }; + 48E7E801EAE1B520AA5F35DD /* Pods-dev.profile-dev.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-dev.profile-dev.xcconfig"; path = "Target Support Files/Pods-dev/Pods-dev.profile-dev.xcconfig"; sourceTree = ""; }; + 4BDAF8FFADB62CA017755094 /* Pods-stable.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-stable.profile.xcconfig"; path = "Target Support Files/Pods-stable/Pods-stable.profile.xcconfig"; sourceTree = ""; }; + 5014E8BD9F7181E528538444 /* Pods-stable.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-stable.release.xcconfig"; path = "Target Support Files/Pods-stable/Pods-stable.release.xcconfig"; sourceTree = ""; }; + 53AD516AAEB9A1331C99CBAE /* Pods-stable.profile-dev.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-stable.profile-dev.xcconfig"; path = "Target Support Files/Pods-stable/Pods-stable.profile-dev.xcconfig"; sourceTree = ""; }; + 5A8B64E98ADDA28FB63AA32C /* Pods-Runner.release-nightly.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.release-nightly.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.release-nightly.xcconfig"; sourceTree = ""; }; + 636F4A85470D9E3B4CC8AFB8 /* Pods-nightly.profile-dev.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-nightly.profile-dev.xcconfig"; path = "Target Support Files/Pods-nightly/Pods-nightly.profile-dev.xcconfig"; sourceTree = ""; }; 66F649AFA6E49EA44F469DA3 /* Pods-Runner.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.debug.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.debug.xcconfig"; sourceTree = ""; }; + 68BE49B58C0EBB578948D773 /* Pods-nightly.release-dev.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-nightly.release-dev.xcconfig"; path = "Target Support Files/Pods-nightly/Pods-nightly.release-dev.xcconfig"; sourceTree = ""; }; + 6AE8151F4499707FA23C8223 /* Pods-dev.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-dev.debug.xcconfig"; path = "Target Support Files/Pods-dev/Pods-dev.debug.xcconfig"; sourceTree = ""; }; 74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Runner-Bridging-Header.h"; sourceTree = ""; }; 74858FAE1ED2DC5600515810 /* AppDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; + 77EFEBB27B276DD5F6B01B4B /* Pods-Runner.debug-nightly.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.debug-nightly.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.debug-nightly.xcconfig"; sourceTree = ""; }; 7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = Release.xcconfig; path = Flutter/Release.xcconfig; sourceTree = ""; }; + 864AC9150518DFBA85A46A15 /* Pods-stable.release-dev.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-stable.release-dev.xcconfig"; path = "Target Support Files/Pods-stable/Pods-stable.release-dev.xcconfig"; sourceTree = ""; }; + 869E7B97AE866F2BCA2E5A6A /* Pods-Runner.release-stable.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.release-stable.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.release-stable.xcconfig"; sourceTree = ""; }; + 89CD409D60E1362C529707A4 /* Pods-nightly.release-nightly.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-nightly.release-nightly.xcconfig"; path = "Target Support Files/Pods-nightly/Pods-nightly.release-nightly.xcconfig"; sourceTree = ""; }; + 8AD587044EF2C6A6FA3059DC /* Pods-stable.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-stable.debug.xcconfig"; path = "Target Support Files/Pods-stable/Pods-stable.debug.xcconfig"; sourceTree = ""; }; + 8B9DFB8E20C11066C3AB696A /* Pods-dev.debug-nightly.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-dev.debug-nightly.xcconfig"; path = "Target Support Files/Pods-dev/Pods-dev.debug-nightly.xcconfig"; sourceTree = ""; }; + 8CF39CF9464623571B63D15B /* Pods-nightly.release-stable.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-nightly.release-stable.xcconfig"; path = "Target Support Files/Pods-nightly/Pods-nightly.release-stable.xcconfig"; sourceTree = ""; }; + 9232DBE472C8CEA1101843D9 /* Pods-nightly.profile-stable.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-nightly.profile-stable.xcconfig"; path = "Target Support Files/Pods-nightly/Pods-nightly.profile-stable.xcconfig"; sourceTree = ""; }; 9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Debug.xcconfig; path = Flutter/Debug.xcconfig; sourceTree = ""; }; 9740EEB31CF90195004384FC /* Generated.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Generated.xcconfig; path = Flutter/Generated.xcconfig; sourceTree = ""; }; 97C146EE1CF9000F007C117D /* Runner.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Runner.app; sourceTree = BUILT_PRODUCTS_DIR; }; @@ -45,7 +128,30 @@ 97C146FD1CF9000F007C117D /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 97C147001CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; 97C147021CF9000F007C117D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + 9878519B106548FD75CA15C0 /* Pods-nightly.debug-dev.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-nightly.debug-dev.xcconfig"; path = "Target Support Files/Pods-nightly/Pods-nightly.debug-dev.xcconfig"; sourceTree = ""; }; + A59B7A01EEC476AF3141B518 /* Pods-Runner.debug-dev.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.debug-dev.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.debug-dev.xcconfig"; sourceTree = ""; }; + B38E6C7315D66215AFD8B218 /* Pods-stable.profile-nightly.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-stable.profile-nightly.xcconfig"; path = "Target Support Files/Pods-stable/Pods-stable.profile-nightly.xcconfig"; sourceTree = ""; }; + B536BDA02B405DB1009B3CE4 /* stable.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = stable.app; sourceTree = BUILT_PRODUCTS_DIR; }; + B536BDA12B405DB1009B3CE4 /* stable-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; name = "stable-Info.plist"; path = "/Users/xiaobowen/Documents/GitHub/spotube/ios/stable-Info.plist"; sourceTree = ""; }; + B536BDBF2B405FDE009B3CE4 /* dev.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = dev.app; sourceTree = BUILT_PRODUCTS_DIR; }; + B536BDC02B405FDE009B3CE4 /* dev-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; name = "dev-Info.plist"; path = "/Users/xiaobowen/Documents/GitHub/spotube/ios/dev-Info.plist"; sourceTree = ""; }; + B536BDE42B4060B3009B3CE4 /* nightly.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = nightly.app; sourceTree = BUILT_PRODUCTS_DIR; }; + B536BDE52B4060B3009B3CE4 /* nightly-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; name = "nightly-Info.plist"; path = "/Users/xiaobowen/Documents/GitHub/spotube/ios/nightly-Info.plist"; sourceTree = ""; }; + B5F91A319C771EEC978B238A /* Pods_stable.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_stable.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + B95530D9046F7F9BA07D2ADD /* Pods-Runner.profile-stable.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.profile-stable.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.profile-stable.xcconfig"; sourceTree = ""; }; + BAC36FC304DBD4E8A8C00694 /* Pods_nightly.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_nightly.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + BDE1B62C8A5219CAA5D19583 /* Pods-nightly.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-nightly.release.xcconfig"; path = "Target Support Files/Pods-nightly/Pods-nightly.release.xcconfig"; sourceTree = ""; }; + C3F494F4E243EAE21CEC5765 /* Pods-Runner.profile-dev.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.profile-dev.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.profile-dev.xcconfig"; sourceTree = ""; }; + C63F01302EF00EAECE6BEA7C /* Pods-dev.release-dev.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-dev.release-dev.xcconfig"; path = "Target Support Files/Pods-dev/Pods-dev.release-dev.xcconfig"; sourceTree = ""; }; + CA0F4EAB0789E68A7C771A07 /* Pods-nightly.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-nightly.profile.xcconfig"; path = "Target Support Files/Pods-nightly/Pods-nightly.profile.xcconfig"; sourceTree = ""; }; CE8646F5A4BCC46B0416DC84 /* Pods-Runner.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.release.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.release.xcconfig"; sourceTree = ""; }; + D32BAE0F55672DD7669755B8 /* Pods-Runner.debug-stable.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Runner.debug-stable.xcconfig"; path = "Target Support Files/Pods-Runner/Pods-Runner.debug-stable.xcconfig"; sourceTree = ""; }; + D9A69004587D01A7C68666CF /* Pods-dev.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-dev.release.xcconfig"; path = "Target Support Files/Pods-dev/Pods-dev.release.xcconfig"; sourceTree = ""; }; + E0EAB4380EE7C7EA7A350B6F /* Pods-stable.release-nightly.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-stable.release-nightly.xcconfig"; path = "Target Support Files/Pods-stable/Pods-stable.release-nightly.xcconfig"; sourceTree = ""; }; + E81F11471FD7D807286E33D6 /* Pods-dev.debug-dev.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-dev.debug-dev.xcconfig"; path = "Target Support Files/Pods-dev/Pods-dev.debug-dev.xcconfig"; sourceTree = ""; }; + EB7783C1029CEC13F4B05D36 /* Pods-nightly.debug-nightly.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-nightly.debug-nightly.xcconfig"; path = "Target Support Files/Pods-nightly/Pods-nightly.debug-nightly.xcconfig"; sourceTree = ""; }; + EBBED0A8DE0D0E230CD03613 /* Pods-dev.release-stable.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-dev.release-stable.xcconfig"; path = "Target Support Files/Pods-dev/Pods-dev.release-stable.xcconfig"; sourceTree = ""; }; + F6F397A82E788E50B186ADC7 /* Pods-stable.debug-stable.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-stable.debug-stable.xcconfig"; path = "Target Support Files/Pods-stable/Pods-stable.debug-stable.xcconfig"; sourceTree = ""; }; F7E9EBDD27997A73A4D38EE1 /* Pods_Runner.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Runner.framework; sourceTree = BUILT_PRODUCTS_DIR; }; /* End PBXFileReference section */ @@ -55,6 +161,31 @@ buildActionMask = 2147483647; files = ( 46249B26D47C5DB81A4F972E /* Pods_Runner.framework in Frameworks */, + 051977801F58E8DBB6712352 /* Pods_Runner.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + B536BD922B405DB1009B3CE4 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 4E86E0C42011EDB42C34AF9A /* Pods_stable.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + B536BDB02B405FDE009B3CE4 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + C36A05AD330BBFAED75A62D5 /* Pods_dev.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + B536BDD22B4060B3009B3CE4 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 17438EB903776D8D0E926C9B /* Pods_nightly.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -65,6 +196,9 @@ isa = PBXGroup; children = ( F7E9EBDD27997A73A4D38EE1 /* Pods_Runner.framework */, + 4238A4985255EC9F93067739 /* Pods_dev.framework */, + BAC36FC304DBD4E8A8C00694 /* Pods_nightly.framework */, + B5F91A319C771EEC978B238A /* Pods_stable.framework */, ); name = Frameworks; sourceTree = ""; @@ -75,8 +209,52 @@ 66F649AFA6E49EA44F469DA3 /* Pods-Runner.debug.xcconfig */, CE8646F5A4BCC46B0416DC84 /* Pods-Runner.release.xcconfig */, 171073CFF94F5751BC2B78DD /* Pods-Runner.profile.xcconfig */, + D32BAE0F55672DD7669755B8 /* Pods-Runner.debug-stable.xcconfig */, + 869E7B97AE866F2BCA2E5A6A /* Pods-Runner.release-stable.xcconfig */, + B95530D9046F7F9BA07D2ADD /* Pods-Runner.profile-stable.xcconfig */, + A59B7A01EEC476AF3141B518 /* Pods-Runner.debug-dev.xcconfig */, + 3E262038FF3BDA3B8A7BDAC3 /* Pods-Runner.release-dev.xcconfig */, + C3F494F4E243EAE21CEC5765 /* Pods-Runner.profile-dev.xcconfig */, + 77EFEBB27B276DD5F6B01B4B /* Pods-Runner.debug-nightly.xcconfig */, + 5A8B64E98ADDA28FB63AA32C /* Pods-Runner.release-nightly.xcconfig */, + 04C104D3779B4D1635D939BF /* Pods-Runner.profile-nightly.xcconfig */, + 6AE8151F4499707FA23C8223 /* Pods-dev.debug.xcconfig */, + 8B9DFB8E20C11066C3AB696A /* Pods-dev.debug-nightly.xcconfig */, + E81F11471FD7D807286E33D6 /* Pods-dev.debug-dev.xcconfig */, + 126B91CED32FAD3C40A67A23 /* Pods-dev.debug-stable.xcconfig */, + D9A69004587D01A7C68666CF /* Pods-dev.release.xcconfig */, + 2F9AD76AF35FFC693C051CE1 /* Pods-dev.release-nightly.xcconfig */, + C63F01302EF00EAECE6BEA7C /* Pods-dev.release-dev.xcconfig */, + EBBED0A8DE0D0E230CD03613 /* Pods-dev.release-stable.xcconfig */, + 46E04A5AA989356A32CD8E66 /* Pods-dev.profile.xcconfig */, + 1C9810F8B3FD927ED8C94791 /* Pods-dev.profile-nightly.xcconfig */, + 48E7E801EAE1B520AA5F35DD /* Pods-dev.profile-dev.xcconfig */, + 29304D1832AA30DE0C33E05C /* Pods-dev.profile-stable.xcconfig */, + 285DE2278D380EE2A6647CA9 /* Pods-nightly.debug.xcconfig */, + EB7783C1029CEC13F4B05D36 /* Pods-nightly.debug-nightly.xcconfig */, + 9878519B106548FD75CA15C0 /* Pods-nightly.debug-dev.xcconfig */, + 0F8FB58820FF492BD3CF9315 /* Pods-nightly.debug-stable.xcconfig */, + BDE1B62C8A5219CAA5D19583 /* Pods-nightly.release.xcconfig */, + 89CD409D60E1362C529707A4 /* Pods-nightly.release-nightly.xcconfig */, + 68BE49B58C0EBB578948D773 /* Pods-nightly.release-dev.xcconfig */, + 8CF39CF9464623571B63D15B /* Pods-nightly.release-stable.xcconfig */, + CA0F4EAB0789E68A7C771A07 /* Pods-nightly.profile.xcconfig */, + 261A31AC0DBA2D93BD1910D9 /* Pods-nightly.profile-nightly.xcconfig */, + 636F4A85470D9E3B4CC8AFB8 /* Pods-nightly.profile-dev.xcconfig */, + 9232DBE472C8CEA1101843D9 /* Pods-nightly.profile-stable.xcconfig */, + 8AD587044EF2C6A6FA3059DC /* Pods-stable.debug.xcconfig */, + 21C0B1DEE0F0BFD3F3651F79 /* Pods-stable.debug-nightly.xcconfig */, + 39E15EE1745C9266FDB59558 /* Pods-stable.debug-dev.xcconfig */, + F6F397A82E788E50B186ADC7 /* Pods-stable.debug-stable.xcconfig */, + 5014E8BD9F7181E528538444 /* Pods-stable.release.xcconfig */, + E0EAB4380EE7C7EA7A350B6F /* Pods-stable.release-nightly.xcconfig */, + 864AC9150518DFBA85A46A15 /* Pods-stable.release-dev.xcconfig */, + 2DA87118BE2AF25875B7C376 /* Pods-stable.release-stable.xcconfig */, + 4BDAF8FFADB62CA017755094 /* Pods-stable.profile.xcconfig */, + B38E6C7315D66215AFD8B218 /* Pods-stable.profile-nightly.xcconfig */, + 53AD516AAEB9A1331C99CBAE /* Pods-stable.profile-dev.xcconfig */, + 3F754C793C1BC0E8B8FFB5B7 /* Pods-stable.profile-stable.xcconfig */, ); - name = Pods; path = Pods; sourceTree = ""; }; @@ -99,6 +277,9 @@ 97C146EF1CF9000F007C117D /* Products */, 67CBFE209DF24C94A9837AD5 /* Pods */, 0E0B839C4E103F896209E822 /* Frameworks */, + B536BDA12B405DB1009B3CE4 /* stable-Info.plist */, + B536BDC02B405FDE009B3CE4 /* dev-Info.plist */, + B536BDE52B4060B3009B3CE4 /* nightly-Info.plist */, ); sourceTree = ""; }; @@ -106,6 +287,9 @@ isa = PBXGroup; children = ( 97C146EE1CF9000F007C117D /* Runner.app */, + B536BDA02B405DB1009B3CE4 /* stable.app */, + B536BDBF2B405FDE009B3CE4 /* dev.app */, + B536BDE42B4060B3009B3CE4 /* nightly.app */, ); name = Products; sourceTree = ""; @@ -150,13 +334,79 @@ productReference = 97C146EE1CF9000F007C117D /* Runner.app */; productType = "com.apple.product-type.application"; }; + B536BD8C2B405DB1009B3CE4 /* stable */ = { + isa = PBXNativeTarget; + buildConfigurationList = B536BD9C2B405DB1009B3CE4 /* Build configuration list for PBXNativeTarget "stable" */; + buildPhases = ( + F0C8BA10A27CA77E18F842E7 /* [CP] Check Pods Manifest.lock */, + B536BD8E2B405DB1009B3CE4 /* Run Script */, + B536BD8F2B405DB1009B3CE4 /* Sources */, + B536BD922B405DB1009B3CE4 /* Frameworks */, + B536BD942B405DB1009B3CE4 /* Resources */, + B536BD992B405DB1009B3CE4 /* Embed Frameworks */, + B536BD9A2B405DB1009B3CE4 /* Thin Binary */, + A6D446F111DE4C4A202BE7F7 /* [CP] Embed Pods Frameworks */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = stable; + productName = Runner; + productReference = B536BDA02B405DB1009B3CE4 /* stable.app */; + productType = "com.apple.product-type.application"; + }; + B536BDAB2B405FDE009B3CE4 /* dev */ = { + isa = PBXNativeTarget; + buildConfigurationList = B536BDB82B405FDE009B3CE4 /* Build configuration list for PBXNativeTarget "dev" */; + buildPhases = ( + 6228176255365EAC646F2745 /* [CP] Check Pods Manifest.lock */, + B536BDAC2B405FDE009B3CE4 /* Run Script */, + B536BDAD2B405FDE009B3CE4 /* Sources */, + B536BDB02B405FDE009B3CE4 /* Frameworks */, + B536BDB12B405FDE009B3CE4 /* Resources */, + B536BDB62B405FDE009B3CE4 /* Embed Frameworks */, + B536BDB72B405FDE009B3CE4 /* Thin Binary */, + 244D41CE80E4BC0FFD63F8C6 /* [CP] Embed Pods Frameworks */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = dev; + productName = Runner; + productReference = B536BDBF2B405FDE009B3CE4 /* dev.app */; + productType = "com.apple.product-type.application"; + }; + B536BDCD2B4060B3009B3CE4 /* nightly */ = { + isa = PBXNativeTarget; + buildConfigurationList = B536BDDA2B4060B3009B3CE4 /* Build configuration list for PBXNativeTarget "nightly" */; + buildPhases = ( + 5CD4405E93760FBD048E36E2 /* [CP] Check Pods Manifest.lock */, + B536BDCE2B4060B3009B3CE4 /* Run Script */, + B536BDCF2B4060B3009B3CE4 /* Sources */, + B536BDD22B4060B3009B3CE4 /* Frameworks */, + B536BDD32B4060B3009B3CE4 /* Resources */, + B536BDD82B4060B3009B3CE4 /* Embed Frameworks */, + B536BDD92B4060B3009B3CE4 /* Thin Binary */, + D566C841A84D807A607F6DE5 /* [CP] Embed Pods Frameworks */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = nightly; + productName = Runner; + productReference = B536BDE42B4060B3009B3CE4 /* nightly.app */; + productType = "com.apple.product-type.application"; + }; /* End PBXNativeTarget section */ /* Begin PBXProject section */ 97C146E61CF9000F007C117D /* Project object */ = { isa = PBXProject; attributes = { - LastUpgradeCheck = 1300; + LastUpgradeCheck = 1430; ORGANIZATIONNAME = ""; TargetAttributes = { 97C146ED1CF9000F007C117D = { @@ -179,6 +429,9 @@ projectRoot = ""; targets = ( 97C146ED1CF9000F007C117D /* Runner */, + B536BD8C2B405DB1009B3CE4 /* stable */, + B536BDAB2B405FDE009B3CE4 /* dev */, + B536BDCD2B4060B3009B3CE4 /* nightly */, ); }; /* End PBXProject section */ @@ -195,9 +448,59 @@ ); runOnlyForDeploymentPostprocessing = 0; }; + B536BD942B405DB1009B3CE4 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + B536BD952B405DB1009B3CE4 /* LaunchScreen.storyboard in Resources */, + B536BD962B405DB1009B3CE4 /* AppFrameworkInfo.plist in Resources */, + B536BD972B405DB1009B3CE4 /* Assets.xcassets in Resources */, + B536BD982B405DB1009B3CE4 /* Main.storyboard in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + B536BDB12B405FDE009B3CE4 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + B536BDB22B405FDE009B3CE4 /* LaunchScreen.storyboard in Resources */, + B536BDB32B405FDE009B3CE4 /* AppFrameworkInfo.plist in Resources */, + B536BDB42B405FDE009B3CE4 /* Assets.xcassets in Resources */, + B536BDB52B405FDE009B3CE4 /* Main.storyboard in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + B536BDD32B4060B3009B3CE4 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + B536BDD42B4060B3009B3CE4 /* LaunchScreen.storyboard in Resources */, + B536BDD52B4060B3009B3CE4 /* AppFrameworkInfo.plist in Resources */, + B536BDD62B4060B3009B3CE4 /* Assets.xcassets in Resources */, + B536BDD72B4060B3009B3CE4 /* Main.storyboard in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; /* End PBXResourcesBuildPhase section */ /* Begin PBXShellScriptBuildPhase section */ + 244D41CE80E4BC0FFD63F8C6 /* [CP] Embed Pods Frameworks */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + "${PODS_ROOT}/Target Support Files/Pods-dev/Pods-dev-frameworks-${CONFIGURATION}-input-files.xcfilelist", + ); + name = "[CP] Embed Pods Frameworks"; + outputFileListPaths = ( + "${PODS_ROOT}/Target Support Files/Pods-dev/Pods-dev-frameworks-${CONFIGURATION}-output-files.xcfilelist", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-dev/Pods-dev-frameworks.sh\"\n"; + showEnvVarsInLog = 0; + }; 2AF6C7D149EE8481703D5255 /* [CP] Check Pods Manifest.lock */ = { isa = PBXShellScriptBuildPhase; buildActionMask = 2147483647; @@ -222,10 +525,12 @@ }; 3B06AD1E1E4923F5004D2608 /* Thin Binary */ = { isa = PBXShellScriptBuildPhase; + alwaysOutOfDate = 1; buildActionMask = 2147483647; files = ( ); inputPaths = ( + "${TARGET_BUILD_DIR}/${INFOPLIST_PATH}", ); name = "Thin Binary"; outputPaths = ( @@ -234,6 +539,50 @@ shellPath = /bin/sh; shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" embed_and_thin"; }; + 5CD4405E93760FBD048E36E2 /* [CP] Check Pods Manifest.lock */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + ); + inputPaths = ( + "${PODS_PODFILE_DIR_PATH}/Podfile.lock", + "${PODS_ROOT}/Manifest.lock", + ); + name = "[CP] Check Pods Manifest.lock"; + outputFileListPaths = ( + ); + outputPaths = ( + "$(DERIVED_FILE_DIR)/Pods-nightly-checkManifestLockResult.txt", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; + showEnvVarsInLog = 0; + }; + 6228176255365EAC646F2745 /* [CP] Check Pods Manifest.lock */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + ); + inputPaths = ( + "${PODS_PODFILE_DIR_PATH}/Podfile.lock", + "${PODS_ROOT}/Manifest.lock", + ); + name = "[CP] Check Pods Manifest.lock"; + outputFileListPaths = ( + ); + outputPaths = ( + "$(DERIVED_FILE_DIR)/Pods-dev-checkManifestLockResult.txt", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; + showEnvVarsInLog = 0; + }; 6E9FEF583EA597C8B76255B2 /* [CP] Embed Pods Frameworks */ = { isa = PBXShellScriptBuildPhase; buildActionMask = 2147483647; @@ -253,6 +602,7 @@ }; 9740EEB61CF901F6004384FC /* Run Script */ = { isa = PBXShellScriptBuildPhase; + alwaysOutOfDate = 1; buildActionMask = 2147483647; files = ( ); @@ -265,6 +615,155 @@ shellPath = /bin/sh; shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build"; }; + A6D446F111DE4C4A202BE7F7 /* [CP] Embed Pods Frameworks */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + "${PODS_ROOT}/Target Support Files/Pods-stable/Pods-stable-frameworks-${CONFIGURATION}-input-files.xcfilelist", + ); + name = "[CP] Embed Pods Frameworks"; + outputFileListPaths = ( + "${PODS_ROOT}/Target Support Files/Pods-stable/Pods-stable-frameworks-${CONFIGURATION}-output-files.xcfilelist", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-stable/Pods-stable-frameworks.sh\"\n"; + showEnvVarsInLog = 0; + }; + B536BD8E2B405DB1009B3CE4 /* Run Script */ = { + isa = PBXShellScriptBuildPhase; + alwaysOutOfDate = 1; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = "Run Script"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build"; + }; + B536BD9A2B405DB1009B3CE4 /* Thin Binary */ = { + isa = PBXShellScriptBuildPhase; + alwaysOutOfDate = 1; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + "${TARGET_BUILD_DIR}/${INFOPLIST_PATH}", + ); + name = "Thin Binary"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" embed_and_thin"; + }; + B536BDAC2B405FDE009B3CE4 /* Run Script */ = { + isa = PBXShellScriptBuildPhase; + alwaysOutOfDate = 1; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = "Run Script"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build"; + }; + B536BDB72B405FDE009B3CE4 /* Thin Binary */ = { + isa = PBXShellScriptBuildPhase; + alwaysOutOfDate = 1; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + "${TARGET_BUILD_DIR}/${INFOPLIST_PATH}", + ); + name = "Thin Binary"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" embed_and_thin"; + }; + B536BDCE2B4060B3009B3CE4 /* Run Script */ = { + isa = PBXShellScriptBuildPhase; + alwaysOutOfDate = 1; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = "Run Script"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build"; + }; + B536BDD92B4060B3009B3CE4 /* Thin Binary */ = { + isa = PBXShellScriptBuildPhase; + alwaysOutOfDate = 1; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + "${TARGET_BUILD_DIR}/${INFOPLIST_PATH}", + ); + name = "Thin Binary"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" embed_and_thin"; + }; + D566C841A84D807A607F6DE5 /* [CP] Embed Pods Frameworks */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + "${PODS_ROOT}/Target Support Files/Pods-nightly/Pods-nightly-frameworks-${CONFIGURATION}-input-files.xcfilelist", + ); + name = "[CP] Embed Pods Frameworks"; + outputFileListPaths = ( + "${PODS_ROOT}/Target Support Files/Pods-nightly/Pods-nightly-frameworks-${CONFIGURATION}-output-files.xcfilelist", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-nightly/Pods-nightly-frameworks.sh\"\n"; + showEnvVarsInLog = 0; + }; + F0C8BA10A27CA77E18F842E7 /* [CP] Check Pods Manifest.lock */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + ); + inputPaths = ( + "${PODS_PODFILE_DIR_PATH}/Podfile.lock", + "${PODS_ROOT}/Manifest.lock", + ); + name = "[CP] Check Pods Manifest.lock"; + outputFileListPaths = ( + ); + outputPaths = ( + "$(DERIVED_FILE_DIR)/Pods-stable-checkManifestLockResult.txt", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; + showEnvVarsInLog = 0; + }; /* End PBXShellScriptBuildPhase section */ /* Begin PBXSourcesBuildPhase section */ @@ -277,6 +776,33 @@ ); runOnlyForDeploymentPostprocessing = 0; }; + B536BD8F2B405DB1009B3CE4 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + B536BD902B405DB1009B3CE4 /* AppDelegate.swift in Sources */, + B536BD912B405DB1009B3CE4 /* GeneratedPluginRegistrant.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + B536BDAD2B405FDE009B3CE4 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + B536BDAE2B405FDE009B3CE4 /* AppDelegate.swift in Sources */, + B536BDAF2B405FDE009B3CE4 /* GeneratedPluginRegistrant.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + B536BDCF2B4060B3009B3CE4 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + B536BDD02B4060B3009B3CE4 /* AppDelegate.swift in Sources */, + B536BDD12B4060B3009B3CE4 /* GeneratedPluginRegistrant.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; /* End PBXSourcesBuildPhase section */ /* Begin PBXVariantGroup section */ @@ -520,6 +1046,1437 @@ }; name = Release; }; + B536BD9D2B405DB1009B3CE4 /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CLANG_ENABLE_MODULES = YES; + CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; + ENABLE_BITCODE = NO; + INFOPLIST_FILE = "stable-Info.plist"; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); + PRODUCT_BUNDLE_IDENTIFIER = oss.krtirtho.spotube.stable; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + SWIFT_VERSION = 5.0; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = Debug; + }; + B536BD9E2B405DB1009B3CE4 /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CLANG_ENABLE_MODULES = YES; + CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; + ENABLE_BITCODE = NO; + INFOPLIST_FILE = "stable-Info.plist"; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); + PRODUCT_BUNDLE_IDENTIFIER = oss.krtirtho.spotube.stable; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; + SWIFT_VERSION = 5.0; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = Release; + }; + B536BD9F2B405DB1009B3CE4 /* Profile */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CLANG_ENABLE_MODULES = YES; + CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; + ENABLE_BITCODE = NO; + INFOPLIST_FILE = "stable-Info.plist"; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); + PRODUCT_BUNDLE_IDENTIFIER = oss.krtirtho.spotube.stable; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; + SWIFT_VERSION = 5.0; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = Profile; + }; + B536BDA22B405E06009B3CE4 /* Debug-stable */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = dwarf; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_TESTABILITY = YES; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_DYNAMIC_NO_PIC = NO; + GCC_NO_COMMON_BLOCKS = YES; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 14.0; + MTL_ENABLE_DEBUG_INFO = YES; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = iphoneos; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = "Debug-stable"; + }; + B536BDA32B405E06009B3CE4 /* Debug-stable */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CLANG_ENABLE_MODULES = YES; + CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; + ENABLE_BITCODE = NO; + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); + PRODUCT_BUNDLE_IDENTIFIER = oss.krtirtho.spotube; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + SWIFT_VERSION = 5.0; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = "Debug-stable"; + }; + B536BDA42B405E06009B3CE4 /* Debug-stable */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CLANG_ENABLE_MODULES = YES; + CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; + ENABLE_BITCODE = NO; + INFOPLIST_FILE = "stable-Info.plist"; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); + PRODUCT_BUNDLE_IDENTIFIER = oss.krtirtho.spotube.stable; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + SWIFT_VERSION = 5.0; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = "Debug-stable"; + }; + B536BDA52B405E19009B3CE4 /* Release-stable */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 14.0; + MTL_ENABLE_DEBUG_INFO = NO; + SDKROOT = iphoneos; + SUPPORTED_PLATFORMS = iphoneos; + SWIFT_COMPILATION_MODE = wholemodule; + SWIFT_OPTIMIZATION_LEVEL = "-O"; + TARGETED_DEVICE_FAMILY = "1,2"; + VALIDATE_PRODUCT = YES; + }; + name = "Release-stable"; + }; + B536BDA62B405E19009B3CE4 /* Release-stable */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CLANG_ENABLE_MODULES = YES; + CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; + ENABLE_BITCODE = NO; + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); + PRODUCT_BUNDLE_IDENTIFIER = oss.krtirtho.spotube; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; + SWIFT_VERSION = 5.0; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = "Release-stable"; + }; + B536BDA72B405E19009B3CE4 /* Release-stable */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CLANG_ENABLE_MODULES = YES; + CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; + ENABLE_BITCODE = NO; + INFOPLIST_FILE = "stable-Info.plist"; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); + PRODUCT_BUNDLE_IDENTIFIER = oss.krtirtho.spotube.stable; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; + SWIFT_VERSION = 5.0; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = "Release-stable"; + }; + B536BDA82B405E1F009B3CE4 /* Profile-stable */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 14.0; + MTL_ENABLE_DEBUG_INFO = NO; + SDKROOT = iphoneos; + SUPPORTED_PLATFORMS = iphoneos; + TARGETED_DEVICE_FAMILY = "1,2"; + VALIDATE_PRODUCT = YES; + }; + name = "Profile-stable"; + }; + B536BDA92B405E1F009B3CE4 /* Profile-stable */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CLANG_ENABLE_MODULES = YES; + CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; + ENABLE_BITCODE = NO; + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); + PRODUCT_BUNDLE_IDENTIFIER = oss.krtirtho.spotube; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; + SWIFT_VERSION = 5.0; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = "Profile-stable"; + }; + B536BDAA2B405E1F009B3CE4 /* Profile-stable */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CLANG_ENABLE_MODULES = YES; + CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; + ENABLE_BITCODE = NO; + INFOPLIST_FILE = "stable-Info.plist"; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); + PRODUCT_BUNDLE_IDENTIFIER = oss.krtirtho.spotube.stable; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; + SWIFT_VERSION = 5.0; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = "Profile-stable"; + }; + B536BDB92B405FDE009B3CE4 /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CLANG_ENABLE_MODULES = YES; + CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; + ENABLE_BITCODE = NO; + INFOPLIST_FILE = "dev-Info.plist"; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); + PRODUCT_BUNDLE_IDENTIFIER = oss.krtirtho.spotube.dev; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + SWIFT_VERSION = 5.0; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = Debug; + }; + B536BDBA2B405FDE009B3CE4 /* Debug-stable */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CLANG_ENABLE_MODULES = YES; + CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; + ENABLE_BITCODE = NO; + INFOPLIST_FILE = "dev-Info.plist"; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); + PRODUCT_BUNDLE_IDENTIFIER = oss.krtirtho.spotube.dev; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + SWIFT_VERSION = 5.0; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = "Debug-stable"; + }; + B536BDBB2B405FDE009B3CE4 /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CLANG_ENABLE_MODULES = YES; + CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; + ENABLE_BITCODE = NO; + INFOPLIST_FILE = "dev-Info.plist"; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); + PRODUCT_BUNDLE_IDENTIFIER = oss.krtirtho.spotube.dev; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; + SWIFT_VERSION = 5.0; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = Release; + }; + B536BDBC2B405FDE009B3CE4 /* Release-stable */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CLANG_ENABLE_MODULES = YES; + CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; + ENABLE_BITCODE = NO; + INFOPLIST_FILE = "dev-Info.plist"; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); + PRODUCT_BUNDLE_IDENTIFIER = oss.krtirtho.spotube.dev; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; + SWIFT_VERSION = 5.0; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = "Release-stable"; + }; + B536BDBD2B405FDE009B3CE4 /* Profile */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CLANG_ENABLE_MODULES = YES; + CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; + ENABLE_BITCODE = NO; + INFOPLIST_FILE = "dev-Info.plist"; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); + PRODUCT_BUNDLE_IDENTIFIER = oss.krtirtho.spotube.dev; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; + SWIFT_VERSION = 5.0; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = Profile; + }; + B536BDBE2B405FDE009B3CE4 /* Profile-stable */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CLANG_ENABLE_MODULES = YES; + CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; + ENABLE_BITCODE = NO; + INFOPLIST_FILE = "dev-Info.plist"; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); + PRODUCT_BUNDLE_IDENTIFIER = oss.krtirtho.spotube.dev; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; + SWIFT_VERSION = 5.0; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = "Profile-stable"; + }; + B536BDC12B406014009B3CE4 /* Debug-dev */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = dwarf; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_TESTABILITY = YES; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_DYNAMIC_NO_PIC = NO; + GCC_NO_COMMON_BLOCKS = YES; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 14.0; + MTL_ENABLE_DEBUG_INFO = YES; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = iphoneos; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = "Debug-dev"; + }; + B536BDC22B406014009B3CE4 /* Debug-dev */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CLANG_ENABLE_MODULES = YES; + CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; + ENABLE_BITCODE = NO; + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); + PRODUCT_BUNDLE_IDENTIFIER = oss.krtirtho.spotube; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + SWIFT_VERSION = 5.0; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = "Debug-dev"; + }; + B536BDC32B406014009B3CE4 /* Debug-dev */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CLANG_ENABLE_MODULES = YES; + CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; + ENABLE_BITCODE = NO; + INFOPLIST_FILE = "stable-Info.plist"; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); + PRODUCT_BUNDLE_IDENTIFIER = oss.krtirtho.spotube.stable; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + SWIFT_VERSION = 5.0; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = "Debug-dev"; + }; + B536BDC42B406014009B3CE4 /* Debug-dev */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CLANG_ENABLE_MODULES = YES; + CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; + ENABLE_BITCODE = NO; + INFOPLIST_FILE = "dev-Info.plist"; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); + PRODUCT_BUNDLE_IDENTIFIER = oss.krtirtho.spotube.dev; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + SWIFT_VERSION = 5.0; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = "Debug-dev"; + }; + B536BDC52B40601C009B3CE4 /* Release-dev */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 14.0; + MTL_ENABLE_DEBUG_INFO = NO; + SDKROOT = iphoneos; + SUPPORTED_PLATFORMS = iphoneos; + SWIFT_COMPILATION_MODE = wholemodule; + SWIFT_OPTIMIZATION_LEVEL = "-O"; + TARGETED_DEVICE_FAMILY = "1,2"; + VALIDATE_PRODUCT = YES; + }; + name = "Release-dev"; + }; + B536BDC62B40601C009B3CE4 /* Release-dev */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CLANG_ENABLE_MODULES = YES; + CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; + ENABLE_BITCODE = NO; + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); + PRODUCT_BUNDLE_IDENTIFIER = oss.krtirtho.spotube; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; + SWIFT_VERSION = 5.0; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = "Release-dev"; + }; + B536BDC72B40601C009B3CE4 /* Release-dev */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CLANG_ENABLE_MODULES = YES; + CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; + ENABLE_BITCODE = NO; + INFOPLIST_FILE = "stable-Info.plist"; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); + PRODUCT_BUNDLE_IDENTIFIER = oss.krtirtho.spotube.stable; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; + SWIFT_VERSION = 5.0; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = "Release-dev"; + }; + B536BDC82B40601C009B3CE4 /* Release-dev */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CLANG_ENABLE_MODULES = YES; + CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; + ENABLE_BITCODE = NO; + INFOPLIST_FILE = "dev-Info.plist"; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); + PRODUCT_BUNDLE_IDENTIFIER = oss.krtirtho.spotube.dev; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; + SWIFT_VERSION = 5.0; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = "Release-dev"; + }; + B536BDC92B406021009B3CE4 /* Profile-dev */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 14.0; + MTL_ENABLE_DEBUG_INFO = NO; + SDKROOT = iphoneos; + SUPPORTED_PLATFORMS = iphoneos; + TARGETED_DEVICE_FAMILY = "1,2"; + VALIDATE_PRODUCT = YES; + }; + name = "Profile-dev"; + }; + B536BDCA2B406021009B3CE4 /* Profile-dev */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CLANG_ENABLE_MODULES = YES; + CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; + ENABLE_BITCODE = NO; + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); + PRODUCT_BUNDLE_IDENTIFIER = oss.krtirtho.spotube; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; + SWIFT_VERSION = 5.0; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = "Profile-dev"; + }; + B536BDCB2B406021009B3CE4 /* Profile-dev */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CLANG_ENABLE_MODULES = YES; + CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; + ENABLE_BITCODE = NO; + INFOPLIST_FILE = "stable-Info.plist"; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); + PRODUCT_BUNDLE_IDENTIFIER = oss.krtirtho.spotube.stable; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; + SWIFT_VERSION = 5.0; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = "Profile-dev"; + }; + B536BDCC2B406021009B3CE4 /* Profile-dev */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CLANG_ENABLE_MODULES = YES; + CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; + ENABLE_BITCODE = NO; + INFOPLIST_FILE = "dev-Info.plist"; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); + PRODUCT_BUNDLE_IDENTIFIER = oss.krtirtho.spotube.dev; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; + SWIFT_VERSION = 5.0; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = "Profile-dev"; + }; + B536BDDB2B4060B3009B3CE4 /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = "AppIcon-nightly"; + CLANG_ENABLE_MODULES = YES; + CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; + ENABLE_BITCODE = NO; + INFOPLIST_FILE = "nightly-Info.plist"; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); + PRODUCT_BUNDLE_IDENTIFIER = oss.krtirtho.spotube.nightly; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + SWIFT_VERSION = 5.0; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = Debug; + }; + B536BDDC2B4060B3009B3CE4 /* Debug-dev */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = "AppIcon-nightly"; + CLANG_ENABLE_MODULES = YES; + CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; + ENABLE_BITCODE = NO; + INFOPLIST_FILE = "nightly-Info.plist"; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); + PRODUCT_BUNDLE_IDENTIFIER = oss.krtirtho.spotube.nightly; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + SWIFT_VERSION = 5.0; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = "Debug-dev"; + }; + B536BDDD2B4060B3009B3CE4 /* Debug-stable */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = "AppIcon-nightly"; + CLANG_ENABLE_MODULES = YES; + CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; + ENABLE_BITCODE = NO; + INFOPLIST_FILE = "nightly-Info.plist"; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); + PRODUCT_BUNDLE_IDENTIFIER = oss.krtirtho.spotube.nightly; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + SWIFT_VERSION = 5.0; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = "Debug-stable"; + }; + B536BDDE2B4060B3009B3CE4 /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = "AppIcon-nightly"; + CLANG_ENABLE_MODULES = YES; + CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; + ENABLE_BITCODE = NO; + INFOPLIST_FILE = "nightly-Info.plist"; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); + PRODUCT_BUNDLE_IDENTIFIER = oss.krtirtho.spotube.nightly; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; + SWIFT_VERSION = 5.0; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = Release; + }; + B536BDDF2B4060B3009B3CE4 /* Release-dev */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = "AppIcon-nightly"; + CLANG_ENABLE_MODULES = YES; + CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; + ENABLE_BITCODE = NO; + INFOPLIST_FILE = "nightly-Info.plist"; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); + PRODUCT_BUNDLE_IDENTIFIER = oss.krtirtho.spotube.nightly; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; + SWIFT_VERSION = 5.0; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = "Release-dev"; + }; + B536BDE02B4060B3009B3CE4 /* Release-stable */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = "AppIcon-nightly"; + CLANG_ENABLE_MODULES = YES; + CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; + ENABLE_BITCODE = NO; + INFOPLIST_FILE = "nightly-Info.plist"; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); + PRODUCT_BUNDLE_IDENTIFIER = oss.krtirtho.spotube.nightly; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; + SWIFT_VERSION = 5.0; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = "Release-stable"; + }; + B536BDE12B4060B3009B3CE4 /* Profile */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = "AppIcon-nightly"; + CLANG_ENABLE_MODULES = YES; + CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; + ENABLE_BITCODE = NO; + INFOPLIST_FILE = "nightly-Info.plist"; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); + PRODUCT_BUNDLE_IDENTIFIER = oss.krtirtho.spotube.nightly; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; + SWIFT_VERSION = 5.0; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = Profile; + }; + B536BDE22B4060B3009B3CE4 /* Profile-dev */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = "AppIcon-nightly"; + CLANG_ENABLE_MODULES = YES; + CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; + ENABLE_BITCODE = NO; + INFOPLIST_FILE = "nightly-Info.plist"; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); + PRODUCT_BUNDLE_IDENTIFIER = oss.krtirtho.spotube.nightly; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; + SWIFT_VERSION = 5.0; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = "Profile-dev"; + }; + B536BDE32B4060B3009B3CE4 /* Profile-stable */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = "AppIcon-nightly"; + CLANG_ENABLE_MODULES = YES; + CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; + ENABLE_BITCODE = NO; + INFOPLIST_FILE = "nightly-Info.plist"; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); + PRODUCT_BUNDLE_IDENTIFIER = oss.krtirtho.spotube.nightly; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; + SWIFT_VERSION = 5.0; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = "Profile-stable"; + }; + B536BDE62B4060FE009B3CE4 /* Debug-nightly */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = dwarf; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_TESTABILITY = YES; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_DYNAMIC_NO_PIC = NO; + GCC_NO_COMMON_BLOCKS = YES; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 14.0; + MTL_ENABLE_DEBUG_INFO = YES; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = iphoneos; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = "Debug-nightly"; + }; + B536BDE72B4060FE009B3CE4 /* Debug-nightly */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CLANG_ENABLE_MODULES = YES; + CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; + ENABLE_BITCODE = NO; + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); + PRODUCT_BUNDLE_IDENTIFIER = oss.krtirtho.spotube; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + SWIFT_VERSION = 5.0; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = "Debug-nightly"; + }; + B536BDE82B4060FE009B3CE4 /* Debug-nightly */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CLANG_ENABLE_MODULES = YES; + CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; + ENABLE_BITCODE = NO; + INFOPLIST_FILE = "stable-Info.plist"; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); + PRODUCT_BUNDLE_IDENTIFIER = oss.krtirtho.spotube.stable; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + SWIFT_VERSION = 5.0; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = "Debug-nightly"; + }; + B536BDE92B4060FE009B3CE4 /* Debug-nightly */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CLANG_ENABLE_MODULES = YES; + CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; + ENABLE_BITCODE = NO; + INFOPLIST_FILE = "dev-Info.plist"; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); + PRODUCT_BUNDLE_IDENTIFIER = oss.krtirtho.spotube.dev; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + SWIFT_VERSION = 5.0; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = "Debug-nightly"; + }; + B536BDEA2B4060FE009B3CE4 /* Debug-nightly */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = "AppIcon-nightly"; + CLANG_ENABLE_MODULES = YES; + CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; + ENABLE_BITCODE = NO; + INFOPLIST_FILE = "nightly-Info.plist"; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); + PRODUCT_BUNDLE_IDENTIFIER = oss.krtirtho.spotube.nightly; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + SWIFT_VERSION = 5.0; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = "Debug-nightly"; + }; + B536BDEB2B406105009B3CE4 /* Release-nightly */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 14.0; + MTL_ENABLE_DEBUG_INFO = NO; + SDKROOT = iphoneos; + SUPPORTED_PLATFORMS = iphoneos; + SWIFT_COMPILATION_MODE = wholemodule; + SWIFT_OPTIMIZATION_LEVEL = "-O"; + TARGETED_DEVICE_FAMILY = "1,2"; + VALIDATE_PRODUCT = YES; + }; + name = "Release-nightly"; + }; + B536BDEC2B406105009B3CE4 /* Release-nightly */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CLANG_ENABLE_MODULES = YES; + CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; + ENABLE_BITCODE = NO; + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); + PRODUCT_BUNDLE_IDENTIFIER = oss.krtirtho.spotube; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; + SWIFT_VERSION = 5.0; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = "Release-nightly"; + }; + B536BDED2B406105009B3CE4 /* Release-nightly */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CLANG_ENABLE_MODULES = YES; + CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; + ENABLE_BITCODE = NO; + INFOPLIST_FILE = "stable-Info.plist"; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); + PRODUCT_BUNDLE_IDENTIFIER = oss.krtirtho.spotube.stable; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; + SWIFT_VERSION = 5.0; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = "Release-nightly"; + }; + B536BDEE2B406105009B3CE4 /* Release-nightly */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CLANG_ENABLE_MODULES = YES; + CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; + ENABLE_BITCODE = NO; + INFOPLIST_FILE = "dev-Info.plist"; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); + PRODUCT_BUNDLE_IDENTIFIER = oss.krtirtho.spotube.dev; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; + SWIFT_VERSION = 5.0; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = "Release-nightly"; + }; + B536BDEF2B406105009B3CE4 /* Release-nightly */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = "AppIcon-nightly"; + CLANG_ENABLE_MODULES = YES; + CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; + ENABLE_BITCODE = NO; + INFOPLIST_FILE = "nightly-Info.plist"; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); + PRODUCT_BUNDLE_IDENTIFIER = oss.krtirtho.spotube.nightly; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; + SWIFT_VERSION = 5.0; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = "Release-nightly"; + }; + B536BDF02B40610B009B3CE4 /* Profile-nightly */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 14.0; + MTL_ENABLE_DEBUG_INFO = NO; + SDKROOT = iphoneos; + SUPPORTED_PLATFORMS = iphoneos; + TARGETED_DEVICE_FAMILY = "1,2"; + VALIDATE_PRODUCT = YES; + }; + name = "Profile-nightly"; + }; + B536BDF12B40610B009B3CE4 /* Profile-nightly */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CLANG_ENABLE_MODULES = YES; + CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; + ENABLE_BITCODE = NO; + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); + PRODUCT_BUNDLE_IDENTIFIER = oss.krtirtho.spotube; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; + SWIFT_VERSION = 5.0; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = "Profile-nightly"; + }; + B536BDF22B40610B009B3CE4 /* Profile-nightly */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CLANG_ENABLE_MODULES = YES; + CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; + ENABLE_BITCODE = NO; + INFOPLIST_FILE = "stable-Info.plist"; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); + PRODUCT_BUNDLE_IDENTIFIER = oss.krtirtho.spotube.stable; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; + SWIFT_VERSION = 5.0; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = "Profile-nightly"; + }; + B536BDF32B40610B009B3CE4 /* Profile-nightly */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CLANG_ENABLE_MODULES = YES; + CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; + ENABLE_BITCODE = NO; + INFOPLIST_FILE = "dev-Info.plist"; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); + PRODUCT_BUNDLE_IDENTIFIER = oss.krtirtho.spotube.dev; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; + SWIFT_VERSION = 5.0; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = "Profile-nightly"; + }; + B536BDF42B40610B009B3CE4 /* Profile-nightly */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = "AppIcon-nightly"; + CLANG_ENABLE_MODULES = YES; + CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; + ENABLE_BITCODE = NO; + INFOPLIST_FILE = "nightly-Info.plist"; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); + PRODUCT_BUNDLE_IDENTIFIER = oss.krtirtho.spotube.nightly; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; + SWIFT_VERSION = 5.0; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = "Profile-nightly"; + }; /* End XCBuildConfiguration section */ /* Begin XCConfigurationList section */ @@ -527,8 +2484,17 @@ isa = XCConfigurationList; buildConfigurations = ( 97C147031CF9000F007C117D /* Debug */, + B536BDE62B4060FE009B3CE4 /* Debug-nightly */, + B536BDC12B406014009B3CE4 /* Debug-dev */, + B536BDA22B405E06009B3CE4 /* Debug-stable */, 97C147041CF9000F007C117D /* Release */, + B536BDEB2B406105009B3CE4 /* Release-nightly */, + B536BDC52B40601C009B3CE4 /* Release-dev */, + B536BDA52B405E19009B3CE4 /* Release-stable */, 249021D3217E4FDB00AE95B9 /* Profile */, + B536BDF02B40610B009B3CE4 /* Profile-nightly */, + B536BDC92B406021009B3CE4 /* Profile-dev */, + B536BDA82B405E1F009B3CE4 /* Profile-stable */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; @@ -537,8 +2503,74 @@ isa = XCConfigurationList; buildConfigurations = ( 97C147061CF9000F007C117D /* Debug */, + B536BDE72B4060FE009B3CE4 /* Debug-nightly */, + B536BDC22B406014009B3CE4 /* Debug-dev */, + B536BDA32B405E06009B3CE4 /* Debug-stable */, 97C147071CF9000F007C117D /* Release */, + B536BDEC2B406105009B3CE4 /* Release-nightly */, + B536BDC62B40601C009B3CE4 /* Release-dev */, + B536BDA62B405E19009B3CE4 /* Release-stable */, 249021D4217E4FDB00AE95B9 /* Profile */, + B536BDF12B40610B009B3CE4 /* Profile-nightly */, + B536BDCA2B406021009B3CE4 /* Profile-dev */, + B536BDA92B405E1F009B3CE4 /* Profile-stable */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + B536BD9C2B405DB1009B3CE4 /* Build configuration list for PBXNativeTarget "stable" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + B536BD9D2B405DB1009B3CE4 /* Debug */, + B536BDE82B4060FE009B3CE4 /* Debug-nightly */, + B536BDC32B406014009B3CE4 /* Debug-dev */, + B536BDA42B405E06009B3CE4 /* Debug-stable */, + B536BD9E2B405DB1009B3CE4 /* Release */, + B536BDED2B406105009B3CE4 /* Release-nightly */, + B536BDC72B40601C009B3CE4 /* Release-dev */, + B536BDA72B405E19009B3CE4 /* Release-stable */, + B536BD9F2B405DB1009B3CE4 /* Profile */, + B536BDF22B40610B009B3CE4 /* Profile-nightly */, + B536BDCB2B406021009B3CE4 /* Profile-dev */, + B536BDAA2B405E1F009B3CE4 /* Profile-stable */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + B536BDB82B405FDE009B3CE4 /* Build configuration list for PBXNativeTarget "dev" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + B536BDB92B405FDE009B3CE4 /* Debug */, + B536BDE92B4060FE009B3CE4 /* Debug-nightly */, + B536BDC42B406014009B3CE4 /* Debug-dev */, + B536BDBA2B405FDE009B3CE4 /* Debug-stable */, + B536BDBB2B405FDE009B3CE4 /* Release */, + B536BDEE2B406105009B3CE4 /* Release-nightly */, + B536BDC82B40601C009B3CE4 /* Release-dev */, + B536BDBC2B405FDE009B3CE4 /* Release-stable */, + B536BDBD2B405FDE009B3CE4 /* Profile */, + B536BDF32B40610B009B3CE4 /* Profile-nightly */, + B536BDCC2B406021009B3CE4 /* Profile-dev */, + B536BDBE2B405FDE009B3CE4 /* Profile-stable */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + B536BDDA2B4060B3009B3CE4 /* Build configuration list for PBXNativeTarget "nightly" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + B536BDDB2B4060B3009B3CE4 /* Debug */, + B536BDEA2B4060FE009B3CE4 /* Debug-nightly */, + B536BDDC2B4060B3009B3CE4 /* Debug-dev */, + B536BDDD2B4060B3009B3CE4 /* Debug-stable */, + B536BDDE2B4060B3009B3CE4 /* Release */, + B536BDEF2B406105009B3CE4 /* Release-nightly */, + B536BDDF2B4060B3009B3CE4 /* Release-dev */, + B536BDE02B4060B3009B3CE4 /* Release-stable */, + B536BDE12B4060B3009B3CE4 /* Profile */, + B536BDF42B40610B009B3CE4 /* Profile-nightly */, + B536BDE22B4060B3009B3CE4 /* Profile-dev */, + B536BDE32B4060B3009B3CE4 /* Profile-stable */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; diff --git a/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme b/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme index c87d15a3..a6b826db 100644 --- a/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme +++ b/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme @@ -1,6 +1,6 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/ios/Runner.xcodeproj/xcshareddata/xcschemes/nightly.xcscheme b/ios/Runner.xcodeproj/xcshareddata/xcschemes/nightly.xcscheme new file mode 100644 index 00000000..7ec18a73 --- /dev/null +++ b/ios/Runner.xcodeproj/xcshareddata/xcschemes/nightly.xcscheme @@ -0,0 +1,77 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/ios/Runner.xcodeproj/xcshareddata/xcschemes/stable.xcscheme b/ios/Runner.xcodeproj/xcshareddata/xcschemes/stable.xcscheme new file mode 100644 index 00000000..ddc19e2e --- /dev/null +++ b/ios/Runner.xcodeproj/xcshareddata/xcschemes/stable.xcscheme @@ -0,0 +1,77 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/ios/Runner/Assets.xcassets/AppIcon-nightly.appiconset/AppIcon-nightly-1024x1024@1x.png b/ios/Runner/Assets.xcassets/AppIcon-nightly.appiconset/AppIcon-nightly-1024x1024@1x.png new file mode 100644 index 0000000000000000000000000000000000000000..dbc4596b3890c55cd35881c4e0de4effc2b6e3b9 GIT binary patch literal 296365 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 z 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%0A?;vo`h%2>QL~BKA8NNzf0< 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 z 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%0DW&|lr0dK)`^G1b#G)c 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 literal 0 HcmV?d00001 diff --git a/ios/Runner/Assets.xcassets/AppIcon-nightly.appiconset/AppIcon-nightly-20x20@2x.png b/ios/Runner/Assets.xcassets/AppIcon-nightly.appiconset/AppIcon-nightly-20x20@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..90954ce985ea06213d56c4472c9bca6ac248ac0a GIT binary patch literal 3063 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 u{PnV$|MydDibt8Cj3E6@sA@<_tY`g5nV_x`{A zk9+_7+4$g^K{7{?kx<&AaVY*En6VG=cml>E6%uMA9ZEWwG@aB-Dnf&8kOoQHNE=9N zNxMm2LIE`J1JVuzP+>X+C%`^RI-PU^X#szBP2FG^rosP`ZZYDB#Q&lwjM+kd`6lUE z(vt}Za9NN5`zh)D0cs@uOQboZi%A#o>)E#BShiCzY}xN01H=eD4cffL;9YA<})Mmq`_pk9`EZuRukDqJlF?*N`rv#EJ#CY!=)iOw$tS z@zqeTB1H|-Xfe=Oc#dNQIJRRr1s72i5qMhb*5!cD;CS9FlkbHqM}MowW=zBhLM+MQ+3tilg~7>0fAnJ>_zT zVc7)@(n=+1!5k&Y)cF`qq|Fv*aGOB+&m>3<*iv94GgRYpUb9}S983v|-QJea5GJ6? z69Fn9+ev>(T1F|l#bO&Q+g1QA1=7mY)y&ysQ<6D3jshC1ubPro4vJ&Qt6@e2Z4#)J znL?>-a)BMUIxF|Ps>9z&e)W7)zvMmU)&I|BT-N)}q8^Wl$HUz1F z3g8svDCZ_%E5n1AQOyO%wF%g9ZFWyUWh!wze=Z;?$zlr9PJrgswW+3Bk|(-0F6u1d z_)-xig0uO(IVy%qn?ms}D91RLVCrFrSL+QdAFAQ;nvXC|7DdD{bpPbL)PqZgLVdF; zBfA%KK?eBgo1_tplTqynsDzM(q}yqeV?pMhb&Lu<;{laqK;q;wy7gY|ct)$Mm9t4b>G71}KTqjIUxA*OQht%Z zzE$_|Yfq=FCK(cTtz;6>uNTSiPe>8RI^MBx4ORSfYQS;rW&Fr>uyp$%ensh~nj&+i z+{>$#*s_47KpcAHZ$YP!8=2D}!@GU`xEEbPf!Sxl~k^-pJ)oyV-Daa$q$PKexl<5^-phPYj@X=s^ zU)pP9F&7}B=N}F{yj}_L)JTXo>JfHQrDd6WDCv0x1Ap3X;iz^83yA#R+iW~i4e|9I zJ}%uI;ro+qoK-e(>GT5Lq~sqRil8?K+HOr#q$z?Bptd9wC=`kX&#V8FC>r#3FB%P0 zw4tB$c{(4n86(HZcGwDB(Hr|sbhO9VL5RD==um3Pp#py*(MfJ8}8(iFWKPZimf(& zH8;YfjtGA>gX;a3mBiKru<#d~ng0;SN&aQ`BfFl56RE~2&@?%?kSc4oBsPVfK(?jAp+gV+N$4Y*45%#s8FDhv zYLjV#j*M~1;LbUy4zp>Nc9O^90*2 z7+KP`i?B z!#sA=EbY)94|d5%ozJZrw6LhVhR${mRVE0(-P*q2Ak+5rwj!>iadf*8PMG51LE8LV zL5yidAM<+~Sh=Irl&FzU{PnABBl)Jtha{EVngX3qawTSt*)-?WR=%6nO%LG)SU=*z zXLhr2l84Y~V0$&f`k}%B13E;_Sj+VM*scZ^PImCnrV`dv4NUC}F{`(c@zYe_ren&$ znwCL3{Sbe8A_Y2^wrQ%4$y2kCGlJa1|RF@bKOlaLMbj7}dxp@EH68!?)@3K_Vn zHqjHeS8)`~AyA2Qzl{|GALb(Vb?F7%;&VpVNB?9WWhX$zvoa1d^;It#EFF^ooy(uC z6zFu(>-0#{FmkRtWr6|u`cv2Am^pO@r4n{UI+rU^jYFr7;i#lOOImj`cQ9ox+P`tj zwY=JrTko+gRQ<~6ARj+wzkAtlh`F$gU1shpi@J-d8xil_0 zM-eNyV_D~gxSV^^Uy$L-1b{B-aIwaZu%hAN%k1|ccP(|vk2$te43)P0a(y@YdVHLD zaEST+6=9DQ+1h8CV{Gp`uE7Nhvypv+EYNADXO@4pqserk`$YsA(d$N3-&pNM zxpyT!v2hAE)Yf4-W5ppeDhlX0Fk9ZFKpTkj8}in3;d0SnNGa13cG1&{P0)6b1m{8r ztRfRQM>~w5OrS%iV$5%=A~q?ia3Vn2uafV_4TXd|?lVodlXF@sAwWXA!pWFjiqYO? zjKi`1CV`|5x&^2x)=-=~S4|$%y~W5a7j|(b-Le#vO*6^lK;34%luREZ0%<28N~Q7e`a*B~OmZZ!<>IBhv(=oDD;t z`$j3yZIP6=ppM;iY|0%jn+oV8SY$qw_{0fgkt$zJx0}ClVyCKx3X8N`+fo2Ux-ce| zL?+i>?V496PiSu%yZ8_Z>%v2V!E@!BcMi>Z_Yw|!v9P6b% zDVy%mk~ORX2c9ZtQJicm8U!jQL3F|dNEPCwmNSwt9BVzH7W(B_pS({5C>=}W=wsZV ztfRkSiRyA*SG@2>Rhp=a&5J~3UaGZeZA#Qt3nogX8HPws@mC>HU3pA);m=7CHmOhQ zRY__g2Az<_3GG;)*~mmSu6)^~LU=C#jw>rnSQ9KoQBmoO{v;Mn$oK=rVvAESi8jHlIsC9GSq+rTFwAI%4<6ABN1Xyz>XW;64dUU)p1~y-osaKabukvqnT=;&TaS=~&zUh(c}LUI zJASh?7aiU2psj5eRd69!+T1Hh)vq`Qojtp`Q+ZqWQ;S^S*d6HYj&bp+$E)0RLH~4o z_59P-w(R+rUdEcW>(%*jS|Jx{5~v97e(3uS@o1oeT#7W0HtN-LrJOFFOM1E8v@Qq&tX;PrH{E=PekN3*M0wgqy(am9I1D+{ z_0sY4Kn1y^H#gHMo#K1-j_h6uJ>A{xw^I3rXP$crXTH7;U7a2383`Q& z1H19Nr&r+K#Y-Dwo1S=hthMd2(kUUvn|^jRRfPQVE2SV+1XL_qU}<%NUSx z)C3s@iCxyEnkE|gkIgK zW+5vK=Z_$fD;tatd<>x0AG6dh*@?8+WCn6%kd8NehCRN5eYmWFq=V@Cjgom(h6leW z7bBcp!mo?4wgRi{I6b6-F|LHifEm-$Q-R#3B8tY^q^PU!6Xb4w6-eqOcc8XnAFtma z=_ot&e;`;#Zhy$dh*q#keKIzi_kaYTp-<4$!{z)zcpg}KkkN8NkmatiP6i}SN(f23 ztJtKdYa&SjxdpkHxi3Idu%Z&z$`u#6{ZTBn*>17T&996m{LYH;@wrng=WQcwUj)A9685?hHsdT`JAZnyRj9 zWtSe2i?JQG>Ey4mDmATFV~!mqx$7;-B8!83 z-#4-MymW+}o-eNy(d8PJ?3PKRl^zN(Ht)IL&env?yc zNbX+f>ok(PN_?NN6!#Zs+EVF?BaoGTgfy3uI4`UPr|TlDQLrq_kgApxeDXPQGd}7+ z9*~2qSRcf`P7)RUCFvz-74`NNVA>AEUr7jajf5H5=E*q?6Af@D9v?~I3zE{^3{od_ zb=^pw7n_$q2l*p3K&+ZBcJ~VGg$-ByV2?A00000NkvXXu0mjfoKO~^ literal 0 HcmV?d00001 diff --git a/ios/Runner/Assets.xcassets/AppIcon-nightly.appiconset/AppIcon-nightly-29x29@3x.png b/ios/Runner/Assets.xcassets/AppIcon-nightly.appiconset/AppIcon-nightly-29x29@3x.png new file mode 100644 index 0000000000000000000000000000000000000000..6cdda1b66e9ff45973ef9a1efa1ad2978890494b GIT binary patch literal 9629 zcmV;OC1To%P)q+M-3OLI>3M6X9tqzT$w|LA20T`UFMm z^xmV0Gx#j}Y=J(-=fn(&p$q{+Adrx7lbhV(Ond0}tzqwV&K*c@2HyT7|JNh^C-`vJc;rc%5&y>TM|=T zu=mThzrgJUG)AeSEI~OH8e9u1SxG?2zQriNkMc&8-!N_PJt%_eBHUL}^P2bhd9UecyrWf=WQ^D8Gqv zKFZnVy&r~=A4ai+VXVMZ1XT?6%xe+L*xoI-6jrY_ak*E3qa;b&PdaTuS%vqP;DC!z z?nn79$`4SsNeT2mVe-BJ*EjVN)IOABQ2q+#HT)c)`EgwJ;z~`xRrdJ;Opi>}3P4Ep zcSW_m2{K_7=F7tps%d<&Q-JJ0BMoRBC-* z6jcfhWl^s^zmx#al>;jUt|Uyu+}wR_-)9BLs$>RW0Bu1|laAkPPR0P6QuS?=?}-Nc z8POnHso0}!Z-7g-(pXVPk4O0w$}0gNv=Aw(e!=CwlC zm)v+03S8eX7$AE-_ql3IJ&Y8S8;yxdmL_i%Z3_tS4WivVO2r;&@t%TfwUvG-4aQ|C zeK1mft=13S3voe#0@VVmKvoQP{&0|%h|1Iq8Cu~D_J?!{46 zyHX0!phsg%oh?~g8ZceCSDvLfVfhCBKzCzu{h2z#HE@Mo_zGa2OTG3obAAnQwdO-E zVy`hd9z!z7U_)D@@FXjSF}e#9o{W~cNbh2SOx?C1Lauwt6^V#5TJ${%)m;43#^p_2h>@B-KCZk zJNt%!dIngp3uuKh*~`60Lucd&vg$d$HRTL#_5t!j)c7ToKSBAGIqPl#yu099DOe<$ zvByGRHLw6uv9utYhvQ*K!a4)EH*d8=8DXz=tlC6z|alh#pgu_ z9ruaW;LhFvm%WmHEQ13^Gbe_jmV&9k23;;!8P=AJb+;v8;|2W{d1HT7=0}lK@w)<0 z=h*2ZG!3#!Uf_3hvge_WSJi8BNs`DHpY_!amx=2e0g=?$*WMvbRWlrG)k!N9MpRTfd2m2 zqlVyU5@FiN*{h3dL^UpOLO^FJC$3Yqnop=xIpuw zBwgVh==~thcUI)f+u}f8AL<*Wk{sAyFn>T!uEp}nZR2uJ+aX#J35wEUEfX4Q2i;;{ zsq`_O8FV@=1{v=~`A5;rol$>h1J|Yu`%ym0eXXzGD~y-pYH2Cx&TM(!R2euL09?Ir zP?l9Isw?}ZpZ+?{n&0MnXaQeJ?U=s5>7^(L4OR}>Q!dE7^ zKSEh;nv?7fxNZdYHk9Mw8Tcys5_Ee7)@Zqj7?}pxQ(*o7dbnSfRVqpbc-&Sr{1c6q zd;`{=pvJ0u<}wdIJv9pD*Y;Vm4DhR4dwQTU2Z3gLu7 zu5!eXh9K#*PsbN;5}kavV{|VHF6*Qm&;Y+5Ww=tUd%g(}yuybKy1W80Ntj+>PwNZh zgNti26tkP=Dz5*+cqUf>Sa#|VpdNu%d~~oXzg-Oto~d*IMn*OgR)(x5Aww8w+BUVEm!Sq$sMLQe0)5W)oCQ384A_K)+0~e99Crq&i(mqovzC+8SHEA zEzk{2rY%=ta}`nCcxO8>%9-H#v6LywE`X;4*Ru8~l(&JcflhD-CJE!{to38NaR@}J(3$u(n%@-HKl56_R}-Gh-jX_|LXa%rQ>Pom4OZ>I9=W+u*`$-^Ls~90se~r~((?=&wltsYot)5 zPN>mRCpr)Ss9O+e-Lfr}+ji#ibZ4dH6Z`?kS{;%i{!#* z+wuf_-G86Vrg7Wba^O`uJ6eDmSgO@GIPAnT-g(?zXaD;d%9=sRs(92 z(?w;%og>a&^3V&e^$_TKoyegX4j^`?3%dlGMY|};%3@LaO_Q^BDd^Fs8=J(Fm6@zq&2opTli zvc)0GeKV?2^#Cx9{skzHN{`<=9k?{g4D&+Bf#qAff5fQ-A{kbGrTiO721cv9IHsx&T%ZP$!`rn?}JQUJM75`+cUXq%y$6RbjfWh(_E`> zSW9n$3^wegSH-C9zl+ZOlD&B^xKY zN15upA9*^I9SMEdRNe>Be`f(chZMBHo^_Ln{LSM5x@IsZPET;8)jK@$SGd~+bT4Q4Wc_SJCn-?1W*dmf3Emr($0vuj0i$1m8cFvxs0 z!c6vd+D#4^{4UCk;*7t!;MyDl-HUz>f4gH|zUyv@<8t-n01m8Xa@G>KR~26ksr&#; zxqCcUz#dmm<-acHnKNayo*GZ&!|P(%+}=CD+HEJK;;){JYdsYZ;)y?sSf`ulvvS~@zP-4vJrA(g*A6z2??#Y$y+ zE0rrA-}}JYt$~Q`ipMMRx%#9WG6)TZp}Q3F@RJ?6Jcmf`8(RZ;*Rl)}2G2roCb6}XTk)oAKT+@ z6j~GfJ2dPZLwffpKfjl}9?Gs?_Hk$Zy z?GurF>X?=c!q4tUkn)j31G)5J4?V||>$mvw!GqfXD3#@qiR0$A<(_SER~tS+4kr>+V3Og~!!wd!Z3p{dJWs*rgVjv2mcHx{o{bTK&CM&A%l5xF*5t(H z<7if{2y^!0jy(KCAR~~Zd&ffg&G}$2*m(2-X!|3*2`eg3E~zzM6vML|z4~ zQ)I!M&@gvVKO`Y;qWcF5+zkfYg8+IK!kFdYEn@ujJLm6X7^mMhi~(F}N}qbl0__5b z{&O`M>v-}4jO>C+2kmXkqJh#ibOF}DTHV#3xPCspEB&F81;tPoTn?FgdeU4ssNEK9 zDzNo9k>6M`AwI(0JkYMoXxmpV*dnqPXW`r|=3%x>I+B2f4?;p}{5;JyEB16lo&Bh% zA02cHLhH=5ccK#_xWM^1B^c6hz(A^pcJTG~)R%dor`)U~mo#Nbe^WM(S7$zl>oK^! z+xI!seTBi(cQtpZ2G=hta5c7MZ}+xjpdlYR?I~FWqYy-hT5xmPX#%f+`TJCAF~RLf znzaOOr!*5?KhOUDfr|W2y`sj^HnbD@)Q*Nckz*DV)-{FP zc(~f7(!*R{v8qWwgHRf+B11IIRtYn?^t31B(4}pOX~;bIwWxm03#G1BD~a+Hvb2p0 z1GuT~c5g(W@uq>AiW4Wmu*0jdd=#zzFC&vv5<$DVosBxr9q3cP9|e$yu})O=&XEa~ z5Srj~6O<@OUtcvT20I^w9XMv$m`cio0C?eoRQ?=<`S_2HkWD+L+KAHrxV_t8mliYX z3vgKmJ=4!Ephfb#%RMMxzVVftW!18_$|HzhlV`@N^38`9$&a5JP~WS@e8MyG>Dvw~FWh(xVnK53QWsvDs2knz zw=z9LOMqP`tcob?>|?e{%zG46<Vd`XK zsxxO#C-6gYll0ix+@zuI^Q~+t90Ar-6BMwjEup#5=E4#%_Vx|)<<@5x z$|p}$lctLZ#=kg2#&P-MNKXdt>*Phc6wI0mS28OxLR| zSKW08EH5dMs3C7{X$dYa7fgUX>jF285=r6`#Dqac%sZIP(DWDIGTd-R_;&to8t@#3 zaiV*W2DgRR2zVX&q2Xf^{O|5uB_|)US!!@8qngMuD|d8(yNkD;0a+2D>2Z_YAk32a zaJ_JUa%k;nE08r?7=t7f9yF2zhrSv~%{V*~W_sR*lK{)&wj@>C)yQrDQPnfR=L&9$ zI@78d7AIH$J9X-`%vJ3P^l&HJ%RPsoc+40AocmuGl9LbIsw8H~aBEIY;eT$Z)SmU8 zsENdRAq_R$)vyvGaHz`I`zBgAu$;L^}Yji;Z@W^Z7f`mPe(LA0R{`xxMw{7M(Ndhdrd95)DXtIT3e zMYbE!0;jwLZp;OjWv9Y5S9V>0n7crCZyp-VMg~!!_C>^ECRK3uOQ;Q)iA)H-$f&d-|?=VO_H~(kvE^CJ3d=dZWhbgVg~g zg|G+Kbty5hvu}zgH|^&dth5(g*6_UgzH0(p-cxN!Vvo$_e1;eejS!zR?Z)3KaD7B$ z3?h8R>Hsc94zIwE%E!CX$be~T*Wh-hJWR4%;F=p|>(K8zMspc54WKRTL4oQ;Jgy_Y zks`fU5)#zabp@Oh9k!;$!NtSQh6HweyH(5}r3IH)%*X0;hN*e+M2z{*&UR7AYIuF0 zvM{7I43SxzPsNBaCKg~=5HE<7F6VIIgP7oM*B7o>mN-C=W$ir#*W55q6C@*ZtL?&D z2*Q4KqZvuE7p2lr5v2u|Jue}^WNuu6k<0KKj@pbnSd@5_PiyM$GEL0q44z%!a=ijz zkQ9{^6@x7v_`>PFCrs{6u4g0LhouD*6L@FIh&@%;hPA=iGA1(GB;P?y6R}3 zcM}I6lG1ed^#;$(1(%Z=a7^0$c&C{omD?EwhP|Hh0thY*8g;HMO?=s>9;VB+-^JrX z$^zUp%0kS6(WecVEwF5&0ES^{S{YY!$>t2Ms&l-&VLf$f=FU@^>qR)u-)?~Ql@V+z zS)d-*Rc{NFov`!CtTb5m8f*-}nv_ajxu8ZN3-&|G!WJB~LOoVr+!cQ1i?wj}F(fjV zvfwLl(Ex7*M+OSus?GT*S?E(2q+}sdzO`y%3ahTXg@U;`SXRED%f>pi2V%iB?`1aPnK7R#j{7~2JG zR_wuCe*KVWH>?ZX+<^Q4P(G9-ZHe=$^W$=%2+sms7_^FNtU=aNL>d{NvJurdbsRL8 zM#A>`u)0*@x|7MT93WABF|K#+290$_tkbu3E>h?43Res_G}1=ciy8nnkV(bfu#C|7 zzmYOY_Pvej^g(4IfI%4TKPNLhV(_9H>x}B0DYQ{t zUr-sAuzvtxZ4z?FkNQoUBW2Jg6{tZMu=*xga63xYTuGS9+>A5L#Q=KyY~b>!f8&}k z_(8}apJKfNRZ3}Suve*YvL?gxryCOSbi>2apfUI=nM)whWxY-6)Ee9+VA%_E1~;rO zLLKvQlFjNGLx3CiEk&Ip8eHQo&SY(>H z^ld>#>w>M88D=?V23)S1aZ#()2sz8qw-xyoU{6_yP0#P-TpGoO#S7=lajTZe15Z3R z6<``PvLKGjI@hGX8p|n1ABAHol6M-iY0J1{z>E|akO^$3-Q;JK1g`$noC#d3yN{sU4S)A! zuB4%->u1V$Ufjb$F)E*xax{*QuDRqRLq18G1Li?CN))i=MbdEv40l zjk@#RN4lhdfMy0*&Npr~`RJh{<#%P4$0CUI2C*()B z{#-8nlk>O`gq-+_BjnbrE|m{_@jJ5m$!Cfo=`e_u_04D;f>J)bc%j7o2jRjs5OLoD zP>>ZS1v$6P*69aPcbz5$sgq4L9g@Q!hk%bJo&_*o+B5Yb&~Gt?Ut;4WWB6e z`>2tGtVa^G)|zC@9Vis~u0=0;uf$3NA7J|nF!vz17`~d($2(?b_tBzpCe1&8{bo7s zbtlMSs}7M$r6MQ4;xM`Ax{u+GCz7Q498us-5iMn5%Sc-)_2qKjxo?(-AAVF`d*T_0 z^JCe*eQeI)K0nezoy+8cx4%_>dFMUy+LO*e98;4Qw(W45pxbc9u}8{|?|)9c<`Y2` z=&)sGr_+(`qoeZK&tI=4AS+p$JIrmjnwF4X7iV7XOyF8+U;^OpQLb$@Cu7bgv1`KQ z=-w*Ez}?=mWkfE!{3^Nn%FE@DLk>~^b7(#^#crxArEGLsF#0<;-y$cUe4@Pb!V8pN z+HSYyh8w>vJIBW74DLdEq!bI+0U-tr~|($~NFT^SwSslHDV&R5fqXOXSd z$O&q)R0G!T$jHbxx#G&t$^)zaqnoW+DF+=e8-W8EMEC0snP#Dj>G~iKpfucq@<*Wl zNen8AHDS~W8<`rvCr*z%`h>je;t$J3?>b-3KJ!%R@9$UB*~>Y+qS(@EwdB4B*5Cs5 z&E4?yM!DpDm&w^@ogwvlT^?M$R(|ozyXFimw~ZU0lZ#R3nXf-x<_!(X>NO9^&wg=d z@%=sbt&vw8b-46(YUMJ9CILgxo6V-&bfOPyNlOtSo z$gYFa<)qI9Zrl8jO90%|Y>Zbqi%-ok$@EMbJF4SDf46QOkt_e<3v%5TZ;+#2{xX?A zZ%87C6*OX#lMT7+?gzV0v}yD6a{Ue8+9N=Fx96YVDmQ-PyVHJm{f*y~wGXY6g$w74 zJJd*E$HvFy(Z`;Y=eN928Zg7sJevZn&T#3uxO4!TvKx=5rsfCtqI?JR|06zgRjJm+ zOZA#Cc1n*L+~f1IsGD7ycfObv>1@+I1h~I9=Cbd)clDGBcG4RhSY0*Rs%0(J3vwbF zGpuEL?+cO{nfq&d3v_0Z>D8z7qDqrxLhn)OTv+C9}%7X znsqU^7xUPyYc_5wd>O!fIcN5B^&)XS0<)>dWHaB4V>v7?X8M#DU4FOs0iKzyQiikQ z7_Mo6O*6gVagugqa$+YdBGI@!Eb|C<#nKtKT?vP*abq@wOYnUgcW^O>_xX6{)O=X3 zhj)DaSbZ+eL^XYY^n$D&wKo9o3DC0ws=qLRijz9bmEp>#0Gk-bc4T5=2M)_fGP+$q z6)guZnqAt}Sd#$rt})BbB}l&7m>i#{0?LXBX^p?AmM-!00z=Qv32+8Dd!?cmm|a1~yZ`(lg-tV#PyzF9zDKf@}4cZU+Id^hL?%`Ag;!+n+M;^F$a2;V$b@6J}&56u;^$h08O zZR;IO>;cuu%i2)3%QGNj(~iqn0?Q}T3GA#(UG;9en}V{@8#k_PcrnU#VDKcsX5Na41jWF2FR)XjAj^t<5z?lmyG5^n#>;3d zrNA=wMGaW*HkbUK1(?_K@1hrS_!1X1DvHT?bGpfh|T5T*glIW$DKncZ&v##_OMDj=*x8Yx2|um?1J3bGW9{X`RA# zx41kMS24;Vk-EqzrpKgDg`a zEh8@zAkdGcyG5^HT;{NDuHE+JQAX-Qx04RkgIXW^ZOz*r1EX z(G2xiy_Y#T2ls(ODZB|geQJgU`T6aVA^EN?reMOAzU`l>Jsyc7owblwtWz+ zSjmhUS03R48O-%&hQWT;ZQ$JJj6IjRGuX7kO*4$0P71mtfk|$FiuU9t(ammuz3Amz zIqYoNy2pRUfZN`D!r9K+v3o8_!fy6wxVU$;T8$b?z%^ki3gl4hYwwylE_1zEz_n7K zb~;GN)gwF8=L=}82&x(LA}cw9K%>QctX-3Qul}u`z5V#O^@Z&Pu)$nplNoXTVU9oO zw41|R6NXEda1jWuveCQVuGU`>aRHv@R0dxuW_b5xw>T4q!!ezt%@0!39vZ5ziOy^> z>a@e*d-YGpaNAeU=G%oM?FDf%0vCa!GyZ!h=fXn21|@_kn7Qzhx-P8&9e9=75T#Z#gIwSU5EuY+p0eZBC3b=mA}9(KR$QNAhq zL2mv{hSvd@*JSOqzauS^h#-M|K8NgeFUxIQvEEUGEVbEW_ohB9`tPA}iV^KVL%RPa z+CBr-Zu@Ih34762D%c%qOdd!1is+?ex!%L8M6XwHD7y7QX__qs4CVC0?#%+q8O*fy zPl=wu&FMA2HlN$|72Ut)x6l6mS?{*Lm+T-I_Alv?L3Z6?j(u}N*IlMf?w?TXH^u&$ zMEhIbAop+RSOD$o>HZewe%n+Y}_qTSR_3Yj9l5YPA!hZhT TzJ)qT00000NkvXXu0mjfqu|gU literal 0 HcmV?d00001 diff --git a/ios/Runner/Assets.xcassets/AppIcon-nightly.appiconset/AppIcon-nightly-40x40@1x.png b/ios/Runner/Assets.xcassets/AppIcon-nightly.appiconset/AppIcon-nightly-40x40@1x.png new file mode 100644 index 0000000000000000000000000000000000000000..90954ce985ea06213d56c4472c9bca6ac248ac0a GIT binary patch literal 3063 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 literal 0 HcmV?d00001 diff --git a/ios/Runner/Assets.xcassets/AppIcon-nightly.appiconset/AppIcon-nightly-40x40@3x.png b/ios/Runner/Assets.xcassets/AppIcon-nightly.appiconset/AppIcon-nightly-40x40@3x.png new file mode 100644 index 0000000000000000000000000000000000000000..57e21a753f1a622a69b0cd821b8588640db986af GIT binary patch literal 15152 zcmV-0JI}<4P)ANifTM$o-~r+)tEkuu)qv3*mG9-t%s9UI z&-f!Ugg^bHra2bR6_e?5>~`)?Higf11@<5n0o1$jxd?O-P(LSyW4HV#lm1iyR)tL9 z1@`DZ7r(pDMUY)`K>2{i_UL~u9*f{Vuha7x;3A+tkfE39dxUv0=KV1*#k>sj63lZj z&&E7tuZiq)TA16ICopff`Dx5gVqS;&QOpn9-(!2NpNoUxc?^uJu_lXdQsk8jl*3qO8(mS`v4^0b?*HbW9*g5_^pKye*eF z!hW_~0*^qw8}n~4{|NI_n42~`z>8o%r|J0sumjeyTnB0eq=Ww)^Q#~aDp9o}FoQ6J zAfOz94g_ZhX8O064o%50)b_J{BB0}TTg5SFjTtQJRJRv{aF25_-;DWM%r{^j!`y(3 zx?`K4Q;L2r0rr(8st2*nl0BY=`EM{E19?`hf-r(8DnS^Qm{OTSQxFMU_h>q(X|Z+5 zQmp%eXaqcH+<7{-+bz{@HG_7$8JHw7w$7)5a2Ar`S7N>b^Hva`9oSB0KPNyx7XTN5 zb<|2qlB3oGAO%%v29!aKQcxYGrqpWB$$yU>gZI6VjQeY{GsYB;f(x;Hst5fLCozNF zYBho+j_Cs8F7LtoR?NS^{C&(fVV;6cpp$3PdApmQO@N)8by}|jb{6J$VSc;)&cNy* zRHae{qEaa*OTkjCe3!>ExGA-E19>NYjslyOgFRz1kd6JUP&9-n63XQ&#Br>e&3e$n z45F>S2J@d`z8&+YG2e^14gxgEYM-L_dV011_T{Vtwu<@XnBNa#+OWxka#fWpeM~JW zpq`?Xg6Xm5jH0C|Idlg#)v=1nm`sf(5G`f%S(Ab518t0EjzW3>f!%0K>Q=MixD(0h zt3asvpFzwoN724AwpY`$0dP^y60iqh{ut)t-ERVH6@e{hvb9LL9`$D5Aq6v2u2gr* z^@%!%vZGr6v&lf`qsh+YvXTLTb*u&hK!dYUpF*JPCEK>wV}2Rti!px#^Eh;u&wC~9 zO@JLscEA$VlHEz#r(?$mtk$J+AC$_K4p7sh_9?cz?Cq^w<>hfM`GC4h9E*0c*#|eJ zUeUC{Qn8#P6AR5Vtgr41xIK;fWPq}o1~@reJ`4i%g&=I3sF_%|)42Bv$a@Q5Cu`~X z1Y{rPBQbv##7Pm6@sYe3RNTRmeZ|VRebdqlta&=}^_4J7mCF6) z4~Cy?>}Ozbl?B^@T#&^oks|_~;E`Iu-|@(t3T^ADiLnsbIk9cB@h``G4(7GC@0@I& zF`IcN0d~q1$y)-J?AlLYJ{@yJvbKU$OZF_g6S0Hy;Cj@n^Q<@zZb7kfe|xdzoq0M^ z;j8RN+pj{xasideR00KTDN69D_*66GES!g^?`4$aw$q6VexSnHhJ)g300qgV|pWyM9RRT;*;OrqUN z-8^4L9&Iv0W^hxIH{QL*UMN{H&>~6&Yy#PSXKF^4P39o>)+DlQ5Z*v~3i-3YXdhgM z{M_>%rDqDTFLMc8nuGl^_~2G+DWC$duUM(VtWU;@bKWV(u5F1u?c5nn8R*I)or3LM zlhM2TY|=Btl?Z5};6#f|CNDNoM8X|ZMg>d}$bq4YMETl``CGOCH*NWx09*u@=4QWw z`33acO0}k(36!zsP72Q1x{wFi2Xl8orAp1k=gkci%nvlw@OgcBTb0Vj-|9$Z6PWAR z+goA-n~}OU;jyu^=62EBgq}T$X4##vsg&Bx%&sk+CQh9b86Bz;)CLAg`J!1X>dTK~ z9tLrYxYU9@)UNjw;3BxhmdQ&qkDl3Ao28sGl~S$8l8aQE_f$boZMjzpu*>!f12{Yi z;D~YvM`E56hS+(i)DV{d$ewLef<2$uV;l2i9K(IhHr(65jK@E=5;jn~HoYfRJ3U+r z6W78eps!pnP3RZ7m4J^cGom!3H71a{#TaKVaGd`G8U@fSs%TsbubO`Ve z=J{mL$`#9&3*h#&d8cE`y(xBO zsNik=RXDD%41GZWWeaSPT7AW=XR?|xCGJI<4#YeV8F+KK1ZU2QVQr%YmygxqS4iEx zfKH1MKZ(b-?Q|pFX|Rro9SE8zy94A9kozGe?+EN%^hYq?gZYoJhao|`3$W9e3EX}V zR`LqWr4lMs6;h~tWy*fmD#$>!)C?ZLc~eL_tXsh+lmmEmtqjLk%g~Q3xMZm{rBn}0 z|Ff|+tFQN_*L$p688L@KJo1zmKEH+oXjT-#rz$0Q2!XzCq7FYnsvhs?;_fm!-vT3l z8Cd+>g_2RyAjrtBCq_x}B4w4_ntzS?5fETWRoG?CdUpVJtl3d6&5{tns4bTTToqUw zw+pxhH>3mDjsA4PzDrt;iqZ#$s&G`*QY_}M0IEBZOx=V{zqu8|gV+rZ#tA%z$4NXt zWqXF5<9PXeyyqZP#8#q0b{ukr{k7ufI?xGl>}6qBSpTDNP_0Cu-`H%y=SL=BbtCT5 zOP;JxohbhAn&qWO8>aX#5FKWbb zHoM!qEAaLk+F7~Fv7W1NF#TDi;lE)n+j?pvlowF>cnyL5>A3-1H984jA8$ZoC)Av3 z+A5JRY$s`!$3n^45;)mVqWtk3bET>p^-1b;iX0_&eLm!st)0r_-2vD+GblWjW`&4~ zL!T|@G-RDQF^ZI%w{_j)^Qnrb&K;=0YX+()4^qXcF5Ju7%s(pSDa)M2zF`@ z*yhZ7-?2eoi1F0Et;1ue{X7;cxDvZ?G1m7jr2yW618lx^ooY+X1T>Cpc+;SQ!%881 zYGe`~kGqT__IgS4WX{4`z>ZuJ@dGgR(rIndpQsHKM9^+EDe#YqrEsR}F#jC#!FP7c`B2OeO>T!a@2GUv(7@;zW#E{TSlQwW3-ZOw8Re-eX%nsg^i0x~PQ?SrB1Fg3fB*jX&P zui7^tnzdognz-g&up6Pdy8^J!nkhz@0FJ`2q{^uy!%lR&?9K1$X}nb3(tZf;=ZE`Y zUj(=6WUbA_iocD({_m+KY(-N>NxRbZIcuBx|S3sQKX z#QoGpIr){T1Vus{zFI5c01{t0aSoEzg9>$p;XW8dcKwa<=|FZt1X(|@3sXx&wHQ?V zNpXOmC|wkQ*lgAbuQ!6Q>RTX_$6d5N+s2;If-O5Uizrt4WXu80=h9?-_epy12pRR| z*>Y#v7dz}z^Qy2I!L1N0RANq0cih@a;LSUlFp|U>utq5N6?pym{T0|R$RupyqA$`j z#vWZ)yAPg;WIOwilEz$t^Uxf-bg}`LO*UZ%-bjOu2G-VC!W%f)IPGdPAwVzmZ!rw_8wpvZcsy_sxRl5Mbo~(L0 zfPLyE#fm2GDe6&296y!UmUV$0`@p6uWe=G<2dVXw^GmR#8bT!`c`Gg->V(^x2Hr5z zM1?BBintk@1YU?hTsT;TBTIqpup|wN6X9gosUV*dYYS(I<+QCI$z|V`raTKD`+>m{ zyd8o3?2bBIIoYAcr1YlWYXvL2cj4e$av2H4zzRUR$yH`3AavlQ*u2s$|+w? zE?dH2?V5B7E1aoaWPaK>FT#w%pI(jm+aRI1J*l`Cz)lLdm?{dABl#Or994%BrR`*a zc7A1F?m7x4lb#CtxtpakcwYrs>j9@@2x%B;7Y z+mlE)Q8uDQ=9;w@u0#MMniYv}C3MnJn%YQPTnJsF$MlDXb)-VDu=eqzY8W zjF2CV;cLx3z@_tVodfWa*(h@(#SP)PQ>^F3$QS=1-&%n8C`ZW(_CbpKheZLrcU=tQJxr+7LN*Ry?PD$M zS_{bZnW(r@sln9b7-6#j#MyKyOtWfYI)I(*eI1C+t4V84Ls&h3vi3eJ=b7^U^#b?! znt`*BdaGE94uo=zisAZkfQv>F0hcDq5#ZC2L@r)bf~po)%oLjdQ#Z{7JwAoX(Y6F` z98)lEdOJ>viAq_6s>+%X16SgJI=b41*UwRK%m8ZN2()vDQo9N8PaxUvi^KjOHzUg? z8Gv>EEe@nl;{6xQwHyoUTt;9Hzyb4aRLVZTQE`2{^?@&qGlz&T=5!8ZS`g4cLQCRy zXaT+)vRE!RYNiF)QLmd&AYLB|^_Czre^e@aU4?u*H^sF}KXarZ-gfRH1N{~3xJcL@ z#WHQevG`${@-|7DPw!Xo)x|XZXTimP#QEwbhA}j6{$o=D-`S?Ig}Sq_-AH5>{cZ~2 zcTX8Oai9g~E^NU<)UK-pv}N4{=-bgGYGN0CW^-&kQwA;{4d5j>U{5CxJys(?kgIt8 z>3Hpp<1ySZp}T1FnLKtOK#&7iTcyhqlvB8n(2$C$v1B$;bmom9ve>yY)6@-MUvqv5 zh+9&Z(@4mSdbLs+MW?`eCQ&cy#eB}97?z-dQZ9)HhwQ&mWMzM|LBn<;%|tlPi~9_G zehIDii)9WMGs)L6q}tzXkKwY78lGqddjx3Dg!R8^T)|zB8u;_!7MwM|4YN^0Cbk{w zm^=BM^A##t3cidW8|!L(FV^Los7@b61|_yB3UB~p|D3nPz~8PhFw$0?AbSWqP2Tv{ zM@mT4N7U~LQ*jdsE*2`Lg#=_WIV#R+)J1@ua^Yj>5?}tYNOmmmP@Qz3v2%6sD|rzKuWoT2>cgU zpi)svth|kpa)BxLYfmA#+oN3-v(GrKsRwZ3;{X@#-+=j5wA0C4BDsil|J%h1?!-ZP z>o`{%wjd2%v>8pfC2gikjrAr+$f@%HzKNn_bF-TmarQ8zlGs?*Y?Q|pEd|rnygnM) zC)&jX@|l=#1HrT9Ke-#gZc>46Vs8d5;q>J~hlZRgRj#tVm7GIrF&s3ABQU}SgbB-@ zCIWcD`pAYlh&T9xWq@{Z%;P#Hvj>j^?sqo;T)U`F*GlaP<}I18<(6z=0L(iNcJM22PvPg70pu@bkK{YUlLeucn7ArvA4M z5Sj?i76#DCP3o^Hx?46c+6})0W6Irvy2OD<2 zCRp+BBO83OZc>0x9!%inbB&zOOcG4RoqO_&>n zOvxl0=T#NFYaa!ldrF*)Bw;Sy6u?C*ni5fqgMsAT84F{$W)qopR@N3+b@oXD4?1PB zN_8KS#}t)`025|32}BF${}m+MHf7V@04DZ)B8Z(8$ZS!k1EX_>NFLFRdfh!WWV^@D zYooy)f(j&foEmZ2rXU43!n(b0IZ|#YEB0bGgADv~tAQ)l)jFR2Y^UFkMR3VuF}#0e z3p)opIiR)$@Rr2@-`y0#<4w8l$6Et9Z>fPLWw8VT1bN|rfn$f7aO?JR*JnG^*o6=& z8&h2b*!6iBhCZ8qE#`j*!8DECDgx}xBU*04;Z3}4f-2g%ne!quiBvC7WSUkDH=%|E zs6*?DM0s-SjsVt7(oHeD*PW)&dhGyb_>|c?vt_x(y+WwP)BAdL{|${=Ic&ICAbJcCcu-6q@v^ zePa0P69H^&OZ3&Xn?rd2e&oIshfP2x)Lb;VqBd-Ab@wqjbt}I_2C`7w0wqTRu)~iQ zw4plK2{1q=e`!G!jf9Ln+eYOmH&w1&wLGA^q~THv4xHV_4#Dvgi0s{r!u4lcXgtL{ zGjs$}?hA)wnJB<>WD;#{w&2Gb2A&Zfdn4UFQi40SO~9%}2?qht)ME*$_%D~X;7gBU zry~`QpnZPbmJnXMuqnLS+Yow%101{bh4bnNaINQaeUr&Jt+mkizIjR}Q>(>$gB%Su4gst-?E~y6m;$_X zHhHfshRz`Ot5N*cn}QEVfI~8kNVy7R#NM(k0v9t(4uMk_5qqY2g*LPh_(@bpf3ben zuJ-t|o*o%1!^2~S9WtRcn}$%MK5n=LH*M7rW1H?831AZ2$WzDooveq0kxP-=wQY1y zDwbG!D~rK1p>mv5dY%IGEWosEi0rU&@F>`U>(=)&z_bxqZYC%NIb+XGvFZh`@?WBxv7rQIuuUp(_cMhO+#)S9=TDQ!fKox#=f18?Rmti zI$P?2RV)QH>h=EWE-n(ZDzyT)dx+0DGe)f?u$sOu1#gSxA_dcr%59PY&bCc0q0B5& zUirPbvw;(qjlio9MN^_Ar5P<3k9e~x{iTFi7~es0Q<^%Z(-A;T+?T^#12mxwJkU;H zdty2U)XXLW%dkvZe@v4i_uDdklVWQlM1=|j;6SDe`pbz8KR|1styyV|xR+^#MgoWI z(}33>wh?~t$9brTi8kHcs|8Y)T^Q%F&y2v7$YJ@y0g}WTXb-L&1yk{~1%uLlm_2j{ zHmyXDL}2{I5l_LZ4jqAk3Tb-4!Y5G@bg;vt;3_I#Ng%UaiE401O~!foOWyPk4wPY4 zwZvgG)b6o%4F57#hie<{Y3s75iDq2h-(P|g`^ssV<5=e9<8`=Zs-1#7*&@rJ!7N$_ z5>r-*@8WeS!! z;zTtCU_Y!F8~t|!B{->8;WbLGW2w{69aQl6wh6eWJ?#pP-A`ENd$7#Y`m4O?%_S=H zoLLGUYfr$Pw#>F%Gj4ImD~pb@n`B*DWs^auHUZsE9&lHpeksI$DPpgc|;$zryQx&!|Rl z&sY;?GR?y>PqSriL#qAS=oBo>(@0_HmgdxN}T)^=RUVOaiI56E#t2ax(McI~T&z zp~umpAWlUlsD?0@WCzH>OQzsW$36l7cFXcEHF3yx(Sz(U(}kFq)0ZK4fltAd*=;0K zgZ}N_gLlFSYdCV>vg!$_)j;HKARD=FZv^mv?_LBydt?YENg&y!lrCb_bqob`5C!|u zuGFz5UL8-tZFRVQO4#{9Q2<9)O8EQCyE2!CvP_i9{P(dbxXzY&AeMP7mbq_~r#7Zu z^1=m9+f`m06s+A*fj9i{ARPRYaL!R1;E>@-Ai)!A1R3u=dF6Jv`O#sx|LOi+s9kqX zYFT_rsNhksyQ~DAO7Qe$6we9r5OB~v`cJQwm z7)0qeJv9WkJUtseck09N(xp3Sb4R4)Ci@ppI%snTz&`z&ZggfjsPZqiIC47**GGlh z^Qo&m&ZmPHkEI$j3L0K{aM5oMKyaxE*|Ka`W0o)!Rq14KEEEj64n!CuYeuO|5XC_Z zZ93oXx%O($6M<_LCBMuhNcembdu1vMC=X71-Y(>p--Qb%R#~NmY!|FP0KR|L?NEz^ zJ-4jM_E^Iisc|Y$Nc@8fXc)7NiHZ4`vPJI;eCf)|84#cId1k#`6eCb#VxUA_I-v)Pg@#XSXa6 z&n)P@BQe*oWd>fE6rYXMmN3`ID#;tGcruushOSOl<|R3G2jKp#v*2Y1u1`CkJX}My z=57IOa-Y+0X=G(sxRz8=)6*8qJuPqSQ=+(|a)qYEC|ZE{bQwllvpnTaSX7(>tSrDG zs7NLjbTS6IfEQC!sg=q$_ajkL90~jOxYCRy<{G6~pvX)R1dz(a0oU@%R3efHARScg zmr~kZ$GMEhwdnkgW{umeOdA3<#s2zPwLFcP!qI)me=nYd)T9XQX_ra0o9zQ^3U{Uw zze}R}2hkuqHFPBJxiZ@MldY+(NGfak#hZ!@uygus4{Gix6=b8B0FFzJU1l0HvC5=` zEV?=K@3vsMZ_7-yduB#EO_KIfP8$R!YaCH=2omE< zBR&I|8cp%U8FQiFJOYzHd(~q~ttekETe$JLI|qvbT&t2iV5Wab)0T zC{sff1q%cc>LVk%05En~8|@DkwMxQHbszxK>Ox+k;j@1&@{nbWPr;5|hI_$IqR7Zd zIGynZTN27(qp)7Dg4o`gyrRIpUQd@&KsgRtJJZ0kVRdBNEsM$(&nIW?voG4~;mBd-J_XYWdc~?qk|N79?g0gY?c~>rD46!D3~e|Hv0A&RSwNP+d)n5IqB__v zqm9!dvHuL(Nt&0mWS%LbtQJj;@ibb)S~L;;47({IPr*ieb~~4uu>8*&Eh0um_Wg<6 zZU9-xjsUyWAZ|`aS=LPeQ@d$V9Yto+GgS{gH)X2!uYnX3N=cH_>Nh|a3Z|Z;7epAo zIKA1V7qDKHm6sXeo+nL*{g@rVngi^pfgu==iZfZvJLE8{vND$d4vC6WF~XpB>ujPX zQiRN2q2SmmZv`_cXknQN53KZ3;#3GQh0ajBg@Rk`189Oy<#5KHH7i^#mcawu&LBpB zv5iVmy9)%C?*9dL&v8%o+C9N6!1RSWYCRMv*sTs<$6rj6l6`)pxDo*5l{0RZ(#jO_ zu%Z^J!*WW&G&4oC7|O;I9u*tLxtYlQI;`57&`54u3U(|qVTFf__OxqZm#FkaGyn1! zR_tg{sRF>ERkVEfC<9zg2ev&0ZOf@r>h;!jwG>lBdOdL|je|#Nnvk$di#+jY{4adM z+kMjjSguPaHiEZ|)Tdw?0*}hG3U5>Edo2}H2eg>QNf;@Wt3qlhIX*0#Ca+Rhw;hqiX_=sbosBu1`QQNYp4l>W<~}q* zlg}riH>fNHD;(G=l$ki3bNP9q$Y6A7Iu_av!mID+y+f%cXi%1hBo)q z8E*&S`4q;J$>0Q89RWO+HH;~^Y3*Q7?yw!)+$&0!m}X52R^EHYWqNX-*BDZ}qq5yz zN(LV&8l=A5RXm{UZk-n@Vmj&*pjZYsGV8$z;iPnHIcci*n)DYw&+j;v6Zb;_V1SH8 zlQWdq^!{;-G-t|?X=zYk&z>eNt>iz78%l~+z`v_t!Zy@E9djSG&9Y@Tg~Vn?XepB^ zxMA%`ud^e&;eOFoS!(PxEjqDf<`uixmg!xpbULsDCxe4=D|-WvHB)4V=2cj!lI6=_ zUZvo+h03$ztfNi(-4P$}d>}HIDoUG(_oQGN1`lK2FK)NBJlmxFK9$P=ZjBT;%60yD zX3>Gz!VIvsTA`Aux2B?<;hZ2%M5yY_4mK=<1F<919)wh>@ntYi&qa{y?3qgJdhAjr z+1zolOtSY`G*x*9O}t^SA38GU=yOZoTE zWp$y`q8*z)oo+IA?|BEZ16nrDHXe)4#v6glRLqeL$|?=Y{m4oc4e}t>31mS9*^zt+ zD;uH2mU^8XyUzBAwQFb3P@-~NnNTRRV^HzZ6+5tfJJ{Enku^^#r)XsWOS@%thYDo* zONTy{)3!{ie>qIzb_*a=uqdZH!}|a`3clN2K(95|R?#Ys9AnAY?UL@wmyui(SEaHn z+V3T7z@(84xh2pr5el|47?@RsITlTJv?>KsMBw$dtoX9gY%`q5b}w0K^vYDBoQINE zX3C=bEEST5T(-`Q3|tOb@;z0q-A3M)#`o$FOyM8osMq7FZl5p#m@uQanzq5)-mpl) z^uzD$F{0O)(<*ZRC5$O0+jse8Zvb;zbj{krvh+m4-yET_>_uHcSTqqRy>;BZuC{|kJ1QnO7rhALMeSBA za3jSD_f(7a*mU+rFtGBsMk~iHcPa+2dmtO&z%v3^Sy`l5$tnPhogGx>aUHa$MU#U+ ztON-3%uo2speoz)i)HG3nWPar(PZso;y`(Di*umB8Z)(<&Qi1~E6^&)lv=Rh76{CL z8+p6kbXQZRy`*z*X7MG7lfiVsuP`5jGB~7n)YEps85O%?Z6S_L6U6kDO{6|v@dix6 z-KOy}kZEg954mX!7@q6?64Ko zo@f#ooM4@e3eq+f!KFm&dQ)FC#f#(R?R1Op%nb5bvV4|};>a|z3KrebUfsd=_M@a5?wX*6mGLy0pR#B$MGqEBAvCkL|eEq`X9Qr1Qb7MVo>QE@OwzwMteN z2q5fo9fW8n^TyT}P4mG#@$JiCl85u`=d7~{;1JIT(abAZ8p{k_ znVuFMxHA1gMU)y^(L{6MQn_iLzhc20c=>Th@b%1YagaQ{Wdb%lz13<=PX6XWb==dk zXNT9-knR4Sv!Z(eOe28=+cz=4ui0z_v^Sz%WSqX$+SvEx8n+b;Htpuy{s6Ci^(%q4 z{t8jipuH9^I{PfxGTMOe{OWhTx-;`d$D&PkuxQIJwb$8Uc{Z}{h1l6GnCV32iwst| zGDYq$#IlWlF)CO!D~IjQ2)cKS*vcgf;hK-V6ROoAONq2)MGUKNy)UEQT=qatgp!+e zjzT52xDDhj;zX1k?>6k_1EQK!kI{&rjkVr^r-t!?x`Kvll1QWm$%OQs^|n%^cCEhU zPPqTUN8#wB4#P&5+2pBKBDnIy?}XRB+Ha-R4`@v813RM?iDa$=vJ`v+LKtOg|`y0Q^ zUI5dD1TuLkh*h77RIGDUY!qa#G|yxP?JN1EOD=~mT=Y?Hq^jDvVr=vqPC1Tqz1f1M z7t35+&FEy0OCzH=T7w}d^;O}NlTU#ge|>kIH@y-*@cNhK+E}ZUz+cTTKs8}} zVgkN>)pf9b{l+f#ZX(2Fof>rXsF%2`dv8P6H|Jo-31y=g1#yYDhM z<&=})szVNjfq{PL!_KeQ>u~#>_x46=57T3hJqhbJY=#%?w*p@J(i7mSD=&jut&huW zG#YUG9rtw9-Jdh>)<&Q05?G`KkB^PRZ&u$9|8m)P3Ra4x-o&Jo%lE}O>irprp46c| zyVT1~??5JiX`5QokWR!0m+1AevOBv3uq%&MgMHTz{k!G|{|~lq+YaZy?_IEH(R?VE z%gpX%KPf7rn}$j9C`RMG#lX2l-~aK`{|7#F{(E8B(j_o=?l3oYe0&^!ebdeGpJw%Iwz-ZZOWo@Yx+Mp0jBRYT znlLH*Pj58>agxC&bBcE+BaDU@T&a;(?cx9>RYWgxb1hxY8!&H!%N2Yd$ei!ld{ z`eZZ4vM)cTN37ql5kBCZVoTZzE<=?yn>?v=>F^Qq5W3TMCVEYuC=b_F;_j<9`X6bJlTR7CH9d;jnd zQ+%hkocw2XR}(5(afMIaet+}c%!rG~kcELr++-wzE<%!>8&@ty0=f~hQ;|UsG$1-j z#GPU=_(S|#DF~8HAY>`J4_Sn4jQ?aUGjHDO*WGqs>#I{=)w$KT|K96RZfA`?|Kc0@{c|sc<5C}IvVn`@pJ+@4ZZ%^RMYZQ# z1U7I{aO=CGMMuX<_?I+mshk%C7h@s$6+iyu9qh_m)eeoCgmLLwb#lmx41L)&`a;7h zuQ$~bbucI8tb)w@pSHJaEVi5sDa)-<@74r)D4wZs1%UaLA8(5?-Bj)c%>ytl0DvJM zV3ObO$8Y=>uA}&tTX#VpYrsy|hl9ZtcIsETf3MSq61z``2U-k%C(XWv6KS4g7sjV?LHvwfln~gi-TwaW+W8By90apE z!q+)XW}v&{xZQmeeg=t?!+Y%@v*OHI0Qu11T5hFL#o>X)==HiNG)lt?k;Q+BG8+RM zQ)%98CJXX^{dmofC;cz1@>X?d@veGUqAqqxIO|Rom(zm9aB_-po=r}kDUuVQQh?ix zPBl4plwKdg;ywV=hPlVKqSs}HTU64#09%V1U+`Daj$6O%_YOADEE=gj`g2llu7Wik zdA5p`RnpQZi)+^WKUzT!Uwle|p3b%56BEGAt@%=PssZ#c0e;X8B^@~LXeo=HaCT8) zCM}YW$czts0fN6*Mf>Jm?(Xldqx~j2w7@TRqbNIo=_qnDIXPrFj3jTRU>?qpC^Yi+b4PzU@rn}=2Sgz=v$c$E;$%FchFDZBDw;-3q?$D7b<6Pn3Qn~ zGEn=cXb;;*{f)Zr-fp#h{+9G%3vz7i9bKphZmhneo^mW6R?p_8y$8}fVHYIn=gwx-dDZe*xcW{ z(K)w$K3!gO^0dtxs3K?q*XUw7wXDh4jEoVgX&kMWZvwL@$n$}jK0OBLM6qmr-H{1i z@EC>Fuz>Hu^+pxJMGDSiq7srW(L$n`bd*gW)W;yqCR``1A72}OKiJ&6dA-`+xhNsY z5R+HsGEB(ff;QHEe6ee|NZick5{|hPXM8jlH@wXNJA8a0z~-eHz_z(UX(gyG03K$8 z%8TWG=3Ka;zY|S-glIlAxS*r%>R~98YkTkeflRe0{6lQ)-@Kt9udN%ytJaDRqTpuh zS`s(cVoKLb1Ugj*u&xzvW0l5M31<0PboMN$Vwd^~f7ftuGN}4J%eep-JM@plxuj(P zOmR(+UllEC`iOt1b%<+#91`Jc&7)Sks%ikO*xIfxRoWhts?sE&6GKZoLmvh3I{m4q z9a~^0=v>RW*3acJTp<&s0;rFRa_&;V1ubJ=9*wTr+{_E2S@zHRhq={@>$T0Ta}KS^ zW5S9i2B3)rk_M_;Z2Qz8vZ+VO(d^-eiFB?ZzQa+SUz>yozKakdfaA6iAV{o zF{+ZaOfC+wWp61Tq?I8Usqk~*3gN}2aV}|@J8Q|o1Q~$CV0grjH~qNN|6(^_d?6!* zT}?45RaGaD*&8>tkujZ56=X?KFojgXO$A}n`}{<{xeW6JcUSc=f)*J`nZTK zefl9_d2V6OEH~qZ0v{# z7cP*snAh=1X)9B=_0wLRRavN?vwSK(LfQp`2o>1l-s-! z2B0efjRw^f7QUy5YDwHIjVM=Ezb^gP&Sa^BE%!Ek-T0mr&E(h!IFivr=0!gNONoUa zF|r>Ka>SdZA+=I)LB|0wi6Yxh03P^5iQ8lR_^ls5i$Hh0cy{O*j${H_-O>PA+CkPg zCh%@axOJnoRHuFZMcq5-}LaUJQa zgC1*BS+#RL-v0-Z4JbUD)w3(pwUg+$0VdJ-;6u|80njkSP+j2Hemv;MeST~z*asL$ zx_1B>T-`w##7?Kl(RwsTyqe;;JXcT=pcoDZA@T%HH5FY6D()S|6Si-DBsryqz*>$y zHm-O0VXTzCA0R~Qm7b)k3~TH>N$4AOZ+gUu>u zjx-MH#vcVUW-($1LO70pr73ZEuSk~qhbXZBHuubJB-VgB5nxFt4KRtE3<#`##{EI3 zA)x>|?Z}cxgKvBQeY5uJdSgH~Hh4qWgQrL(G zHwPP{7&9iPTCP5EU`eM1V3HNx6x+-k!M%cWQ27M)L$Eg!bssMKahD%I_v5FcEplVQ z59S(#jZ>3mytMGKJN;|XFzbKfz#_mvGMF5eQ;*ennwL%+z$D8-k;ReX&G;Lr@7kIb;#ek$p-0&K}n zBD+yx*ecruo#(JAu99@0+Ii=_W0)zi-e+)0BvSs+GwuQ2(3(p97n8HO=vS&nI0mcc)KYk_~% z4T=23G2%E%q9|0v_lNn>)1=4K*DA?B89*lk#37YPmy&KFqpO`<-pb`%!?JTQO;a(i z0gzH4iZ}U9Vk1csLqHKszwbA$4t(z_0(^y&{*m-3=_n~U5kMybL{z9iT1EPjVVb|~ zx<%8?7r6Vj0$_>+OaajjrZotljbhjY<8TAwsAT!Rx4hxi?jyKcIQ4GQ6Qmln%AGPG zGH(v)b7bz1-FzwM=8J|!076uwR1z%!Es10(^q(XHL=XZd*6Ie!c93%mrr)S9_3G6} zcx@x6-T`e>{;2>WhAhVWkZtGAEtWeCzCwerQV^B~A<{_I$!G_WjUUgg4!}%cDliseGva2*hRC{Ilz3%fy;c!Na5J>3)u#e89T1VkO49f8g>rwPSkjUZ zAelNTDVR+)GE(kk(Z#lj0mnk8e9rgdWOi>DV`mU)JrVFC5q_A+|1vMuubIQhql5cn zb=E3l-{h?8dDjn9Fz*%UDhTIa7n%5hr*lN-!L21MlLsGc6Op;kvjam&3&! zMZDhd@wForJV`)G8AZ*KG(~9RETMwONnEa1#~)ELAO+yS&;labeNI z=lIxvs`_|vypD^50NCK zAh}!~4JS9Bl9BlGw@AHMI}k|#KTQy3GuTZ4p(m{@18Wx;2<#9y>@iS}LOecbV$ccj zY9+*%_r&-`1#LN&ejTF9JY7vlA>KC};Esg^*6HwG1DC%M;ExW+*fa=yu-Cw)yno9G z^v0xR57z222wu!O9n)qE=AFYB@@j+Xmv81sv%%5>Tkd* zCiwR2E?sMgn-?`uGXvbWt3VLuluS=GLWcFP>~ipMZxz=L*m&fCiEkY?@xbyBzq260 zmP3xp$Bgv(vau@5HYFc(QLl}k$B+6*l?=#YP8<+VrBd-M0W^%Js>|!jJ`XWn>yO{I z@qsxWdO8~T#lZx>9?hLFh-~by+t@ag;G^7>OQ>d#zg0wq3FVo+4Y*c`&I8RPG|TBS zFjOyx>U9BU>=qzmA7@klOl8;^fM)ip-*>wa=5{x*JFqb1CHTPN2K=0dXAYH48bmh! zgFAomdq=Ul-^BWTdHfHnkd<8l20DDadel`?$%?dgFpP5sfk=hAE(5ZR?#-B(#b#NO z9=&BBM#0Cf@e;2lSTfh6VtROWbk@5DvTM{qgKI6BYpO(YSKXlWee`u|AVAjHXfN87 z@yq39Bs&8#V5u6rRTLRnD$dbUqOU*aAdF%}H<~CQ-JO((<6)#>DFa)}2wmU}k1^1V z%ut}p1FtALm`8iu!1-@`Hi0zIRW{YyL!wTF2$!!oj5o(^yfKn*^=J$5fFI;aV{nhowfDl3_Rue z*b_#$vD2Mi95SD&%5%)ieq0Oi)wu=rz>xkTaudbF8>4w#v*msG%9`C+)&CYQ{msKz z_uPUBYiRRTe`NtP12Sa*IOFsRZ3B4pm%XTkHcLi{QYL{AOzNG(ysv7Fm=qMImxhce z=j+;?P9rGkIw@8_=oJmAO-%TSg-5o}$9eDBkEMeQ_0LVYoZ?-8$eLc-7SJEH>3E4r zpjBkV4m%Wp$k5#qvoIT$Sy8(Z<_Rifnoczfi_&Y$PY=ZPRa&1=HG+}=FTg5vkO~B0 zsb`2KjRr;7#W^T<#>cIZwD@eMD3UmjNOq~SaLSakAG8azabl7>_;%fdRI<1cr zmGev07-c~AN(V4)o~0P{tL4t-17;y)4W2NH8%){)mTz`pJ{*hg#dsTGp^n(2zo#&Q zqNqyO%s`}8Hy!v2$Q&}v^@=Xn9;H-lmGK5rnU+o?kSZq+H#axyjY-}Goyvz9kXKa; zQ#yc2hFCw;%FU*D`w%;02&hWABu2z~R7u2+xU<7ltvVtWDX}f8Rhbrq0>VJ5ffOjg zadpiu&L`y&Sv937BKgqD6I?fe93?x$6C@%eJPYrcL_`5!h(gtiRZTPXYQ?H$BS2)g zOzwWe^jPD>R4@V32gepKvz z%#zcDL(>9ril^(yY*mo&mQ-m!LG<%_Cu){U-G>f%R!*s$={B1EVgVrh1%WT?dVY@vL+0fHj$57|?uGxS7%U@yrhAp^e?Pd7MJ%2{M)OzaJ7Ah6(q4peT;P)?E zi}CR)_U_+5EeIKJzE#DI*MAC&m!6G%LuSf=scdj$!~M#m*#sH{0e-smS!~*}O-Umn z2zn}b^_uYeUD5$e(nXOr>5wM~>qA z8=u5CzqKB|-%tQz5+woJvPk1=n4+&GC`U^waZ=0!$8(0rtNf1V}p{&wNg9~|R&y*)SnL5#t8FH;2=~#i(uu}k06fkB4 zpxP&t$ggSi??0-0|=89+L(JLXm8P%RK5 zg^;#Fex%tTMtM7F1gULI1qA7Yy`&p>6Lomh?R7xb$JF^AR!p|03PQ1*BPAl-7PT)n_WAB!jemhCT;r zhmuKYG5~E?pp$Jag)Cxgo6wRF5S7YNX0-8_pxy1H1r54bXP5KVAPFeQo320Lg~zl-Q0WZF1NmQkqXt7m`-8D3CVhAoS_5bRqe5C|c2&hU?W@B6-M*n92$|L0^lCkYF_{L?;r_}=w? z(^`A&P@eeBGvdB4e^+j)BQt$|Lbh;!pTK}-mF+vPfq5-U8JM&ri6e38b9vh*M0=tD zVij+dPYDOe63C&DgCXOPg^-&0jepyNbRgRyTOsQq4?)&Jn&x*`VkrW(-@)0RfVfPs z3a>ySBTs@n3-WZxk&we7!!p=xm78mtEISCyeURTm?u6V8nHCLT*GNx_;Oz6ZKLByf zkOiSCTG=N;PKG>BG#~}@q?#Xy@B91!(XaV#Q~iIMNRpKd1N*1c8L9{(=7` zaqM+_ouJq40H7|9e+uMOvQEhP4tMSMIQQxKcdmpAR2t!G6+$2f7Zo3(FI;{}DABGJ+ z1bHXqYRKh~4Wfermoa+3~0p79M9fPO%V z=4xjiU9&-dqkzcFnEp&(!&l$e42o(E>2}(Fr`?QT(ip}44diu@e}P;9*(OEC%sVK1 z0}#*bm#iQV3{yW0Ib9S$UJzAliV^Ik76h;4s67`1uV|)`gr+U@BGrfo5H@Y^W9aQd==hnW+a|rhyup|gY&FGA~3w!oU9-+TPfP7Tn4#BbY;M@Wlo^X z6%Y#sP1FeFjiO`vI@l028Y9|a7r>z3ups!(``nSc(Ud-jmmjV8&4AO%-)T;GS=)iMkSU|FO1Ktlhoua++QoUhnnUh*%JOhfC zfg?0iC15lt+P5I;66?!qwIOyauQ@%5>ra_aF`*#E+9o9in)e9j0?uDomT%xFQcIu3o@R>$hUY}Hm1cQS ztUwZdp}Zb%dTOEqbN3W{b(QEu_a2!8D0>2kYo-Xs1)@X3s8%0V;VhNUNJ;|{lzd0g zXAA zWPJ5i(PrC%VvC!*+;$g`vd>`nr@*K;Mm*hX1~DTToNG7$c;3!ISb(37i9%Ub3FKhN z5-_ZReGd7a3h}0)xG6+QTjN9??j^Fe+ml~)V%dUa3e8`;Evzvk$-YH>yhlm>AN7wBuMF1u(yC_vFXT zj@$`=y5*y|z+~v;tl?*${>0BCKQDXLG6ZKoHMyNkIZSl)^;*$&F$>BrHa2EcJg5 z@)pVSlU+(4cNGw8s;Dd0q&_Cbfk#n&7BGThSX%<5%nDNPtf5F=JyMfpP$Ge-5CqGF zQt8Cz5qZub=2-cjk;&;g4qodxrx5`3wrW-Wa-=KQPqySMlWo~l0%oSlzOR6RcA;M1 z?>~Q5N*hBXiYe#})YC^Ge=i!0w(NqF-xWYSb1dp>Ipoujp-NQs8BN*fsq8mA8|IcO zw==QgIZ+_*8EeSOS`|r54ut(Xs;mR0-WjLzlU^+M;&lxaxdY#|Qr!h>9_j1JlLJpy zp(8vC=I&2JPdPi)L0E=|RPdhQya6Wgl%c9zwtZTzo$eO3S`+a6>niU%*jMr8e!(M`?4#DNV}ndLq{w1`^n( z;@nOHIHw~JI5yC1i#R@lbF4x>1Yn*&)s&02PRsh)*urbEKE-HOxs`$?0^nqKGVHaQ z%u|##`IYG5kKC9P$=iZMZ z^iZ>xfDp8kMuy}lL~!SCnUY)Ey_rF=YVow$%FUN8!vyMmq{dldmhzX1F0U{gwk7*s zd5^mSh-<2riMEBIVus4VgDeZrowiQ)e9zx07*9cO{ipF^IfN#P4%;w__Wb--N3H}I zOv(sC4XV|dXbOdfa#AIfr-XqV0T9RWH+AD!dPaMQwO0=*pdwwp-SG*$$EwGOCEVCYY1zOIm+3<=K$h|7+@gB-xBEhI086mpInn9Qrr0LHPAFBcy$BulFidZ?#p z&t&ZSPEX!F*^%u4A`}e<&--am{OjtGoEcSQv0t*>Y3|mCJ#AN)0jv|zm)?q?u!-Mq z>U8Crc1LbP&)3C6Pi_PAUI4&8i2c65&H=I%=2B!4qPla?QAUDE`O3r$pg5n^@V_tS zTysMrny zVT*&w%*r2e+A|?-9$~pr zmNF$aN5DT-{Bs6abw(qUd*F*ciOA}^t)5~V0$I6eI+36DLb+nBA|u!y;SnM+U)~Wm zWFnoCYbQ(Ar7#|&J&6ufbacnjN7YGu4T>I9Y5H;8;~X;PZmjvuIEFG4ATB$&g9=N} zfvw!yu?!_MjP?z1;7g$33lEB9X#;shkg7~K!FK<+EtdZ`)l>d~7qbA}@b93Y*AGWJ z?gt1=_9%p-n`r65Jn=O)WpxGv^g|V#6CE~3=tCPeLypApzXTI`TPu)rx3=ZJSewD0 zb`p8h_C&544^^awL;?))ov<$&hEzQ`->NX5PL(fEmtzWiTQr>BCDxIdmAz;E1}XtE`s* zjLQIquZC0;ISzK?^9NMr&|~5 z0vSOtz^Ez&XmzmVQ%fsy+DWLK*S{mG7{F{WYShadeV%*2n5pu183A7+CtZi*Y!Z z)hgtv3w$|iQCGgc**BG67lb_j$xN50$5W`Q)aZ%k-mrw7{jH*N6Fc-fDG{K{e0(__cQ5k`6JW)E zY)s^`4FNKAue{scZVw?3`S3%jykucl{$_bs7S}7v;WOO+i*Zlx2dloYQS0XOTLU>B z=X4Up!#UQV=hrPw<(7$59_@G~P~7^LWDHTD_{MBeupf48!xGLl;A|W_!k9U!G9cDm zJqhvx1xU4K9JphmEGV`Nl9fICP1VT@dvY{PMkPvgDH|Q)@7IO0rK`bM6vT4Lq1aat zs|X4%Lbf3s{q%z(KiF288w%xy^SNPLAosOm`S^;K95NIdPy%`HQcv!fj=@At+7GP{ z8AUHni~-l@}9(rnn*HR*~ezGg`nR=i%X%MSl4$UjMmC1GLD zIXhHYoihrvv5Y=*Rbs~gFhB}7dVa+0jQ^fwnC1nfEw)BTE1XS;BFoe-_OWJ599!h@Df# z^7@~PVn;m(q3p~H?C3XDY%e*WEz1$y2V@8GmL15TFMc#KBR#RaV`(DCkEP0IbO6Q{ zFyo_ZD)QUOy+7snF=Xt2e{Uq0{7F+*z^~NMS;lLDoPQV${Jk7g@#McY2lAQ&5N3{~ zY8J{66#Uxd9r?uChT4YN$d2O0TIYW1(vC#9NIFNBt-rD%k{v31jOAc}^!7t~DrWD& zc~8NFUHNbTFy`4z&C<5?e7WTQNG^I>OM*%u6)@$wp2qi^EzeAr;Aet@WYPK(R)YCn)w#laZ`q`1q83!bC|CSU z^QJOl^t0ozp`IMNAjOWfsp_Jad~E{{m#CcM%`jzAq$8>}{uU$Vh&nn+}TRl;c zZ$H|W*RF_F1V|J8jzd$qX*13l3j7&-&L5C59MNEe7)u@f_=JTWx$*J3`uhS)j2==u zvn8wL6~$!l)c2o?wn!X*Cre}yAlyjRtcp9d(>wEsCy%W1W)FJYqBiU$dPJzlrEdZK zH!&3gAY+KOUIFT-U`|YSAOgAkj}22o-1qI8hwF06A={8EXqK!R^X1u)pKkZnIelwm zDCex`C{r6k*~c$#XMhx%)r%PiPF-uFa0QYRVUqFxNzS0lz-F+$ozR&Pg7-BFug zE$>E~iUaxKhKjs$q^A-(Uc;FPjeibyBv9aY9hUf^`2HFEAqYdS-)Bhfyfc;*5y>O1RE`8ge1MS# zq4HKg-(t-baskB-)~C8^wC~3o_8%Cw-2(si(!-mo#1ld_CoP3}T3wY%ob#r3DEBr+ zRt?h!^kmUcBFh?Gd33rQ0*i4amLZZ`7^h?NJNoCY2IP3rx>o}!q23~62yd|TNvX2G z$enn8kR8cq(^o+W&y8*=o5#QG1u=Uq*{-qbd#g`1e1Y&4`y&{<)nSu3fLMm`223wwh{K5t6!*9@aAesC z0D;oeFi-q^2B3cw&kez$dibKFmDHI#oU0-kE%DVnT+AJpz3mHQ_H zb>4caX)MbZbZ6X;wgq+$v6q7)jt12s0*QNSZYu8%zC##HnSBrt4$}@%^S&8uv3$#X zL!rnzb40YT0sm3yDF4CD9%-sk4aJay7g+z%k{%rBy2*VX>dw?2fzrEPM`Cp!u!nQa zrYP9UCeoh2oek<44l0?C6*+$GNj)13STANCY0Wz!282m=8LLx{UA& zuVpwqQ$9Fu>4ZG*@F|!qn1Mh8yRDONJr0MM;HWX|a1UQU-YjP2tlO-DSFPf=wY@~P zBzZJ5AB|%bD{)>6pzufIMAjwwK>4O-1)T)v%`pvxb5#*K2U-0mN&ni*NSw9UTc%@v*VGEUjphISrHcFFTs@?Pf3U z5OZi_*u{AZ>hiQ&q(&Dz$bW8_YRRW3JIaSlcLQ{irb-6r*lV~3ed4;WZvlYgHJnR| zY<;vVZ+p(P9JhRneCD>prP*~sF2B z(T~Z?k9%B!5eA$oj=m0uzJ9U-vs6*z*K7@3P#VIi$1qy~0nryixBig@H952zArwxf ziJrR%!Nt24G~^H6Nm(85($v^l+k1v1Ilf+1!^WGT+$HFtFU1Mp-%I7%7Aws@0MX}_ zz=2a0!w62c#d>Pb&o|WNj1}9|B+HB*62K#D^3xrsG3?T z_jF@*p}*_IYU0FLkni7in8aEuFP|IP1%tlzhsAQk!;9r}r~E;lvY4hVks2()%bvbo zZdo&qZ3djHS9;C9&%UVHUtNz{nfQz?=~KfLRxQ+4*AWx1?GzLD66lPf>y~Bbk7B3 zaHue2)4MzDfN811Z+N`h4)k5OqarsxaDcFy%!}c;f|_v6shx@;$jyVMR*VY>6cAUt zDq+l&2tX15o`f^byxgtRO(J9VOs$E4#P}{w++&K00+X<%PEFszmQPr(oTK5H|6MrBfLoyLwKhWx96(DH-WO=-O#SUiLaV)Kwv_8azkd@%ya{4aK#+ z%m5L6dlAEIWyd#X3Q{q9~tjD!7Q11FDg*q;)WH~MCWoWU6Jrb-78n3%W<(-F?Y>J?x` zT-8iVjq6N(0-hEC@ey(d6^8Aky)&H~=O1TIS?6laxQ6YAptH6F2!$JU#}}3LHsG^k z(kzl`D0#PMaVsqXk}uw(=57x1SD;5wS%?!OARIfdxfzivUvm*LYqm5X5tI?(m75sl z6TGOS=3?oXNK|I56c*0isjG3yO2=G-VS_bUoO5K3>4#%DFOLI48W1&cSF<~oJZV<1 zxB$O0f*sYxCrg5vMmzI)zb-gwzJ?SRQ_F^MEg;+6KPvrgVb{e#3?~&XKyNoU>(INa z6HgT*$dVpjBYx(fe>h~O1K}b<8UbTIIeCsg#F>ny7@~a0JdCk3XsB8rVn+MON*>dh zmFR~fkWdZjYQ+Z%lvwo4kvy>RbZ5l&s^AEgF}p7-D|J7(uWH4+jQQK`5B5s=%VTP@ zB+jQWr)J`C2^{|JnYmJ)>Lo+)BZ019f+49bs_6|>`I^3gWe4^sG9w6Rce}is(kRF6 zt>!rNA=RF8vU6@che%t7)U#1mtdAKL0STf=RT|X!`#S9H+S!?6Si=A%Aj=mhKmzE^ z3o^@7WP(U`f02H#HLT6Edi%JTdl4-|_{+n3o1|}N790gci6h!%jjH-S@1jDQj^xUh zO6q{>b8c>+ru-|0z~7|3L;>P?6KXr9oN7lBC!o?kqyrxBW&k*-(Igrl!uRT`RAh%^ zw)6e-TKr1YB)I%$3I^VH{D}sGrnu{4yGT!*(JaLK(!Dq) z%K{PuZO$|I>`FQPP>V^H^qqH_A;VxuMbG^OZ4oOW=rYsvQ{O0@Gu8v+Ll6WYcK1Wt zbY4W9M_Jt*Y(`gc)S4HQrF@8uvYb3bMR8G(ZKv2?p*huxk3AgU_i{jtUumnUQGo(a z0TTCcZLtO<%~e%aUdEPGTtFTYGg;08!VlC8@2g%J$FUj{Q9H0p7`cbYNRk>rMwFvg zm15)~DU{sh>N&9;sL}o-<}`hR$BO_Xf=V0Lyx9PvO-jd1tE(3$)Cjyo#4 ziESEQewVBoTTmC=fXPZ!G~<~Nl$deh*2EdjWrC)@n+K<^ikWub86f?~)L@L5C`(L- zN%ifvc;E54rk0MpJWpRc_2b7~9r9-my|~_ErbFXb;$GKiM47A2GQfurkYDnB4?A}w ztu!s}*i*e-*J?a3GQFy1d`L%ZbcNVMIIp6Xh+$Qr7{Uuql@AH?JjB)cKr$I1*- z?{|x{1g)E?TZT*_K90EXF!Ks`O~MQyRp(F5NrlFTXh3{JTh*X!t~b(w>8h%mx)B;? zfF#B&1ZGo!Rf95|h{uCp3ToJQl$(@2Zj4}S!}_fqDB>}BS8+9`pmypbDr48_Mxab> z54vb6Kav;Vtp8Mi^g6hxW3#&hwA}F@D$>)fxR< z@jy=x>&s0^Jv4wcq{3rX^J99-scS%V+7YO+|E6;2VV!DL@pogR zeZ>&ZVMtvmKWy{dCiI^XkUH}gyUyfX5DBExSgz06-=;3vH^&U>`7r~-;J`4Xi*s+P zDnn2J!(JD+RZDgN5Fb%j#*02yB-#6JFJs4Q(UXbnz3T-)5`)zDA^!jbD~JO6&6Y*m z(_JA}xrKJr9JG(3Mp+YLyg7~<8y_;N^AM+&MIbBnr4lsTIUo@kav)wgW$CfG;lZ0e z>&wiC38e#?m=MPdtIhnFm0`zZF+&ebHKBhjs1jC<4?)h=Wu-dGS&;=pNePrhdYudq z>ccfj8_}K!_Mwa%!jD3Ym{sF!G&xVyDOKm_jD)55eA#sC7?P94b zn0bh=rVpDctLm)>OV}hE)~fG<${2d}!C(l_cW!|2*kMDTo9A)a5#|jIwg0eAFz(mq zq1Z915?yWHDxy1Ze}Qx5!AsP(s{R&C%a(23Qr?mDv4gosuSa{KD9>9F>?%QhfLO=Q z4Y+>bi@Ke5sBVY$%yOybZlKgN>k{I1&3%s|1BaRNM^uIMIY*Dm)1G{g{N{l{3Z%&z zQKm>|>f$h@4&}g}PwmLI_5nzU?}BJz4^eOr9Vj2=W#e*f6+0t}N%-ukiB^w^!BKNL+OcsqV(#a+lbm$Ur83!SOSvi2W}JEu z#&)1znJk)=u%6Fk45Cq(v1Qo)kv%}5*vLehL|r*ItPE>v|6$FEvXqab363NiRPWoD z$ffUmr95fbAxa0`xFb`o3Ay90dom`7(N&s(qCa;#E$gqpA-eMy){rl!T-I#SsFEcg zX}4QZC8|krX>NOCyzUKO{rYus?6Jp4RP%XbqC8{O5%RqY-YaK+@f-5%`yWRMyf%~r64e%IGZWmqr#NJdOT+lJgJAddvq;p%L-BOeV)<*pGDF_umARUek5DBZqH3tQuG_C27}*G z$6O@yCz3B7Fe4xqJ#P5#kar;;Ij{?sWVd9o{$myv*2A-@-1d_@<)$CqCa0fvG9s-Z zbwkRDe{zJ}@ws!QgA?v_^9!z5D}{sEwrLB@Qe|A09lBIbeBQI=;dPJ5^Iz~H391Lm z=56lK=$^G56I0TThh=2pxSalyQ{}tgyHQR(?Ii$YschW($9^rCcHfm3WTkTgQ;RBD zhvWldnyr?sUHgE1-*dxhlB#3~Gj4k}7mvqi)D70CNKttJ;o z&JLi!Nc32_T9*pnU2yR~%lM*&^2`&Clc6ElX7)swuL@U(3yP_BUdu_cYhQcc1Mjb&@!jEO!ZQQs~Zv5e`yQ}}cM&TVn>kjAS=Sbfo|v4J_nmXToc*4+$V*Rup$rcXaf$2vnINT$ zLgEQ!G-cbi+=-um!KdVX@A+$a&a+QYA@qX}J|vg^-!H*WZQLUe%I(Ulu2JJ0Xa0}V zq*klRmMvT5@++>E+wZt5+h)V#n`C@^yl{JkbK-gd9I&3}{>!_6E1$UNbFyyTddD>7 zCab`XmSP9p!52lx*!IrbLYt{6`uA&9FCT{asyHQeI~~7;2yD7JIQ!nQV;;iXSsFV-bB1Hze&?^{b#H#Z zj0_K%95~mRxxoXwrweeHsuqL zFL&D0H9n>&zoRPFv-`{`XYl(!V{!*I$hbcdFy~*`iq1* z$8e%4`XI8yu!QUo-MPObx^6WiJJ@Ce#3qW|!7Y$);RIgQY))0UHZAeWZqqVl1yv7L zEH@<<(Ld>lg8hEPwkHxW`OtOWF9WK!iNg*JK$5W|Rux@DsAK|bKU^cr5FFnE_&K z9RNgZ-t&2hFjdXz30opLM|4(B&pzu4*E<8mWeK0T#D}$9#fO>j`59a(NH=}2m8!D) z&LYE}G`^L^^%C?YMO_=_9?*lU{5GD`l2gC&<=?4QWX--Y@ zy`7`*N!bNcW!tWfR=cL_QsHBM()7jX1rZ%`v90(&6EDY znMc6?6Q>+912ba%ijK-^F3l370sfLPPT190jiSJu1=C$fSMGvV_y+!-(Sy>%jlXXZ(YfMnTsQm##vz(9E0ZZ`=AP5Zf`*Ds+(*{ct9u?Y@AVMXpOLQvw~AzYWX zVa%7G=9^ni=&4NlSx-f_7_O)nJsWbSviI&QdKWIIzy=vG{Az))<|@vksU&BH0fT1! z+8ThdwX z_RW8oPe0-+zWiEp;7LB>r!(-fsY;a3FlLJ8{5;VGS^H?#eezH+aSlXKSfAkIo3CuuPG`aX+>B8%o*9+2Y;l<*vg-h)r58u}=KFy_IMGyA zm9{_-oLGmpjHZkOr_W$Yz(FS$jNPX2T;>G2pl}eJtN(uv7w}v@%%qkMtEcZMb|^6H z0`+OOCY4>^)?KkqGse1n4Nf+>+fK@LR>Uv!D|K~Hz+(Ui>T@~ib3m}euLcMU3X?wO z878!4G(`tapD`ye*ycJ((_Q7C6Se76_?Vy9wx%a5=t=4sxV+Kcu7&QIm7ewb@nv8f zP*MjRQ+i1)Q!HLm0>EvKAIsksL9pgjzjwyIOZkQy>arZd4BRAr?1)_bo6(eArf*IU zDxQy9VXRNFqm6vd$Ze31@?j=?eg+@ez;y;wvlhCa25Q2DT^rq3BazPYM#NpcPV}pN zYNv57-cByr1wnr{z*;t#-}+{UIJt)Vs)lM2N%eGX%2vVo%wOgi?o*@Z)aGkFRtt(< zT>jgl=d51BhnevC8J$i`)xYd)NM)uBQ`EY)_PcCZ4+Dr(;`f|at!8hqJF$vaFGWCf zWHv*g&`wAw0m6{hl+eiv77F<+kefvN4mCA9l~;q+Tpd zKSjV@=T`cd!ri+|9PMIaXv~w#3>m}@n}wV4Z%#-^^({`k22T0p;1W$Sfp8}%%o`YN zdus`4d!m-+oEFH(Cb9C#`p%1S(G>_MbgSp*+GT0osLQgWyu_f0l)~UrE14|UU(95# z7|Oydar`1RQ+0UW4~j0Pa@f`0KxkPpFD9zo_U4-277XiGNO?Y4h9wt1KjZD9ZVu{3 z)4guM<+lk6oxfs@<3qdxBOKG^ycCXV-(~=aWbAMO0VBGIn&7Cp9=l~Xg}0bpE_!wd zYj-Vk{(FTLZrl5dtmhYCL7|V~JrTSYg-hGRSR5$qT1H7G3uEk!Z8T@5qR~4uoy{0uZ*;5$hm%vA-2P zX7E|aDUdTD&qL2`aM}??Sjp!qUfHAi%p+bcbL{$%;`P;_1{49^bFj>1`G>R685uq( zISBiN5#_e80I|(7#VUgrP6eo-4F1?SP-}gHRZhImCVwDa-~NaF z5Bs_J|7$kMB01@I^SfyYDV{`0O4HihY3xe?*lC|RQl2!6w1_l6{obA4k4RP05NRvv zHPRMRgXELK^qFY^JRKkfoCghR2I)M~*`#-q4zn!VvTd6mB+G*QQ|wA&5?dT4aU9E~ zJ)||Hr%3;fHs}DF%ZJ?F4oCy8OgfEp1?fTps<>XxcHNxix*jasfq+vlSQ%+e_Ll77?k@=mT$B(NL^ zlz>R;(}LmPWQ|PJ4*{7V_HxL@F+s;x6o!RnvwmLSH_qj~|KZbrL3)TZk%B!aF+Nz3 zqH_h(J4rW?F3RN!ZoXKy9LI(2I0Q(V3{Y`!UyurB(h^<$8OLxO50nNgipoy2Q9I6W z*8hh0ujUJ1f#z@xT4$#nq&!<8{T^urMX|3?s#uM6e8_$R*hSEQSvbvT$#kfM77q_1(hmlsPFCtoNMn3{wJ=d?K} zpJ;Iq`-*BCrGctI+QLnn0Ofle5vW->>EE@yppdUs$FAcdoWeIgN!oxZi0@QD3cxv} z?{ctnOONG*%maw3FS!$B=92@5qb684xS0RTopLH$GRax?g&(z7OUpE7+Y4~`&=3`wL zx7Q}2l!%UIj8}F6OXVJ`hOq^-!1wd%i%ILCMR&>|#fplN`7?reZ@H2MXh7;!oveRH zyEd-sDd9bpB1+`6o4MCaN!+1wI>3xv4)3m%aCH>n*;)g4j@IzJAE~vnI1TQkTofxa zMq9s2Z>q5VQvsP6ecNA=|_y?Da~~!480~o7pDX1Ixs(=`P~(-U_-r ziZicoph*6+A7gbG;iV|SP;6XNiY{L}jtg}r7v*Bl!3my+bGuzEEfuk9tcq`rROtbv z`pj|c#3)^gFzrf!PK@n6J&vQV@XF^%W0<6$`vWQ0ju9>vixtPq=wQo|wscSrI>1TX zI-?7xm5a!cdoL2uO^qfV_e1Jg%mqkr6ag(ImH1ABqPmTu`XU!#jn8-4*Qp%iOGS@f zg^S%x+Phvh?K*dQWorNX8EL;L*3P$dvX5a^Y>_yp-+pxwbY1u5N?NY~SI>6dMy z1uhj)+iDvbX*~q^o!MPjOb!V6o9h8?tx+hG2q$|MK0$rFfFdc+shz(yl7%{df6@=| zJ?iAo{W^X-@NrookDJRLjxFbLr_+tAc8p=80%~;tm989zASoTfhi$@MRf__)7b!@9`Bz5O2Mc{Xl!iumN#8ipwy zEuj3cZQ&xVyCeImi$bAn(OEc}d+6nS=niPFXdjSmI0 z(g6pN6XEJz0UoP|IH!s-@dQ3h=jjXwK$x7%#$ChY~zijj*gM#<%9O zo4ASBsv*9;EymBrp{-+U9if133WO3oJm%xXvXABSY$XxjV4r>L@6J5|t{skX*IdSI zGcA0i4&1j(_n~nLM^mT4*86oXUj#*VE{)J7d}O5zl?7=m>J?rt?@Z=kcB7Y8;ai_M zB1XOxUA-`@Qym(N9p+7 zJQv&ODExQ?xR+t}W&JU(Sdic+V-~hF0HZHz3rj(&`Nj&U-KbA|jJLlFy<^1&q^ODb zri?0zR)@1~XEtHznDC<60S0^N9oyvM8!o*V0z8V6;rV!eIKrQ<%cB}k0br&z=;7S7 zksR@wc+Z>=D~@pR+)D{=-Qi)`%n+4IjNh3T;kNa8C8AoWtPY@>n+4FB=kAb*ZFwvU zQa;bKbikVdn6aek>WPtDHopm{=wj87i_MJ)e{h(O!Agjs8YlN!>7W6c782;q>vLGx zU&9eS4nDKM#TVAuxM#P8YYz``?qMPB+?>O>iapZkMu4V%t(Af$1}6-f7eQwk0s~U^ z@^d{#^tRpJCTtTbWw^MgJHWiYkU=i+;I0ylNQ6rlG|{v}Jh0Wp_J(sv08JYYZQMrI0v1_=%R~Z(?j)rBA`YOR!7mnYm~*Vy=#lgvcUN%y;K-vNH+p_vut$&S#h8 z+$n)PmZ8=za{g1p6S!lbgcEWOp5-K>v~O{4#;NZYuR0D_oU{v9zH2KkJZTSBzuu2m zcUDqxFtXd?DqEL)HI~B5BJ0e_SXi=P6eX(MZVt5K>4lOA=GGA?^BvRZM4q@;(s64ZqUDejkavKyWb>Khb&D~MDYgnl}yuEvphG$I>!tX+Up7wo|?eRZ6&aHIt? zGjnLGtG>8dkYQGtlhzOYWk#P5t6<~hpB*r_P>M;W=(fll)3tID(mrJ5Qf&IL+` zv|W4ambf9pVyHR^^G(Eoo^PTmDl|AM@}N#yx@NR?cOMqb8Ntkf{boC|lW#fba;2us zu?gHK<-KzGGCX=Xk=v(bM-3>cjR;O*2HboFmP2=o;ZIQJ7Go6&kRS_^)h`|pWb8%= zOMh`f(zu5M3OL>~3{0Uu-X+No$(P>+MAqm6Tg2GZ|LJ zmo%edqHY7&cDvvf2H@mMDM$yQ6~hsr`B}Ud@^Yj(S+21c4KmC}Qv*p64T}v0GAxjj zo=cG}vERAyBqp^aUUk&CGQOQ7NQP;S7qsV^0jJ6iu_~JkXF+adc#>#tCYc4%uPcy6 zdgL?+R0|cqB?K98aHr7AdkGhNm>{bN%XRgh64%0kjZTY`MV+w-3k`zg!q9@t!n#F| z3pz%_CR`&&$<@dcPL{do6330USlO0F0U60R6;m3JuQH-eI%*OrK&5$Jg`Ez9BNI_Po#JfXlSQr)MdbG%V5LNsNNF*&J?h;TplBqiywUoK!l_K>YA{PDTtg_IsOpJE^9 zBmHkQDXlg@$rQwq;QAF(aTUZOE6;^t@cy)XrXIA@)V=MdoXqXvfZG^Hx?)$==I<0l zC#gerUPb9irKH(U?_~<=s2lgmq^uuKO6NE zZ}Qq4xMe|mVAsyc^&{6U)%Ji6$3g-iC)vMNg#vuXLtPE+sPVOp;C#GY9U`iMDv*L{ zb;`UrvrppR;wW4ZhG9XH$f|rMF&imN3IsD7<+9nAG*F)t5mPSuAzO$=kon#dc<*@y z(kn|i_xb@r+WCIuyQQY|61=X39BWi<=APnYk>iNS8b?(U%3|#3yP}-2rcsN?ELoCA zkk&^GNa;ap^iTQC`uP%c3frZ8CL*}?4H^@72F_aCkKW2-7@4T2K)I@F3n>tDL4hpv zF6QMIcuhcdPYI;vPoun*tp=d-+<-yVe|HCt8lApngr-K z<=PJDM01!0Y4q~Gz;B!<6<$eZsrn#aUj6h7*gXZci;S*>TXDKo3?)_TpS>afLj-lANtype!Y#f`nY-eQB z#PUD+57u%6N2Gh(k8q`nLsSd!{p|3jYjn}2A+~H&;?KqwC1^A z;v-F24-!` zz-rQL)WjHkoU|Tqa<1pC5~cEjSgDV4gZ+^lLXgt6Ib5U)pmKOYB7ZAU78oYWH%WxE z01V*Cpi*dQoi>@|k49}BOhr@xl8a(Lt|C2yLp=QD z%uS|llC;D%dxmF!;LM4v%=fJRWpvQ!p%KxPg91Xs5zbWRzTY*J99GoaL_~)zOOu)bfcGjP__xNqEm~= z4-%xbFdaaSk*t-M=tU$cfF2=^uVcHmKBDHd3QFcg zWURTCNYW|I$;iSQ2`{^hs$^`1^WF94nVUU!-e9nAH82iU?{oet7 z2)~T>UlYhX;&6zil&qRq@K-Z^3D@4%0ejP?^G_zs-*$*W5Dv>eCVQ-d&c6*YO&yj@ h--$Bcrv+HH{U2@FoA{B#WIzA_002ovPDHLkV1nbkxo!Xe literal 0 HcmV?d00001 diff --git a/ios/Runner/Assets.xcassets/AppIcon-nightly.appiconset/AppIcon-nightly-57x57@2x.png b/ios/Runner/Assets.xcassets/AppIcon-nightly.appiconset/AppIcon-nightly-57x57@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..22da495020b15bcfaf10635973eb9bd670b18096 GIT binary patch literal 14102 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⋙xU(Kpwy`vLT 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 U{YXANifTM$o-~r+)tEkuu)qv3*mG9-t%s9UI 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 sQ2^J=qdrG%8|U|$etX<~zepHq)$ literal 0 HcmV?d00001 diff --git a/ios/Runner/Assets.xcassets/AppIcon-nightly.appiconset/AppIcon-nightly-72x72@1x.png b/ios/Runner/Assets.xcassets/AppIcon-nightly.appiconset/AppIcon-nightly-72x72@1x.png new file mode 100644 index 0000000000000000000000000000000000000000..a826bb738dc448be4cdb81dd9d379e2fc917a64e GIT binary patch literal 7219 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 BuCD+9 literal 0 HcmV?d00001 diff --git a/ios/Runner/Assets.xcassets/AppIcon-nightly.appiconset/AppIcon-nightly-72x72@2x.png b/ios/Runner/Assets.xcassets/AppIcon-nightly.appiconset/AppIcon-nightly-72x72@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..3a8a783224aac626902e9f63ffbe5be96a1877ba GIT binary patch literal 19833 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 z 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%0AFkYKT=W)XxRVzefvViwUW{7 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ν^G=x5 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


{jC5dwLOVe1`-bBH(F$vG&a`XS4^ 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 literal 0 HcmV?d00001 diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/AppIcon-20x20@1x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/AppIcon-20x20@1x.png new file mode 100644 index 0000000000000000000000000000000000000000..2ac9068e0d20f013307a2c1cc4bfa78f24861c66 GIT binary patch literal 1169 zcmeAS@N?(olHy`uVBq!ia0vp^A|TAc1|)ksWqE;=YKdz^NlIc#s#S7PDv)9@GB7gM zH2@-u5CbDC6B8?A3vB}fD+7bZ^?#F5H00)|WTsW(*6`tz>wTaG4Y&;@nYpROC5gEO zxb-Z5o&waue8|(qF{FZV?UdWy(xEcP_ou(xJUPW&ddu#ct9NWrI<57s?GhK4R;|Di zey*2|*2L5MtWSQ^c=yJsFg}0!~?fa#wn1+`5}LImg`iq@U4u<9~ja zj^u2x`zg(5e8%#5@xJHf`}Qw>@NZ#2^s=%khG9#}y*9eOk6#(PeA=D-O9d;goXgtv zvn{d5W>FT~h+%lHEoqQU1HwncH8D+=rSey&q|B#2<2Hw&ycU@ zDctNbS#-l2n{}b}hpxQw-k{QV?VVQ8Whb@i^*a;a*ZIxKXAQVo`q}sJ7AwoiYdKpk zAAfMeJRm?RCwGst)~?F*Nqx@V&jZS?1;*I$p4`dQT0A4IZR?$5x3_%lW~y*8U)$bl zbS#7Wvwza+O-;_1y9?_7Jvh+0)W+fQ`TmKvKgIIi{^_gvSmmZ$I>f>C30k6PuLw zgxWkfeC-a;qpP9`S$v+S0=|2DgnZh0|82hsYgv%mZ55Bmo)_y&x1^_8AK1qqd@jG( zYmI?!>WsdQDU%Ob^j^GRyQ1ihrmWyRDWzrgD_6+$mI^WKw4R=$JZG!2$hww=^Jm!{ zcF=ZS>S*OGr2gTHL=J<*rIqYbC#U+}vVScm%UC(7!E54`gjj~_OzT6tj2CkUt!DJ; zVOCrDWzxE&&i|8zBXuOo6$~=7)VNQsYkI@9>b-pC5n0BbrUTXYzemaU)%|Ba%zeJ; zInRu6Esjr?FScENF1b}Ise4aUX`ve zZ2kM*gz!hWePr&5)h;bci`7?DN{!2w&%69@(k^|zYegQ~dtTkxJ^fh2zo!aWTgxwh zIqPe1ZgTbQoIuyBVJ{ux#9y&BDs4M-pnBQ9@SpEruV&BQ{qn%qtLIODsNLb)Jb&@+ z$Mw4tTwSi%DQ=w~7`^Dd@{)o@+6H%*nOn-wKD;3A4{ySy6P?DUtRcYc%;4$j=d#Wz Gp$PyiZxV?B literal 0 HcmV?d00001 diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/AppIcon-20x20@2x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/AppIcon-20x20@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..d0a01485fd1f68ed3685eae4e7f5310b3e26d7d0 GIT binary patch literal 2967 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�zE^$^31nAIP3q01 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 literal 0 HcmV?d00001 diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/AppIcon-29x29@3x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/AppIcon-29x29@3x.png new file mode 100644 index 0000000000000000000000000000000000000000..eaa1de13c6cea5b6b619d5c568d522a69f6b9f9f GIT binary patch literal 8997 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

WX^q&D$># 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 literal 0 HcmV?d00001 diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/AppIcon-40x40@1x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/AppIcon-40x40@1x.png new file mode 100644 index 0000000000000000000000000000000000000000..d0a01485fd1f68ed3685eae4e7f5310b3e26d7d0 GIT binary patch literal 2967 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 szeF`F``_kP-Nmiy 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 I5@tXD2YHXj%>V!Z literal 0 HcmV?d00001 diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/AppIcon-50x50@1x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/AppIcon-50x50@1x.png new file mode 100644 index 0000000000000000000000000000000000000000..a26cd0886121c4f825c098822ab45d3744203def GIT binary patch literal 3996 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 literal 0 HcmV?d00001 diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/AppIcon-50x50@2x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/AppIcon-50x50@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..8d860f1544f1cc0ea4998826a7cf34f9139f2ad8 GIT binary patch literal 10909 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≺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 I5@tXD2YHXj%>V!Z literal 0 HcmV?d00001 diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/AppIcon-60x60@3x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/AppIcon-60x60@3x.png new file mode 100644 index 0000000000000000000000000000000000000000..2b5872355d9b98500ce12083ea9c95a3aab6f14d GIT binary patch literal 25638 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 literal 0 HcmV?d00001 diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/AppIcon-72x72@1x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/AppIcon-72x72@1x.png new file mode 100644 index 0000000000000000000000000000000000000000..efac11baadf5d1e18a0f8de1d4d7756f0a5d1bd6 GIT binary patch literal 6770 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 DE=aI{ literal 0 HcmV?d00001 diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/AppIcon-76x76@1x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/AppIcon-76x76@1x.png new file mode 100644 index 0000000000000000000000000000000000000000..e8ac9032f80cf64a59f98f6abd4503b3136963cc GIT binary patch literal 7415 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 W_nq(c4F5e1v9#6opEs#N-u(}lr~0%2 literal 0 HcmV?d00001 diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/AppIcon-76x76@2x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/AppIcon-76x76@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..e1859a0df8f72cbe3470860452bc70cc6eba6e3d GIT binary patch literal 20128 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 literal 0 HcmV?d00001 diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/AppIcon-83.5x83.5@2x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/AppIcon-83.5x83.5@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..f863a9232f3c05e10360ccf190c3a6748d8b3857 GIT binary patch literal 22732 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

  • wnif?2G)f0! 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 literal 0 HcmV?d00001 diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json index d36b1fab..05843b52 100644 --- a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json +++ b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json @@ -1,122 +1 @@ -{ - "images" : [ - { - "size" : "20x20", - "idiom" : "iphone", - "filename" : "Icon-App-20x20@2x.png", - "scale" : "2x" - }, - { - "size" : "20x20", - "idiom" : "iphone", - "filename" : "Icon-App-20x20@3x.png", - "scale" : "3x" - }, - { - "size" : "29x29", - "idiom" : "iphone", - "filename" : "Icon-App-29x29@1x.png", - "scale" : "1x" - }, - { - "size" : "29x29", - "idiom" : "iphone", - "filename" : "Icon-App-29x29@2x.png", - "scale" : "2x" - }, - { - "size" : "29x29", - "idiom" : "iphone", - "filename" : "Icon-App-29x29@3x.png", - "scale" : "3x" - }, - { - "size" : "40x40", - "idiom" : "iphone", - "filename" : "Icon-App-40x40@2x.png", - "scale" : "2x" - }, - { - "size" : "40x40", - "idiom" : "iphone", - "filename" : "Icon-App-40x40@3x.png", - "scale" : "3x" - }, - { - "size" : "60x60", - "idiom" : "iphone", - "filename" : "Icon-App-60x60@2x.png", - "scale" : "2x" - }, - { - "size" : "60x60", - "idiom" : "iphone", - "filename" : "Icon-App-60x60@3x.png", - "scale" : "3x" - }, - { - "size" : "20x20", - "idiom" : "ipad", - "filename" : "Icon-App-20x20@1x.png", - "scale" : "1x" - }, - { - "size" : "20x20", - "idiom" : "ipad", - "filename" : "Icon-App-20x20@2x.png", - "scale" : "2x" - }, - { - "size" : "29x29", - "idiom" : "ipad", - "filename" : "Icon-App-29x29@1x.png", - "scale" : "1x" - }, - { - "size" : "29x29", - "idiom" : "ipad", - "filename" : "Icon-App-29x29@2x.png", - "scale" : "2x" - }, - { - "size" : "40x40", - "idiom" : "ipad", - "filename" : "Icon-App-40x40@1x.png", - "scale" : "1x" - }, - { - "size" : "40x40", - "idiom" : "ipad", - "filename" : "Icon-App-40x40@2x.png", - "scale" : "2x" - }, - { - "size" : "76x76", - "idiom" : "ipad", - "filename" : "Icon-App-76x76@1x.png", - "scale" : "1x" - }, - { - "size" : "76x76", - "idiom" : "ipad", - "filename" : "Icon-App-76x76@2x.png", - "scale" : "2x" - }, - { - "size" : "83.5x83.5", - "idiom" : "ipad", - "filename" : "Icon-App-83.5x83.5@2x.png", - "scale" : "2x" - }, - { - "size" : "1024x1024", - "idiom" : "ios-marketing", - "filename" : "Icon-App-1024x1024@1x.png", - "scale" : "1x" - } - ], - "info" : { - "version" : 1, - "author" : "xcode" - } -} +{"images":[{"size":"20x20","idiom":"iphone","filename":"AppIcon-20x20@2x.png","scale":"2x"},{"size":"20x20","idiom":"iphone","filename":"AppIcon-20x20@3x.png","scale":"3x"},{"size":"29x29","idiom":"iphone","filename":"AppIcon-29x29@1x.png","scale":"1x"},{"size":"29x29","idiom":"iphone","filename":"AppIcon-29x29@2x.png","scale":"2x"},{"size":"29x29","idiom":"iphone","filename":"AppIcon-29x29@3x.png","scale":"3x"},{"size":"40x40","idiom":"iphone","filename":"AppIcon-40x40@2x.png","scale":"2x"},{"size":"40x40","idiom":"iphone","filename":"AppIcon-40x40@3x.png","scale":"3x"},{"size":"50x50","idiom":"ipad","filename":"AppIcon-50x50@1x.png","scale":"1x"},{"size":"50x50","idiom":"ipad","filename":"AppIcon-50x50@2x.png","scale":"2x"},{"size":"57x57","idiom":"iphone","filename":"AppIcon-57x57@1x.png","scale":"1x"},{"size":"57x57","idiom":"iphone","filename":"AppIcon-57x57@2x.png","scale":"2x"},{"size":"60x60","idiom":"iphone","filename":"AppIcon-60x60@2x.png","scale":"2x"},{"size":"60x60","idiom":"iphone","filename":"AppIcon-60x60@3x.png","scale":"3x"},{"size":"20x20","idiom":"ipad","filename":"AppIcon-20x20@1x.png","scale":"1x"},{"size":"20x20","idiom":"ipad","filename":"AppIcon-20x20@2x.png","scale":"2x"},{"size":"29x29","idiom":"ipad","filename":"AppIcon-29x29@1x.png","scale":"1x"},{"size":"29x29","idiom":"ipad","filename":"AppIcon-29x29@2x.png","scale":"2x"},{"size":"40x40","idiom":"ipad","filename":"AppIcon-40x40@1x.png","scale":"1x"},{"size":"40x40","idiom":"ipad","filename":"AppIcon-40x40@2x.png","scale":"2x"},{"size":"72x72","idiom":"ipad","filename":"AppIcon-72x72@1x.png","scale":"1x"},{"size":"72x72","idiom":"ipad","filename":"AppIcon-72x72@2x.png","scale":"2x"},{"size":"76x76","idiom":"ipad","filename":"AppIcon-76x76@1x.png","scale":"1x"},{"size":"76x76","idiom":"ipad","filename":"AppIcon-76x76@2x.png","scale":"2x"},{"size":"83.5x83.5","idiom":"ipad","filename":"AppIcon-83.5x83.5@2x.png","scale":"2x"},{"size":"1024x1024","idiom":"ios-marketing","filename":"AppIcon-1024x1024@1x.png","scale":"1x"}],"info":{"version":1,"author":"xcode"}} \ No newline at end of file diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png deleted file mode 100644 index dc9ada4725e9b0ddb1deab583e5b5102493aa332..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 10932 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 diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png deleted file mode 100644 index f091b6b0bca859a3f474b03065bef75ba58a9e4c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1588 zcmV-42Fv-0P)C1SqPt}wig>|5Crh^=oyX$BK<}M8eLU3e2hGT;=G|!_SP)7zNI6fqUMB=)y zRAZ>eDe#*r`yDAVgB_R*LB*MAc)8(b{g{9McCXW!lq7r(btRoB9!8B-#AI6JMb~YFBEvdsV)`mEQO^&#eRKx@b&x- z5lZm*!WfD8oCLzfHGz#u7sT0^VLMI1MqGxF^v+`4YYnVYgk*=kU?HsSz{v({E3lb9 z>+xILjBN)t6`=g~IBOelGQ(O990@BfXf(DRI5I$qN$0Gkz-FSc$3a+2fX$AedL4u{ z4V+5Ong(9LiGcIKW?_352sR;LtDPmPJXI{YtT=O8=76o9;*n%_m|xo!i>7$IrZ-{l z-x3`7M}qzHsPV@$v#>H-TpjDh2UE$9g6sysUREDy_R(a)>=eHw-WAyfIN z*qb!_hW>G)Tu8nSw9yn#3wFMiLcfc4pY0ek1}8(NqkBR@t4{~oC>ryc-h_ByH(Cg5 z>ao-}771+xE3um9lWAY1FeQFxowa1(!J(;Jg*wrg!=6FdRX+t_<%z&d&?|Bn){>zm zZQj(aA_HeBY&OC^jj*)N`8fa^ePOU72VpInJoI1?`ty#lvlNzs(&MZX+R%2xS~5Kh zX*|AU4QE#~SgPzOXe9>tRj>hjU@c1k5Y_mW*Jp3fI;)1&g3j|zDgC+}2Q_v%YfDax z!?umcN^n}KYQ|a$Lr+51Nf9dkkYFSjZZjkma$0KOj+;aQ&721~t7QUKx61J3(P4P1 zstI~7-wOACnWP4=8oGOwz%vNDqD8w&Q`qcNGGrbbf&0s9L0De{4{mRS?o0MU+nR_! zrvshUau0G^DeMhM_v{5BuLjb#Hh@r23lDAk8oF(C+P0rsBpv85EP>4CVMx#04MOfG z;P%vktHcXwTj~+IE(~px)3*MY77e}p#|c>TD?sMatC0Tu4iKKJ0(X8jxQY*gYtxsC z(zYC$g|@+I+kY;dg_dE>scBf&bP1Nc@Hz<3R)V`=AGkc;8CXqdi=B4l2k|g;2%#m& z*jfX^%b!A8#bI!j9-0Fi0bOXl(-c^AB9|nQaE`*)Hw+o&jS9@7&Gov#HbD~#d{twV zXd^Tr^mWLfFh$@Dr$e;PBEz4(-2q1FF0}c;~B5sA}+Q>TOoP+t>wf)V9Iy=5ruQa;z)y zI9C9*oUga6=hxw6QasLPnee@3^Rr*M{CdaL5=R41nLs(AHk_=Y+A9$2&H(B7!_pURs&8aNw7?`&Z&xY_Ye z)~D5Bog^td-^QbUtkTirdyK^mTHAOuptDflut!#^lnKqU md>ggs(5nOWAqO?umG&QVYK#ibz}*4>0000U6E9hRK9^#O7(mu>ETqrXGsduA8$)?`v2seloOCza43C{NQ$$gAOH**MCn0Q?+L7dl7qnbRdqZ8LSVp1ItDxhxD?t@5_yHg6A8yI zC*%Wgg22K|8E#!~cTNYR~@Y9KepMPrrB8cABapAFa=`H+UGhkXUZV1GnwR1*lPyZ;*K(i~2gp|@bzp8}og7e*#% zEnr|^CWdVV!-4*Y_7rFvlww2Ze+>j*!Z!pQ?2l->4q#nqRu9`ELo6RMS5=br47g_X zRw}P9a7RRYQ%2Vsd0Me{_(EggTnuN6j=-?uFS6j^u69elMypu?t>op*wBx<=Wx8?( ztpe^(fwM6jJX7M-l*k3kEpWOl_Vk3@(_w4oc}4YF4|Rt=2V^XU?#Yz`8(e?aZ@#li0n*=g^qOcVpd-Wbok=@b#Yw zqn8u9a)z>l(1kEaPYZ6hwubN6i<8QHgsu0oE) ziJ(p;Wxm>sf!K+cw>R-(^Y2_bahB+&KI9y^);#0qt}t-$C|Bo71lHi{_+lg#f%RFy z0um=e3$K3i6K{U_4K!EX?F&rExl^W|G8Z8;`5z-k}OGNZ0#WVb$WCpQu-_YsiqKP?BB# vzVHS-CTUF4Ozn5G+mq_~Qqto~ahA+K`|lyv3(-e}00000NkvXXu0mjfd`9t{ diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png deleted file mode 100644 index d0ef06e7edb86cdfe0d15b4b0d98334a86163658..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1716 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 diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png deleted file mode 100644 index c8f9ed8f5cee1c98386d13b17e89f719e83555b2..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1895 zcmV-t2blPYP)FQtfgmafE#=YDCq`qUBt#QpG%*H6QHY765~R=q zZ6iudfM}q!Pz#~9JgOi8QJ|DSu?1-*(kSi1K4#~5?#|rh?sS)(-JQqX*}ciXJ56_H zdw=^s_srbAdqxlvGyrgGet#6T7_|j;95sL%MtM;q86vOxKM$f#puR)Bjv9Zvz9-di zXOTSsZkM83)E9PYBXC<$6(|>lNLVBb&&6y{NByFCp%6+^ALR@NCTse_wqvNmSWI-m z!$%KlHFH2omF!>#%1l3LTZg(s7eof$7*xB)ZQ0h?ejh?Ta9fDv59+u#MokW+1t8Zb zgHv%K(u9G^Lv`lh#f3<6!JVTL3(dCpxHbnbA;kKqQyd1~^Xe0VIaYBSWm6nsr;dFj z4;G-RyL?cYgsN1{L4ZFFNa;8)Rv0fM0C(~Tkit94 zz#~A)59?QjD&pAPSEQ)p8gP|DS{ng)j=2ux)_EzzJ773GmQ_Cic%3JJhC0t2cx>|v zJcVusIB!%F90{+}8hG3QU4KNeKmK%T>mN57NnCZ^56=0?&3@!j>a>B43pi{!u z7JyDj7`6d)qVp^R=%j>UIY6f+3`+qzIc!Y_=+uN^3BYV|o+$vGo-j-Wm<10%A=(Yk^beI{t%ld@yhKjq0iNjqN4XMGgQtbKubPM$JWBz}YA65k%dm*awtC^+f;a-x4+ddbH^7iDWGg&N0n#MW{kA|=8iMUiFYvMoDY@sPC#t$55gn6ykUTPAr`a@!(;np824>2xJthS z*ZdmT`g5-`BuJs`0LVhz+D9NNa3<=6m;cQLaF?tCv8)zcRSh66*Z|vXhG@$I%U~2l z?`Q zykI#*+rQ=z6Jm=Bui-SfpDYLA=|vzGE(dYm=OC8XM&MDo7ux4UF1~0J1+i%aCUpRe zt3L_uNyQ*cE(38Uy03H%I*)*Bh=Lb^Xj3?I^Hnbeq72(EOK^Y93CNp*uAA{5Lc=ky zx=~RKa4{iTm{_>_vSCm?$Ej=i6@=m%@VvAITnigVg{&@!7CDgs908761meDK5azA} z4?=NOH|PdvabgJ&fW2{Mo$Q0CcD8Qc84%{JPYt5EiG{MdLIAeX%T=D7NIP4%Hw}p9 zg)==!2Lbp#j{u_}hMiao9=!VSyx0gHbeCS`;q&vzeq|fs`y&^X-lso(Ls@-706qmA z7u*T5PMo_w3{se1t2`zWeO^hOvTsohG_;>J0wVqVe+n)AbQCx)yh9;w+J6?NF5Lmo zecS@ieAKL8%bVd@+-KT{yI|S}O>pYckUFs;ry9Ow$CD@ztz5K-*D$^{i(_1llhSh^ zEkL$}tsQt5>QA^;QgjgIfBDmcOgi5YDyu?t6vSnbp=1+@6D& z5MJ}B8q;bRlVoxasyhcUF1+)o`&3r0colr}QJ3hcSdLu;9;td>kf@Tcn<@9sIx&=m z;AD;SCh95=&p;$r{Xz3iWCO^MX83AGJ(yH&eTXgv|0=34#-&WAmw{)U7OU9!Wz^!7 zZ%jZFi@JR;>Mhi7S>V7wQ176|FdW2m?&`qa(ScO^CFPR80HucLHOTy%5s*HR0^8)i h0WYBP*#0Ks^FNSabJA*5${_#%002ovPDHLkV1oKhTl@e3 diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png deleted file mode 100644 index a6d6b8609df07bf62e5100a53a01510388bd2b22..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2665 zcmV-v3YPVWP)oFh3q0MFesq&64WThn3$;G69TfjsAv=f2G9}p zgSx99+!YV6qME!>9MD13x)k(+XE7W?_O4LoLb5ND8 zaV{9+P@>42xDfRiYBMSgD$0!vssptcb;&?u9u(LLBKmkZ>RMD=kvD3h`sk6!QYtBa ztlZI#nu$8lJ^q2Z79UTgZe>BU73(Aospiq+?SdMt8lDZ;*?@tyWVZVS_Q7S&*tJaiRlJ z+aSMOmbg3@h5}v;A*c8SbqM3icg-`Cnwl;7Ts%A1RkNIp+Txl-Ckkvg4oxrqGA5ewEgYqwtECD<_3Egu)xGllKt&J8g&+=ac@Jq4-?w6M3b*>w5 z69N3O%=I^6&UL5gZ!}trC7bUj*12xLdkNs~Bz4QdJJ*UDZox2UGR}SNg@lmOvhCc~ z*f_UeXv(=#I#*7>VZx2ObEN~UoGUTl=-@)E;YtCRZ>SVp$p9yG5hEFZ!`wI!spd)n zSk+vK0Vin7FL{7f&6OB%f;SH22dtbcF<|9fi2Fp%q4kxL!b1#l^)8dUwJ zwEf{(wJj@8iYDVnKB`eSU+;ml-t2`@%_)0jDM`+a46xhDbBj2+&Ih>1A>6aky#(-SYyE{R3f#y57wfLs z6w1p~$bp;6!9DX$M+J~S@D6vJAaElETnsX4h9a5tvPhC3L@qB~bOzkL@^z0k_hS{T4PF*TDrgdXp+dzsE? z>V|VR035Pl9n5&-RePFdS{7KAr2vPOqR9=M$vXA1Yy5>w;EsF`;OK{2pkn-kpp9Pw z)r;5JfJKKaT$4qCb{TaXHjb$QA{y0EYy*+b1XI;6Ah- zw13P)xT`>~eFoJC!>{2XL(a_#upp3gaR1#5+L(Jmzp4TBnx{~WHedpJ1ch8JFk~Sw z>F+gN+i+VD?gMXwcIhn8rz`>e>J^TI3E-MW>f}6R-pL}>WMOa0k#jN+`RyUVUC;#D zg|~oS^$6%wpF{^Qr+}X>0PKcr3Fc&>Z>uv@C);pwDs@2bZWhYP!rvGx?_|q{d`t<*XEb#=aOb=N+L@CVBGqImZf&+a zCQEa3$~@#kC);pasdG=f6tuIi0PO-y&tvX%>Mv=oY3U$nD zJ#gMegnQ46pq+3r=;zmgcG+zRc9D~c>z+jo9&D+`E6$LmyFqlmCYw;-Zooma{sR@~ z)_^|YL1&&@|GXo*pivH7k!msl+$Sew3%XJnxajt0K%3M6Bd&YFNy9}tWG^aovK2eX z1aL1%7;KRDrA@eG-Wr6w+;*H_VD~qLiVI`{_;>o)k`{8xa3EJT1O_>#iy_?va0eR? zDV=N%;Zjb%Z2s$@O>w@iqt!I}tLjGk!=p`D23I}N4Be@$(|iSA zf3Ih7b<{zqpDB4WF_5X1(peKe+rASze%u8eKLn#KKXt;UZ+Adf$_TO+vTqshLLJ5c z52HucO=lrNVae5XWOLm!V@n-ObU11!b+DN<$RuU+YsrBq*lYT;?AwJpmNKniF0Q1< zJCo>Q$=v$@&y=sj6{r!Y&y&`0$-I}S!H_~pI&2H8Z1C|BX4VgZ^-! zje3-;x0PBD!M`v*J_)rL^+$<1VJhH*2Fi~aA7s&@_rUHYJ9zD=M%4AFQ`}k8OC$9s XsPq=LnkwKG00000NkvXXu0mjfhAk5^ diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png deleted file mode 100644 index a6d6b8609df07bf62e5100a53a01510388bd2b22..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2665 zcmV-v3YPVWP)oFh3q0MFesq&64WThn3$;G69TfjsAv=f2G9}p zgSx99+!YV6qME!>9MD13x)k(+XE7W?_O4LoLb5ND8 zaV{9+P@>42xDfRiYBMSgD$0!vssptcb;&?u9u(LLBKmkZ>RMD=kvD3h`sk6!QYtBa ztlZI#nu$8lJ^q2Z79UTgZe>BU73(Aospiq+?SdMt8lDZ;*?@tyWVZVS_Q7S&*tJaiRlJ z+aSMOmbg3@h5}v;A*c8SbqM3icg-`Cnwl;7Ts%A1RkNIp+Txl-Ckkvg4oxrqGA5ewEgYqwtECD<_3Egu)xGllKt&J8g&+=ac@Jq4-?w6M3b*>w5 z69N3O%=I^6&UL5gZ!}trC7bUj*12xLdkNs~Bz4QdJJ*UDZox2UGR}SNg@lmOvhCc~ z*f_UeXv(=#I#*7>VZx2ObEN~UoGUTl=-@)E;YtCRZ>SVp$p9yG5hEFZ!`wI!spd)n zSk+vK0Vin7FL{7f&6OB%f;SH22dtbcF<|9fi2Fp%q4kxL!b1#l^)8dUwJ zwEf{(wJj@8iYDVnKB`eSU+;ml-t2`@%_)0jDM`+a46xhDbBj2+&Ih>1A>6aky#(-SYyE{R3f#y57wfLs z6w1p~$bp;6!9DX$M+J~S@D6vJAaElETnsX4h9a5tvPhC3L@qB~bOzkL@^z0k_hS{T4PF*TDrgdXp+dzsE? z>V|VR035Pl9n5&-RePFdS{7KAr2vPOqR9=M$vXA1Yy5>w;EsF`;OK{2pkn-kpp9Pw z)r;5JfJKKaT$4qCb{TaXHjb$QA{y0EYy*+b1XI;6Ah- zw13P)xT`>~eFoJC!>{2XL(a_#upp3gaR1#5+L(Jmzp4TBnx{~WHedpJ1ch8JFk~Sw z>F+gN+i+VD?gMXwcIhn8rz`>e>J^TI3E-MW>f}6R-pL}>WMOa0k#jN+`RyUVUC;#D zg|~oS^$6%wpF{^Qr+}X>0PKcr3Fc&>Z>uv@C);pwDs@2bZWhYP!rvGx?_|q{d`t<*XEb#=aOb=N+L@CVBGqImZf&+a zCQEa3$~@#kC);pasdG=f6tuIi0PO-y&tvX%>Mv=oY3U$nD zJ#gMegnQ46pq+3r=;zmgcG+zRc9D~c>z+jo9&D+`E6$LmyFqlmCYw;-Zooma{sR@~ z)_^|YL1&&@|GXo*pivH7k!msl+$Sew3%XJnxajt0K%3M6Bd&YFNy9}tWG^aovK2eX z1aL1%7;KRDrA@eG-Wr6w+;*H_VD~qLiVI`{_;>o)k`{8xa3EJT1O_>#iy_?va0eR? zDV=N%;Zjb%Z2s$@O>w@iqt!I}tLjGk!=p`D23I}N4Be@$(|iSA zf3Ih7b<{zqpDB4WF_5X1(peKe+rASze%u8eKLn#KKXt;UZ+Adf$_TO+vTqshLLJ5c z52HucO=lrNVae5XWOLm!V@n-ObU11!b+DN<$RuU+YsrBq*lYT;?AwJpmNKniF0Q1< zJCo>Q$=v$@&y=sj6{r!Y&y&`0$-I}S!H_~pI&2H8Z1C|BX4VgZ^-! zje3-;x0PBD!M`v*J_)rL^+$<1VJhH*2Fi~aA7s&@_rUHYJ9zD=M%4AFQ`}k8OC$9s XsPq=LnkwKG00000NkvXXu0mjfhAk5^ diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png deleted file mode 100644 index 75b2d164a5a98e212cca15ea7bf2ab5de5108680..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3831 zcmVjJBgitF5mAp-i>4+KS_oR{|13AP->1TD4=w)g|)JHOx|a2Wk1Va z!k)vP$UcQ#mdj%wNQoaJ!w>jv_6&JPyutpQps?s5dmDQ>`%?Bvj>o<%kYG!YW6H-z zu`g$@mp`;qDR!51QaS}|ZToSuAGcJ7$2HF0z`ln4t!#Yg46>;vGG9N9{V@9z#}6v* zfP?}r6b{*-C*)(S>NECI_E~{QYzN5SXRmVnP<=gzP+_Sp(Aza_hKlZ{C1D&l*(7IKXxQC1Z9#6wx}YrGcn~g%;icdw>T0Rf^w0{ z$_wn1J+C0@!jCV<%Go5LA45e{5gY9PvZp8uM$=1}XDI+9m7!A95L>q>>oe0$nC->i zeexUIvq%Uk<-$>DiDb?!In)lAmtuMWxvWlk`2>4lNuhSsjAf2*2tjT`y;@d}($o)S zn(+W&hJ1p0xy@oxP%AM15->wPLp{H!k)BdBD$toBpJh+crWdsNV)qsHaqLg2_s|Ih z`8E9z{E3sA!}5aKu?T!#enD(wLw?IT?k-yWVHZ8Akz4k5(TZJN^zZgm&zM28sfTD2BYJ|Fde3Xzh;;S` z=GXTnY4Xc)8nYoz6&vF;P7{xRF-{|2Xs5>a5)@BrnQ}I(_x7Cgpx#5&Td^4Q9_FnQ zX5so*;#8-J8#c$OlA&JyPp$LKUhC~-e~Ij!L%uSMu!-VZG7Hx-L{m2DVR2i=GR(_% zCVD!4N`I)&Q5S`?P&fQZ=4#Dgt_v2-DzkT}K(9gF0L(owe-Id$Rc2qZVLqI_M_DyO z9@LC#U28_LU{;wGZ&))}0R2P4MhajKCd^K#D+JJ&JIXZ_p#@+7J9A&P<0kdRujtQ_ zOy>3=C$kgi6$0pW06KaLz!21oOryKM3ZUOWqppndxfH}QpgjEJ`j7Tzn5bk6K&@RA?vl##y z$?V~1E(!wB5rH`>3nc&@)|#<1dN2cMzzm=PGhQ|Yppne(C-Vlt450IXc`J4R0W@I7 zd1e5uW6juvO%ni(WX7BsKx3MLngO7rHO;^R5I~0^nE^9^E_eYLgiR9&KnJ)pBbfno zSVnW$0R+&6jOOsZ82}nJ126+c|%svPo;TeUku<2G7%?$oft zyaO;tVo}(W)VsTUhq^XmFi#2z%-W9a{7mXn{uzivYQ_d6b7VJG{77naW(vHt-uhnY zVN#d!JTqVh(7r-lhtXVU6o})aZbDt_;&wJVGl2FKYFBFpU-#9U)z#(A%=IVnqytR$SY-sO( z($oNE09{D^@OuYPz&w~?9>Fl5`g9u&ecFGhqX=^#fmR=we0CJw+5xna*@oHnkahk+ z9aWeE3v|An+O5%?4fA&$Fgu~H_YmqR!yIU!bFCk4!#pAj%(lI(A5n)n@Id#M)O9Yx zJU9oKy{sRAIV3=5>(s8n{8ryJ!;ho}%pn6hZKTKbqk=&m=f*UnK$zW3YQP*)pw$O* zIfLA^!-bmBl6%d_n$#tP8Zd_(XdA*z*WH|E_yILwjtI~;jK#v-6jMl^?<%Y%`gvpwv&cFb$||^v4D&V=aNy?NGo620jL3VZnA%s zH~I|qPzB~e(;p;b^gJr7Ure#7?8%F0m4vzzPy^^(q4q1OdthF}Fi*RmVZN1OwTsAP zn9CZP`FazX3^kG(KodIZ=Kty8DLTy--UKfa1$6XugS zk%6v$Kmxt6U!YMx0JQ)0qX*{CXwZZk$vEROidEc7=J-1;peNat!vS<3P-FT5po>iE z!l3R+<`#x|+_hw!HjQGV=8!q|76y8L7N8gP3$%0kfush|u0uU^?dKBaeRSBUpOZ0c z62;D&Mdn2}N}xHRFTRI?zRv=>=AjHgH}`2k4WK=#AHB)UFrR-J87GgX*x5fL^W2#d z=(%K8-oZfMO=i{aWRDg=FX}UubM4eotRDcn;OR#{3q=*?3mE3_oJ-~prjhxh%PgQT zyn)Qozaq0@o&|LEgS{Ind4Swsr;b`u185hZPOBLL<`d2%^Yp1?oL)=jnLi;Zo0ZDliTtQ^b5SmfIMe{T==zZkbvn$KTQGlbG8w}s@M3TZnde;1Am46P3juKb zl9GU&3F=q`>j!`?SyH#r@O59%@aMX^rx}Nxe<>NqpUp5=lX1ojGDIR*-D^SDuvCKF z?3$xG(gVUsBERef_YjPFl^rU9EtD{pt z0CXwpN7BN3!8>hajGaTVk-wl=9rxmfWtIhC{mheHgStLi^+Nz12a?4r(fz)?3A%at zMlvQmL<2-R)-@G1wJ0^zQK%mR=r4d{Y3fHp){nWXUL#|CqXl(+v+qDh>FkF9`eWrW zfr^D%LNfOcTNvtx0JXR35J0~Jpi2#P3Q&80w+nqNfc}&G0A~*)lGHKv=^FE+b(37|)zL;KLF>oiGfb(?&1 zV3XRu!Sw>@quKiab%g6jun#oZ%!>V#A%+lNc?q>6+VvyAn=kf_6z^(TZUa4Eelh{{ zqFX-#dY(EV@7l$NE&kv9u9BR8&Ojd#ZGJ6l8_BW}^r?DIS_rU2(XaGOK z225E@kH5Opf+CgD^{y29jD4gHbGf{1MD6ggQ&%>UG4WyPh5q_tb`{@_34B?xfSO*| zZv8!)q;^o-bz`MuxXk*G^}(6)ACb@=Lfs`Hxoh>`Y0NE8QRQ!*p|SH@{r8=%RKd4p z+#Ty^-0kb=-H-O`nAA3_6>2z(D=~Tbs(n8LHxD0`R0_ATFqp-SdY3(bZ3;VUM?J=O zKCNsxsgt@|&nKMC=*+ZqmLHhX1KHbAJs{nGVMs6~TiF%Q)P@>!koa$%oS zjXa=!5>P`vC-a}ln!uH1ooeI&v?=?v7?1n~P(wZ~0>xWxd_Aw;+}9#eULM7M8&E?Y zC-ZLhi3RoM92SXUb-5i-Lmt5_rfjE{6y^+24`y$1lywLyHO!)Boa7438K4#iLe?rh z2O~YGSgFUBH?og*6=r9rme=peP~ah`(8Zt7V)j5!V0KPFf_mebo3z95U8(up$-+EA^9dTRLq>Yl)YMBuch9%=e5B`Vnb>o zt03=kq;k2TgGe4|lGne&zJa~h(UGutjP_zr?a7~#b)@15XNA>Dj(m=gg2Q5V4-$)D|Q9}R#002ovPDHLkV1o7DH3k3x diff --git a/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png b/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png deleted file mode 100644 index c4df70d39da7941ef3f6dcb7f06a192d8dcb308d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1888 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 iW8CFBundleDevelopmentRegion $(DEVELOPMENT_LANGUAGE) CFBundleDisplayName - Sptube + Spotube CFBundleExecutable $(EXECUTABLE_NAME) CFBundleIdentifier @@ -60,5 +60,7 @@ This app require access to the device camera NSMicrophoneUsageDescription This app does not require access to the device microphone - + UIApplicationSupportsIndirectInputEvents + + diff --git a/ios/build/.last_build_id b/ios/build/.last_build_id new file mode 100644 index 00000000..ee73fd53 --- /dev/null +++ b/ios/build/.last_build_id @@ -0,0 +1 @@ +6f5ed64a4065df2d43bfb5b18863018c \ No newline at end of file diff --git a/ios/dev-Info.plist b/ios/dev-Info.plist new file mode 100644 index 00000000..022d5419 --- /dev/null +++ b/ios/dev-Info.plist @@ -0,0 +1,66 @@ + + + + + CADisableMinimumFrameDurationOnPhone + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleDisplayName + Spotube Dev + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + spotube + CFBundlePackageType + APPL + CFBundleShortVersionString + $(FLUTTER_BUILD_NAME) + CFBundleSignature + ???? + CFBundleVersion + $(FLUTTER_BUILD_NUMBER) + LSRequiresIPhoneOS + + NSAppTransportSecurity + + NSAllowsArbitraryLoads + + NSAllowsArbitraryLoadsForMedia + + + NSCameraUsageDescription + This app require access to the device camera + NSMicrophoneUsageDescription + This app does not require access to the device microphone + NSPhotoLibraryUsageDescription + This app require access to the photo library + UIApplicationSupportsIndirectInputEvents + + UILaunchStoryboardName + LaunchScreen + UIMainStoryboardFile + Main + UIStatusBarHidden + + UISupportedInterfaceOrientations + + UIInterfaceOrientationPortrait + UIInterfaceOrientationLandscapeLeft + UIInterfaceOrientationLandscapeRight + + UISupportedInterfaceOrientations~ipad + + UIInterfaceOrientationPortrait + UIInterfaceOrientationPortraitUpsideDown + UIInterfaceOrientationLandscapeLeft + UIInterfaceOrientationLandscapeRight + + UIViewControllerBasedStatusBarAppearance + + + diff --git a/ios/nightly-Info.plist b/ios/nightly-Info.plist new file mode 100644 index 00000000..5ba9991f --- /dev/null +++ b/ios/nightly-Info.plist @@ -0,0 +1,66 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleDisplayName + Spotube + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + spotube + CFBundlePackageType + APPL + CFBundleShortVersionString + $(FLUTTER_BUILD_NAME) + CFBundleSignature + ???? + CFBundleVersion + $(FLUTTER_BUILD_NUMBER) + LSRequiresIPhoneOS + + UILaunchStoryboardName + LaunchScreen + UIMainStoryboardFile + Main + UISupportedInterfaceOrientations + + UIInterfaceOrientationPortrait + UIInterfaceOrientationLandscapeLeft + UIInterfaceOrientationLandscapeRight + + UISupportedInterfaceOrientations~ipad + + UIInterfaceOrientationPortrait + UIInterfaceOrientationPortraitUpsideDown + UIInterfaceOrientationLandscapeLeft + UIInterfaceOrientationLandscapeRight + + UIViewControllerBasedStatusBarAppearance + + NSAppTransportSecurity + + NSAllowsArbitraryLoads + + NSAllowsArbitraryLoadsForMedia + + + CADisableMinimumFrameDurationOnPhone + + UIStatusBarHidden + + NSPhotoLibraryUsageDescription + This app require access to the photo library + NSCameraUsageDescription + This app require access to the device camera + NSMicrophoneUsageDescription + This app does not require access to the device microphone + UIApplicationSupportsIndirectInputEvents + + + diff --git a/ios/stable-Info.plist b/ios/stable-Info.plist new file mode 100644 index 00000000..5ba9991f --- /dev/null +++ b/ios/stable-Info.plist @@ -0,0 +1,66 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleDisplayName + Spotube + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + spotube + CFBundlePackageType + APPL + CFBundleShortVersionString + $(FLUTTER_BUILD_NAME) + CFBundleSignature + ???? + CFBundleVersion + $(FLUTTER_BUILD_NUMBER) + LSRequiresIPhoneOS + + UILaunchStoryboardName + LaunchScreen + UIMainStoryboardFile + Main + UISupportedInterfaceOrientations + + UIInterfaceOrientationPortrait + UIInterfaceOrientationLandscapeLeft + UIInterfaceOrientationLandscapeRight + + UISupportedInterfaceOrientations~ipad + + UIInterfaceOrientationPortrait + UIInterfaceOrientationPortraitUpsideDown + UIInterfaceOrientationLandscapeLeft + UIInterfaceOrientationLandscapeRight + + UIViewControllerBasedStatusBarAppearance + + NSAppTransportSecurity + + NSAllowsArbitraryLoads + + NSAllowsArbitraryLoadsForMedia + + + CADisableMinimumFrameDurationOnPhone + + UIStatusBarHidden + + NSPhotoLibraryUsageDescription + This app require access to the photo library + NSCameraUsageDescription + This app require access to the device camera + NSMicrophoneUsageDescription + This app does not require access to the device microphone + UIApplicationSupportsIndirectInputEvents + + + diff --git a/pubspec.yaml b/pubspec.yaml index 16cdc2b6..36a2f398 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -152,6 +152,7 @@ flutter: - LICENSE flutter_launcher_icons: + ios: true android: true image_path: "assets/spotube-logo.png" adaptive_icon_foreground: "assets/spotube-logo-foreground.jpg" From d1ed56926d27043684f44d69cf98a08815ddb830 Mon Sep 17 00:00:00 2001 From: Kingkor Roy Tirtho Date: Wed, 3 Jan 2024 14:08:06 +0600 Subject: [PATCH 089/195] chore: remove build-IPA.yml as no longer needed --- .github/workflows/build-iPA.yml | 42 --------------------------------- 1 file changed, 42 deletions(-) delete mode 100644 .github/workflows/build-iPA.yml diff --git a/.github/workflows/build-iPA.yml b/.github/workflows/build-iPA.yml deleted file mode 100644 index 72e68774..00000000 --- a/.github/workflows/build-iPA.yml +++ /dev/null @@ -1,42 +0,0 @@ -name: Build iPA -on: workflow_dispatch - -jobs: - build: - runs-on: macos-latest - steps: - - name: Checkout - uses: actions/checkout@master - - uses: actions/checkout@v4 - - name: submodules-init - uses: snickerbockers/submodules-init@v4 - - name: Set up Flutter - uses: subosito/flutter-action@v2 - with: - channel: 'stable' - - name: Build - run: | - cp .env.example .env - flutter pub get && dart run build_runner build --delete-conflicting-outputs --enable-experiment=records,patterns - flutter build ios --release --no-codesign --flavor dev - flutter build ios --release --no-codesign --flavor stable - flutter build ios --release --no-codesign --flavor nightly - ln -sf ./build/ios/iphoneos Payload - zip -r9 spotube-dev.ipa Payload/dev.app - zip -r9 spotube-stable.ipa Payload/stable.app - zip -r9 spotube-nightly.ipa Payload/nightly.app - - name: Upload spotube-dev.ipa - uses: actions/upload-artifact@v4 - with: - name: "spotube-dev.ipa" - path: "spotube-dev.ipa" - - name: Upload spotube-stable.ipa - uses: actions/upload-artifact@v4 - with: - name: "spotube-stable.ipa" - path: "spotube-stable.ipa" - - name: Upload spotube-nightly.ipa - uses: actions/upload-artifact@v4 - with: - name: "spotube-nightly.ipa" - path: "spotube-nightly.ipa" From 988a975bf1a675df0cfc7b17776bcec74c67f1f2 Mon Sep 17 00:00:00 2001 From: Kingkor Roy Tirtho Date: Fri, 5 Jan 2024 14:14:15 +0600 Subject: [PATCH 090/195] feat(deep-link): add track opening page --- lib/collections/routes.dart | 10 + .../player/player_track_details.dart | 11 +- lib/components/shared/links/link_text.dart | 3 + .../shared/track_tile/track_options.dart | 4 +- .../shared/track_tile/track_tile.dart | 4 +- lib/hooks/configurators/use_deep_linking.dart | 8 + lib/pages/artist/artist.dart | 2 +- lib/pages/track/track.dart | 227 ++++++++++++++++++ lib/services/queries/queries.dart | 2 + lib/services/queries/tracks.dart | 16 ++ pubspec.lock | 56 +++-- 11 files changed, 317 insertions(+), 26 deletions(-) create mode 100644 lib/pages/track/track.dart create mode 100644 lib/services/queries/tracks.dart diff --git a/lib/collections/routes.dart b/lib/collections/routes.dart index 7816f204..3e2c42e0 100644 --- a/lib/collections/routes.dart +++ b/lib/collections/routes.dart @@ -17,6 +17,7 @@ import 'package:spotube/pages/search/search.dart'; import 'package:spotube/pages/settings/blacklist.dart'; import 'package:spotube/pages/settings/about.dart'; import 'package:spotube/pages/settings/logs.dart'; +import 'package:spotube/pages/track/track.dart'; import 'package:spotube/utils/platform.dart'; import 'package:spotube/components/shared/spotube_page_route.dart'; import 'package:spotube/pages/artist/artist.dart'; @@ -144,6 +145,15 @@ final router = GoRouter( ); }, ), + GoRoute( + path: "/track/:id", + pageBuilder: (context, state) { + final id = state.pathParameters["id"]!; + return SpotubePage( + child: TrackPage(trackId: id), + ); + }, + ), ], ), GoRoute( diff --git a/lib/components/player/player_track_details.dart b/lib/components/player/player_track_details.dart index d6f275fa..66cb9ef5 100644 --- a/lib/components/player/player_track_details.dart +++ b/lib/components/player/player_track_details.dart @@ -4,6 +4,7 @@ import 'package:spotify/spotify.dart'; import 'package:spotube/collections/assets.gen.dart'; import 'package:spotube/components/shared/image/universal_image.dart'; +import 'package:spotube/components/shared/links/link_text.dart'; import 'package:spotube/extensions/constrains.dart'; import 'package:spotube/provider/proxy_playlist/proxy_playlist_provider.dart'; import 'package:spotube/utils/service_utils.dart'; @@ -44,10 +45,12 @@ class PlayerTrackDetails extends HookConsumerWidget { crossAxisAlignment: CrossAxisAlignment.start, children: [ const SizedBox(height: 4), - Text( + LinkText( playback.activeTrack?.name ?? "", + "/track/${playback.activeTrack?.id}", + push: true, overflow: TextOverflow.ellipsis, - style: theme.textTheme.bodyMedium?.copyWith( + style: theme.textTheme.bodyMedium!.copyWith( color: color, ), ), @@ -66,8 +69,10 @@ class PlayerTrackDetails extends HookConsumerWidget { flex: 1, child: Column( children: [ - Text( + LinkText( playback.activeTrack?.name ?? "", + "/track/${playback.activeTrack?.id}", + push: true, overflow: TextOverflow.ellipsis, style: TextStyle(fontWeight: FontWeight.bold, color: color), ), diff --git a/lib/components/shared/links/link_text.dart b/lib/components/shared/links/link_text.dart index 217b247d..d7b00b72 100644 --- a/lib/components/shared/links/link_text.dart +++ b/lib/components/shared/links/link_text.dart @@ -8,6 +8,7 @@ class LinkText extends StatelessWidget { final TextAlign? textAlign; final TextOverflow? overflow; final String route; + final int? maxLines; final T? extra; final bool push; @@ -19,6 +20,7 @@ class LinkText extends StatelessWidget { this.extra, this.overflow, this.style = const TextStyle(), + this.maxLines, this.push = false, }) : super(key: key); @@ -37,6 +39,7 @@ class LinkText extends StatelessWidget { overflow: overflow, style: style, textAlign: textAlign, + maxLines: maxLines, ); } } diff --git a/lib/components/shared/track_tile/track_options.dart b/lib/components/shared/track_tile/track_options.dart index 8405d6ea..724bc029 100644 --- a/lib/components/shared/track_tile/track_options.dart +++ b/lib/components/shared/track_tile/track_options.dart @@ -43,12 +43,14 @@ class TrackOptions extends HookConsumerWidget { final bool userPlaylist; final String? playlistId; final ObjectRef?>? showMenuCbRef; + final Widget? icon; const TrackOptions({ Key? key, required this.track, this.showMenuCbRef, this.userPlaylist = false, this.playlistId, + this.icon, }) : super(key: key); void actionShare(BuildContext context, Track track) { @@ -207,7 +209,7 @@ class TrackOptions extends HookConsumerWidget { break; } }, - icon: const Icon(SpotubeIcons.moreHorizontal), + icon: icon ?? const Icon(SpotubeIcons.moreHorizontal), headings: [ ListTile( dense: true, diff --git a/lib/components/shared/track_tile/track_tile.dart b/lib/components/shared/track_tile/track_tile.dart index 961f29c9..c3b03f3c 100644 --- a/lib/components/shared/track_tile/track_tile.dart +++ b/lib/components/shared/track_tile/track_tile.dart @@ -193,8 +193,10 @@ class TrackTile extends HookConsumerWidget { children: [ Expanded( flex: 6, - child: Text( + child: LinkText( track.name!, + "/track/${track.id}", + push: true, maxLines: 1, overflow: TextOverflow.ellipsis, ), diff --git a/lib/hooks/configurators/use_deep_linking.dart b/lib/hooks/configurators/use_deep_linking.dart index be6facf9..3b7ec3f3 100644 --- a/lib/hooks/configurators/use_deep_linking.dart +++ b/lib/hooks/configurators/use_deep_linking.dart @@ -48,6 +48,11 @@ void useDeepLinking(WidgetRef ref) { ), ); break; + case "track": + router.push( + "/track/${url.pathSegments.last}", + ); + break; default: break; } @@ -80,6 +85,9 @@ void useDeepLinking(WidgetRef ref) { case "spotify:artist": await router.push("/artist/$endSegment"); break; + case "spotify:track": + await router.push("/track/$endSegment"); + break; case "spotify:playlist": await router.push( "/playlist/$endSegment", diff --git a/lib/pages/artist/artist.dart b/lib/pages/artist/artist.dart index 92470397..d511cb97 100644 --- a/lib/pages/artist/artist.dart +++ b/lib/pages/artist/artist.dart @@ -35,7 +35,7 @@ class ArtistPage extends HookConsumerWidget { ), extendBodyBehindAppBar: true, body: Builder(builder: (context) { - if (artistQuery.hasError) { + if (artistQuery.hasError && artistQuery.data == null) { return Center(child: Text(artistQuery.error.toString())); } return Skeletonizer( diff --git a/lib/pages/track/track.dart b/lib/pages/track/track.dart new file mode 100644 index 00000000..14052c10 --- /dev/null +++ b/lib/pages/track/track.dart @@ -0,0 +1,227 @@ +import 'dart:ui'; + +import 'package:flutter/material.dart'; +import 'package:gap/gap.dart'; +import 'package:hooks_riverpod/hooks_riverpod.dart'; +import 'package:skeletonizer/skeletonizer.dart'; +import 'package:spotube/collections/fake.dart'; +import 'package:spotube/collections/spotube_icons.dart'; +import 'package:spotube/components/shared/heart_button.dart'; +import 'package:spotube/components/shared/image/universal_image.dart'; +import 'package:spotube/components/shared/links/link_text.dart'; +import 'package:spotube/components/shared/page_window_title_bar.dart'; +import 'package:spotube/components/shared/track_tile/track_options.dart'; +import 'package:spotube/extensions/context.dart'; +import 'package:spotube/provider/proxy_playlist/proxy_playlist_provider.dart'; +import 'package:spotube/services/audio_player/audio_player.dart'; +import 'package:spotube/services/queries/queries.dart'; +import 'package:spotube/utils/type_conversion_utils.dart'; +import 'package:spotube/extensions/constrains.dart'; + +class TrackPage extends HookConsumerWidget { + final String trackId; + const TrackPage({ + Key? key, + required this.trackId, + }) : super(key: key); + + @override + Widget build(BuildContext context, ref) { + final ThemeData(:textTheme, :colorScheme) = Theme.of(context); + final mediaQuery = MediaQuery.of(context); + + final playlist = ref.watch(ProxyPlaylistNotifier.provider); + final playlistNotifier = ref.watch(ProxyPlaylistNotifier.notifier); + + final isActive = playlist.activeTrack?.id == trackId; + + final trackQuery = useQueries.tracks.track(ref, trackId); + + final track = trackQuery.data ?? FakeData.track; + + void onPlay() async { + if (isActive) { + audioPlayer.pause(); + } else { + await playlistNotifier.load([track], autoPlay: true); + } + } + + return Scaffold( + appBar: const PageWindowTitleBar( + automaticallyImplyLeading: true, + backgroundColor: Colors.transparent, + ), + extendBodyBehindAppBar: true, + body: Stack( + children: [ + Positioned.fill( + child: Container( + decoration: BoxDecoration( + image: DecorationImage( + image: UniversalImage.imageProvider( + TypeConversionUtils.image_X_UrlString( + track.album!.images, + placeholder: ImagePlaceholder.albumArt, + ), + ), + fit: BoxFit.cover, + colorFilter: ColorFilter.mode( + colorScheme.surface.withOpacity(0.5), + BlendMode.srcOver, + ), + alignment: Alignment.topCenter, + ), + ), + ), + ), + Positioned.fill( + child: BackdropFilter( + filter: ImageFilter.blur(sigmaX: 10, sigmaY: 10), + child: Skeletonizer( + enabled: trackQuery.isLoading, + child: Container( + alignment: Alignment.topCenter, + decoration: BoxDecoration( + gradient: LinearGradient( + colors: [ + colorScheme.surface, + Colors.transparent, + ], + begin: Alignment.topCenter, + end: Alignment.bottomCenter, + stops: const [0.2, 1], + ), + ), + child: SafeArea( + child: Wrap( + spacing: 20, + runSpacing: 20, + alignment: WrapAlignment.center, + crossAxisAlignment: WrapCrossAlignment.center, + runAlignment: WrapAlignment.center, + children: [ + ClipRRect( + borderRadius: BorderRadius.circular(10), + child: UniversalImage( + path: TypeConversionUtils.image_X_UrlString( + track.album!.images, + placeholder: ImagePlaceholder.albumArt, + ), + height: 200, + width: 200, + ), + ), + Padding( + padding: const EdgeInsets.symmetric(horizontal: 16.0), + child: Column( + crossAxisAlignment: mediaQuery.smAndDown + ? CrossAxisAlignment.center + : CrossAxisAlignment.start, + mainAxisSize: MainAxisSize.min, + children: [ + Text( + track.name!, + style: textTheme.titleLarge, + ), + const Gap(10), + Row( + mainAxisSize: MainAxisSize.min, + children: [ + const Icon(SpotubeIcons.album), + const Gap(5), + Flexible( + child: LinkText( + track.album!.name!, + '/album/${track.album!.id}', + push: true, + extra: track.album, + ), + ), + ], + ), + const Gap(10), + Row( + mainAxisSize: MainAxisSize.min, + children: [ + const Icon(SpotubeIcons.artist), + const Gap(5), + TypeConversionUtils + .artists_X_ClickableArtists( + track.artists!, + ), + ], + ), + const Gap(10), + ConstrainedBox( + constraints: + const BoxConstraints(maxWidth: 350), + child: Row( + mainAxisSize: mediaQuery.smAndDown + ? MainAxisSize.max + : MainAxisSize.min, + children: [ + const Gap(5), + if (!isActive && + !playlist.tracks.contains(track)) + OutlinedButton.icon( + icon: const Icon(SpotubeIcons.queueAdd), + label: Text(context.l10n.queue), + onPressed: () { + playlistNotifier.addTrack(track); + }, + ), + const Gap(5), + if (!isActive && + !playlist.tracks.contains(track)) + IconButton.outlined( + icon: + const Icon(SpotubeIcons.lightning), + tooltip: context.l10n.play_next, + onPressed: () { + playlistNotifier + .addTracksAtFirst([track]); + }, + ), + const Gap(5), + IconButton.filled( + tooltip: isActive + ? context.l10n.pause_playback + : context.l10n.play, + icon: Icon( + isActive + ? SpotubeIcons.pause + : SpotubeIcons.play, + color: colorScheme.onPrimary, + ), + onPressed: onPlay, + ), + const Gap(5), + if (mediaQuery.smAndDown) + const Spacer() + else + const Gap(20), + TrackHeartButton(track: track), + TrackOptions( + track: track, + userPlaylist: false, + ), + const Gap(5), + ], + ), + ), + ], + ), + ), + ], + ), + ), + ), + ), + ), + ), + ], + ), + ); + } +} diff --git a/lib/services/queries/queries.dart b/lib/services/queries/queries.dart index cc3ce132..30c23268 100644 --- a/lib/services/queries/queries.dart +++ b/lib/services/queries/queries.dart @@ -4,6 +4,7 @@ import 'package:spotube/services/queries/category.dart'; import 'package:spotube/services/queries/lyrics.dart'; import 'package:spotube/services/queries/playlist.dart'; import 'package:spotube/services/queries/search.dart'; +import 'package:spotube/services/queries/tracks.dart'; import 'package:spotube/services/queries/user.dart'; import 'package:spotube/services/queries/views.dart'; @@ -17,6 +18,7 @@ class Queries { final search = const SearchQueries(); final user = const UserQueries(); final views = const ViewsQueries(); + final tracks = const TracksQueries(); } const useQueries = Queries._(); diff --git a/lib/services/queries/tracks.dart b/lib/services/queries/tracks.dart new file mode 100644 index 00000000..52bab984 --- /dev/null +++ b/lib/services/queries/tracks.dart @@ -0,0 +1,16 @@ +import 'package:fl_query/fl_query.dart'; +import 'package:hooks_riverpod/hooks_riverpod.dart'; +import 'package:spotify/spotify.dart'; +import 'package:spotube/hooks/spotify/use_spotify_query.dart'; + +class TracksQueries { + const TracksQueries(); + + Query track(WidgetRef ref, String id) { + return useSpotifyQuery( + "track/$id", + (spotify) => spotify.tracks.get(id), + ref: ref, + ); + } +} diff --git a/pubspec.lock b/pubspec.lock index 526898d5..b4182d12 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -543,10 +543,10 @@ packages: dependency: transitive description: name: file - sha256: "1b92bec4fc2a72f59a8e15af5f52cd441e4a7860b49499d69dfa817af20e925d" + sha256: "5fc22d7c25582e38ad9a8515372cd9a93834027aacf1801cf01164dac0ffa08c" url: "https://pub.dev" source: hosted - version: "6.1.4" + version: "7.0.0" file_picker: dependency: "direct main" description: @@ -1255,6 +1255,22 @@ packages: url: "https://pub.dev" source: hosted version: "0.4.2" + leak_tracker: + dependency: transitive + description: + name: leak_tracker + sha256: "04be76c4a4bb50f14904e64749237e541e7c7bcf7ec0b196907322ab5d2fc739" + url: "https://pub.dev" + source: hosted + version: "9.0.16" + leak_tracker_testing: + dependency: transitive + description: + name: leak_tracker_testing + sha256: b06739349ec2477e943055aea30172c5c7000225f79dad4702e2ec0eda79a6ff + url: "https://pub.dev" + source: hosted + version: "1.0.5" lints: dependency: transitive description: @@ -1307,10 +1323,10 @@ packages: dependency: transitive description: name: material_color_utilities - sha256: "9528f2f296073ff54cb9fee677df673ace1218163c3bc7628093e7eed5203d41" + sha256: "0e0a020085b65b6083975e499759762399b4475f766c21668c4ecca34ea74e5a" url: "https://pub.dev" source: hosted - version: "0.5.0" + version: "0.8.0" media_kit: dependency: "direct main" description: @@ -1379,10 +1395,10 @@ packages: dependency: transitive description: name: meta - sha256: a6e590c838b18133bb482a2745ad77c5bb7715fb0451209e1a7567d416678b8e + sha256: d584fa6707a52763a52446f02cc621b077888fb63b93bbcb1143a7be5a0c0c04 url: "https://pub.dev" source: hosted - version: "1.10.0" + version: "1.11.0" metadata_god: dependency: "direct main" description: @@ -1595,10 +1611,10 @@ packages: dependency: transitive description: name: platform - sha256: ae68c7bfcd7383af3629daafb32fb4e8681c7154428da4febcff06200585f102 + sha256: "0a279f0707af40c890e80b1e9df8bb761694c074ba7e1d4ab1bc4b728e200b59" url: "https://pub.dev" source: hosted - version: "3.1.2" + version: "3.1.3" plugin_platform_interface: dependency: transitive description: @@ -1635,10 +1651,10 @@ packages: dependency: transitive description: name: process - sha256: "53fd8db9cec1d37b0574e12f07520d582019cb6c44abf5479a01505099a34a09" + sha256: "266ca5be5820feefc777793d0a583acfc8c40834893c87c00c6c09e2cf58ea42" url: "https://pub.dev" source: hosted - version: "4.2.4" + version: "5.0.1" provider: dependency: transitive description: @@ -1780,10 +1796,10 @@ packages: dependency: transitive description: name: shared_preferences_linux - sha256: c2eb5bf57a2fe9ad6988121609e47d3e07bb3bdca5b6f8444e4cf302428a128a + sha256: "9f2cbcf46d4270ea8be39fa156d86379077c8a5228d9dfdb1164ae0bb93f1faa" url: "https://pub.dev" source: hosted - version: "2.3.1" + version: "2.3.2" shared_preferences_platform_interface: dependency: transitive description: @@ -1804,10 +1820,10 @@ packages: dependency: transitive description: name: shared_preferences_windows - sha256: f763a101313bd3be87edffe0560037500967de9c394a714cd598d945517f694f + sha256: "841ad54f3c8381c480d0c9b508b89a34036f512482c407e6df7a9c4aa2ef8f59" url: "https://pub.dev" source: hosted - version: "2.3.1" + version: "2.3.2" shelf: dependency: transitive description: @@ -2217,10 +2233,10 @@ packages: dependency: transitive description: name: vm_service - sha256: c538be99af830f478718b51630ec1b6bee5e74e52c8a802d328d9e71d35d2583 + sha256: b3d56ff4341b8f182b96aceb2fa20e3dcb336b9f867bc0eafc0de10f1048e957 url: "https://pub.dev" source: hosted - version: "11.10.0" + version: "13.0.0" watcher: dependency: transitive description: @@ -2233,10 +2249,10 @@ packages: dependency: transitive description: name: web - sha256: afe077240a270dcfd2aafe77602b4113645af95d0ad31128cc02bce5ac5d5152 + sha256: edc8a9573dd8c5a83a183dae1af2b6fd4131377404706ca4e5420474784906fa url: "https://pub.dev" source: hosted - version: "0.3.0" + version: "0.4.0" web_socket_channel: dependency: transitive description: @@ -2249,10 +2265,10 @@ packages: dependency: transitive description: name: webdriver - sha256: "3c923e918918feeb90c4c9fdf1fe39220fa4c0e8e2c0fffaded174498ef86c49" + sha256: "003d7da9519e1e5f329422b36c4dcdf18d7d2978d1ba099ea4e45ba490ed845e" url: "https://pub.dev" source: hosted - version: "3.0.2" + version: "3.0.3" wikipedia_api: dependency: "direct main" description: From c203ac69ee74ba8722dae3da4b47761cd8d59c34 Mon Sep 17 00:00:00 2001 From: Kingkor Roy Tirtho Date: Fri, 5 Jan 2024 20:02:27 +0600 Subject: [PATCH 091/195] fix: search page vertical scrollbar moves on horizontal scroll #1017 --- .../horizontal_playbutton_card_view.dart | 86 ++++++++++--------- 1 file changed, 45 insertions(+), 41 deletions(-) diff --git a/lib/components/shared/horizontal_playbutton_card_view/horizontal_playbutton_card_view.dart b/lib/components/shared/horizontal_playbutton_card_view/horizontal_playbutton_card_view.dart index d00e5c4b..2075acbb 100644 --- a/lib/components/shared/horizontal_playbutton_card_view/horizontal_playbutton_card_view.dart +++ b/lib/components/shared/horizontal_playbutton_card_view/horizontal_playbutton_card_view.dart @@ -55,48 +55,52 @@ class HorizontalPlaybuttonCardView extends HookWidget { ), SizedBox( height: height, - child: ScrollConfiguration( - behavior: ScrollConfiguration.of(context).copyWith( - dragDevices: { - PointerDeviceKind.touch, - PointerDeviceKind.mouse, - }, - ), - child: items.isEmpty - ? ListView.builder( - scrollDirection: Axis.horizontal, - itemCount: 5, - itemBuilder: (context, index) { - return AlbumCard(FakeData.albumSimple); - }, - ) - : InfiniteList( - scrollController: scrollController, - scrollDirection: Axis.horizontal, - padding: const EdgeInsets.symmetric(vertical: 8.0), - itemCount: items.length, - onFetchData: onFetchMore, - loadingBuilder: (context) => Skeletonizer( - enabled: true, - child: AlbumCard(FakeData.albumSimple), - ), - isLoading: isLoadingNextPage, - hasReachedMax: !hasNextPage, - itemBuilder: (context, index) { - final item = items[index]; - - return switch (item.runtimeType) { - PlaylistSimple => - PlaylistCard(item as PlaylistSimple), - Album => AlbumCard(item as Album), - Artist => Padding( - padding: - const EdgeInsets.symmetric(horizontal: 12.0), - child: ArtistCard(item as Artist), + child: NotificationListener( + // disable multiple scrollbar to use this + onNotification: (notification) => true, + child: ScrollConfiguration( + behavior: ScrollConfiguration.of(context).copyWith( + dragDevices: { + PointerDeviceKind.touch, + PointerDeviceKind.mouse, + }, + ), + child: items.isEmpty + ? ListView.builder( + scrollDirection: Axis.horizontal, + itemCount: 5, + itemBuilder: (context, index) { + return AlbumCard(FakeData.albumSimple); + }, + ) + : InfiniteList( + scrollController: scrollController, + scrollDirection: Axis.horizontal, + padding: const EdgeInsets.symmetric(vertical: 8.0), + itemCount: items.length, + onFetchData: onFetchMore, + loadingBuilder: (context) => Skeletonizer( + enabled: true, + child: AlbumCard(FakeData.albumSimple), ), - _ => const SizedBox.shrink(), - }; - }), + isLoading: isLoadingNextPage, + hasReachedMax: !hasNextPage, + itemBuilder: (context, index) { + final item = items[index]; + + return switch (item.runtimeType) { + PlaylistSimple => + PlaylistCard(item as PlaylistSimple), + Album => AlbumCard(item as Album), + Artist => Padding( + padding: const EdgeInsets.symmetric( + horizontal: 12.0), + child: ArtistCard(item as Artist), + ), + _ => const SizedBox.shrink(), + }; + }), + ), ), ), ], From 5509cae91c8b1f5cb9fac179060f477397a4a27f Mon Sep 17 00:00:00 2001 From: Kingkor Roy Tirtho Date: Fri, 5 Jan 2024 20:26:57 +0600 Subject: [PATCH 092/195] fix(android): download failing for permission issues #1015 --- .../download_manager/chunked_download.dart | 1 - .../download_manager/download_manager.dart | 22 ++++++++++++++++--- 2 files changed, 19 insertions(+), 4 deletions(-) diff --git a/lib/services/download_manager/chunked_download.dart b/lib/services/download_manager/chunked_download.dart index b2849a3c..9e5e0a98 100644 --- a/lib/services/download_manager/chunked_download.dart +++ b/lib/services/download_manager/chunked_download.dart @@ -2,7 +2,6 @@ import 'dart:async'; import 'dart:io'; import 'package:dio/dio.dart'; -import 'package:flutter/foundation.dart'; import 'package:spotube/models/logger.dart'; final logger = getLogger("ChunkedDownload"); diff --git a/lib/services/download_manager/download_manager.dart b/lib/services/download_manager/download_manager.dart index 904f06cf..d7a42430 100644 --- a/lib/services/download_manager/download_manager.dart +++ b/lib/services/download_manager/download_manager.dart @@ -6,6 +6,8 @@ import 'package:collection/collection.dart'; import 'package:dio/dio.dart'; import 'package:flutter/foundation.dart'; +import 'package:path/path.dart' as path; +import 'package:path_provider/path_provider.dart'; import 'package:spotube/models/logger.dart'; import 'package:spotube/services/download_manager/chunked_download.dart'; import 'package:spotube/services/download_manager/download_request.dart'; @@ -77,7 +79,18 @@ class DownloadManager { logger.d("[DownloadManager] $url"); final file = File(savePath.toString()); - partialFilePath = savePath + partialExtension; + + final tmpDirPath = await Directory( + path.join( + (await getTemporaryDirectory()).path, + "spotube-downloads", + ), + ).create(recursive: true); + + partialFilePath = path.join( + tmpDirPath.path, + path.basename(savePath) + partialExtension, + ); partialFile = File(partialFilePath); final fileExist = await file.exists(); @@ -111,7 +124,9 @@ class DownloadManager { await ioSink.addStream(partialChunkFile.openRead()); await partialChunkFile.delete(); await ioSink.close(); - await partialFile.rename(savePath); + + await partialFile.copy(savePath); + await partialFile.delete(); setStatus(task, DownloadStatus.completed); } @@ -125,7 +140,8 @@ class DownloadManager { ); if (response.statusCode == HttpStatus.ok) { - await partialFile.rename(savePath); + await partialFile.copy(savePath); + await partialFile.delete(); setStatus(task, DownloadStatus.completed); } } From 29f162c80100fcb9ad51ee3103f04cf2facc17e9 Mon Sep 17 00:00:00 2001 From: Kingkor Roy Tirtho Date: Fri, 5 Jan 2024 21:25:23 +0600 Subject: [PATCH 093/195] chore: remove the sp_key cookie requirement as no longer necessary --- lib/components/desktop_login/login_form.dart | 15 +--- lib/l10n/app_ar.arb | 2 - lib/l10n/app_bn.arb | 2 - lib/l10n/app_ca.arb | 2 - lib/l10n/app_de.arb | 2 - lib/l10n/app_en.arb | 6 +- lib/l10n/app_es.arb | 2 - lib/l10n/app_fa.arb | 2 - lib/l10n/app_fr.arb | 2 - lib/l10n/app_hi.arb | 2 - lib/l10n/app_it.arb | 2 - lib/l10n/app_ja.arb | 2 - lib/l10n/app_nl.arb | 2 - lib/l10n/app_pl.arb | 2 - lib/l10n/app_pt.arb | 2 - lib/l10n/app_ru.arb | 2 - lib/l10n/app_tr.arb | 2 - lib/l10n/app_uk.arb | 2 - lib/l10n/app_zh.arb | 2 - lib/pages/mobile_login/mobile_login.dart | 7 +- untranslated_messages.json | 87 +++++++++++++++++++- 21 files changed, 92 insertions(+), 57 deletions(-) diff --git a/lib/components/desktop_login/login_form.dart b/lib/components/desktop_login/login_form.dart index f2b183f4..5abb9524 100644 --- a/lib/components/desktop_login/login_form.dart +++ b/lib/components/desktop_login/login_form.dart @@ -17,7 +17,6 @@ class TokenLoginForm extends HookConsumerWidget { final authenticationNotifier = ref.watch(AuthenticationNotifier.provider.notifier); final directCodeController = useTextEditingController(); - final keyCodeController = useTextEditingController(); final mounted = useIsMounted(); final isLoading = useState(false); @@ -37,23 +36,13 @@ class TokenLoginForm extends HookConsumerWidget { keyboardType: TextInputType.visiblePassword, ), const SizedBox(height: 10), - TextField( - controller: keyCodeController, - decoration: InputDecoration( - hintText: context.l10n.spotify_cookie("\"sp_key (or sp_gaid)\""), - labelText: context.l10n.cookie_name_cookie("sp_key (or sp_gaid)"), - ), - keyboardType: TextInputType.visiblePassword, - ), - const SizedBox(height: 20), FilledButton( onPressed: isLoading.value ? null : () async { try { isLoading.value = true; - if (keyCodeController.text.isEmpty || - directCodeController.text.isEmpty) { + if (directCodeController.text.isEmpty) { ScaffoldMessenger.of(context).showSnackBar( SnackBar( content: Text(context.l10n.fill_in_all_fields), @@ -63,7 +52,7 @@ class TokenLoginForm extends HookConsumerWidget { return; } final cookieHeader = - "sp_dc=${directCodeController.text.trim()}; sp_key=${keyCodeController.text.trim()}"; + "sp_dc=${directCodeController.text.trim()}"; authenticationNotifier.setCredentials( await AuthenticationCredentials.fromCookie( diff --git a/lib/l10n/app_ar.arb b/lib/l10n/app_ar.arb index 2bdde72a..20b6a47c 100644 --- a/lib/l10n/app_ar.arb +++ b/lib/l10n/app_ar.arb @@ -177,11 +177,9 @@ "step_2": "الخطوة 2", "step_2_steps": "1. بمجرد تسجيل الدخول، اضغط على F12 أو انقر بزر الماوس الأيمن > فحص لفتح أدوات تطوير المتصفح.\n2. ثم انتقل إلى علامة التبويب \"التطبيقات\" (Chrome وEdge وBrave وما إلى ذلك.) أو علامة التبويب \"التخزين\" (Firefox وPalemoon وما إلى ذلك..)\n3. انتقل إلى قسم \"ملفات تعريف الارتباط\" ثم القسم الفرعي \"https://accounts.spotify.com\"", "step_3": "الخطوة 3", - "step_3_steps": "انسخ قيم \"sp_dc\" و \"sp_key\" (أو sp_gaid) الكويز", "success_emoji": "نجاح 🥳", "success_message": "لقد قمت الآن بتسجيل الدخول بنجاح باستخدام حساب Spotify الخاص بك. عمل جيد يا صديقي!", "step_4": "الخطوة 4", - "step_4_steps": "قم بلصق قيم \"sp_dc\" و \"sp_key\" (أو sp_gaid) المنسوخة في الحقول المعنية", "something_went_wrong": "هناك خطأ ما", "piped_instance": "مثيل خادم Piped", "piped_description": "مثيل خادم Piped الذي سيتم استخدامه لمطابقة المقطوعة", diff --git a/lib/l10n/app_bn.arb b/lib/l10n/app_bn.arb index 39f8a1ee..74dc200d 100644 --- a/lib/l10n/app_bn.arb +++ b/lib/l10n/app_bn.arb @@ -175,11 +175,9 @@ "step_2": "ধাপ 2", "step_2_steps": "১. একবার আপনি লগ ইন করলে, ব্রাউজার ডেভটুল খুলতে F12 বা মাউসের রাইট ক্লিক > \"Inspect to open Browser DevTools\" টিপুন।\n২. তারপর \"Application\" ট্যাবে যান (Chrome, Edge, Brave etc..) অথবা \"Storage\" Tab (Firefox, Palemoon etc..)\n৩. \"Cookies \" বিভাগে যান তারপর \"https://accounts.spotify.com\" উপবিভাগে যান", "step_3": "ধাপ 3", - "step_3_steps": "\"sp_dc\" এবং \"sp_key\" (অথবা sp_gaid) কুকিজের মান কপি করুন", "success_emoji": "আমরা সফল🥳", "success_message": "এখন আপনি সফলভাবে আপনার Spotify অ্যাকাউন্ট দিয়ে লগ ইন করেছেন। সাধুভাত আপনাকে", "step_4": "ধাপ 4", - "step_4_steps": "কপি করা \"sp_dc\" এবং \"sp_key\" (অথবা sp_gaid) এর মান সংশ্লিষ্ট ফিল্ডে পেস্ট করুন", "something_went_wrong": "কিছু ভুল হয়েছে", "piped_instance": "Piped সার্ভার এড্রেস", "piped_description": "গান ম্যাচ করার জন্য ব্যবহৃত পাইপড সার্ভার", diff --git a/lib/l10n/app_ca.arb b/lib/l10n/app_ca.arb index 15ca9e31..2c952457 100644 --- a/lib/l10n/app_ca.arb +++ b/lib/l10n/app_ca.arb @@ -175,11 +175,9 @@ "step_2": "Pas 2", "step_2_steps": "1. Una vegada que hagi iniciat sessió, premi F12 o faci clic dret amb el ratolí > Inspeccionar per obrir les eines de desenvolulpador del navegador.\n2. Després vagi a la pestanya \"Application\" (Chrome, Edge, Brave, etc.) o \"Storage\" (Firefox, Palemoon, etc.)\n3. Vagi a la secció \"Cookies\" i després a la subsecció \"https://accounts.spotify.com\"", "step_3": "Pas 3", - "step_3_steps": "Copiï els valors de les Cookies \"sp_dc\" i \"sp_key\" (o sp_gaid)", "success_emoji": "Èxit! 🥳", "success_message": "Ara has iniciat sessió amb èxit al teu compte de Spotify. Bona feina!", "step_4": "Pas 4", - "step_4_steps": "Enganxi els valors coppiats de \"sp_dc\" i \"sp_key\" (o sp_gaid) en els camps respectius", "something_went_wrong": "Quelcom ha sortit malament", "piped_instance": "Instància del servidor Piped", "piped_description": "La instància del servidor Piped a utilitzar per la coincidència de cançons", diff --git a/lib/l10n/app_de.arb b/lib/l10n/app_de.arb index 1a13e4a1..59f832ea 100644 --- a/lib/l10n/app_de.arb +++ b/lib/l10n/app_de.arb @@ -175,11 +175,9 @@ "step_2": "Schritt 2", "step_2_steps": "1. Wenn du angemeldet bist, drücke F12 oder klicke mit der rechten Maustaste > Inspektion, um die Browser-Entwicklertools zu öffnen.\n2. Gehe dann zum \"Anwendungs\"-Tab (Chrome, Edge, Brave usw.) oder zum \"Storage\"-Tab (Firefox, Palemoon usw.)\n3. Gehe zum Abschnitt \"Cookies\" und dann zum Unterabschnitt \"https://accounts.spotify.com\"", "step_3": "Schritt 3", - "step_3_steps": "Kopiere die Werte der Cookies \"sp_dc\" und \"sp_key\" (oder sp_gaid)", "success_emoji": "Erfolg🥳", "success_message": "Jetzt bist du erfolgreich mit deinem Spotify-Konto angemeldet. Gut gemacht, Kumpel!", "step_4": "Schritt 4", - "step_4_steps": "Füge die kopierten Werte von \"sp_dc\" und \"sp_key\" (oder sp_gaid) in die entsprechenden Felder ein", "something_went_wrong": "Etwas ist schiefgelaufen", "piped_instance": "Piped-Serverinstanz", "piped_description": "Die Piped-Serverinstanz, die zur Titelzuordnung verwendet werden soll", diff --git a/lib/l10n/app_en.arb b/lib/l10n/app_en.arb index bebfafac..82877ea1 100644 --- a/lib/l10n/app_en.arb +++ b/lib/l10n/app_en.arb @@ -177,11 +177,11 @@ "step_2": "Step 2", "step_2_steps": "1. Once you're logged in, press F12 or Mouse Right Click > Inspect to Open the Browser devtools.\n2. Then go the \"Application\" Tab (Chrome, Edge, Brave etc..) or \"Storage\" Tab (Firefox, Palemoon etc..)\n3. Go to the \"Cookies\" section then the \"https://accounts.spotify.com\" subsection", "step_3": "Step 3", - "step_3_steps": "Copy the values of \"sp_dc\" and \"sp_key\" (or sp_gaid) Cookies", + "step_3_steps": "Copy the value of \"sp_dc\" Cookie", "success_emoji": "Success🥳", - "success_message": "Now you're successfully Logged In with your Spotify account. Good Job, mate!", + "success_message": "Now you've successfully Logged in with your Spotify account. Good Job, mate!", "step_4": "Step 4", - "step_4_steps": "Paste the copied \"sp_dc\" and \"sp_key\" (or sp_gaid) values in the respective fields", + "step_4_steps": "Paste the copied \"sp_dc\" value", "something_went_wrong": "Something went wrong", "piped_instance": "Piped Server Instance", "piped_description": "The Piped server instance to use for track matching", diff --git a/lib/l10n/app_es.arb b/lib/l10n/app_es.arb index 2fecd8f1..e04b4798 100644 --- a/lib/l10n/app_es.arb +++ b/lib/l10n/app_es.arb @@ -175,11 +175,9 @@ "step_2": "Paso 2", "step_2_steps": "1. Una vez que hayas iniciado sesión, presiona F12 o haz clic derecho con el ratón > Inspeccionar para abrir las herramientas de desarrollo del navegador.\n2. Luego ve a la pestaña \"Application\" (Chrome, Edge, Brave, etc.) o \"Storage\" (Firefox, Palemoon, etc.)\n3. Ve a la sección \"Cookies\" y luego la subsección \"https://accounts.spotify.com\"", "step_3": "Paso 3", - "step_3_steps": "Copia los valores de las Cookies \"sp_dc\" y \"sp_key\" (o sp_gaid)", "success_emoji": "¡Éxito! 🥳", "success_message": "Ahora has iniciado sesión con éxito en tu cuenta de Spotify. ¡Buen trabajo!", "step_4": "Paso 4", - "step_4_steps": "Pega los valores copiados de \"sp_dc\" y \"sp_key\" (o sp_gaid) en los campos respectivos", "something_went_wrong": "Algo salió mal", "piped_instance": "Instancia del servidor Piped", "piped_description": "La instancia del servidor Piped a utilizar para la coincidencia de pistas", diff --git a/lib/l10n/app_fa.arb b/lib/l10n/app_fa.arb index 84b9b448..c9586cde 100644 --- a/lib/l10n/app_fa.arb +++ b/lib/l10n/app_fa.arb @@ -177,11 +177,9 @@ "step_2": "گام 2", "step_2_steps": "1. پس از ورود به سیستم، F12 یا کلیک راست ماوس > Inspect را فشار دهید تا ابزارهای توسعه مرورگر باز شود..\n2. سپس به تب \"Application\" (Chrome, Edge, Brave etc..) یا \"Storage\" Tab (Firefox, Palemoon etc..)\n3. به قسمت \"Cookies\" و به پخش \"https://accounts.spotify.com\" بروید", "step_3": "گام 3", - "step_3_steps": "کپی کردن مقادیر \"sp_dc\" و \"sp_key\" (یا sp_gaid) کوکی", "success_emoji": "موفقیت🥳", "success_message": "اکنون با موفقیت با حساب اسپوتیفای خود وارد شده اید", "step_4": "مرحله 4", - "step_4_steps": "مقدار کپی شده را \"sp_dc\" and \"sp_key\" (یا sp_gaid) در فیلد مربوط پر کنید", "something_went_wrong": "اشتباهی رخ داده", "piped_instance": "مشکل در ارتباط با سرور", "piped_description": "مشکل در ارتباط با سرور در دریافت آهنگ ها", diff --git a/lib/l10n/app_fr.arb b/lib/l10n/app_fr.arb index 82997bad..0c3eb653 100644 --- a/lib/l10n/app_fr.arb +++ b/lib/l10n/app_fr.arb @@ -175,11 +175,9 @@ "step_2": "Étape 2", "step_2_steps": "1. Une fois connecté, appuyez sur F12 ou clic droit de la souris > Inspecter pour ouvrir les outils de développement du navigateur.\n2. Ensuite, allez dans l'onglet \"Application\" (Chrome, Edge, Brave, etc.) ou l'onglet \"Stockage\" (Firefox, Palemoon, etc.)\n3. Allez dans la section \"Cookies\", puis dans la sous-section \"https://accounts.spotify.com\"", "step_3": "Étape 3", - "step_3_steps": "Copiez les valeurs des cookies \"sp_dc\" et \"sp_key\" (ou sp_gaid)", "success_emoji": "Succès🥳", "success_message": "Vous êtes maintenant connecté avec succès à votre compte Spotify. Bon travail, mon ami!", "step_4": "Étape 4", - "step_4_steps": "Collez les valeurs copiées de \"sp_dc\" et \"sp_key\" (ou sp_gaid) dans les champs respectifs", "something_went_wrong": "Quelque chose s'est mal passé", "piped_instance": "Instance pipée", "piped_description": "L'instance de serveur Piped à utiliser pour la correspondance des pistes", diff --git a/lib/l10n/app_hi.arb b/lib/l10n/app_hi.arb index 4bfff3da..dd27dabf 100644 --- a/lib/l10n/app_hi.arb +++ b/lib/l10n/app_hi.arb @@ -175,11 +175,9 @@ "step_2": "2 चरण", "step_2_steps": "1. जब आप लॉगिन हो जाएँ, तो F12 दबाएं या माउस राइट क्लिक> निरीक्षण करें ताकि ब्राउज़र डेवटूल्स खुलें।\n2. फिर ब्राउज़र के \"एप्लिकेशन\" टैब (Chrome, Edge, Brave आदि) या \"स्टोरेज\" टैब (Firefox, Palemoon आदि) में जाएं\n3. \"कुकीज़\" अनुभाग में जाएं फिर \"https: //accounts.spotify.com\" उप-अनुभाग में जाएं", "step_3": "स्टेप 3", - "step_3_steps": "\"sp_dc\" और \"sp_key\" (या sp_gaid) कुकीज़ के मान कॉपी करें", "success_emoji": "सफलता🥳", "success_message": "अब आप अपने स्पॉटिफाई अकाउंट से सफलतापूर्वक लॉगइन हो गए हैं। अच्छा काम किया!", "step_4": "स्टेप 4", - "step_4_steps": "कॉपी की गई \"sp_dc\" और \"sp_key\" (या sp_gaid) मानों को संबंधित फील्ड में पेस्ट करें", "something_went_wrong": "कुछ गलत हो गया", "piped_instance": "पाइप्ड सर्वर", "piped_description": "पाइप किए गए सर्वर", diff --git a/lib/l10n/app_it.arb b/lib/l10n/app_it.arb index 033bb516..3680933a 100644 --- a/lib/l10n/app_it.arb +++ b/lib/l10n/app_it.arb @@ -177,11 +177,9 @@ "step_2": "Passo 2", "step_2_steps": "1. Quando sei acceduto premi F12 o premi il tasto destro del Mouse > Ispeziona per aprire gli strumenti di sviluppo del browser.\n2. Vai quindi nel tab \"Applicazione\" (Chrome, Edge, Brave etc..) o tab \"Archiviazione\" (Firefox, Palemoon etc..)\n3. Vai nella sezione \"Cookies\" quindi nella sezione \"https://accounts.spotify.com\"", "step_3": "Passo 3", - "step_3_steps": "Copia il valore dei cookie \"sp_dc\" e \"sp_key\" (o sp_gaid)", "success_emoji": "Successo🥳", "success_message": "Ora hai correttamente effettuato il login al tuo account Spotify. Bel lavoro, amico!", "step_4": "Passo 4", - "step_4_steps": "Incolla i valori copiati di \"sp_dc\" e \"sp_key\" (o sp_gaid) nei campi rispettivi", "something_went_wrong": "Qualcosa è andato storto", "piped_instance": "Istanza Server Piped", "piped_description": "L'istanza server Piped da usare per il match della tracccia", diff --git a/lib/l10n/app_ja.arb b/lib/l10n/app_ja.arb index ac23728b..39e0dad8 100644 --- a/lib/l10n/app_ja.arb +++ b/lib/l10n/app_ja.arb @@ -175,11 +175,9 @@ "step_2": "ステップ 2", "step_2_steps": "1. ログインしたら、F12を押すか、マウス右クリック > 調査(検証)でブラウザの開発者ツール (devtools) を開きます。\n2. アプリケーション (Application) タブ (Chrome, Edge, Brave など) またはストレージタブ (Firefox, Palemoon など)\n3. Cookies 欄を選択し、https://accounts.spotify.com の枝を選びます", "step_3": "ステップ 3", - "step_3_steps": "sp_dc と sp_key (または or sp_gaid) の値 (Value) をコピーします", "success_emoji": "成功🥳", "success_message": "アカウントへのログインに成功しました。よくできました!", "step_4": "ステップ 4", - "step_4_steps": "コピーした sp_dc と sp_key (または or sp_gaid) の値をそれぞれの入力欄に貼り付けます", "something_went_wrong": "何か誤りがあります", "piped_instance": "Piped サーバーのインスタンス", "piped_description": "曲の一致に使う Piped サーバーのインスタンス", diff --git a/lib/l10n/app_nl.arb b/lib/l10n/app_nl.arb index 6e50c461..23eee51b 100644 --- a/lib/l10n/app_nl.arb +++ b/lib/l10n/app_nl.arb @@ -177,11 +177,9 @@ "step_2": "Stap 2", "step_2_steps": "1. Zodra je bent aangemeld, druk je op F12 of klik je met de rechtermuisknop > Inspect om de Browser devtools te openen.\n2. Ga vervolgens naar het tabblad \"Toepassing\" (Chrome, Edge, Brave enz..) of naar het tabblad \"Opslag\" (Firefox, Palemoon enz..).\n3. Ga naar de sectie \"Cookies\" en vervolgens naar de subsectie \"https://accounts.spotify.com\".", "step_3": "Stap 3", - "step_3_steps": "Kopieer de waarden van \"sp_dc\" en \"sp_key\" (of sp_gaid) Cookies", "success_emoji": "Succes🥳", "success_message": "Je bent nu succesvol ingelogd met je Spotify account. Goed gedaan, maat!", "step_4": "Stap 4", - "step_4_steps": "Plak de gekopieerde \"sp_dc\" en \"sp_key\" (of sp_gaid) waarden in de respectievelijke velden", "something_went_wrong": "Er ging iets mis", "piped_instance": "Piped-serverinstantie", "piped_description": "De Piped-serverinstantie die moet worden gebruikt voor het matchen van sporen", diff --git a/lib/l10n/app_pl.arb b/lib/l10n/app_pl.arb index dd173a37..4ae48338 100644 --- a/lib/l10n/app_pl.arb +++ b/lib/l10n/app_pl.arb @@ -175,11 +175,9 @@ "step_2": "Krok 2", "step_2_steps": "1. Jeśli jesteś zalogowany, naciśnij klawisz F12 lub Kliknij prawym przyciskiem myszy > Zbadaj, aby odtworzyć narzędzia developerskie.\n2. Następnie przejdź do zakładki \"Application\" (Chrome, Edge, Brave etc..) lub zakładki \"Storage\" (Firefox, Palemoon etc..)\n3. Przejdź do sekcji \"Cookies\" a następnie do pod-sekcji \"https://accounts.spotify.com\"", "step_3": "Krok 3", - "step_3_steps": "Skopiuj wartości \"sp_dc\" i \"sp_key\" (lub sp_gaid) Ciasteczek", "success_emoji": "Sukces!🥳", "success_message": "Udało ci się zalogować! Dobra robota, stary!", "step_4": "Krok 4", - "step_4_steps": "Wklej wartości \"sp_dc\" i \"sp_key\" (lub sp_gaid) do odpowiednich pul.", "something_went_wrong": "Coś poszło nie tak 🙁", "piped_instance": "Instancja serwera Piped", "piped_description": "Instancja serwera Piped używana jest do dopasowania utworów.", diff --git a/lib/l10n/app_pt.arb b/lib/l10n/app_pt.arb index 705217c1..5ea4cca0 100644 --- a/lib/l10n/app_pt.arb +++ b/lib/l10n/app_pt.arb @@ -175,11 +175,9 @@ "step_2": "Passo 2", "step_2_steps": "1. Uma vez logado, pressione F12 ou clique com o botão direito do mouse > Inspecionar para abrir as ferramentas de desenvolvimento do navegador.\n2. Em seguida, vá para a guia \"Aplicativo\" (Chrome, Edge, Brave, etc.) ou \"Armazenamento\" (Firefox, Palemoon, etc.)\n3. Acesse a seção \"Cookies\" e depois a subseção \"https://accounts.spotify.com\"", "step_3": "Passo 3", - "step_3_steps": "Copie os valores dos Cookies \"sp_dc\" e \"sp_key\" (ou sp_gaid)", "success_emoji": "Sucesso🥳", "success_message": "Agora você está logado com sucesso em sua conta do Spotify. Bom trabalho!", "step_4": "Passo 4", - "step_4_steps": "Cole os valores copiados \"sp_dc\" e \"sp_key\" (ou sp_gaid) nos campos correspondentes", "something_went_wrong": "Algo deu errado", "piped_instance": "Instância do Servidor Piped", "piped_description": "A instância do servidor Piped a ser usada para correspondência de faixas", diff --git a/lib/l10n/app_ru.arb b/lib/l10n/app_ru.arb index 32415863..24120d62 100644 --- a/lib/l10n/app_ru.arb +++ b/lib/l10n/app_ru.arb @@ -175,11 +175,9 @@ "step_2": "Шаг 2", "step_2_steps": "1. После входа в систему нажмите F12 или щелкните правой кнопкой мыши > «Проверить», чтобы открыть инструменты разработчика браузера.\n2. Затем перейдите на вкладку \"Application\" (Chrome, Edge, Brave и т.д..) or \"Storage\" (Firefox, Palemoon и т.д..)\n3. Перейдите в раздел \"Cookies\", а затем в подраздел \"https://accounts.spotify.com\"", "step_3": "Шаг 3", - "step_3_steps": "Скопируйте значения \"sp_dc\" и \"sp_key\" (или sp_gaid) Cookies", "success_emoji": "Успешно 🥳", "success_message": "Теперь вы успешно вошли в свою учетную запись Spotify. Отличная работа, приятель!", "step_4": "Шаг 4", - "step_4_steps": "Вставьте скопированные \"sp_dc\" и \"sp_key\" (или sp_gaid) значения в соответствующие поля", "something_went_wrong": "Что-то пошло не так", "piped_instance": "Экземпляр сервера Piped", "piped_description": "Серверный экземпляр Piped для сопоставления треков", diff --git a/lib/l10n/app_tr.arb b/lib/l10n/app_tr.arb index 63646af6..e6b0ce34 100644 --- a/lib/l10n/app_tr.arb +++ b/lib/l10n/app_tr.arb @@ -177,11 +177,9 @@ "step_2": "2. Adım", "step_2_steps": "1. Giriş yaptıktan sonra, Tarayıcı devtools.\n2'yi açmak için F12'ye basın veya Fare Sağ Tıklaması > İncele'ye basın. Ardından \"Uygulama\" Sekmesine (Chrome, Edge, Brave vb.) veya \"Depolama\" Sekmesine (Firefox, Palemoon vb.) gidin\n3. \"Çerezler\" bölümüne ve ardından \"https://accounts.spotify.com\" alt bölümüne gidin", "step_3": "3. Adım", - "step_3_steps": "\"sp_dc\" ve \"sp_key\" (veya sp_gaid) Çerezlerinin değerlerini kopyalayın", "success_emoji": "Başarılı🥳", "success_message": "Şimdi Spotify hesabınızla başarılı bir şekilde oturum açtınız. İyi iş, dostum!", "step_4": "4. Adım", - "step_4_steps": "Kopyalanan \"sp_dc\" ve \"sp_key\" (veya sp_gaid) değerlerini ilgili alanlara yapıştırın", "something_went_wrong": "Bir şeyler ters gitti", "piped_instance": "Piped Sunucu Örneği", "piped_description": "Parça eşleştirme için kullanılacak Piped sunucu örneği", diff --git a/lib/l10n/app_uk.arb b/lib/l10n/app_uk.arb index 2ae29237..a5199a04 100644 --- a/lib/l10n/app_uk.arb +++ b/lib/l10n/app_uk.arb @@ -177,11 +177,9 @@ "step_2": "Крок 2", "step_2_steps": "1. Після входу натисніть F12 або клацніть правою кнопкою миші > Інспектувати, щоб відкрити інструменти розробки браузера.\n2. Потім перейдіть на вкладку 'Програма' (Chrome, Edge, Brave тощо) або вкладку 'Сховище' (Firefox, Palemoon тощо).\n3. Перейдіть до розділу 'Кукі-файли', а потім до підрозділу 'https://accounts.spotify.com'", "step_3": "Крок 3", - "step_3_steps": "Скопіюйте значення кукі-файлів 'sp_dc' та 'sp_key' (або sp_gaid)", "success_emoji": "Успіх🥳", "success_message": "Тепер ви успішно ввійшли у свій обліковий запис Spotify. Гарна робота, друже!", "step_4": "Крок 4", - "step_4_steps": "Вставте скопійовані значення 'sp_dc' та 'sp_key' (або sp_gaid) у відповідні поля", "something_went_wrong": "Щось пішло не так", "piped_instance": "Примірник сервера Piped", "piped_description": "Примірник сервера Piped, який використовуватиметься для зіставлення треків", diff --git a/lib/l10n/app_zh.arb b/lib/l10n/app_zh.arb index 85b57724..30f4a82c 100644 --- a/lib/l10n/app_zh.arb +++ b/lib/l10n/app_zh.arb @@ -175,11 +175,9 @@ "step_2": "步骤 2", "step_2_steps": "1. 一旦你已经完成登录, 按 F12 键或者鼠标右击网页空白区域 > 选择“检查”以打开浏览器开发者工具(DevTools)\n2. 然后选择 \"应用(Application)\" 标签页(Chrome, Edge, Brave 等基于 Chromium 的浏览器) 或 \"存储(Storage)\" 标签页 (Firefox, Palemoon 等基于 Firefox 的浏览器))\n3. 选择 \"Cookies\" 栏目然后选择 \"https://accounts.spotify.com\" 子栏目", "step_3": "步骤 3", - "step_3_steps": "复制名称为 \"sp_dc\" 和 \"sp_key\" (或 sp_gaid) 的值(Cookie Value)", "success_emoji": "成功🥳", "success_message": "你已经成功使用 Spotify 登录。干得漂亮!", "step_4": "步骤 4", - "step_4_steps": "将 \"sp_dc\" 与 \"sp_key\" (或 sp_gaid) 的值分别复制后粘贴到对应的区域", "something_went_wrong": "某些地方出现了问题", "piped_instance": "管道服务器实例", "piped_description": "管道服务器实例用于匹配歌曲", diff --git a/lib/pages/mobile_login/mobile_login.dart b/lib/pages/mobile_login/mobile_login.dart index 7ab0ea2a..8b9bce4c 100644 --- a/lib/pages/mobile_login/mobile_login.dart +++ b/lib/pages/mobile_login/mobile_login.dart @@ -55,12 +55,7 @@ class WebViewLogin extends HookConsumerWidget { final cookies = await CookieManager.instance().getCookies(url: action); final cookieHeader = - cookies.fold("", (previousValue, element) { - if (element.name == "sp_dc" || element.name == "sp_key") { - return "$previousValue; ${element.name}=${element.value}"; - } - return previousValue; - }); + "sp_dc=${cookies.firstWhere((element) => element.name == "sp_dc").value}"; authenticationNotifier.setCredentials( await AuthenticationCredentials.fromCookie(cookieHeader), diff --git a/untranslated_messages.json b/untranslated_messages.json index 9e26dfee..59b26614 100644 --- a/untranslated_messages.json +++ b/untranslated_messages.json @@ -1 +1,86 @@ -{} \ No newline at end of file +{ + "ar": [ + "step_3_steps", + "step_4_steps" + ], + + "bn": [ + "step_3_steps", + "step_4_steps" + ], + + "ca": [ + "step_3_steps", + "step_4_steps" + ], + + "de": [ + "step_3_steps", + "step_4_steps" + ], + + "es": [ + "step_3_steps", + "step_4_steps" + ], + + "fa": [ + "step_3_steps", + "step_4_steps" + ], + + "fr": [ + "step_3_steps", + "step_4_steps" + ], + + "hi": [ + "step_3_steps", + "step_4_steps" + ], + + "it": [ + "step_3_steps", + "step_4_steps" + ], + + "ja": [ + "step_3_steps", + "step_4_steps" + ], + + "nl": [ + "step_3_steps", + "step_4_steps" + ], + + "pl": [ + "step_3_steps", + "step_4_steps" + ], + + "pt": [ + "step_3_steps", + "step_4_steps" + ], + + "ru": [ + "step_3_steps", + "step_4_steps" + ], + + "tr": [ + "step_3_steps", + "step_4_steps" + ], + + "uk": [ + "step_3_steps", + "step_4_steps" + ], + + "zh": [ + "step_3_steps", + "step_4_steps" + ] +} From a76ee0acf2615a41b0527163cbd7e1d20fed226d Mon Sep 17 00:00:00 2001 From: Kingkor Roy Tirtho Date: Mon, 8 Jan 2024 22:57:03 +0600 Subject: [PATCH 094/195] chore: new liked tracks image --- assets/liked-tracks.jpg | Bin 0 -> 27058 bytes lib/components/library/user_playlists.dart | 30 +++++++++--------- .../sections/header/flexible_header.dart | 3 +- lib/pages/playlist/liked_playlist.dart | 6 +--- 4 files changed, 17 insertions(+), 22 deletions(-) create mode 100644 assets/liked-tracks.jpg diff --git a/assets/liked-tracks.jpg b/assets/liked-tracks.jpg new file mode 100644 index 0000000000000000000000000000000000000000..62dad65ea112e49db84afab026803502c221a249 GIT binary patch literal 27058 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 literal 0 HcmV?d00001 diff --git a/lib/components/library/user_playlists.dart b/lib/components/library/user_playlists.dart index a65c6d0e..32e91ed6 100644 --- a/lib/components/library/user_playlists.dart +++ b/lib/components/library/user_playlists.dart @@ -37,21 +37,21 @@ class UserPlaylists extends HookConsumerWidget { ); final likedTracksPlaylist = useMemoized( - () => PlaylistSimple() - ..name = context.l10n.liked_tracks - ..description = context.l10n.liked_tracks_description - ..type = "playlist" - ..collaborative = false - ..public = false - ..id = "user-liked-tracks" - ..images = [ - Image() - ..height = 300 - ..width = 300 - ..url = - "https://t.scdn.co/images/3099b3803ad9496896c43f22fe9be8c4.png" - ], - [context.l10n]); + () => PlaylistSimple() + ..name = context.l10n.liked_tracks + ..description = context.l10n.liked_tracks_description + ..type = "playlist" + ..collaborative = false + ..public = false + ..id = "user-liked-tracks" + ..images = [ + Image() + ..height = 300 + ..width = 300 + ..url = "assets/liked-tracks.jpg" + ], + [context.l10n], + ); final playlists = useMemoized( () { diff --git a/lib/components/shared/tracks_view/sections/header/flexible_header.dart b/lib/components/shared/tracks_view/sections/header/flexible_header.dart index e16ccbff..19241dc6 100644 --- a/lib/components/shared/tracks_view/sections/header/flexible_header.dart +++ b/lib/components/shared/tracks_view/sections/header/flexible_header.dart @@ -1,6 +1,5 @@ import 'dart:ui'; -import 'package:cached_network_image/cached_network_image.dart'; import 'package:flutter/material.dart'; import 'package:flutter_desktop_tools/flutter_desktop_tools.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; @@ -62,7 +61,7 @@ class TrackViewFlexHeader extends HookConsumerWidget { clipBehavior: Clip.hardEdge, decoration: BoxDecoration( image: DecorationImage( - image: CachedNetworkImageProvider(props.image), + image: UniversalImage.imageProvider(props.image), fit: BoxFit.cover, ), ), diff --git a/lib/pages/playlist/liked_playlist.dart b/lib/pages/playlist/liked_playlist.dart index 5972a303..1fb2e1dc 100644 --- a/lib/pages/playlist/liked_playlist.dart +++ b/lib/pages/playlist/liked_playlist.dart @@ -4,7 +4,6 @@ import 'package:spotify/spotify.dart'; import 'package:spotube/components/shared/tracks_view/track_view.dart'; import 'package:spotube/components/shared/tracks_view/track_view_props.dart'; import 'package:spotube/services/queries/queries.dart'; -import 'package:spotube/utils/type_conversion_utils.dart'; class LikedPlaylistPage extends HookConsumerWidget { final PlaylistSimple playlist; @@ -20,10 +19,7 @@ class LikedPlaylistPage extends HookConsumerWidget { return InheritedTrackView( collectionId: playlist.id!, - image: TypeConversionUtils.image_X_UrlString( - playlist.images, - placeholder: ImagePlaceholder.collection, - ), + image: "assets/liked-tracks.jpg", pagination: PaginationProps( hasNextPage: false, isLoading: false, From 3d344bdcddb193e7faf4d292bc5a5286e858d5f6 Mon Sep 17 00:00:00 2001 From: MerkomassDev <70111455+MerkomassDev@users.noreply.github.com> Date: Thu, 11 Jan 2024 05:07:36 +0100 Subject: [PATCH 095/195] docs: Readme.md rephrasing (#914) * Rephrased README.md * Update README.md Put extra emphasis on the fact that Shows and Podcasts can ONLY be accessed with spotify premium * One line fix in README.md last change was unnecessary :) --- README.md | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index 2736d1f1..e637f6c6 100644 --- a/README.md +++ b/README.md @@ -2,10 +2,10 @@ Spotube Logo An open source, cross-platform Spotify client compatible across multiple platforms
    -utilizing Spotify's data API and YouTube (or Piped.video or JioSaavn) as an audio source,
    +utilizing Spotify's data API and YouTube, Piped.video or JioSaavn as an audio source,
    eliminating the need for Spotify Premium -Btw it's not another Electron app😉 +Btw it's not just another Electron app 😉
    Visit the website Discord Server @@ -26,7 +26,7 @@ Btw it's not another Electron app😉 ## 🌃 Features - 🚫 No ads, thanks to the use of public & free Spotify and YT Music APIs¹ -- ⬇️ Downloadable tracks +- ⬇️ Freely downloadable tracks - 🖥️ 📱 Cross-platform support - 🪶 Small size & less data usage - 🕵️ Anonymous/guest login @@ -40,13 +40,13 @@ Btw it's not another Electron app😉 ### ❌ Unsupported features -- 🗣️ **Spotify Shows & Podcasts:** Shows and Podcasts can **never be supported** because the audio tracks are _only_ available on Spotify and accessing them would require Spotify Premium. +- 🗣️ **Spotify Shows & Podcasts:** Shows and Podcasts will **never be supported** because the audio tracks are _only_ available on Spotify and accessing them would require Spotify Premium. - 🎧 **Spotify Listen Along:** [Coming soon!](https://github.com/KRTirtho/spotube/issues/8) ## 📜 ⬇️ Installation guide -New releases usually appear after 3-4 months.
    -This handy table lists all methods you can use to install Spotube: +New versions usually release every 3-4 months.
    +This handy table lists all the methods you can use to install Spotube: From 72ed3ce2d17d81cb4c373a35d200124ddd903d62 Mon Sep 17 00:00:00 2001 From: Taha Ghadirian Date: Mon, 22 Jan 2024 06:31:51 +0330 Subject: [PATCH 096/195] actions: Add Up for grab checkbox to issue templates. (#1074) --- .github/ISSUE_TEMPLATE/bug_report.yml | 7 +++++++ .github/ISSUE_TEMPLATE/new_feature.yml | 9 ++++++++- 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/.github/ISSUE_TEMPLATE/bug_report.yml b/.github/ISSUE_TEMPLATE/bug_report.yml index e0031d17..64ee89d2 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.yml +++ b/.github/ISSUE_TEMPLATE/bug_report.yml @@ -71,3 +71,10 @@ body: description: Anything else you'd like to include? validations: required: false + - type: checkboxes + attributes: + label: Self grab + description: If you are a developer and want to work on this issue yourself, you can check this box and wait for maintainer response. We welcome contributions! + options: + - label: I'm ready to work on this issue! + required: false \ No newline at end of file diff --git a/.github/ISSUE_TEMPLATE/new_feature.yml b/.github/ISSUE_TEMPLATE/new_feature.yml index 9742f91f..7f02ea38 100644 --- a/.github/ISSUE_TEMPLATE/new_feature.yml +++ b/.github/ISSUE_TEMPLATE/new_feature.yml @@ -35,4 +35,11 @@ body: label: Additional information description: Anything else you'd like to include? validations: - required: false \ No newline at end of file + required: false + - type: checkboxes + attributes: + label: Self grab + description: If you are a developer and want to work on this issue yourself, you can check this box and wait for maintainer response. We welcome contributions! + options: + - label: I'm ready to work on this issue! + required: false \ No newline at end of file From db0e4cada61d0442a8851c95e17c17e99651daa7 Mon Sep 17 00:00:00 2001 From: Muhammad Jawad <70428284+m-Jawa-d@users.noreply.github.com> Date: Mon, 22 Jan 2024 14:10:33 +0500 Subject: [PATCH 097/195] docs: update copyright year in README.md (#1100) year changed from 2023 to 2024 --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 2736d1f1..d009fd92 100644 --- a/README.md +++ b/README.md @@ -304,4 +304,4 @@ If you are concerned, you can [read the reason of choosing this license](https:/ 1. [dart_discord_rpc](https://github.com/alexmercerind/dart_discord_rpc) - Discord Rich Presence for Flutter & Dart apps & games. -

    © Copyright Spotube 2023

    +

    © Copyright Spotube 2024

    From 27057ea0c8d83c9701057c18b473f1af4e4e82be Mon Sep 17 00:00:00 2001 From: Kingkor Roy Tirtho Date: Mon, 22 Jan 2024 17:20:30 +0600 Subject: [PATCH 098/195] fix(macos): system tray shows name and sidebar weird gap #1083 --- .vscode/launch.json | 6 + lib/collections/assets.gen.dart | 3 + lib/components/root/sidebar.dart | 2 +- .../configurators/use_init_sys_tray.dart | 2 +- macos/Podfile | 2 +- macos/Podfile.lock | 135 ++++++++++++------ macos/Runner.xcodeproj/project.pbxproj | 17 +-- .../xcshareddata/xcschemes/Runner.xcscheme | 2 +- 8 files changed, 112 insertions(+), 57 deletions(-) diff --git a/.vscode/launch.json b/.vscode/launch.json index 9add0735..7a1e8b9b 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -6,6 +6,12 @@ "type": "dart", "request": "launch", "program": "lib/main.dart", + }, + { + "name": "spotube (mobile)", + "type": "dart", + "request": "launch", + "program": "lib/main.dart", "args": [ "--flavor", "dev" diff --git a/lib/collections/assets.gen.dart b/lib/collections/assets.gen.dart index ac39cf68..d7149834 100644 --- a/lib/collections/assets.gen.dart +++ b/lib/collections/assets.gen.dart @@ -34,6 +34,8 @@ class Assets { AssetGenImage('assets/bengali-patterns-bg.jpg'); static const AssetGenImage branding = AssetGenImage('assets/branding.png'); static const AssetGenImage emptyBox = AssetGenImage('assets/empty_box.png'); + static const AssetGenImage likedTracks = + AssetGenImage('assets/liked-tracks.jpg'); static const AssetGenImage placeholder = AssetGenImage('assets/placeholder.png'); static const AssetGenImage spotubeHeroBanner = @@ -74,6 +76,7 @@ class Assets { bengaliPatternsBg, branding, emptyBox, + likedTracks, placeholder, spotubeHeroBanner, spotubeLogoForeground, diff --git a/lib/components/root/sidebar.dart b/lib/components/root/sidebar.dart index ac5233ed..9b3fd3ed 100644 --- a/lib/components/root/sidebar.dart +++ b/lib/components/root/sidebar.dart @@ -159,7 +159,7 @@ class Sidebar extends HookConsumerWidget { margin: EdgeInsets.only( bottom: 10, left: 0, - top: kIsMacOS ? 35 : 5, + top: kIsMacOS ? 0 : 5, ), padding: const EdgeInsets.symmetric(horizontal: 6), decoration: BoxDecoration( diff --git a/lib/hooks/configurators/use_init_sys_tray.dart b/lib/hooks/configurators/use_init_sys_tray.dart index db4964ce..8080bea6 100644 --- a/lib/hooks/configurators/use_init_sys_tray.dart +++ b/lib/hooks/configurators/use_init_sys_tray.dart @@ -25,7 +25,7 @@ void useInitSysTray(WidgetRef ref) { } final enabled = !playlist.isFetching; systemTray.value = await DesktopTools.createSystemTrayMenu( - title: DesktopTools.platform.isLinux ? "" : "Spotube", + title: DesktopTools.platform.isWindows ? "Spotube" : "", iconPath: "assets/spotube-logo.png", windowsIconPath: "assets/spotube-logo.ico", items: [ diff --git a/macos/Podfile b/macos/Podfile index fe733905..049abe29 100644 --- a/macos/Podfile +++ b/macos/Podfile @@ -1,4 +1,4 @@ -platform :osx, '10.13' +platform :osx, '10.14' # CocoaPods analytics sends network stats synchronously affecting flutter build latency. ENV['COCOAPODS_DISABLE_STATS'] = 'true' diff --git a/macos/Podfile.lock b/macos/Podfile.lock index 99c0177d..65fe3535 100644 --- a/macos/Podfile.lock +++ b/macos/Podfile.lock @@ -1,101 +1,146 @@ PODS: + - app_links (1.0.0): + - FlutterMacOS - audio_service (0.14.1): - FlutterMacOS - audio_session (0.0.1): - FlutterMacOS - - audioplayers_darwin (0.0.1): + - device_info_plus (0.0.1): - FlutterMacOS - - bitsdojo_window_macos (0.0.1): + - file_selector_macos (0.0.1): - FlutterMacOS - - connectivity_plus_macos (0.0.1): + - flutter_secure_storage_macos (6.1.1): - FlutterMacOS - - ReachabilitySwift - FlutterMacOS (1.0.0) - FMDB (2.7.5): - FMDB/standard (= 2.7.5) - FMDB/standard (2.7.5) - - macos_ui (0.1.0): + - local_notifier (0.1.0): - FlutterMacOS - - metadata_god (0.0.1): + - media_kit_libs_macos_audio (1.0.4): - FlutterMacOS - - package_info_plus_macos (0.0.1): + - media_kit_native_event_loop (1.0.0): - FlutterMacOS - - path_provider_macos (0.0.1): + - metadata_god (0.0.1) + - package_info_plus (0.0.1): - FlutterMacOS - - ReachabilitySwift (5.0.0) - - shared_preferences_macos (0.0.1): + - path_provider_foundation (0.0.1): + - Flutter + - FlutterMacOS + - screen_retriever (0.0.1): + - FlutterMacOS + - shared_preferences_foundation (0.0.1): + - Flutter - FlutterMacOS - sqflite (0.0.2): - FlutterMacOS - FMDB (>= 2.7.5) + - system_theme (0.0.1): + - FlutterMacOS + - system_tray (0.0.1): + - FlutterMacOS - url_launcher_macos (0.0.1): - FlutterMacOS + - window_manager (0.2.0): + - FlutterMacOS + - window_size (0.0.2): + - FlutterMacOS DEPENDENCIES: + - app_links (from `Flutter/ephemeral/.symlinks/plugins/app_links/macos`) - audio_service (from `Flutter/ephemeral/.symlinks/plugins/audio_service/macos`) - audio_session (from `Flutter/ephemeral/.symlinks/plugins/audio_session/macos`) - - audioplayers_darwin (from `Flutter/ephemeral/.symlinks/plugins/audioplayers_darwin/macos`) - - bitsdojo_window_macos (from `Flutter/ephemeral/.symlinks/plugins/bitsdojo_window_macos/macos`) - - connectivity_plus_macos (from `Flutter/ephemeral/.symlinks/plugins/connectivity_plus_macos/macos`) + - device_info_plus (from `Flutter/ephemeral/.symlinks/plugins/device_info_plus/macos`) + - file_selector_macos (from `Flutter/ephemeral/.symlinks/plugins/file_selector_macos/macos`) + - flutter_secure_storage_macos (from `Flutter/ephemeral/.symlinks/plugins/flutter_secure_storage_macos/macos`) - FlutterMacOS (from `Flutter/ephemeral`) - - macos_ui (from `Flutter/ephemeral/.symlinks/plugins/macos_ui/macos`) + - local_notifier (from `Flutter/ephemeral/.symlinks/plugins/local_notifier/macos`) + - media_kit_libs_macos_audio (from `Flutter/ephemeral/.symlinks/plugins/media_kit_libs_macos_audio/macos`) + - media_kit_native_event_loop (from `Flutter/ephemeral/.symlinks/plugins/media_kit_native_event_loop/macos`) - metadata_god (from `Flutter/ephemeral/.symlinks/plugins/metadata_god/macos`) - - package_info_plus_macos (from `Flutter/ephemeral/.symlinks/plugins/package_info_plus_macos/macos`) - - path_provider_macos (from `Flutter/ephemeral/.symlinks/plugins/path_provider_macos/macos`) - - shared_preferences_macos (from `Flutter/ephemeral/.symlinks/plugins/shared_preferences_macos/macos`) + - package_info_plus (from `Flutter/ephemeral/.symlinks/plugins/package_info_plus/macos`) + - path_provider_foundation (from `Flutter/ephemeral/.symlinks/plugins/path_provider_foundation/darwin`) + - screen_retriever (from `Flutter/ephemeral/.symlinks/plugins/screen_retriever/macos`) + - shared_preferences_foundation (from `Flutter/ephemeral/.symlinks/plugins/shared_preferences_foundation/darwin`) - sqflite (from `Flutter/ephemeral/.symlinks/plugins/sqflite/macos`) + - system_theme (from `Flutter/ephemeral/.symlinks/plugins/system_theme/macos`) + - system_tray (from `Flutter/ephemeral/.symlinks/plugins/system_tray/macos`) - url_launcher_macos (from `Flutter/ephemeral/.symlinks/plugins/url_launcher_macos/macos`) + - window_manager (from `Flutter/ephemeral/.symlinks/plugins/window_manager/macos`) + - window_size (from `Flutter/ephemeral/.symlinks/plugins/window_size/macos`) SPEC REPOS: trunk: - FMDB - - ReachabilitySwift EXTERNAL SOURCES: + app_links: + :path: Flutter/ephemeral/.symlinks/plugins/app_links/macos audio_service: :path: Flutter/ephemeral/.symlinks/plugins/audio_service/macos audio_session: :path: Flutter/ephemeral/.symlinks/plugins/audio_session/macos - audioplayers_darwin: - :path: Flutter/ephemeral/.symlinks/plugins/audioplayers_darwin/macos - bitsdojo_window_macos: - :path: Flutter/ephemeral/.symlinks/plugins/bitsdojo_window_macos/macos - connectivity_plus_macos: - :path: Flutter/ephemeral/.symlinks/plugins/connectivity_plus_macos/macos + device_info_plus: + :path: Flutter/ephemeral/.symlinks/plugins/device_info_plus/macos + file_selector_macos: + :path: Flutter/ephemeral/.symlinks/plugins/file_selector_macos/macos + flutter_secure_storage_macos: + :path: Flutter/ephemeral/.symlinks/plugins/flutter_secure_storage_macos/macos FlutterMacOS: :path: Flutter/ephemeral - macos_ui: - :path: Flutter/ephemeral/.symlinks/plugins/macos_ui/macos + local_notifier: + :path: Flutter/ephemeral/.symlinks/plugins/local_notifier/macos + media_kit_libs_macos_audio: + :path: Flutter/ephemeral/.symlinks/plugins/media_kit_libs_macos_audio/macos + media_kit_native_event_loop: + :path: Flutter/ephemeral/.symlinks/plugins/media_kit_native_event_loop/macos metadata_god: :path: Flutter/ephemeral/.symlinks/plugins/metadata_god/macos - package_info_plus_macos: - :path: Flutter/ephemeral/.symlinks/plugins/package_info_plus_macos/macos - path_provider_macos: - :path: Flutter/ephemeral/.symlinks/plugins/path_provider_macos/macos - shared_preferences_macos: - :path: Flutter/ephemeral/.symlinks/plugins/shared_preferences_macos/macos + package_info_plus: + :path: Flutter/ephemeral/.symlinks/plugins/package_info_plus/macos + path_provider_foundation: + :path: Flutter/ephemeral/.symlinks/plugins/path_provider_foundation/darwin + screen_retriever: + :path: Flutter/ephemeral/.symlinks/plugins/screen_retriever/macos + shared_preferences_foundation: + :path: Flutter/ephemeral/.symlinks/plugins/shared_preferences_foundation/darwin sqflite: :path: Flutter/ephemeral/.symlinks/plugins/sqflite/macos + system_theme: + :path: Flutter/ephemeral/.symlinks/plugins/system_theme/macos + system_tray: + :path: Flutter/ephemeral/.symlinks/plugins/system_tray/macos url_launcher_macos: :path: Flutter/ephemeral/.symlinks/plugins/url_launcher_macos/macos + window_manager: + :path: Flutter/ephemeral/.symlinks/plugins/window_manager/macos + window_size: + :path: Flutter/ephemeral/.symlinks/plugins/window_size/macos SPEC CHECKSUMS: + app_links: 4481ed4d71f384b0c3ae5016f4633aa73d32ff67 audio_service: b88ff778e0e3915efd4cd1a5ad6f0beef0c950a9 audio_session: dea1f41890dbf1718f04a56f1d6150fd50039b72 - audioplayers_darwin: dcad41de4fbd0099cb3749f7ab3b0cb8f70b810c - bitsdojo_window_macos: 44e3b8fe3dd463820e0321f6256c5b1c16bb6a00 - connectivity_plus_macos: f6e86fd000e971d361e54b5afcadc8c8fa773308 - FlutterMacOS: ae6af50a8ea7d6103d888583d46bd8328a7e9811 + device_info_plus: 5401765fde0b8d062a2f8eb65510fb17e77cf07f + file_selector_macos: 468fb6b81fac7c0e88d71317f3eec34c3b008ff9 + flutter_secure_storage_macos: d56e2d218c1130b262bef8b4a7d64f88d7f9c9ea + FlutterMacOS: 8f6f14fa908a6fb3fba0cd85dbd81ec4b251fb24 FMDB: 2ce00b547f966261cd18927a3ddb07cb6f3db82a - macos_ui: 125c911559d646194386d84c017ad6819122e2db - metadata_god: 55a71136c95eb75ec28142f6fbfc2bcff6f881b1 - package_info_plus_macos: f010621b07802a241d96d01876d6705f15e77c1c - path_provider_macos: 3c0c3b4b0d4a76d2bf989a913c2de869c5641a19 - ReachabilitySwift: 985039c6f7b23a1da463388634119492ff86c825 - shared_preferences_macos: a64dc611287ed6cbe28fd1297898db1336975727 + local_notifier: e9506bc66fc70311e8bc7291fb70f743c081e4ff + media_kit_libs_macos_audio: 3871782a4f3f84c77f04d7666c87800a781c24da + media_kit_native_event_loop: 7321675377cb9ae8596a29bddf3a3d2b5e8792c5 + metadata_god: eceae399d0020475069a5cebc35943ce8562b5d7 + package_info_plus: 02d7a575e80f194102bef286361c6c326e4c29ce + path_provider_foundation: 29f094ae23ebbca9d3d0cec13889cd9060c0e943 + screen_retriever: 59634572a57080243dd1bf715e55b6c54f241a38 + shared_preferences_foundation: 5b919d13b803cadd15ed2dc053125c68730e5126 sqflite: a5789cceda41d54d23f31d6de539d65bb14100ea - url_launcher_macos: 597e05b8e514239626bcf4a850fcf9ef5c856ec3 + system_theme: c7b9f6659a5caa26c9bc2284da096781e9a6fcbc + system_tray: e53c972838c69589ff2e77d6d3abfd71332f9e5d + url_launcher_macos: d2691c7dd33ed713bf3544850a623080ec693d95 + window_manager: 3a1844359a6295ab1e47659b1a777e36773cd6e8 + window_size: 339dafa0b27a95a62a843042038fa6c3c48de195 -PODFILE CHECKSUM: a884f6dd3f7494f3892ee6c81feea3a3abbf9153 +PODFILE CHECKSUM: 353c8bcc5d5b0994e508d035b5431cfe18c1dea7 -COCOAPODS: 1.11.3 +COCOAPODS: 1.14.3 diff --git a/macos/Runner.xcodeproj/project.pbxproj b/macos/Runner.xcodeproj/project.pbxproj index 9b86152a..f7711c83 100644 --- a/macos/Runner.xcodeproj/project.pbxproj +++ b/macos/Runner.xcodeproj/project.pbxproj @@ -3,7 +3,7 @@ archiveVersion = 1; classes = { }; - objectVersion = 51; + objectVersion = 54; objects = { /* Begin PBXAggregateTarget section */ @@ -208,7 +208,7 @@ isa = PBXProject; attributes = { LastSwiftUpdateCheck = 0920; - LastUpgradeCheck = 1300; + LastUpgradeCheck = 1430; ORGANIZATIONNAME = ""; TargetAttributes = { 33CC10EC2044A3C60003C045 = { @@ -261,6 +261,7 @@ /* Begin PBXShellScriptBuildPhase section */ 3399D490228B24CF009A79C7 /* ShellScript */ = { isa = PBXShellScriptBuildPhase; + alwaysOutOfDate = 1; buildActionMask = 2147483647; files = ( ); @@ -409,7 +410,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - MACOSX_DEPLOYMENT_TARGET = 10.13; + MACOSX_DEPLOYMENT_TARGET = 10.14; MTL_ENABLE_DEBUG_INFO = NO; SDKROOT = macosx; SWIFT_COMPILATION_MODE = wholemodule; @@ -431,7 +432,7 @@ "$(inherited)", "@executable_path/../Frameworks", ); - MACOSX_DEPLOYMENT_TARGET = 10.13; + MACOSX_DEPLOYMENT_TARGET = 10.14; PROVISIONING_PROFILE_SPECIFIER = ""; SWIFT_VERSION = 5.0; }; @@ -489,7 +490,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - MACOSX_DEPLOYMENT_TARGET = 10.13; + MACOSX_DEPLOYMENT_TARGET = 10.14; MTL_ENABLE_DEBUG_INFO = YES; ONLY_ACTIVE_ARCH = YES; SDKROOT = macosx; @@ -536,7 +537,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - MACOSX_DEPLOYMENT_TARGET = 10.13; + MACOSX_DEPLOYMENT_TARGET = 10.14; MTL_ENABLE_DEBUG_INFO = NO; SDKROOT = macosx; SWIFT_COMPILATION_MODE = wholemodule; @@ -558,7 +559,7 @@ "$(inherited)", "@executable_path/../Frameworks", ); - MACOSX_DEPLOYMENT_TARGET = 10.13; + MACOSX_DEPLOYMENT_TARGET = 10.14; PROVISIONING_PROFILE_SPECIFIER = ""; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; SWIFT_VERSION = 5.0; @@ -579,7 +580,7 @@ "$(inherited)", "@executable_path/../Frameworks", ); - MACOSX_DEPLOYMENT_TARGET = 10.13; + MACOSX_DEPLOYMENT_TARGET = 10.14; PROVISIONING_PROFILE_SPECIFIER = ""; SWIFT_VERSION = 5.0; }; diff --git a/macos/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme b/macos/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme index 741e68bc..8f69f0c6 100644 --- a/macos/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme +++ b/macos/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme @@ -1,6 +1,6 @@ Date: Mon, 22 Jan 2024 17:51:12 +0600 Subject: [PATCH 099/195] fix: artist page error #1018 --- .../spotify_endpoints.dart | 56 +++++++++++++++++++ lib/services/queries/artist.dart | 7 ++- 2 files changed, 61 insertions(+), 2 deletions(-) diff --git a/lib/services/custom_spotify_endpoints/spotify_endpoints.dart b/lib/services/custom_spotify_endpoints/spotify_endpoints.dart index 4a55130a..0510e69a 100644 --- a/lib/services/custom_spotify_endpoints/spotify_endpoints.dart +++ b/lib/services/custom_spotify_endpoints/spotify_endpoints.dart @@ -162,4 +162,60 @@ class CustomSpotifyEndpoints { result["tracks"].map((track) => Track.fromJson(track)).toList(), ); } + + Future artist({required String id}) async { + final pathQuery = "$_baseUrl/artists/$id"; + + final res = await _client.get( + Uri.parse(pathQuery), + headers: { + "content-type": "application/json", + if (accessToken.isNotEmpty) "authorization": "Bearer $accessToken", + "accept": "application/json", + }, + ); + + final data = jsonDecode(res.body); + + return Artist.fromJson(_purifyArtistResponse(data)); + } + + Future> relatedArtists({required String id}) async { + final pathQuery = "$_baseUrl/artists/$id/related-artists"; + + final res = await _client.get( + Uri.parse(pathQuery), + headers: { + "content-type": "application/json", + if (accessToken.isNotEmpty) "authorization": "Bearer $accessToken", + "accept": "application/json", + }, + ); + + final data = jsonDecode(res.body); + + return List.castFrom( + data["artists"] + .map((artist) => Artist.fromJson(_purifyArtistResponse(artist))) + .toList(), + ); + } + + Map _purifyArtistResponse(Map data) { + if (data["popularity"] != null) { + data["popularity"] = data["popularity"].toInt(); + } + if (data["followers"]?["total"] != null) { + data["followers"]["total"] = data["followers"]["total"].toInt(); + } + if (data["images"] != null) { + data["images"] = data["images"].map((e) { + e["height"] = e["height"].toInt(); + e["width"] = e["width"].toInt(); + return e; + }).toList(); + } + + return data; + } } diff --git a/lib/services/queries/artist.dart b/lib/services/queries/artist.dart index 1b939c82..5ccc4955 100644 --- a/lib/services/queries/artist.dart +++ b/lib/services/queries/artist.dart @@ -4,6 +4,7 @@ import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:spotify/spotify.dart'; import 'package:spotube/hooks/spotify/use_spotify_infinite_query.dart'; import 'package:spotube/hooks/spotify/use_spotify_query.dart'; +import 'package:spotube/provider/custom_spotify_endpoint_provider.dart'; import 'package:spotube/provider/user_preferences/user_preferences_provider.dart'; import 'package:spotube/services/wikipedia/wikipedia.dart'; import 'package:wikipedia_api/wikipedia_api.dart'; @@ -15,9 +16,10 @@ class ArtistQueries { WidgetRef ref, String artist, ) { + final customSpotify = ref.watch(customSpotifyEndpointProvider); return useSpotifyQuery( "artist-profile/$artist", - (spotify) => spotify.artists.get(artist), + (spotify) => customSpotify.artist(id: artist), ref: ref, ); } @@ -125,10 +127,11 @@ class ArtistQueries { WidgetRef ref, String artist, ) { + final customSpotify = ref.watch(customSpotifyEndpointProvider); return useSpotifyQuery, dynamic>( "artist-related-artist-query/$artist", (spotify) { - return spotify.artists.relatedArtists(artist); + return customSpotify.relatedArtists(id: artist); }, ref: ref, ); From 59e0e6bb659b70831f6e0ae064100381c57f149c Mon Sep 17 00:00:00 2001 From: Kingkor Roy Tirtho Date: Mon, 22 Jan 2024 18:03:08 +0600 Subject: [PATCH 100/195] fix: track pad horizontal scrolling not working --- .../horizontal_playbutton_card_view.dart | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/lib/components/shared/horizontal_playbutton_card_view/horizontal_playbutton_card_view.dart b/lib/components/shared/horizontal_playbutton_card_view/horizontal_playbutton_card_view.dart index 2075acbb..dc9d30da 100644 --- a/lib/components/shared/horizontal_playbutton_card_view/horizontal_playbutton_card_view.dart +++ b/lib/components/shared/horizontal_playbutton_card_view/horizontal_playbutton_card_view.dart @@ -60,10 +60,7 @@ class HorizontalPlaybuttonCardView extends HookWidget { onNotification: (notification) => true, child: ScrollConfiguration( behavior: ScrollConfiguration.of(context).copyWith( - dragDevices: { - PointerDeviceKind.touch, - PointerDeviceKind.mouse, - }, + dragDevices: PointerDeviceKind.values.toSet(), ), child: items.isEmpty ? ListView.builder( From a8e9b824f33add8f6a83f0d147e889eb6beeb442 Mon Sep 17 00:00:00 2001 From: Kingkor Roy Tirtho Date: Mon, 22 Jan 2024 19:02:10 +0600 Subject: [PATCH 101/195] fix: alternative searched sources doesn't play #1059 --- assets/jiosaavn.png | Bin 0 -> 14045 bytes lib/collections/assets.gen.dart | 2 + lib/collections/spotube_icons.dart | 1 + .../player/sibling_tracks_sheet.dart | 54 ++++++++++++++++-- lib/services/sourced_track/enums.dart | 2 +- .../sourced_track/sources/jiosaavn.dart | 25 ++++++-- lib/services/sourced_track/sources/piped.dart | 27 +++++++-- .../sourced_track/sources/youtube.dart | 27 +++++++-- 8 files changed, 117 insertions(+), 21 deletions(-) create mode 100644 assets/jiosaavn.png diff --git a/assets/jiosaavn.png b/assets/jiosaavn.png new file mode 100644 index 0000000000000000000000000000000000000000..4d2d46e4b079fa9d1a60ef10a3aab3dd96750b90 GIT binary patch literal 14045 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 literal 0 HcmV?d00001 diff --git a/lib/collections/assets.gen.dart b/lib/collections/assets.gen.dart index d7149834..2587800e 100644 --- a/lib/collections/assets.gen.dart +++ b/lib/collections/assets.gen.dart @@ -34,6 +34,7 @@ class Assets { AssetGenImage('assets/bengali-patterns-bg.jpg'); static const AssetGenImage branding = AssetGenImage('assets/branding.png'); static const AssetGenImage emptyBox = AssetGenImage('assets/empty_box.png'); + static const AssetGenImage jiosaavn = AssetGenImage('assets/jiosaavn.png'); static const AssetGenImage likedTracks = AssetGenImage('assets/liked-tracks.jpg'); static const AssetGenImage placeholder = @@ -76,6 +77,7 @@ class Assets { bengaliPatternsBg, branding, emptyBox, + jiosaavn, likedTracks, placeholder, spotubeHeroBanner, diff --git a/lib/collections/spotube_icons.dart b/lib/collections/spotube_icons.dart index 00010aae..c6acd669 100644 --- a/lib/collections/spotube_icons.dart +++ b/lib/collections/spotube_icons.dart @@ -109,4 +109,5 @@ abstract class SpotubeIcons { static const normalize = FeatherIcons.barChart2; static const wikipedia = SimpleIcons.wikipedia; static const discord = SimpleIcons.discord; + static const youtube = SimpleIcons.youtube; } diff --git a/lib/components/player/sibling_tracks_sheet.dart b/lib/components/player/sibling_tracks_sheet.dart index cf1429b9..181c363a 100644 --- a/lib/components/player/sibling_tracks_sheet.dart +++ b/lib/components/player/sibling_tracks_sheet.dart @@ -5,6 +5,7 @@ import 'package:flutter/material.dart'; import 'package:flutter_hooks/flutter_hooks.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:spotify/spotify.dart' hide Offset; +import 'package:spotube/collections/assets.gen.dart'; import 'package:spotube/collections/spotube_icons.dart'; import 'package:spotube/components/shared/image/universal_image.dart'; @@ -19,10 +20,28 @@ import 'package:spotube/provider/user_preferences/user_preferences_state.dart'; import 'package:spotube/services/sourced_track/models/source_info.dart'; import 'package:spotube/services/sourced_track/models/video_info.dart'; import 'package:spotube/services/sourced_track/sourced_track.dart'; +import 'package:spotube/services/sourced_track/sources/jiosaavn.dart'; +import 'package:spotube/services/sourced_track/sources/piped.dart'; import 'package:spotube/services/sourced_track/sources/youtube.dart'; import 'package:spotube/utils/service_utils.dart'; import 'package:spotube/utils/type_conversion_utils.dart'; +final sourceInfoToIconMap = { + YoutubeSourceInfo: const Icon(SpotubeIcons.youtube, color: Color(0xFFFF0000)), + JioSaavnSourceInfo: Container( + height: 30, + width: 30, + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(90), + image: DecorationImage( + image: Assets.jiosaavn.provider(), + fit: BoxFit.cover, + ), + ), + ), + PipedSourceInfo: const Icon(SpotubeIcons.piped), +}; + class SiblingTracksSheet extends HookConsumerWidget { final bool floating; const SiblingTracksSheet({ @@ -64,17 +83,34 @@ class SiblingTracksSheet extends HookConsumerWidget { return []; } - final results = await youtubeClient.search.search(searchTerm.trim()); + final resultsYt = await youtubeClient.search.search(searchTerm.trim()); + final resultsJioSaavn = + await jiosaavnClient.search.songs(searchTerm.trim()); - return await Future.wait( - results.map(YoutubeVideoInfo.fromVideo).mapIndexed((i, video) async { + final searchResults = await Future.wait([ + ...resultsJioSaavn.results.mapIndexed((i, song) async { + final siblingType = JioSaavnSourcedTrack.toSiblingType(song); + return siblingType.info; + }), + ...resultsYt + .map(YoutubeVideoInfo.fromVideo) + .mapIndexed((i, video) async { final siblingType = await YoutubeSourcedTrack.toSiblingType(i, video); return siblingType.info; }), - ); + ]); + final activeSourceInfo = + (playlist.activeTrack! as SourcedTrack).sourceInfo; + return searchResults + ..removeWhere((element) => element.id == activeSourceInfo.id) + ..insert( + 0, + activeSourceInfo, + ); }, [ searchTerm, searchMode.value, + playlist.activeTrack, ]); final siblings = useMemoized( @@ -104,6 +140,7 @@ class SiblingTracksSheet extends HookConsumerWidget { final itemBuilder = useCallback( (SourceInfo sourceInfo) { + final icon = sourceInfoToIconMap[sourceInfo.runtimeType]; return ListTile( title: Text(sourceInfo.title), leading: Padding( @@ -118,7 +155,12 @@ class SiblingTracksSheet extends HookConsumerWidget { borderRadius: BorderRadius.circular(5), ), trailing: Text(sourceInfo.duration.toHumanReadableString()), - subtitle: Text(sourceInfo.artist), + subtitle: Row( + children: [ + if (icon != null) icon, + Text(" • ${sourceInfo.artist}"), + ], + ), enabled: playlist.isFetching != true, selected: playlist.isFetching != true && sourceInfo.id == @@ -137,7 +179,7 @@ class SiblingTracksSheet extends HookConsumerWidget { [playlist.isFetching, playlist.activeTrack, siblings], ); - var mediaQuery = MediaQuery.of(context); + final mediaQuery = MediaQuery.of(context); return SafeArea( child: ClipRRect( borderRadius: borderRadius, diff --git a/lib/services/sourced_track/enums.dart b/lib/services/sourced_track/enums.dart index 48ce1cbd..e47ee6bd 100644 --- a/lib/services/sourced_track/enums.dart +++ b/lib/services/sourced_track/enums.dart @@ -15,4 +15,4 @@ enum SourceQualities { low, } -typedef SiblingType = ({SourceInfo info, SourceMap? source}); +typedef SiblingType = ({T info, SourceMap? source}); diff --git a/lib/services/sourced_track/sources/jiosaavn.dart b/lib/services/sourced_track/sources/jiosaavn.dart index a447b0c1..281be998 100644 --- a/lib/services/sourced_track/sources/jiosaavn.dart +++ b/lib/services/sourced_track/sources/jiosaavn.dart @@ -12,6 +12,19 @@ import 'package:spotube/extensions/string.dart'; final jiosaavnClient = JioSaavnClient(); +class JioSaavnSourceInfo extends SourceInfo { + JioSaavnSourceInfo({ + required super.id, + required super.title, + required super.artist, + required super.thumbnail, + required super.pageUrl, + required super.duration, + required super.artistUrl, + required super.album, + }); +} + class JioSaavnSourcedTrack extends SourcedTrack { JioSaavnSourcedTrack({ required super.ref, @@ -70,7 +83,7 @@ class JioSaavnSourcedTrack extends SourcedTrack { static SiblingType toSiblingType(SongResponse result) { final SiblingType sibling = ( - info: SourceInfo( + info: JioSaavnSourceInfo( artist: [ result.primaryArtists, if (result.featuredArtists.isNotEmpty) ", ", @@ -155,12 +168,16 @@ class JioSaavnSourcedTrack extends SourcedTrack { @override Future swapWithSibling(SourceInfo sibling) async { - if (sibling.id == sourceInfo.id || - siblings.none((s) => s.id == sibling.id)) { + if (sibling.id == sourceInfo.id) { return null; } - final newSourceInfo = siblings.firstWhere((s) => s.id == sibling.id); + // a sibling source that was fetched from the search results + final isStepSibling = siblings.none((s) => s.id == sibling.id); + + final newSourceInfo = isStepSibling + ? sibling + : siblings.firstWhere((s) => s.id == sibling.id); final newSiblings = siblings.where((s) => s.id != sibling.id).toList() ..insert(0, sourceInfo); diff --git a/lib/services/sourced_track/sources/piped.dart b/lib/services/sourced_track/sources/piped.dart index 0778a7cf..f9e4368d 100644 --- a/lib/services/sourced_track/sources/piped.dart +++ b/lib/services/sourced_track/sources/piped.dart @@ -22,6 +22,19 @@ final pipedProvider = Provider( }, ); +class PipedSourceInfo extends SourceInfo { + PipedSourceInfo({ + required super.id, + required super.title, + required super.artist, + required super.thumbnail, + required super.pageUrl, + required super.duration, + required super.artistUrl, + required super.album, + }); +} + class PipedSourcedTrack extends SourcedTrack { PipedSourcedTrack({ required super.ref, @@ -71,7 +84,7 @@ class PipedSourcedTrack extends SourcedTrack { ref: ref, siblings: [], source: toSourceMap(manifest), - sourceInfo: SourceInfo( + sourceInfo: PipedSourceInfo( id: manifest.id, artist: manifest.uploader, artistUrl: manifest.uploaderUrl, @@ -122,7 +135,7 @@ class PipedSourcedTrack extends SourcedTrack { } final SiblingType sibling = ( - info: SourceInfo( + info: PipedSourceInfo( id: item.id, artist: item.channelName, artistUrl: "https://www.youtube.com/${item.channelId}", @@ -233,12 +246,16 @@ class PipedSourcedTrack extends SourcedTrack { @override Future swapWithSibling(SourceInfo sibling) async { - if (sibling.id == sourceInfo.id || - siblings.none((s) => s.id == sibling.id)) { + if (sibling.id == sourceInfo.id) { return null; } - final newSourceInfo = siblings.firstWhere((s) => s.id == sibling.id); + // a sibling source that was fetched from the search results + final isStepSibling = siblings.none((s) => s.id == sibling.id); + + final newSourceInfo = isStepSibling + ? sibling + : siblings.firstWhere((s) => s.id == sibling.id); final newSiblings = siblings.where((s) => s.id != sibling.id).toList() ..insert(0, sourceInfo); diff --git a/lib/services/sourced_track/sources/youtube.dart b/lib/services/sourced_track/sources/youtube.dart index 2bcd6e3e..c4105d75 100644 --- a/lib/services/sourced_track/sources/youtube.dart +++ b/lib/services/sourced_track/sources/youtube.dart @@ -17,6 +17,19 @@ final officialMusicRegex = RegExp( caseSensitive: false, ); +class YoutubeSourceInfo extends SourceInfo { + YoutubeSourceInfo({ + required super.id, + required super.title, + required super.artist, + required super.thumbnail, + required super.pageUrl, + required super.duration, + required super.artistUrl, + required super.album, + }); +} + class YoutubeSourcedTrack extends SourcedTrack { YoutubeSourcedTrack({ required super.source, @@ -64,7 +77,7 @@ class YoutubeSourcedTrack extends SourcedTrack { ref: ref, siblings: [], source: toSourceMap(manifest), - sourceInfo: SourceInfo( + sourceInfo: YoutubeSourceInfo( id: item.id.value, artist: item.author, artistUrl: "https://www.youtube.com/channel/${item.channelId}", @@ -117,7 +130,7 @@ class YoutubeSourcedTrack extends SourcedTrack { } final SiblingType sibling = ( - info: SourceInfo( + info: YoutubeSourceInfo( id: item.id, artist: item.channelName, artistUrl: "https://www.youtube.com/channel/${item.channelId}", @@ -217,12 +230,16 @@ class YoutubeSourcedTrack extends SourcedTrack { @override Future swapWithSibling(SourceInfo sibling) async { - if (sibling.id == sourceInfo.id || - siblings.none((s) => s.id == sibling.id)) { + if (sibling.id == sourceInfo.id) { return null; } - final newSourceInfo = siblings.firstWhere((s) => s.id == sibling.id); + // a sibling source that was fetched from the search results + final isStepSibling = siblings.none((s) => s.id == sibling.id); + + final newSourceInfo = isStepSibling + ? sibling + : siblings.firstWhere((s) => s.id == sibling.id); final newSiblings = siblings.where((s) => s.id != sibling.id).toList() ..insert(0, sourceInfo); From 682e88e0c55bc0f4708bc0b4681b129e5c61c999 Mon Sep 17 00:00:00 2001 From: Kingkor Roy Tirtho Date: Mon, 22 Jan 2024 19:09:57 +0600 Subject: [PATCH 102/195] fix: releases section is empty when user doesn't follow any artists #1104 --- .../home/sections/new_releases.dart | 25 +++++++++++-------- 1 file changed, 15 insertions(+), 10 deletions(-) diff --git a/lib/components/home/sections/new_releases.dart b/lib/components/home/sections/new_releases.dart index 77481de1..0f4a046a 100644 --- a/lib/components/home/sections/new_releases.dart +++ b/lib/components/home/sections/new_releases.dart @@ -21,16 +21,21 @@ class HomeNewReleasesSection extends HookConsumerWidget { userArtistsQuery.data?.map((s) => s.id!).toList() ?? const []; final albums = useMemoized( - () => newReleases.pages - .whereType>() - .expand((page) => page.items ?? const []) - .where((album) { - return album.artists - ?.any((artist) => userArtists.contains(artist.id!)) == - true; - }) - .map((album) => TypeConversionUtils.simpleAlbum_X_Album(album)) - .toList(), + () { + final allReleases = newReleases.pages + .whereType>() + .expand((page) => page.items ?? const []) + .map((album) => TypeConversionUtils.simpleAlbum_X_Album(album)); + + final userArtistReleases = allReleases.where((album) { + return album.artists + ?.any((artist) => userArtists.contains(artist.id!)) == + true; + }).toList(); + + if (userArtistReleases.isEmpty) return allReleases.toList(); + return userArtistReleases; + }, [newReleases.pages], ); From 79839329b0970acccb0c566a31eee508adbc8557 Mon Sep 17 00:00:00 2001 From: Kingkor Roy Tirtho Date: Tue, 23 Jan 2024 22:44:00 +0600 Subject: [PATCH 103/195] feat: add spotify friends activity (#1130) * feat: add spotify friend endpoint * feat: add friend activity in home screen * fix: when no friends, dummy UI still shows giving the user a false hope of friendship :'( --- lib/collections/fake.dart | 32 +++++ lib/components/home/sections/friends.dart | 95 ++++++++++++ .../home/sections/friends/friend_item.dart | 136 ++++++++++++++++++ .../shared/page_window_title_bar.dart | 4 +- lib/l10n/app_en.arb | 3 +- lib/main.dart | 4 +- lib/models/spotify_friends.dart | 111 ++++++++++++++ lib/models/spotify_friends.g.dart | 65 +++++++++ lib/pages/home/home.dart | 2 + .../spotify_endpoints.dart | 14 +- lib/services/queries/user.dart | 13 ++ untranslated_messages.json | 51 ++++--- 12 files changed, 507 insertions(+), 23 deletions(-) create mode 100644 lib/components/home/sections/friends.dart create mode 100644 lib/components/home/sections/friends/friend_item.dart create mode 100644 lib/models/spotify_friends.dart create mode 100644 lib/models/spotify_friends.g.dart diff --git a/lib/collections/fake.dart b/lib/collections/fake.dart index 10cf2819..8f5f9e8b 100644 --- a/lib/collections/fake.dart +++ b/lib/collections/fake.dart @@ -1,5 +1,6 @@ import 'package:spotify/spotify.dart'; import 'package:spotube/extensions/track.dart'; +import 'package:spotube/models/spotify_friends.dart'; abstract class FakeData { static final Image image = Image() @@ -164,4 +165,35 @@ abstract class FakeData { ..icons = [image] ..id = "1" ..name = "category"; + + static final friends = SpotifyFriends( + friends: [ + for (var i = 0; i < 3; i++) + SpotifyFriendActivity( + user: const SpotifyFriend( + name: "name", + imageUrl: "imageUrl", + uri: "uri", + ), + track: SpotifyActivityTrack( + name: "name", + artist: const SpotifyActivityArtist( + name: "name", + uri: "uri", + ), + album: const SpotifyActivityAlbum( + name: "name", + uri: "uri", + ), + context: SpotifyActivityContext( + name: "name", + index: i, + uri: "uri", + ), + imageUrl: "imageUrl", + uri: "uri", + ), + ), + ], + ); } diff --git a/lib/components/home/sections/friends.dart b/lib/components/home/sections/friends.dart new file mode 100644 index 00000000..ef24b8d5 --- /dev/null +++ b/lib/components/home/sections/friends.dart @@ -0,0 +1,95 @@ +import 'package:flutter/material.dart'; +import 'package:hooks_riverpod/hooks_riverpod.dart'; +import 'package:skeletonizer/skeletonizer.dart'; +import 'package:spotube/collections/fake.dart'; +import 'package:spotube/components/home/sections/friends/friend_item.dart'; +import 'package:spotube/hooks/utils/use_breakpoint_value.dart'; +import 'package:spotube/models/spotify_friends.dart'; +import 'package:spotube/services/queries/queries.dart'; + +class HomePageFriendsSection extends HookConsumerWidget { + const HomePageFriendsSection({Key? key}) : super(key: key); + + @override + Widget build(BuildContext context, ref) { + final friendsQuery = useQueries.user.friendActivity(ref); + final friends = friendsQuery.data?.friends ?? FakeData.friends.friends; + + final groupCount = useBreakpointValue( + sm: 3, + xs: 2, + md: 4, + lg: 5, + xl: 6, + xxl: 7, + ); + + final friendGroup = friends.fold>>( + [], + (previousValue, element) { + if (previousValue.isEmpty) { + return [ + [element] + ]; + } + + final lastGroup = previousValue.last; + if (lastGroup.length < groupCount) { + return [ + ...previousValue.sublist(0, previousValue.length - 1), + [...lastGroup, element] + ]; + } + + return [ + ...previousValue, + [element] + ]; + }, + ); + + if (!friendsQuery.isLoading && + (!friendsQuery.hasData || friendsQuery.data!.friends.isEmpty)) { + return const SliverToBoxAdapter( + child: SizedBox.shrink(), + ); + } + + return Skeletonizer.sliver( + enabled: friendsQuery.isLoading, + child: SliverMainAxisGroup( + slivers: [ + SliverToBoxAdapter( + child: Padding( + padding: const EdgeInsets.all(8.0), + child: Text( + 'Friends', + style: Theme.of(context).textTheme.titleMedium, + ), + ), + ), + SliverToBoxAdapter( + child: SingleChildScrollView( + scrollDirection: Axis.horizontal, + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + for (final group in friendGroup) + Row( + children: [ + for (final friend in group) + Padding( + padding: const EdgeInsets.all(8.0), + child: FriendItem(friend: friend), + ), + ], + ), + ], + ), + ), + ), + ], + ), + ); + } +} diff --git a/lib/components/home/sections/friends/friend_item.dart b/lib/components/home/sections/friends/friend_item.dart new file mode 100644 index 00000000..fcdadab7 --- /dev/null +++ b/lib/components/home/sections/friends/friend_item.dart @@ -0,0 +1,136 @@ +import 'package:fl_query_hooks/fl_query_hooks.dart'; +import 'package:flutter/gestures.dart'; +import 'package:flutter/material.dart'; +import 'package:gap/gap.dart'; +import 'package:go_router/go_router.dart'; +import 'package:hooks_riverpod/hooks_riverpod.dart'; +import 'package:spotify/spotify.dart'; +import 'package:spotube/collections/spotube_icons.dart'; +import 'package:spotube/components/shared/image/universal_image.dart'; +import 'package:spotube/models/spotify_friends.dart'; +import 'package:spotube/provider/spotify_provider.dart'; + +class FriendItem extends HookConsumerWidget { + final SpotifyFriendActivity friend; + const FriendItem({ + Key? key, + required this.friend, + }) : super(key: key); + + @override + Widget build(BuildContext context, ref) { + final ThemeData( + textTheme: textTheme, + colorScheme: colorScheme, + ) = Theme.of(context); + + final queryClient = useQueryClient(); + final spotify = ref.watch(spotifyProvider); + + return Container( + padding: const EdgeInsets.all(8), + decoration: BoxDecoration( + color: colorScheme.surfaceVariant.withOpacity(0.3), + borderRadius: BorderRadius.circular(15), + ), + constraints: const BoxConstraints( + minWidth: 300, + ), + height: 80, + child: Row( + children: [ + CircleAvatar( + backgroundImage: UniversalImage.imageProvider( + friend.user.imageUrl, + ), + ), + const Gap(8), + Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + friend.user.name, + style: textTheme.bodyLarge, + ), + RichText( + text: TextSpan( + style: textTheme.bodySmall, + children: [ + TextSpan( + text: friend.track.name, + recognizer: TapGestureRecognizer() + ..onTap = () { + context.push("/track/${friend.track.id}"); + }, + ), + const TextSpan(text: " • "), + const WidgetSpan( + child: Icon( + SpotubeIcons.artist, + size: 12, + ), + ), + TextSpan( + text: " ${friend.track.artist.name}", + recognizer: TapGestureRecognizer() + ..onTap = () { + context.push( + "/artist/${friend.track.artist.id}", + ); + }, + ), + const TextSpan(text: "\n"), + TextSpan( + text: friend.track.context.name, + recognizer: TapGestureRecognizer() + ..onTap = () async { + context.push( + "/${friend.track.context.path}", + extra: !friend.track.context.path + .startsWith("album") + ? null + : await queryClient.fetchQuery( + "album/${friend.track.album.id}", + () => spotify.albums.get( + friend.track.album.id, + ), + ), + ); + }, + ), + const TextSpan(text: " • "), + const WidgetSpan( + child: Icon( + SpotubeIcons.album, + size: 12, + ), + ), + TextSpan( + text: " ${friend.track.album.name}", + recognizer: TapGestureRecognizer() + ..onTap = () async { + final album = + await queryClient.fetchQuery( + "album/${friend.track.album.id}", + () => spotify.albums.get( + friend.track.album.id, + ), + ); + if (context.mounted) { + context.push( + "/album/${friend.track.album.id}", + extra: album, + ); + } + }, + ), + ], + ), + ), + ], + ), + ], + ), + ); + } +} diff --git a/lib/components/shared/page_window_title_bar.dart b/lib/components/shared/page_window_title_bar.dart index d8e20184..4f522e0c 100644 --- a/lib/components/shared/page_window_title_bar.dart +++ b/lib/components/shared/page_window_title_bar.dart @@ -2,14 +2,12 @@ import 'package:flutter/material.dart'; import 'package:flutter_hooks/flutter_hooks.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:spotube/provider/user_preferences/user_preferences_provider.dart'; -import 'package:spotube/provider/user_preferences/user_preferences_state.dart'; import 'package:spotube/utils/platform.dart'; import 'package:titlebar_buttons/titlebar_buttons.dart'; import 'dart:math'; import 'package:flutter/foundation.dart' show kIsWeb; -import 'dart:io' show Platform, exit; +import 'dart:io' show Platform; import 'package:flutter_desktop_tools/flutter_desktop_tools.dart'; -import 'package:local_notifier/local_notifier.dart'; class PageWindowTitleBar extends StatefulHookConsumerWidget implements PreferredSizeWidget { diff --git a/lib/l10n/app_en.arb b/lib/l10n/app_en.arb index 82877ea1..6b61cbae 100644 --- a/lib/l10n/app_en.arb +++ b/lib/l10n/app_en.arb @@ -284,5 +284,6 @@ "discord_rich_presence": "Discord Rich Presence", "browse_all": "Browse All", "genres": "Genres", - "explore_genres": "Explore Genres" + "explore_genres": "Explore Genres", + "friends": "Friends" } \ No newline at end of file diff --git a/lib/main.dart b/lib/main.dart index f96920a1..b6afa85c 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -228,7 +228,9 @@ class SpotubeState extends ConsumerState { builder: (context, child) { return DevicePreview.appBuilder( context, - DragToResizeArea(child: child!), + DesktopTools.platform.isDesktop + ? DragToResizeArea(child: child!) + : child, ); }, themeMode: themeMode, diff --git a/lib/models/spotify_friends.dart b/lib/models/spotify_friends.dart new file mode 100644 index 00000000..b386fb81 --- /dev/null +++ b/lib/models/spotify_friends.dart @@ -0,0 +1,111 @@ +import 'package:json_annotation/json_annotation.dart'; + +part 'spotify_friends.g.dart'; + +@JsonSerializable(createToJson: false) +class SpotifyFriend { + final String uri; + final String name; + final String imageUrl; + + const SpotifyFriend({ + required this.uri, + required this.name, + required this.imageUrl, + }); + + factory SpotifyFriend.fromJson(Map json) => + _$SpotifyFriendFromJson(json); + + String get id => uri.split(":").last; +} + +@JsonSerializable(createToJson: false) +class SpotifyActivityArtist { + final String uri; + final String name; + + const SpotifyActivityArtist({required this.uri, required this.name}); + + factory SpotifyActivityArtist.fromJson(Map json) => + _$SpotifyActivityArtistFromJson(json); + + String get id => uri.split(":").last; +} + +@JsonSerializable(createToJson: false) +class SpotifyActivityAlbum { + final String uri; + final String name; + + const SpotifyActivityAlbum({required this.uri, required this.name}); + + factory SpotifyActivityAlbum.fromJson(Map json) => + _$SpotifyActivityAlbumFromJson(json); + + String get id => uri.split(":").last; +} + +@JsonSerializable(createToJson: false) +class SpotifyActivityContext { + final String uri; + final String name; + final num index; + + const SpotifyActivityContext({ + required this.uri, + required this.name, + required this.index, + }); + + factory SpotifyActivityContext.fromJson(Map json) => + _$SpotifyActivityContextFromJson(json); + + String get id => uri.split(":").last; + String get path => uri.split(":").skip(1).join("/"); +} + +@JsonSerializable(createToJson: false) +class SpotifyActivityTrack { + final String uri; + final String name; + final String imageUrl; + final SpotifyActivityArtist artist; + final SpotifyActivityAlbum album; + final SpotifyActivityContext context; + + const SpotifyActivityTrack({ + required this.uri, + required this.name, + required this.imageUrl, + required this.artist, + required this.album, + required this.context, + }); + + factory SpotifyActivityTrack.fromJson(Map json) => + _$SpotifyActivityTrackFromJson(json); + + String get id => uri.split(":").last; +} + +@JsonSerializable(createToJson: false) +class SpotifyFriendActivity { + SpotifyFriend user; + SpotifyActivityTrack track; + + SpotifyFriendActivity({required this.user, required this.track}); + + factory SpotifyFriendActivity.fromJson(Map json) => + _$SpotifyFriendActivityFromJson(json); +} + +@JsonSerializable(createToJson: false) +class SpotifyFriends { + List friends; + + SpotifyFriends({required this.friends}); + + factory SpotifyFriends.fromJson(Map json) => + _$SpotifyFriendsFromJson(json); +} diff --git a/lib/models/spotify_friends.g.dart b/lib/models/spotify_friends.g.dart new file mode 100644 index 00000000..4a32dd09 --- /dev/null +++ b/lib/models/spotify_friends.g.dart @@ -0,0 +1,65 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +part of 'spotify_friends.dart'; + +// ************************************************************************** +// JsonSerializableGenerator +// ************************************************************************** + +SpotifyFriend _$SpotifyFriendFromJson(Map json) => + SpotifyFriend( + uri: json['uri'] as String, + name: json['name'] as String, + imageUrl: json['imageUrl'] as String, + ); + +SpotifyActivityArtist _$SpotifyActivityArtistFromJson( + Map json) => + SpotifyActivityArtist( + uri: json['uri'] as String, + name: json['name'] as String, + ); + +SpotifyActivityAlbum _$SpotifyActivityAlbumFromJson( + Map json) => + SpotifyActivityAlbum( + uri: json['uri'] as String, + name: json['name'] as String, + ); + +SpotifyActivityContext _$SpotifyActivityContextFromJson( + Map json) => + SpotifyActivityContext( + uri: json['uri'] as String, + name: json['name'] as String, + index: json['index'] as num, + ); + +SpotifyActivityTrack _$SpotifyActivityTrackFromJson( + Map json) => + SpotifyActivityTrack( + uri: json['uri'] as String, + name: json['name'] as String, + imageUrl: json['imageUrl'] as String, + artist: SpotifyActivityArtist.fromJson( + json['artist'] as Map), + album: + SpotifyActivityAlbum.fromJson(json['album'] as Map), + context: SpotifyActivityContext.fromJson( + json['context'] as Map), + ); + +SpotifyFriendActivity _$SpotifyFriendActivityFromJson( + Map json) => + SpotifyFriendActivity( + user: SpotifyFriend.fromJson(json['user'] as Map), + track: + SpotifyActivityTrack.fromJson(json['track'] as Map), + ); + +SpotifyFriends _$SpotifyFriendsFromJson(Map json) => + SpotifyFriends( + friends: (json['friends'] as List) + .map((e) => SpotifyFriendActivity.fromJson(e as Map)) + .toList(), + ); diff --git a/lib/pages/home/home.dart b/lib/pages/home/home.dart index 9b33a66c..eb2ddb94 100644 --- a/lib/pages/home/home.dart +++ b/lib/pages/home/home.dart @@ -3,6 +3,7 @@ import 'package:flutter_desktop_tools/flutter_desktop_tools.dart'; import 'package:flutter_hooks/flutter_hooks.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:spotube/components/home/sections/featured.dart'; +import 'package:spotube/components/home/sections/friends.dart'; import 'package:spotube/components/home/sections/genres.dart'; import 'package:spotube/components/home/sections/made_for_user.dart'; import 'package:spotube/components/home/sections/new_releases.dart'; @@ -31,6 +32,7 @@ class HomePage extends HookConsumerWidget { HomeNewReleasesSection(), ], ), + const HomePageFriendsSection(), const SliverSafeArea(sliver: HomeMadeForUserSection()), ], ), diff --git a/lib/services/custom_spotify_endpoints/spotify_endpoints.dart b/lib/services/custom_spotify_endpoints/spotify_endpoints.dart index 0510e69a..e27b701b 100644 --- a/lib/services/custom_spotify_endpoints/spotify_endpoints.dart +++ b/lib/services/custom_spotify_endpoints/spotify_endpoints.dart @@ -2,6 +2,7 @@ import 'dart:convert'; import 'package:http/http.dart' as http; import 'package:spotify/spotify.dart'; +import 'package:spotube/models/spotify_friends.dart'; class CustomSpotifyEndpoints { static const _baseUrl = 'https://api.spotify.com/v1'; @@ -163,6 +164,18 @@ class CustomSpotifyEndpoints { ); } + Future getFriendActivity() async { + final res = await _client.get( + Uri.parse("https://guc-spclient.spotify.com/presence-view/v1/buddylist"), + headers: { + "content-type": "application/json", + "authorization": "Bearer $accessToken", + "accept": "application/json", + }, + ); + return SpotifyFriends.fromJson(jsonDecode(res.body)); + } + Future artist({required String id}) async { final pathQuery = "$_baseUrl/artists/$id"; @@ -174,7 +187,6 @@ class CustomSpotifyEndpoints { "accept": "application/json", }, ); - final data = jsonDecode(res.body); return Artist.fromJson(_purifyArtistResponse(data)); diff --git a/lib/services/queries/user.dart b/lib/services/queries/user.dart index 40799c1e..82af600f 100644 --- a/lib/services/queries/user.dart +++ b/lib/services/queries/user.dart @@ -3,7 +3,9 @@ import 'package:flutter_hooks/flutter_hooks.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:spotify/spotify.dart'; import 'package:spotube/hooks/spotify/use_spotify_query.dart'; +import 'package:spotube/models/spotify_friends.dart'; import 'package:spotube/provider/authentication_provider.dart'; +import 'package:spotube/provider/custom_spotify_endpoint_provider.dart'; import 'package:spotube/utils/type_conversion_utils.dart'; class UserQueries { @@ -37,4 +39,15 @@ class UserQueries { ref: ref, ); } + + Query friendActivity(WidgetRef ref) { + final customSpotify = ref.read(customSpotifyEndpointProvider); + return useSpotifyQuery( + "friend-activity", + (spotify) { + return customSpotify.getFriendActivity(); + }, + ref: ref, + ); + } } diff --git a/untranslated_messages.json b/untranslated_messages.json index 59b26614..2fd7ceca 100644 --- a/untranslated_messages.json +++ b/untranslated_messages.json @@ -1,86 +1,103 @@ { "ar": [ "step_3_steps", - "step_4_steps" + "step_4_steps", + "friends" ], "bn": [ "step_3_steps", - "step_4_steps" + "step_4_steps", + "friends" ], "ca": [ "step_3_steps", - "step_4_steps" + "step_4_steps", + "friends" ], "de": [ "step_3_steps", - "step_4_steps" + "step_4_steps", + "friends" ], "es": [ "step_3_steps", - "step_4_steps" + "step_4_steps", + "friends" ], "fa": [ "step_3_steps", - "step_4_steps" + "step_4_steps", + "friends" ], "fr": [ "step_3_steps", - "step_4_steps" + "step_4_steps", + "friends" ], "hi": [ "step_3_steps", - "step_4_steps" + "step_4_steps", + "friends" ], "it": [ "step_3_steps", - "step_4_steps" + "step_4_steps", + "friends" ], "ja": [ "step_3_steps", - "step_4_steps" + "step_4_steps", + "friends" ], "nl": [ "step_3_steps", - "step_4_steps" + "step_4_steps", + "friends" ], "pl": [ "step_3_steps", - "step_4_steps" + "step_4_steps", + "friends" ], "pt": [ "step_3_steps", - "step_4_steps" + "step_4_steps", + "friends" ], "ru": [ "step_3_steps", - "step_4_steps" + "step_4_steps", + "friends" ], "tr": [ "step_3_steps", - "step_4_steps" + "step_4_steps", + "friends" ], "uk": [ "step_3_steps", - "step_4_steps" + "step_4_steps", + "friends" ], "zh": [ "step_3_steps", - "step_4_steps" + "step_4_steps", + "friends" ] } From e58e18de33d7bc6fb0e4ddd7ccf6ea14472642b1 Mon Sep 17 00:00:00 2001 From: Kingkor Roy Tirtho Date: Tue, 23 Jan 2024 23:13:13 +0600 Subject: [PATCH 104/195] fix: better error message for failing to find lyrics #1085 --- lib/pages/lyrics/plain_lyrics.dart | 2 +- lib/pages/lyrics/synced_lyrics.dart | 2 +- lib/services/queries/lyrics.dart | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/lib/pages/lyrics/plain_lyrics.dart b/lib/pages/lyrics/plain_lyrics.dart index f6eaa5d5..0ac1ac66 100644 --- a/lib/pages/lyrics/plain_lyrics.dart +++ b/lib/pages/lyrics/plain_lyrics.dart @@ -73,7 +73,7 @@ class PlainLyrics extends HookConsumerWidget { return const ShimmerLyrics(); } else if (lyricsQuery.hasError) { return Text( - "Sorry, no Lyrics were found for `${playlist.activeTrack?.name}` :'(\n${lyricsQuery.error.toString()}", + "Sorry, no Lyrics were found for `${playlist.activeTrack?.name}` :'(\n${lyricsQuery.error.toString().replaceAll("Exception: ", "")}", style: textTheme.bodyLarge?.copyWith( color: palette.bodyTextColor, ), diff --git a/lib/pages/lyrics/synced_lyrics.dart b/lib/pages/lyrics/synced_lyrics.dart index 04d7c04a..0dc0b1f1 100644 --- a/lib/pages/lyrics/synced_lyrics.dart +++ b/lib/pages/lyrics/synced_lyrics.dart @@ -190,7 +190,7 @@ class SyncedLyrics extends HookConsumerWidget { else if (playlist.activeTrack != null && (timedLyricsQuery.hasError)) Text( - "Sorry, no Lyrics were found for `${playlist.activeTrack?.name}` :'(\n${timedLyricsQuery.error.toString()}", + "Sorry, no Lyrics were found for `${playlist.activeTrack?.name}` :'(\n${timedLyricsQuery.error.toString().replaceAll("Exception: ", "")}", style: bodyTextTheme, ) else if (isUnSyncLyric == true) diff --git a/lib/services/queries/lyrics.dart b/lib/services/queries/lyrics.dart index faa5bdec..618f960f 100644 --- a/lib/services/queries/lyrics.dart +++ b/lib/services/queries/lyrics.dart @@ -63,8 +63,8 @@ class LyricsQueries { /// Special thanks to [raptag](https://github.com/raptag) for discovering this /// jem - Query spotifySynced(WidgetRef ref, Track? track) { - return useSpotifyQuery( + Query spotifySynced(WidgetRef ref, Track? track) { + return useSpotifyQuery( "spotify-synced-lyrics/${track?.id}}", (spotify) async { if (track == null) { From a6cb78380d57ea9f3f68c82aee2c211e38287813 Mon Sep 17 00:00:00 2001 From: Kingkor Roy Tirtho Date: Wed, 24 Jan 2024 00:22:14 +0600 Subject: [PATCH 105/195] chore: show icon with error msg #1085 --- lib/collections/spotube_icons.dart | 1 + lib/l10n/app_en.arb | 3 +- lib/pages/lyrics/plain_lyrics.dart | 23 ++++++++++--- lib/pages/lyrics/synced_lyrics.dart | 21 ++++++++---- untranslated_messages.json | 51 +++++++++++++++++++---------- 5 files changed, 71 insertions(+), 28 deletions(-) diff --git a/lib/collections/spotube_icons.dart b/lib/collections/spotube_icons.dart index c6acd669..65e6c1a0 100644 --- a/lib/collections/spotube_icons.dart +++ b/lib/collections/spotube_icons.dart @@ -41,6 +41,7 @@ abstract class SpotubeIcons { static const clock = FeatherIcons.clock; static const lyrics = Icons.lyrics_rounded; static const lyricsOff = Icons.lyrics_outlined; + static const noLyrics = Icons.music_off_outlined; static const logout = FeatherIcons.logOut; static const login = FeatherIcons.logIn; static const dashboard = FeatherIcons.grid; diff --git a/lib/l10n/app_en.arb b/lib/l10n/app_en.arb index 6b61cbae..07df5f06 100644 --- a/lib/l10n/app_en.arb +++ b/lib/l10n/app_en.arb @@ -285,5 +285,6 @@ "browse_all": "Browse All", "genres": "Genres", "explore_genres": "Explore Genres", - "friends": "Friends" + "friends": "Friends", + "no_lyrics_available": "Sorry, unable find lyrics for this track" } \ No newline at end of file diff --git a/lib/pages/lyrics/plain_lyrics.dart b/lib/pages/lyrics/plain_lyrics.dart index 0ac1ac66..bee5114d 100644 --- a/lib/pages/lyrics/plain_lyrics.dart +++ b/lib/pages/lyrics/plain_lyrics.dart @@ -1,12 +1,15 @@ import 'package:collection/collection.dart'; import 'package:flutter/material.dart'; import 'package:flutter_hooks/flutter_hooks.dart'; +import 'package:gap/gap.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:palette_generator/palette_generator.dart'; import 'package:spotify/spotify.dart'; +import 'package:spotube/collections/spotube_icons.dart'; import 'package:spotube/components/lyrics/zoom_controls.dart'; import 'package:spotube/components/shared/shimmers/shimmer_lyrics.dart'; import 'package:spotube/extensions/constrains.dart'; +import 'package:spotube/extensions/context.dart'; import 'package:spotube/provider/proxy_playlist/proxy_playlist_provider.dart'; @@ -72,10 +75,22 @@ class PlainLyrics extends HookConsumerWidget { if (lyricsQuery.isLoading || lyricsQuery.isRefreshing) { return const ShimmerLyrics(); } else if (lyricsQuery.hasError) { - return Text( - "Sorry, no Lyrics were found for `${playlist.activeTrack?.name}` :'(\n${lyricsQuery.error.toString().replaceAll("Exception: ", "")}", - style: textTheme.bodyLarge?.copyWith( - color: palette.bodyTextColor, + return Container( + alignment: Alignment.center, + padding: const EdgeInsets.all(16), + child: Column( + mainAxisSize: MainAxisSize.min, + children: [ + Text( + context.l10n.no_lyrics_available, + style: textTheme.bodyLarge?.copyWith( + color: palette.bodyTextColor, + ), + textAlign: TextAlign.center, + ), + const Gap(26), + const Icon(SpotubeIcons.noLyrics, size: 60), + ], ), ); } diff --git a/lib/pages/lyrics/synced_lyrics.dart b/lib/pages/lyrics/synced_lyrics.dart index 0dc0b1f1..ddef1c65 100644 --- a/lib/pages/lyrics/synced_lyrics.dart +++ b/lib/pages/lyrics/synced_lyrics.dart @@ -1,5 +1,6 @@ import 'package:flutter/material.dart'; import 'package:flutter_hooks/flutter_hooks.dart'; +import 'package:gap/gap.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:palette_generator/palette_generator.dart'; import 'package:spotify/spotify.dart' hide Offset; @@ -7,6 +8,7 @@ import 'package:spotube/collections/spotube_icons.dart'; import 'package:spotube/components/lyrics/zoom_controls.dart'; import 'package:spotube/components/shared/shimmers/shimmer_lyrics.dart'; import 'package:spotube/extensions/constrains.dart'; +import 'package:spotube/extensions/context.dart'; import 'package:spotube/hooks/controllers/use_auto_scroll_controller.dart'; import 'package:spotube/components/lyrics/use_synced_lyrics.dart'; import 'package:scroll_to_index/scroll_to_index.dart'; @@ -188,12 +190,19 @@ class SyncedLyrics extends HookConsumerWidget { child: ShimmerLyrics(), ) else if (playlist.activeTrack != null && - (timedLyricsQuery.hasError)) - Text( - "Sorry, no Lyrics were found for `${playlist.activeTrack?.name}` :'(\n${timedLyricsQuery.error.toString().replaceAll("Exception: ", "")}", - style: bodyTextTheme, - ) - else if (isUnSyncLyric == true) + (timedLyricsQuery.hasError)) ...[ + Container( + alignment: Alignment.center, + padding: const EdgeInsets.all(16), + child: Text( + context.l10n.no_lyrics_available, + style: bodyTextTheme, + textAlign: TextAlign.center, + ), + ), + const Gap(26), + const Icon(SpotubeIcons.noLyrics, size: 60), + ] else if (isUnSyncLyric == true) Expanded( child: Center( child: RichText( diff --git a/untranslated_messages.json b/untranslated_messages.json index 2fd7ceca..45a6df11 100644 --- a/untranslated_messages.json +++ b/untranslated_messages.json @@ -2,102 +2,119 @@ "ar": [ "step_3_steps", "step_4_steps", - "friends" + "friends", + "no_lyrics_available" ], "bn": [ "step_3_steps", "step_4_steps", - "friends" + "friends", + "no_lyrics_available" ], "ca": [ "step_3_steps", "step_4_steps", - "friends" + "friends", + "no_lyrics_available" ], "de": [ "step_3_steps", "step_4_steps", - "friends" + "friends", + "no_lyrics_available" ], "es": [ "step_3_steps", "step_4_steps", - "friends" + "friends", + "no_lyrics_available" ], "fa": [ "step_3_steps", "step_4_steps", - "friends" + "friends", + "no_lyrics_available" ], "fr": [ "step_3_steps", "step_4_steps", - "friends" + "friends", + "no_lyrics_available" ], "hi": [ "step_3_steps", "step_4_steps", - "friends" + "friends", + "no_lyrics_available" ], "it": [ "step_3_steps", "step_4_steps", - "friends" + "friends", + "no_lyrics_available" ], "ja": [ "step_3_steps", "step_4_steps", - "friends" + "friends", + "no_lyrics_available" ], "nl": [ "step_3_steps", "step_4_steps", - "friends" + "friends", + "no_lyrics_available" ], "pl": [ "step_3_steps", "step_4_steps", - "friends" + "friends", + "no_lyrics_available" ], "pt": [ "step_3_steps", "step_4_steps", - "friends" + "friends", + "no_lyrics_available" ], "ru": [ "step_3_steps", "step_4_steps", - "friends" + "friends", + "no_lyrics_available" ], "tr": [ "step_3_steps", "step_4_steps", - "friends" + "friends", + "no_lyrics_available" ], "uk": [ "step_3_steps", "step_4_steps", - "friends" + "friends", + "no_lyrics_available" ], "zh": [ "step_3_steps", "step_4_steps", - "friends" + "friends", + "no_lyrics_available" ] } From 7c0689c056f75a27de33d2a03cec47836ec4de16 Mon Sep 17 00:00:00 2001 From: Meenbeese Date: Tue, 23 Jan 2024 22:07:33 -0500 Subject: [PATCH 106/195] docs: Reword and improve the support message (#1084) --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index e637f6c6..11f1db2e 100644 --- a/README.md +++ b/README.md @@ -36,7 +36,7 @@ Btw it's not just another Electron app 😉 - 📖 Open source/libre software - 🔉 Playback control is done locally, not on the server -**¹** It is still **recommended** to support the creators by watching/liking/subscribing to the artists' YouTube channels or liking their tracks on Spotify (or purchasing a Spotify Premium subscription too). +**¹** It is still **recommended** to support creators by engaging with their YouTube channels/Spotify tracks (or preferably by buying their merch/concert tickets/physical media). ### ❌ Unsupported features From c3ebf56ac149b0af8815a5533fe6c386df743440 Mon Sep 17 00:00:00 2001 From: Nabraj Khadka <40161692+iamnabink@users.noreply.github.com> Date: Wed, 24 Jan 2024 09:37:49 +0545 Subject: [PATCH 107/195] =?UTF-8?q?feat(translations):=20add=20Nepali=20(?= =?UTF-8?q?=E0=A4=A8=E0=A5=87=E0=A4=AA=E0=A4=BE=E0=A4=B2=E0=A5=80)=20trans?= =?UTF-8?q?lations=20(#1111)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * actions: Add Up for grab checkbox to issue templates. (#1074) * docs: update copyright year in README.md (#1100) year changed from 2023 to 2024 * feat(translations): add Nepali (नेपाली) translations --------- Co-authored-by: Taha Ghadirian Co-authored-by: Muhammad Jawad <70428284+m-Jawa-d@users.noreply.github.com> --- .github/ISSUE_TEMPLATE/bug_report.yml | 7 + .github/ISSUE_TEMPLATE/new_feature.yml | 9 +- README.md | 2 +- lib/collections/language_codes.dart | 8 +- lib/l10n/app_ne.arb | 288 +++++++++++++++++++++++++ lib/l10n/l10n.dart | 1 + 6 files changed, 309 insertions(+), 6 deletions(-) create mode 100644 lib/l10n/app_ne.arb diff --git a/.github/ISSUE_TEMPLATE/bug_report.yml b/.github/ISSUE_TEMPLATE/bug_report.yml index e0031d17..64ee89d2 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.yml +++ b/.github/ISSUE_TEMPLATE/bug_report.yml @@ -71,3 +71,10 @@ body: description: Anything else you'd like to include? validations: required: false + - type: checkboxes + attributes: + label: Self grab + description: If you are a developer and want to work on this issue yourself, you can check this box and wait for maintainer response. We welcome contributions! + options: + - label: I'm ready to work on this issue! + required: false \ No newline at end of file diff --git a/.github/ISSUE_TEMPLATE/new_feature.yml b/.github/ISSUE_TEMPLATE/new_feature.yml index 9742f91f..7f02ea38 100644 --- a/.github/ISSUE_TEMPLATE/new_feature.yml +++ b/.github/ISSUE_TEMPLATE/new_feature.yml @@ -35,4 +35,11 @@ body: label: Additional information description: Anything else you'd like to include? validations: - required: false \ No newline at end of file + required: false + - type: checkboxes + attributes: + label: Self grab + description: If you are a developer and want to work on this issue yourself, you can check this box and wait for maintainer response. We welcome contributions! + options: + - label: I'm ready to work on this issue! + required: false \ No newline at end of file diff --git a/README.md b/README.md index 11f1db2e..791d5da0 100644 --- a/README.md +++ b/README.md @@ -304,4 +304,4 @@ If you are concerned, you can [read the reason of choosing this license](https:/ 1. [dart_discord_rpc](https://github.com/alexmercerind/dart_discord_rpc) - Discord Rich Presence for Flutter & Dart apps & games. -

    © Copyright Spotube 2023

    +

    © Copyright Spotube 2024

    diff --git a/lib/collections/language_codes.dart b/lib/collections/language_codes.dart index de6f6d1c..4554de63 100644 --- a/lib/collections/language_codes.dart +++ b/lib/collections/language_codes.dart @@ -452,10 +452,10 @@ abstract class LanguageLocals { // name: "North Ndebele", // nativeName: "isiNdebele", // ), - // "ne": const ISOLanguageName( - // name: "Nepali", - // nativeName: "नेपाली", - // ), + "ne": const ISOLanguageName( + name: "Nepali", + nativeName: "नेपाली", + ), // "ng": const ISOLanguageName( // name: "Ndonga", // nativeName: "Owambo", diff --git a/lib/l10n/app_ne.arb b/lib/l10n/app_ne.arb new file mode 100644 index 00000000..9fca9ea4 --- /dev/null +++ b/lib/l10n/app_ne.arb @@ -0,0 +1,288 @@ +{ + "guest": "अतिथि", + "browse": "ब्राउज़ गर्नुहोस्", + "search": "खोजी गर्नुहोस्", + "library": "पुस्तकालय", + "lyrics": "गीतको शब्द", + "settings": "सेटिङ", + "genre_categories_filter": "शैली वा शैलीहरू फिल्टर गर्नुहोस्...", + "genre": "शैली", + "personalized": "व्यक्तिगत", + "featured": "विशेष", + "new_releases": "नयाँ रिलिज", + "songs": "गीतहरू", + "playing_track": "{track} बज्यो", + "queue_clear_alert": "यो हालको कतारलाई हटाउँछ। {track_length} ट्र्याकहरू हटाईन्छ\nके तपाईं जारी राख्न चाहनुहुन्छ?", + "load_more": "थप लोड गर्नुहोस्", + "playlists": "प्लेलिस्टहरू", + "artists": "कलाकारहरू", + "albums": "आल्बमहरू", + "tracks": "ट्र्याकहरू", + "downloads": "डाउनलोडहरू", + "filter_playlists": "तपाईंको प्लेलिस्टहरू फिल्टर गर्नुहोस्...", + "liked_tracks": "मन परेका ट्र्याकहरू", + "liked_tracks_description": "तपाईंको मन परेका सबै ट्र्याकहरू", + "create_playlist": "प्लेलिस्ट बनाउनुहोस्", + "create_a_playlist": "प्लेलिस्ट बनाउनुहोस्", + "update_playlist": "प्लेलिस्ट अपडेट गर्नुहोस्", + "create": "बनाउनुहोस्", + "cancel": "रद्द गर्नुहोस्", + "update": "अपडेट गर्नुहोस्", + "playlist_name": "प्लेलिस्टको नाम", + "name_of_playlist": "प्लेलिस्टको नाम", + "description": "विवरण", + "public": "सार्वजनिक", + "collaborative": "सहकारी", + "search_local_tracks": "स्थानीय ट्र्याकहरू खोजी गर्नुहोस्...", + "play": "बजाउनुहोस्", + "delete": "मेटाउनुहोस्", + "none": "कुनै पनि होइन", + "sort_a_z": "A-Zमा क्रमबद्ध गर्नुहोस्", + "sort_z_a": "Z-Aमा क्रमबद्ध गर्नुहोस्", + "sort_artist": "कलाकारबाट क्रमबद्ध गर्नुहोस्", + "sort_album": "आल्बमबाट क्रमबद्ध गर्नुहोस्", + "sort_tracks": "ट्र्याकहरूलाई क्रमबद्ध गर्नुहोस्", + "currently_downloading": "हाल डाउनलोड गर्दैछ ({tracks_length})", + "cancel_all": "सब रद्द गर्नुहोस्", + "filter_artist": "कलाकारहरूलाई फिल्टर गर्नुहोस्...", + "followers": "{followers} अनुयायीहरू", + "add_artist_to_blacklist": "कलाकारलाई कालोसूचीमा थप्नुहोस्", + "top_tracks": "शीर्ष ट्र्याकहरू", + "fans_also_like": "अनुयायीहरू पनि लाइक गर्छन्", + "loading": "लोड हुँदैछ...", + "artist": "कलाकार", + "blacklisted": "कालोसूचीमा", + "following": "फल्लो गर्दै", + "follow": "फल्लो गर्नुहोस्", + "artist_url_copied": "कलाकार URL क्लिपबोर्डमा प्रतिलिपि गरिएको छ", + "added_to_queue": "{tracks} ट्र्याकहरूलाई कतारमा थपिएको छ", + "filter_albums": "आल्बमहरूलाई फिल्टर गर्नुहोस्...", + "synced": "सिङ्क गरिएको", + "plain": "साधा", + "shuffle": "शफल", + "search_tracks": "ट्र्याकहरू खोजी गर्नुहोस्...", + "released": "रिलिज गरिएको", + "error": "त्रुटि {error}", + "title": "शीर्षक", + "time": "समय", + "more_actions": "थप कार्यहरू", + "download_count": "डाउनलोड ({count})", + "add_count_to_playlist": "प्लेलिस्टमा थप्नुहोस् ({count})", + "add_count_to_queue": "कतारमा थप्नुहोस् ({count})", + "play_count_next": "प्लेगरी गर्नुहोस् ({count})", + "album": "आल्बम", + "copied_to_clipboard": "{data} क्लिपबोर्डमा प्रतिलिपि गरिएको छ", + "add_to_following_playlists": "{track} लाई तलका प्लेलिस्टमा थप्नुहोस्", + "add": "थप्नुहोस्", + "added_track_to_queue": "{track} लाई कतारमा थपिएको छ", + "add_to_queue": "कतारमा थप्नुहोस्", + "track_will_play_next": "{track} अरूलाई पहिलोमा बज्नेछ", + "play_next": "पछिबजाउनुहोस्", + "removed_track_from_queue": "{track} लाई कतारबाट हटाइएको छ", + "remove_from_queue": "कतारबाट हटाउनुहोस्", + "remove_from_favorites": "पसन्दीदामा बाट हटाउनुहोस्", + "save_as_favorite": "पसन्दीदा बनाउनुहोस्", + "add_to_playlist": "प्लेलिस्टमा थप्नुहोस्", + "remove_from_playlist": "प्लेलिस्टबाट हटाउनुहोस्", + "add_to_blacklist": "कालोसूचीमा थप्नुहोस्", + "remove_from_blacklist": "कालोसूचीबाट हटाउनुहोस्", + "share": "साझा गर्नुहोस्", + "mini_player": "मिनि प्लेयर", + "slide_to_seek": "अगाडि वा पछाडि खोजी गर्नका लागि स्लाइड गर्नुहोस्", + "shuffle_playlist": "प्लेलिस्ट शफल गर्नुहोस्", + "unshuffle_playlist": "प्लेलिस्ट शफल नगर्नुहोस्", + "previous_track": "पूर्व ट्र्याक", + "next_track": "अरू ट्र्याक", + "pause_playback": "प्लेब्याक रोक्नुहोस्", + "resume_playback": "प्लेब्याक पुनः सुरु गर्नुहोस्", + "loop_track": "ट्र्याकलाई दोहोरोपट्टी बजाउनुहोस्", + "repeat_playlist": "प्लेलिस्ट पुनः बजाउनुहोस्", + "queue": "कतार", + "alternative_track_sources": "वैकल्पिक ट्र्याक स्रोतहरू", + "download_track": "ट्र्याक डाउनलोड गर्नुहोस्", + "tracks_in_queue": "कतारमा {tracks} ट्र्याकहरू", + "clear_all": "सब मेटाउनुहोस्", + "show_hide_ui_on_hover": "हवर गरेपछि UI देखाउनुहोस्/लुकाउनुहोस्", + "always_on_top": "सधैं टपमा राख्नुहोस्", + "exit_mini_player": "मिनि प्लेयर बाट बाहिर निस्कनुहोस्", + "download_location": "डाउनलोड स्थान", + "account": "खाता", + "login_with_spotify": "तपाईंको Spotify खातासँग लगइन गर्नुहोस्", + "connect_with_spotify": "Spotify सँग जडान गर्नुहोस्", + "logout": "बाहिर निस्कनुहोस्", + "logout_of_this_account": "यो खाताबाट बाहिर निस्कनुहोस्", + "language_region": "भाषा र क्षेत्र", + "language": "भाषा", + "system_default": "सिस्टम पूर्वनिर्धारित", + "market_place_region": "बजार स्थान", + "recommendation_country":"सिफारिस गरिएको देश", + "appearance": "दृष्टिकोण", + "layout_mode": "लेआउट मोड", + "override_layout_settings": "अनुकूलित प्रतिकृयात्मक लेआउट मोड सेटिङ्गहरू", + "adaptive": "अनुकूलित", + "compact": "संकुचित", + "extended": "बढाइएको", + "theme": "थिम", + "dark": "गाढा", + "light": "प्रकाश", + "system": "सिस्टम", + "accent_color": "एक्सेन्ट रङ्ग", + "sync_album_color": "एल्बम रङ्ग सिङ्क गर्नुहोस्", + "sync_album_color_description": "एल्बम कला को प्रमुख रङ्गलाई एक्सेन्ट रङ्गको रूपमा प्रयोग गर्दछ", + "playback": "प्लेब्याक", + "audio_quality": "आडियो गुणस्तर", + "high": "उच्च", + "low": "न्यून", + "pre_download_play": "पूर्व-डाउनलोड र प्ले गर्नुहोस्", + "pre_download_play_description": "आडियो स्ट्रिम गर्नु नगरी बाइटहरू डाउनलोड गरी बजाउँछ (उच्च ब्यान्डविथ उपयोगकर्ताहरूको लागि सिफारिस गरिएको)", + "skip_non_music": "गीतहरू बाहेक कुनै अनुष्ठान छोड्नुहोस् (स्पन्सरब्लक)", + "blacklist_description": "कालोसूची गीत र कलाकारहरू", + "wait_for_download_to_finish": "कृपया हालको डाउनलोड समाप्त हुन लागि पर्खनुहोस्", + "desktop": "डेस्कटप", + "close_behavior": "बन्द व्यवहार", + "close": "बन्द गर्नुहोस्", + "minimize_to_tray": "ट्रेमा कम गर्नुहोस्", + "show_tray_icon": "सिस्टम ट्रे आइकन देखाउनुहोस्", + "about": "बारेमा", + "u_love_spotube": "हामीले थाहा पारेका छौं तपाईंलाई Spotube मन पर्छ", + "check_for_updates": "अपडेटहरूको लागि जाँच गर्नुहोस्", + "about_spotube": "Spotube को बारेमा", + "blacklist": "कालोसूची", + "please_sponsor": "कृपया स्पन्सर/डोनेट गर्नुहोस्", + "spotube_description": "Spotube, एक हल्का, समृद्ध, स्वतन्त्र Spotify क्लाइयन", + "version": "संस्करण", + "build_number": "निर्माण नम्बर", + "founder": "संस्थापक", + "repository": "पुनरावलोकन स्थल", + "bug_issues": "त्रुटि + समस्याहरू", + "made_with": "❤️ 2021-2024 बाट बनाइएको", + "kingkor_roy_tirtho": "किङ्कोर राय तिर्थो", + "copyright": "© 2021-{current_year} किङ्कोर राय तिर्थो", + "license": "लाइसेन्स", + "add_spotify_credentials": "सुरु हुनका लागि तपाईंको स्पटिफाई क्रेडेन्शियल थप्नुहोस्", + "credentials_will_not_be_shared_disclaimer": "चिन्ता नगर्नुहोस्, तपाईंको कुनै पनि क्रेडेन्शियलहरूले कसैले संग्रह वा साझा गर्नेछैन", + "know_how_to_login": "कसरी लगिन गर्ने भन्ने थाहा छैन?", + "follow_step_by_step_guide": "चरणबद्ध मार्गदर्शनमा साथी बनाउनुहोस्", + "spotify_cookie": "Spotify {name} कुकी", + "cookie_name_cookie": "{name} कुकी", + "fill_in_all_fields": "कृपया सबै क्षेत्रहरू भर्नुहोस्", + "submit": "पेश गर्नुहोस्", + "exit": "बाहिर निस्कनुहोस्", + "previous": "पूर्ववत", + "next": "अरू", + "done": "गरिएको", + "step_1": "कदम 1", + "first_go_to": "पहिलो, जानुहोस्", + "login_if_not_logged_in": "र लगइन/साइनअप गर्नुहोस् जुन तपाईंले लगइन गरेनन्", + "step_2": "कदम 2", + "step_2_steps": "1. एकबार तपाईं लगइन गरे पछि, F12 थिच्नुहोस् वा माउस राइट क्लिक गर्नुहोस् > इन्स्पेक्ट गर्नुहोस् भने ब्राउजर डेभटुलहरू खुलाउनका लागि।\n2. तपाईंको \"एप्लिकेसन\" ट्याबमा जानुहोस् (Chrome, Edge, Brave इत्यादि) वा \"स्टोरेज\" ट्याबमा जानुहोस् (Firefox, Palemoon इत्यादि)\n3. तपाईंको इन्सेक्ट गरेको ब्राउजर डेभटुलहरूमा \"कुकीहरू\" खण्डमा जानुहोस् अनि \"https://accounts.spotify.com\" उपकोणमा जानुहोस्", + "step_3": "कदम 3", + "step_3_steps": "\"sp_dc\" र \"sp_key\" (वा sp_gaid) कुकीहरूको मानहरू प्रतिलिपि गर्नुहोस्", + "success_emoji": "सफलता 🥳", + "success_message": "हाम्रो सानो भाइ, अब तपाईं सफलतापूर्वक आफ्नो Spotify खातामा लगइन गरेका छौं। राम्रो काम गरेको!", + "step_4": "कदम 4", + "step_4_steps": "प्रतिलिपि गरेको \"sp_dc\" र \"sp_key\" (वा sp_gaid) मानहरूलाई आफ्नो ठाउँमा पेस्ट गर्नुहोस्", + "something_went_wrong": "केहि गल्ति भएको छ", + "piped_instance": "पाइपड सर्भर इन्स्ट्यान्स", + "piped_description": "गीत मिलाउको लागि प्रयोग गर्ने पाइपड सर्भर इन्स्ट्यान्स", + "piped_warning": "तिनीहरूमध्ये केहि ठिक गर्न सक्छ। यसलाई आफ्नो जोखिममा प्रयोग गर्नुहोस्", + "generate_playlist": "प्लेलिस्ट बनाउनुहोस्", + "track_exists": "ट्र्याक {track} पहिले नै छ", + "replace_downloaded_tracks": "सबै डाउनलोड गरिएका ट्र्याकहरूलाई परिवर्तन गर्नुहोस्", + "skip_download_tracks": "सबै डाउनलोड गरिएका ट्र्याकहरूलाई छोड्नुहोस्", + "do_you_want_to_replace": "के तपाईंले वर्तमान ट्र्याकलाई परिवर्तन गर्न चाहनुहुन्छ?", + "replace": "परिवर्तन गर्नुहोस्", + "skip": "छोड्नुहोस्", + "select_up_to_count_type": "{count} {type} सम्म चयन गर्नुहोस्", + "select_genres": "जनरहरू चयन गर्नुहोस्", + "add_genres": "जनरहरू थप्नुहोस्", + "country": "देश", + "number_of_tracks_generate": "बनाउनका लागि ट्र्याकहरूको संख्या", + "acousticness": "एकोस्टिकनेस", + "danceability": "नृत्यक्षमता", + "energy": "ऊर्जा", + "instrumentalness": "साजा रहेकोता", + "liveness": "प्राणिकता", + "loudness": "शोर", + "speechiness": "भाषण", + "valence": "मानसिक स्वभाव", + "popularity": "लोकप्रियता", + "key": "कुञ्जी", + "duration": "अवधि (सेकेण्ड)", + "tempo": "गति (बीपीएम)", + "mode": "मोड", + "time_signature": "समय हस्ताक्षर", + "short": "सानो", + "medium": "मध्यम", + "long": "लामो", + "min": "न्यून", + "max": "अधिक", + "target": "लक्ष्य", + "moderate": "मध्यस्थ", + "deselect_all": "सबै छान्नुहोस्", + "select_all": "सबै चयन गर्नुहोस्", + "are_you_sure": "के तपाईं सुनिश्चित हुनुहुन्छ?", + "generating_playlist": "तपाईंको विशेष प्लेलिस्ट बनाइएको छ...", + "selected_count_tracks": "{count} ट्र्याकहरू छन् चयन गरिएका", + "download_warning": "यदि तपाईं सबै ट्र्याकहरूलाई बल्कमा डाउनलोड गर्छनु हो भने तपाईं स्पष्ट रूपमा साङ्गीत चोरी गरिरहेका छन् र यो साङ्गीतको रचनात्मक समाजलाई क्षति पनि पुर्याउँछ। उमेराइएको छ कि तपाईं यसको बारेमा जागरूक छिनुहुन्छ। सधैं, कला गर्दै र कलाकारको कडा परम्परा समर्थन गर्दै आइन्छ।", + "download_ip_ban_warning": "बितिएका डाउनलोड अनुरोधहरूका कारण तपाईंको आइपीले YouTube मा ब्लक हुन सक्छ। आइपी ब्लक भनेको कम्तीमा 2-3 महिनासम्म तपाईं त्यस आइपी यन्त्रबाट YouTube प्रयोग गर्न सक्नुहुन्छ। र यदि यो हुँदैछ भने स्पट्यूबले यसलाई कसैले गरेको बारेमा कुनै दायित्व लिन्छैन।", + "by_clicking_accept_terms": "'स्वीकृत' गरेर तपाईं निम्नलिखित निर्वाचन गर्दैछिन्:", + "download_agreement_1": "म मन्ने छु कि म साङ्गीत चोरी गरिरहेको छु। म बुरो हुँ", + "download_agreement_2": "म कहिल्यै कहिल्यै तिनीहरूलाई समर्थन गर्नेछु र म यो तिनीहरूको कला किन्ने पैसा छैन भने मा मात्र यो गरेको छु", + "download_agreement_3": "म पूरा रूपमा जान्छु कि मेरो आइपी YouTube मा ब्लक हुन सक्छ र म मन्छेहरूले मेरो चासोबाट भएको कुनै दुर्घटनामा स्पट्यूब वा तिनीहरूको मालिकहरू/सहयोगीहरूलाई दायित्वी ठान्छुँभन्ने पूर्ण जानकारी छैन", + "decline": "अस्वीकृत", + "accept": "स्वीकृत", + "details": "विवरण", + "youtube": "YouTube", + "channel": "च्यानल", + "likes": "लाइकहरू", + "dislikes": "असुनुहरू", + "views": "हेरिएको", + "streamUrl": "स्ट्रिम यूआरएल", + "stop": "रोक्नुहोस्", + "sort_newest": "नयाँ थपिएकोमा क्रमबद्ध गर्नुहोस्", + "sort_oldest": "पुरानो थपिएकोमा क्रमबद्ध गर्नुहोस्", + "sleep_timer": "सुत्ने टाइमर", + "mins": "{minutes} मिनेटहरू", + "hours": "{hours} घण्टाहरू", + "hour": "{hours} घण्टा", + "custom_hours": "कस्टम घण्टाहरू", + "logs": "लगहरू", + "developers": "डेभेलपर्स", + "not_logged_in": "तपाईंले लगइन गरेका छैनौं", + "search_mode": "खोज मोड", + "audio_source": "अडियो स्रोत", + "ok": "ठिक छ", + "failed_to_encrypt": "एन्क्रिप्ट गर्न सकिएन", + "encryption_failed_warning": "स्पट्यूबले तपाईंको डेटा सुरक्षित रूपमा स्टोर गर्नका लागि एन्क्रिप्ट गर्न खोजेको छ। तर यसले गरेको छैन। यसले असुरक्षित स्टोरेजमा फल्लब्याक गर्दछ\nयदि तपाईंले लिनक्स प्रयोग गरिरहेका छन् भने कृपया सुनिश्चित गर्नुहोस् कि तपाईंले कुनै सीक्रेट-सर्भिस (गोनोम-किरिङ, केडीइ-वालेट, किपासेक्ससि इत्यादि) इन्स्टल गरेका छौं", + "querying_info": "जानकारी हेर्दै...", + "piped_api_down": "पाइपड एपीआई डाउन छ", + "piped_down_error_instructions": "पाइपड इन्स्ट्यान्स {pipedInstance} हाल डाउन छ\n\nजीसनै इन्स्ट्यान्स परिवर्तन गर्नुहोस् वा 'एपीआई प्रकार' लाइ YouTube आफिसियल एपीआईमा परिवर्तन गर्नुहोस्\n\nपरिवर्तनपछि एप्लिकेसन पुन: सुरु गर्नुहोस्", + "you_are_offline": "तपाईं वर्तमान अफलाइन हुनुहुन्छ", + "connection_restored": "तपाईंको इन्टरनेट कनेक्सन पुन: स्थापित भएको छ", + "use_system_title_bar": "सिस्टम शीर्षक पट्टी प्रयोग गर्नुहोस्", + "crunching_results": "परिणामहरू कपालबाट पीस्दै...", + "search_to_get_results": "परिणामहरू प्राप्त गर्नका लागि खोज्नुहोस्", + "use_amoled_mode": "कृष्ण ब्ल्याक गाढा थिम प्रयोग गर्नुहोस्", + "pitch_dark_theme": "एमोलेड मोड", + "normalize_audio": "अडियो सामान्य गर्नुहोस्", + "change_cover": "कवर परिवर्तन गर्नुहोस्", + "add_cover": "कवर थप्नुहोस्", + "restore_defaults": "पूर्वनिर्धारितहरू पुनः स्थापित गर्नुहोस्", + "download_music_codec": "साङ्गीत कोडेक डाउनलोड गर्नुहोस्", + "streaming_music_codec": "स्ट्रिमिङ साङ्गीत कोडेक", + "login_with_lastfm": "लास्ट.एफ.एम सँग लगइन गर्नुहोस्", + "connect": "जडान गर्नुहोस्", + "disconnect_lastfm": "लास्ट.एफ.एम डिसकनेक्ट गर्नुहोस्", + "disconnect": "डिसकनेक्ट", + "username": "प्रयोगकर्ता नाम", + "password": "पासवर्ड", + "login": "लगइन", + "login_with_your_lastfm": "तपाईंको लास्ट.एफ.एम खातामा लगइन गर्नुहोस्", + "scrobble_to_lastfm": "लास्ट.एफ.एम मा स्क्रबल गर्नुहोस्", + "go_to_album": "आल्बममा जानुहोस्", + "discord_rich_presence": "डिस्कर्ड धनी उपस्थिति", + "browse_all": "सबै हेर्नुहोस्", + "genres": "शैलीहरू", + "explore_genres": "शैलीहरू अन्वेषण गर्नुहोस्" +} \ No newline at end of file diff --git a/lib/l10n/l10n.dart b/lib/l10n/l10n.dart index 47e5eb99..335be545 100644 --- a/lib/l10n/l10n.dart +++ b/lib/l10n/l10n.dart @@ -21,6 +21,7 @@ class L10n { const Locale('es', 'ES'), const Locale("fa", "IR"), const Locale('fr', 'FR'), + const Locale('ne', 'NP'), const Locale('hi', 'IN'), const Locale('it', 'IT'), const Locale('ja', 'JP'), From 9b289605c7e803605c83b81e62ecc089ea668b60 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 24 Jan 2024 09:59:20 +0600 Subject: [PATCH 108/195] chore(deps): bump shared_preferences from 2.2.1 to 2.2.2 (#796) Bumps [shared_preferences](https://github.com/flutter/packages/tree/main/packages/shared_preferences) from 2.2.1 to 2.2.2. - [Release notes](https://github.com/flutter/packages/releases) - [Commits](https://github.com/flutter/packages/commits/shared_preferences-v2.2.2/packages/shared_preferences) --- updated-dependencies: - dependency-name: shared_preferences dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- pubspec.lock | 4 ++-- pubspec.yaml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/pubspec.lock b/pubspec.lock index b4182d12..2278f185 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -1772,10 +1772,10 @@ packages: dependency: "direct main" description: name: shared_preferences - sha256: b7f41bad7e521d205998772545de63ff4e6c97714775902c199353f8bf1511ac + sha256: "81429e4481e1ccfb51ede496e916348668fd0921627779233bd24cc3ff6abd02" url: "https://pub.dev" source: hosted - version: "2.2.1" + version: "2.2.2" shared_preferences_android: dependency: transitive description: diff --git a/pubspec.yaml b/pubspec.yaml index 36a2f398..4798aeec 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -83,7 +83,7 @@ dependencies: url: https://github.com/KRTirtho/scrobblenaut.git ref: dart-3-support scroll_to_index: ^3.0.1 - shared_preferences: ^2.0.11 + shared_preferences: ^2.2.2 sidebarx: ^0.15.0 skeleton_text: ^3.0.1 smtc_windows: ^0.1.1 From ab09ae60f06930299e1f17138931fd1604530af4 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 24 Jan 2024 10:00:35 +0600 Subject: [PATCH 109/195] chore(deps): bump visibility_detector from 0.3.3 to 0.4.0+2 (#797) Bumps [visibility_detector](https://github.com/google/flutter.widgets/tree/master/packages) from 0.3.3 to 0.4.0+2. - [Commits](https://github.com/google/flutter.widgets/commits/HEAD/packages) --- updated-dependencies: - dependency-name: visibility_detector dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- pubspec.lock | 4 ++-- pubspec.yaml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/pubspec.lock b/pubspec.lock index 2278f185..5141b46b 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -2225,10 +2225,10 @@ packages: dependency: "direct main" description: name: visibility_detector - sha256: "15c54a459ec2c17b4705450483f3d5a2858e733aee893dcee9d75fd04814940d" + sha256: dd5cc11e13494f432d15939c3aa8ae76844c42b723398643ce9addb88a5ed420 url: "https://pub.dev" source: hosted - version: "0.3.3" + version: "0.4.0+2" vm_service: dependency: transitive description: diff --git a/pubspec.yaml b/pubspec.yaml index 4798aeec..d49c02a1 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -94,7 +94,7 @@ dependencies: url_launcher: ^6.1.7 uuid: ^3.0.7 version: ^3.0.2 - visibility_detector: ^0.3.3 + visibility_detector: ^0.4.0+2 window_manager: ^0.3.1 window_size: git: From 7b6042d01f3eb115fd244409901824b2773c7816 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 24 Jan 2024 10:02:25 +0600 Subject: [PATCH 110/195] chore(deps): bump google_fonts from 5.1.0 to 6.1.0 (#798) Bumps [google_fonts](https://github.com/material-foundation/flutter-packages/tree/main/packages) from 5.1.0 to 6.1.0. - [Commits](https://github.com/material-foundation/flutter-packages/commits/HEAD/packages) --- updated-dependencies: - dependency-name: google_fonts dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Kingkor Roy Tirtho --- pubspec.lock | 4 ++-- pubspec.yaml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/pubspec.lock b/pubspec.lock index 5141b46b..b70b9dc0 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -1014,10 +1014,10 @@ packages: dependency: "direct main" description: name: google_fonts - sha256: e20ff62b158b96f392bfc8afe29dee1503c94fbea2cbe8186fd59b756b8ae982 + sha256: f0b8d115a13ecf827013ec9fc883390ccc0e87a96ed5347a3114cac177ef18e8 url: "https://pub.dev" source: hosted - version: "5.1.0" + version: "6.1.0" graphs: dependency: transitive description: diff --git a/pubspec.yaml b/pubspec.yaml index d49c02a1..b7d2493b 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -55,7 +55,7 @@ dependencies: flutter_svg: ^1.1.6 form_validator: ^2.1.1 fuzzywuzzy: ^1.1.6 - google_fonts: ^5.1.0 + google_fonts: ^6.1.0 go_router: ^11.1.2 hive: ^2.2.3 hive_flutter: ^1.1.0 From a72bb0c73b71cd13ab54307cfbd7426648a490f3 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 24 Jan 2024 10:03:56 +0600 Subject: [PATCH 111/195] chore(deps): bump subosito/flutter-action from 2.10.0 to 2.12.0 (#855) Bumps [subosito/flutter-action](https://github.com/subosito/flutter-action) from 2.10.0 to 2.12.0. - [Release notes](https://github.com/subosito/flutter-action/releases) - [Commits](https://github.com/subosito/flutter-action/compare/v2.10.0...v2.12.0) --- updated-dependencies: - dependency-name: subosito/flutter-action dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Kingkor Roy Tirtho --- .github/workflows/spotube-release-binary.yml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/spotube-release-binary.yml b/.github/workflows/spotube-release-binary.yml index b561bca8..8fa0e2f5 100644 --- a/.github/workflows/spotube-release-binary.yml +++ b/.github/workflows/spotube-release-binary.yml @@ -33,7 +33,7 @@ jobs: runs-on: windows-latest steps: - uses: actions/checkout@v4 - - uses: subosito/flutter-action@v2.10.0 + - uses: subosito/flutter-action@v2.12.0 with: cache: true flutter-version: ${{ env.FLUTTER_VERSION }} @@ -107,7 +107,7 @@ jobs: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - - uses: subosito/flutter-action@v2.10.0 + - uses: subosito/flutter-action@v2.12.0 with: cache: true flutter-version: ${{ env.FLUTTER_VERSION }} @@ -200,7 +200,7 @@ jobs: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - - uses: subosito/flutter-action@v2.10.0 + - uses: subosito/flutter-action@v2.12.0 with: cache: true flutter-version: ${{ env.FLUTTER_VERSION }} @@ -276,7 +276,7 @@ jobs: runs-on: macos-12 steps: - uses: actions/checkout@v4 - - uses: subosito/flutter-action@v2.10.0 + - uses: subosito/flutter-action@v2.12.0 with: cache: true flutter-version: ${{ env.FLUTTER_VERSION }} From 1bdae90fb01f0f8cac9925576ce068dba38e5250 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 24 Jan 2024 10:07:24 +0600 Subject: [PATCH 112/195] chore(deps): bump sidebarx from 0.15.0 to 0.16.3 (#896) Bumps [sidebarx](https://github.com/Frezyx/sidebarx) from 0.15.0 to 0.16.3. - [Release notes](https://github.com/Frezyx/sidebarx/releases) - [Changelog](https://github.com/Frezyx/sidebarx/blob/main/CHANGELOG.md) - [Commits](https://github.com/Frezyx/sidebarx/compare/0.15.0...0.16.3) --- updated-dependencies: - dependency-name: sidebarx dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Kingkor Roy Tirtho --- pubspec.lock | 4 ++-- pubspec.yaml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/pubspec.lock b/pubspec.lock index b70b9dc0..3835f711 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -1852,10 +1852,10 @@ packages: dependency: "direct main" description: name: sidebarx - sha256: "26a8392ceddb659c8f2c688beba6c04bcbf520b4d5decb143c5fd7253653081f" + sha256: "7042d64844b8e64ca5c17e70d89b49df35b54a26c015b90000da9741eab70bc0" url: "https://pub.dev" source: hosted - version: "0.15.0" + version: "0.16.3" simple_icons: dependency: "direct main" description: diff --git a/pubspec.yaml b/pubspec.yaml index b7d2493b..d0c51a15 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -83,8 +83,8 @@ dependencies: url: https://github.com/KRTirtho/scrobblenaut.git ref: dart-3-support scroll_to_index: ^3.0.1 + sidebarx: ^0.16.3 shared_preferences: ^2.2.2 - sidebarx: ^0.15.0 skeleton_text: ^3.0.1 smtc_windows: ^0.1.1 spotify: ^0.12.0 From 2c88561b4433c08c347b444feb33f9171f593ac2 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 24 Jan 2024 10:07:48 +0600 Subject: [PATCH 113/195] chore(deps): bump actions/download-artifact from 3 to 4 (#948) Bumps [actions/download-artifact](https://github.com/actions/download-artifact) from 3 to 4. - [Release notes](https://github.com/actions/download-artifact/releases) - [Commits](https://github.com/actions/download-artifact/compare/v3...v4) --- updated-dependencies: - dependency-name: actions/download-artifact dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/spotube-release-binary.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/spotube-release-binary.yml b/.github/workflows/spotube-release-binary.yml index 8fa0e2f5..470544e3 100644 --- a/.github/workflows/spotube-release-binary.yml +++ b/.github/workflows/spotube-release-binary.yml @@ -386,7 +386,7 @@ jobs: - macos - iOS steps: - - uses: actions/download-artifact@v3 + - uses: actions/download-artifact@v4 with: name: Spotube-Release-Binaries path: ./Spotube-Release-Binaries From 0dea3249a5cbe36c726a15ea772b8648ac5d5658 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 24 Jan 2024 10:08:03 +0600 Subject: [PATCH 114/195] chore(deps): bump actions/upload-artifact from 3 to 4 (#949) Bumps [actions/upload-artifact](https://github.com/actions/upload-artifact) from 3 to 4. - [Release notes](https://github.com/actions/upload-artifact/releases) - [Commits](https://github.com/actions/upload-artifact/compare/v3...v4) --- updated-dependencies: - dependency-name: actions/upload-artifact dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/spotube-release-binary.yml | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/.github/workflows/spotube-release-binary.yml b/.github/workflows/spotube-release-binary.yml index 470544e3..ff305d8b 100644 --- a/.github/workflows/spotube-release-binary.yml +++ b/.github/workflows/spotube-release-binary.yml @@ -89,7 +89,7 @@ jobs: - name: Upload Artifact - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 with: if-no-files-found: error name: Spotube-Release-Binaries @@ -180,7 +180,7 @@ jobs: mv dist/**/spotube-*-linux.rpm dist/Spotube-linux-x86_64.rpm - - uses: actions/upload-artifact@v3 + - uses: actions/upload-artifact@v4 with: if-no-files-found: error name: Spotube-Release-Binaries @@ -257,7 +257,7 @@ jobs: mv build/app/outputs/bundle/${{ inputs.channel }}Release/app-${{ inputs.channel }}-release.aab build/Spotube-playstore-all-arch.aab - - uses: actions/upload-artifact@v3 + - uses: actions/upload-artifact@v4 with: if-no-files-found: error name: Spotube-Release-Binaries @@ -363,7 +363,7 @@ jobs: ln -sf ./build/ios/iphoneos Payload zip -r9 Spotube-iOS.ipa Payload/${{ inputs.channel }}.app - - uses: actions/upload-artifact@v3 + - uses: actions/upload-artifact@v4 with: if-no-files-found: error name: Spotube-Release-Binaries @@ -401,7 +401,7 @@ jobs: sha256sum Spotube-Release-Binaries/* >> RELEASE.sha256sum sed -i 's|Spotube-Release-Binaries/||' RELEASE.sha256sum RELEASE.md5sum - - uses: actions/upload-artifact@v3 + - uses: actions/upload-artifact@v4 with: if-no-files-found: error name: Spotube-Release-Binaries From 9bd16e096f598397b7199c71f7a291a5d439e99b Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 24 Jan 2024 10:18:10 +0600 Subject: [PATCH 115/195] chore(deps): bump go_router from 11.1.2 to 13.0.1 (#1020) Bumps [go_router](https://github.com/flutter/packages/tree/main/packages) from 11.1.2 to 13.0.1. - [Release notes](https://github.com/flutter/packages/releases) - [Commits](https://github.com/flutter/packages/commits/go_router-v13.0.1/packages) --- updated-dependencies: - dependency-name: go_router dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Kingkor Roy Tirtho --- pubspec.lock | 4 ++-- pubspec.yaml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/pubspec.lock b/pubspec.lock index 3835f711..e2809e74 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -1006,10 +1006,10 @@ packages: dependency: "direct main" description: name: go_router - sha256: a07c781bf55bf11ae85133338e4850f0b4e33e261c44a66c750fc707d65d8393 + sha256: "3b40e751eaaa855179b416974d59d29669e750d2e50fcdb2b37f1cb0ca8c803a" url: "https://pub.dev" source: hosted - version: "11.1.2" + version: "13.0.1" google_fonts: dependency: "direct main" description: diff --git a/pubspec.yaml b/pubspec.yaml index d0c51a15..f9da61d2 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -55,8 +55,8 @@ dependencies: flutter_svg: ^1.1.6 form_validator: ^2.1.1 fuzzywuzzy: ^1.1.6 + go_router: ^13.0.1 google_fonts: ^6.1.0 - go_router: ^11.1.2 hive: ^2.2.3 hive_flutter: ^1.1.0 hooks_riverpod: ^2.4.3 From fd1899f162395752142d7aa7320d1c39b0995070 Mon Sep 17 00:00:00 2001 From: Kingkor Roy Tirtho Date: Wed, 24 Jan 2024 10:46:42 +0600 Subject: [PATCH 116/195] fix: audio resumes after a phone call even if it was paused before #926 --- android/app/build.gradle | 2 +- .../audio_services/mobile_audio_service.dart | 17 +++++++++++++---- 2 files changed, 14 insertions(+), 5 deletions(-) diff --git a/android/app/build.gradle b/android/app/build.gradle index df13c9f4..2f85cdeb 100644 --- a/android/app/build.gradle +++ b/android/app/build.gradle @@ -32,7 +32,7 @@ if (keystorePropertiesFile.exists()) { } android { - compileSdkVersion 33 + compileSdkVersion 34 ndkVersion "21.4.7075529" diff --git a/lib/services/audio_services/mobile_audio_service.dart b/lib/services/audio_services/mobile_audio_service.dart index 9750fce8..833df89c 100644 --- a/lib/services/audio_services/mobile_audio_service.dart +++ b/lib/services/audio_services/mobile_audio_service.dart @@ -17,6 +17,9 @@ class MobileAudioService extends BaseAudioHandler { AudioSession.instance.then((s) { session = s; session?.configure(const AudioSessionConfiguration.music()); + + bool wasPausedByBeginEvent = false; + s.interruptionEventStream.listen((event) async { if (event.begin) { switch (event.type) { @@ -25,17 +28,23 @@ class MobileAudioService extends BaseAudioHandler { break; case AudioInterruptionType.pause: case AudioInterruptionType.unknown: - await audioPlayer.pause(); - break; + { + wasPausedByBeginEvent = audioPlayer.isPlaying; + await audioPlayer.pause(); + break; + } } } else { switch (event.type) { case AudioInterruptionType.duck: await audioPlayer.setVolume(1.0); break; - case AudioInterruptionType.pause: - case AudioInterruptionType.unknown: + case AudioInterruptionType.pause when wasPausedByBeginEvent: + case AudioInterruptionType.unknown when wasPausedByBeginEvent: await audioPlayer.resume(); + wasPausedByBeginEvent = false; + break; + default: break; } } From 9d74cf5fc250a6a143321d49b8e045519b4c2872 Mon Sep 17 00:00:00 2001 From: Kingkor Roy Tirtho Date: Wed, 24 Jan 2024 11:45:26 +0600 Subject: [PATCH 117/195] fix(macos): download folder unchangeable --- lib/pages/settings/sections/downloads.dart | 2 +- macos/Runner.xcodeproj/project.pbxproj | 2 +- .../xcshareddata/xcschemes/Runner.xcscheme | 2 +- macos/Runner/DebugProfile.entitlements | 40 ++++++++----------- macos/Runner/Release.entitlements | 36 +++++++---------- pubspec.lock | 40 +++++++++---------- untranslated_messages.json | 5 +++ 7 files changed, 60 insertions(+), 67 deletions(-) diff --git a/lib/pages/settings/sections/downloads.dart b/lib/pages/settings/sections/downloads.dart index 12026909..b1e360d0 100644 --- a/lib/pages/settings/sections/downloads.dart +++ b/lib/pages/settings/sections/downloads.dart @@ -18,7 +18,7 @@ class SettingsDownloadsSection extends HookConsumerWidget { final preferences = ref.watch(userPreferencesProvider); final pickDownloadLocation = useCallback(() async { - if (DesktopTools.platform.isMobile) { + if (DesktopTools.platform.isMobile || DesktopTools.platform.isMacOS) { final dirStr = await FilePicker.platform.getDirectoryPath( initialDirectory: preferences.downloadLocation, ); diff --git a/macos/Runner.xcodeproj/project.pbxproj b/macos/Runner.xcodeproj/project.pbxproj index f7711c83..16e242c7 100644 --- a/macos/Runner.xcodeproj/project.pbxproj +++ b/macos/Runner.xcodeproj/project.pbxproj @@ -208,7 +208,7 @@ isa = PBXProject; attributes = { LastSwiftUpdateCheck = 0920; - LastUpgradeCheck = 1430; + LastUpgradeCheck = 1510; ORGANIZATIONNAME = ""; TargetAttributes = { 33CC10EC2044A3C60003C045 = { diff --git a/macos/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme b/macos/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme index 8f69f0c6..1407feb3 100644 --- a/macos/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme +++ b/macos/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme @@ -1,6 +1,6 @@ - - com.apple.security.app-sandbox - - com.apple.security.cs.allow-jit - - com.apple.security.network.server - - com.apple.security.network.client - - - - - - - com.apple.security.files.user-selected.read-write - - - \ No newline at end of file + + com.apple.security.app-sandbox + + com.apple.security.assets.music.read-write + + com.apple.security.cs.allow-jit + + com.apple.security.files.downloads.read-write + + com.apple.security.files.user-selected.read-write + + com.apple.security.network.client + + com.apple.security.network.server + + + diff --git a/macos/Runner/Release.entitlements b/macos/Runner/Release.entitlements index dc5df580..f05277de 100644 --- a/macos/Runner/Release.entitlements +++ b/macos/Runner/Release.entitlements @@ -1,24 +1,18 @@ - - com.apple.security.app-sandbox - - com.apple.security.network.server - - com.apple.security.network.client - - - - - - - com.apple.security.files.user-selected.read-write - - - \ No newline at end of file + + com.apple.security.app-sandbox + + com.apple.security.assets.music.read-write + + com.apple.security.files.downloads.read-write + + com.apple.security.files.user-selected.read-write + + com.apple.security.network.client + + com.apple.security.network.server + + + diff --git a/pubspec.lock b/pubspec.lock index e2809e74..1a95f20e 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -1259,18 +1259,26 @@ packages: dependency: transitive description: name: leak_tracker - sha256: "04be76c4a4bb50f14904e64749237e541e7c7bcf7ec0b196907322ab5d2fc739" + sha256: "78eb209deea09858f5269f5a5b02be4049535f568c07b275096836f01ea323fa" url: "https://pub.dev" source: hosted - version: "9.0.16" + version: "10.0.0" + leak_tracker_flutter_testing: + dependency: transitive + description: + name: leak_tracker_flutter_testing + sha256: b46c5e37c19120a8a01918cfaf293547f47269f7cb4b0058f21531c2465d6ef0 + url: "https://pub.dev" + source: hosted + version: "2.0.1" leak_tracker_testing: dependency: transitive description: name: leak_tracker_testing - sha256: b06739349ec2477e943055aea30172c5c7000225f79dad4702e2ec0eda79a6ff + sha256: a597f72a664dbd293f3bfc51f9ba69816f84dcd403cdac7066cb3f6003f3ab47 url: "https://pub.dev" source: hosted - version: "1.0.5" + version: "2.0.1" lints: dependency: transitive description: @@ -1315,10 +1323,10 @@ packages: dependency: transitive description: name: matcher - sha256: "1803e76e6653768d64ed8ff2e1e67bea3ad4b923eb5c56a295c3e634bad5960e" + sha256: d2323aa2060500f906aa31a895b4030b6da3ebdcc5619d14ce1aada65cd161cb url: "https://pub.dev" source: hosted - version: "0.12.16" + version: "0.12.16+1" material_color_utilities: dependency: transitive description: @@ -1483,10 +1491,10 @@ packages: dependency: "direct main" description: name: path - sha256: "8829d8a55c13fc0e37127c29fedf290c102f4e40ae94ada574091fe0ff96c917" + sha256: "087ce49c3f0dc39180befefc60fdb4acd8f8620e5682fe2476afd0b3688bb4af" url: "https://pub.dev" source: hosted - version: "1.8.3" + version: "1.9.0" path_drawing: dependency: transitive description: @@ -1611,10 +1619,10 @@ packages: dependency: transitive description: name: platform - sha256: "0a279f0707af40c890e80b1e9df8bb761694c074ba7e1d4ab1bc4b728e200b59" + sha256: "12220bb4b65720483f8fa9450b4332347737cf8213dd2840d8b2c823e47243ec" url: "https://pub.dev" source: hosted - version: "3.1.3" + version: "3.1.4" plugin_platform_interface: dependency: transitive description: @@ -1651,10 +1659,10 @@ packages: dependency: transitive description: name: process - sha256: "266ca5be5820feefc777793d0a583acfc8c40834893c87c00c6c09e2cf58ea42" + sha256: "21e54fd2faf1b5bdd5102afd25012184a6793927648ea81eea80552ac9405b32" url: "https://pub.dev" source: hosted - version: "5.0.1" + version: "5.0.2" provider: dependency: transitive description: @@ -2245,14 +2253,6 @@ packages: url: "https://pub.dev" source: hosted version: "1.1.0" - web: - dependency: transitive - description: - name: web - sha256: edc8a9573dd8c5a83a183dae1af2b6fd4131377404706ca4e5420474784906fa - url: "https://pub.dev" - source: hosted - version: "0.4.0" web_socket_channel: dependency: transitive description: diff --git a/untranslated_messages.json b/untranslated_messages.json index 45a6df11..ae05dfeb 100644 --- a/untranslated_messages.json +++ b/untranslated_messages.json @@ -69,6 +69,11 @@ "no_lyrics_available" ], + "ne": [ + "friends", + "no_lyrics_available" + ], + "nl": [ "step_3_steps", "step_4_steps", From a752cf4c978d1b05851aabb6c84c7862de551320 Mon Sep 17 00:00:00 2001 From: Kingkor Roy Tirtho Date: Wed, 24 Jan 2024 11:50:48 +0600 Subject: [PATCH 118/195] fix: track index not showing after 200 --- lib/components/shared/track_tile/track_tile.dart | 2 +- .../shared/tracks_view/sections/body/track_view_body.dart | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/lib/components/shared/track_tile/track_tile.dart b/lib/components/shared/track_tile/track_tile.dart index c3b03f3c..d268c783 100644 --- a/lib/components/shared/track_tile/track_tile.dart +++ b/lib/components/shared/track_tile/track_tile.dart @@ -110,7 +110,7 @@ class TrackTile extends HookConsumerWidget { ...?leadingActions, if (index != null && onChanged == null && constrains.mdAndUp) SizedBox( - width: 34, + width: 50, child: Padding( padding: const EdgeInsets.symmetric(horizontal: 6), child: Text( diff --git a/lib/components/shared/tracks_view/sections/body/track_view_body.dart b/lib/components/shared/tracks_view/sections/body/track_view_body.dart index 20caf4f1..b7149cc2 100644 --- a/lib/components/shared/tracks_view/sections/body/track_view_body.dart +++ b/lib/components/shared/tracks_view/sections/body/track_view_body.dart @@ -8,7 +8,6 @@ import 'package:skeletonizer/skeletonizer.dart'; import 'package:spotify/spotify.dart'; import 'package:spotube/collections/fake.dart'; import 'package:spotube/components/shared/expandable_search/expandable_search.dart'; -import 'package:spotube/components/shared/fallbacks/not_found.dart'; import 'package:spotube/components/shared/track_tile/track_tile.dart'; import 'package:spotube/components/shared/tracks_view/sections/body/track_view_body_headers.dart'; import 'package:spotube/components/shared/tracks_view/sections/body/use_is_user_playlist.dart'; From b9417ca3575992673357230dab49e0124dd576b1 Mon Sep 17 00:00:00 2001 From: Kingkor Roy Tirtho Date: Wed, 24 Jan 2024 12:03:31 +0600 Subject: [PATCH 119/195] fix(macos): backbutton and window button overlap and unused empty space on home --- .../shared/page_window_title_bar.dart | 61 ++++++++++++------- .../shared/themed_button_tab_bar.dart | 12 +--- lib/pages/home/home.dart | 10 ++- 3 files changed, 47 insertions(+), 36 deletions(-) diff --git a/lib/components/shared/page_window_title_bar.dart b/lib/components/shared/page_window_title_bar.dart index 4f522e0c..9aa2d4a8 100644 --- a/lib/components/shared/page_window_title_bar.dart +++ b/lib/components/shared/page_window_title_bar.dart @@ -62,28 +62,45 @@ class _PageWindowTitleBarState extends ConsumerState { @override Widget build(BuildContext context) { - return GestureDetector( - onHorizontalDragStart: onDrag, - onVerticalDragStart: onDrag, - child: AppBar( - leading: widget.leading, - automaticallyImplyLeading: widget.automaticallyImplyLeading, - actions: [ - ...?widget.actions, - WindowTitleBarButtons(foregroundColor: widget.foregroundColor), - ], - backgroundColor: widget.backgroundColor, - foregroundColor: widget.foregroundColor, - actionsIconTheme: widget.actionsIconTheme, - centerTitle: widget.centerTitle, - titleSpacing: widget.titleSpacing, - toolbarOpacity: widget.toolbarOpacity, - leadingWidth: widget.leadingWidth, - toolbarTextStyle: widget.toolbarTextStyle, - titleTextStyle: widget.titleTextStyle, - title: widget.title, - ), - ); + final mediaQuery = MediaQuery.of(context); + + return LayoutBuilder(builder: (context, constrains) { + final hasFullscreen = mediaQuery.size.width == constrains.maxWidth; + final hasLeadingOrCanPop = + widget.leading != null || Navigator.canPop(context); + + return GestureDetector( + onHorizontalDragStart: onDrag, + onVerticalDragStart: onDrag, + child: Padding( + padding: EdgeInsets.only( + left: DesktopTools.platform.isMacOS && + hasFullscreen && + hasLeadingOrCanPop + ? 65 + : 0, + ), + child: AppBar( + leading: widget.leading, + automaticallyImplyLeading: widget.automaticallyImplyLeading, + actions: [ + ...?widget.actions, + WindowTitleBarButtons(foregroundColor: widget.foregroundColor), + ], + backgroundColor: widget.backgroundColor, + foregroundColor: widget.foregroundColor, + actionsIconTheme: widget.actionsIconTheme, + centerTitle: widget.centerTitle, + titleSpacing: widget.titleSpacing, + toolbarOpacity: widget.toolbarOpacity, + leadingWidth: widget.leadingWidth, + toolbarTextStyle: widget.toolbarTextStyle, + titleTextStyle: widget.titleTextStyle, + title: widget.title, + ), + ), + ); + }); } } diff --git a/lib/components/shared/themed_button_tab_bar.dart b/lib/components/shared/themed_button_tab_bar.dart index 079a4e8a..d5798189 100644 --- a/lib/components/shared/themed_button_tab_bar.dart +++ b/lib/components/shared/themed_button_tab_bar.dart @@ -1,9 +1,7 @@ import 'package:buttons_tabbar/buttons_tabbar.dart'; import 'package:flutter/material.dart'; import 'package:flutter_hooks/flutter_hooks.dart'; -import 'package:spotube/hooks/utils/use_breakpoint_value.dart'; import 'package:spotube/hooks/utils/use_brightness_value.dart'; -import 'package:spotube/utils/platform.dart'; class ThemedButtonsTabBar extends HookWidget implements PreferredSizeWidget { final List tabs; @@ -17,16 +15,8 @@ class ThemedButtonsTabBar extends HookWidget implements PreferredSizeWidget { Color.lerp(theme.colorScheme.primary, Colors.black, 0.7)!, ); - final breakpoint = useBreakpointValue( - xs: 85.0, - sm: 85.0, - md: 35.0, - others: 0.0, - ); - return Padding( - padding: EdgeInsets.only( - left: kIsMacOS ? breakpoint : 0, + padding: const EdgeInsets.only( top: 8, bottom: 8, ), diff --git a/lib/pages/home/home.dart b/lib/pages/home/home.dart index eb2ddb94..2994eac3 100644 --- a/lib/pages/home/home.dart +++ b/lib/pages/home/home.dart @@ -1,6 +1,7 @@ import 'package:flutter/material.dart'; import 'package:flutter_desktop_tools/flutter_desktop_tools.dart'; import 'package:flutter_hooks/flutter_hooks.dart'; +import 'package:gap/gap.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:spotube/components/home/sections/featured.dart'; import 'package:spotube/components/home/sections/friends.dart'; @@ -19,12 +20,15 @@ class HomePage extends HookConsumerWidget { return SafeArea( bottom: false, child: Scaffold( - appBar: DesktopTools.platform.isMobile - ? null - : const PageWindowTitleBar(), + appBar: + DesktopTools.platform.isLinux || DesktopTools.platform.isWindows + ? const PageWindowTitleBar() + : null, body: CustomScrollView( controller: controller, slivers: [ + if (DesktopTools.platform.isMacOS || DesktopTools.platform.isWeb) + const SliverGap(20), const HomeGenresSection(), SliverList.list( children: const [ From eb7477273f159df368e0a15d4c5b8d2aeabdd4de Mon Sep 17 00:00:00 2001 From: Kingkor Roy Tirtho Date: Wed, 24 Jan 2024 12:11:49 +0600 Subject: [PATCH 120/195] chore: fix wrong audio source result showing up in Alternative track sheet --- .../player/sibling_tracks_sheet.dart | 59 ++++++++++++------- 1 file changed, 37 insertions(+), 22 deletions(-) diff --git a/lib/components/player/sibling_tracks_sheet.dart b/lib/components/player/sibling_tracks_sheet.dart index 181c363a..58b1ca8c 100644 --- a/lib/components/player/sibling_tracks_sheet.dart +++ b/lib/components/player/sibling_tracks_sheet.dart @@ -82,35 +82,50 @@ class SiblingTracksSheet extends HookConsumerWidget { if (searchTerm.trim().isEmpty) { return []; } - - final resultsYt = await youtubeClient.search.search(searchTerm.trim()); - final resultsJioSaavn = - await jiosaavnClient.search.songs(searchTerm.trim()); - - final searchResults = await Future.wait([ - ...resultsJioSaavn.results.mapIndexed((i, song) async { + if (preferences.audioSource == AudioSource.jiosaavn) { + final resultsJioSaavn = + await jiosaavnClient.search.songs(searchTerm.trim()); + final results = await Future.wait( + resultsJioSaavn.results.mapIndexed((i, song) async { final siblingType = JioSaavnSourcedTrack.toSiblingType(song); return siblingType.info; - }), - ...resultsYt - .map(YoutubeVideoInfo.fromVideo) - .mapIndexed((i, video) async { - final siblingType = await YoutubeSourcedTrack.toSiblingType(i, video); - return siblingType.info; - }), - ]); - final activeSourceInfo = - (playlist.activeTrack! as SourcedTrack).sourceInfo; - return searchResults - ..removeWhere((element) => element.id == activeSourceInfo.id) - ..insert( - 0, - activeSourceInfo, + })); + + final activeSourceInfo = + (playlist.activeTrack! as SourcedTrack).sourceInfo; + + return results + ..removeWhere((element) => element.id == activeSourceInfo.id) + ..insert( + 0, + activeSourceInfo, + ); + } else { + final resultsYt = await youtubeClient.search.search(searchTerm.trim()); + + final searchResults = await Future.wait( + resultsYt + .map(YoutubeVideoInfo.fromVideo) + .mapIndexed((i, video) async { + final siblingType = + await YoutubeSourcedTrack.toSiblingType(i, video); + return siblingType.info; + }), ); + final activeSourceInfo = + (playlist.activeTrack! as SourcedTrack).sourceInfo; + return searchResults + ..removeWhere((element) => element.id == activeSourceInfo.id) + ..insert( + 0, + activeSourceInfo, + ); + } }, [ searchTerm, searchMode.value, playlist.activeTrack, + preferences.audioSource, ]); final siblings = useMemoized( From 624220090572eb643dce37ca8ffd85d2b3f5c9df Mon Sep 17 00:00:00 2001 From: Kingkor Roy Tirtho Date: Wed, 24 Jan 2024 12:29:35 +0600 Subject: [PATCH 121/195] feat: haptic feedback on long press and reordering actions --- lib/components/player/player_queue.dart | 6 ++++++ .../shared/tracks_view/sections/body/track_view_body.dart | 2 ++ 2 files changed, 8 insertions(+) diff --git a/lib/components/player/player_queue.dart b/lib/components/player/player_queue.dart index 8142740c..2784fb5f 100644 --- a/lib/components/player/player_queue.dart +++ b/lib/components/player/player_queue.dart @@ -210,6 +210,12 @@ class PlayerQueue extends HookConsumerWidget { itemCount: tracks.length, shrinkWrap: true, buildDefaultDragHandles: false, + onReorderStart: (index) { + HapticFeedback.selectionClick(); + }, + onReorderEnd: (index) { + HapticFeedback.selectionClick(); + }, itemBuilder: (context, i) { final track = tracks.elementAt(i); return AutoScrollTag( diff --git a/lib/components/shared/tracks_view/sections/body/track_view_body.dart b/lib/components/shared/tracks_view/sections/body/track_view_body.dart index b7149cc2..33c8fa82 100644 --- a/lib/components/shared/tracks_view/sections/body/track_view_body.dart +++ b/lib/components/shared/tracks_view/sections/body/track_view_body.dart @@ -1,5 +1,6 @@ import 'package:collection/collection.dart'; import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; import 'package:flutter_hooks/flutter_hooks.dart'; import 'package:fuzzywuzzy/fuzzywuzzy.dart'; import 'package:gap/gap.dart'; @@ -116,6 +117,7 @@ class TrackViewBodySection extends HookConsumerWidget { }, onLongPress: () { trackViewState.selectTrack(track.id!); + HapticFeedback.selectionClick(); }, onTap: () async { if (trackViewState.isSelecting) { From 1b5d435b86764e156c8f6d203b8ba46dede5dc15 Mon Sep 17 00:00:00 2001 From: Kingkor Roy Tirtho Date: Wed, 24 Jan 2024 12:46:27 +0600 Subject: [PATCH 122/195] cd: add macos pkg format --- .github/workflows/spotube-release-binary.yml | 17 ++++++++++++++++- ios/Runner.xcodeproj/project.pbxproj | 12 ++++++++++++ macos/packaging/pkg/make_config.yaml | 1 + 3 files changed, 29 insertions(+), 1 deletion(-) create mode 100644 macos/packaging/pkg/make_config.yaml diff --git a/.github/workflows/spotube-release-binary.yml b/.github/workflows/spotube-release-binary.yml index ff305d8b..27ae683e 100644 --- a/.github/workflows/spotube-release-binary.yml +++ b/.github/workflows/spotube-release-binary.yml @@ -320,9 +320,24 @@ jobs: npm install -g appdmg mkdir -p build/${{ env.BUILD_VERSION }} appdmg appdmg.json build/Spotube-macos-universal.dmg + flutter_distributor package --platform=macos --targets pkg --skip-clean + mv dist/**/spotube-*-macos.pkg build/Spotube-macos-universal.pkg + + - uses: actions/upload-artifact@v4 + with: + if-no-files-found: error + name: Spotube-Release-Binaries + path: | + build/Spotube-macos-universal.dmg + build/Spotube-macos-universal.pkg + + - name: Debug With SSH When fails + if: ${{ failure() && inputs.debug && inputs.channel == 'nightly' }} + uses: mxschmitt/action-tmate@v3 + with: + limit-access-to-actor: true iOS: - runs-on: macos-latest steps: - uses: actions/checkout@v4 diff --git a/ios/Runner.xcodeproj/project.pbxproj b/ios/Runner.xcodeproj/project.pbxproj index 8b7c2b1e..6edf52e3 100644 --- a/ios/Runner.xcodeproj/project.pbxproj +++ b/ios/Runner.xcodeproj/project.pbxproj @@ -882,6 +882,7 @@ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CLANG_ENABLE_MODULES = YES; CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; + DEVELOPMENT_TEAM = 88NVGSJ5N3; ENABLE_BITCODE = NO; INFOPLIST_FILE = Runner/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -1010,6 +1011,7 @@ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CLANG_ENABLE_MODULES = YES; CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; + DEVELOPMENT_TEAM = 88NVGSJ5N3; ENABLE_BITCODE = NO; INFOPLIST_FILE = Runner/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -1032,6 +1034,7 @@ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CLANG_ENABLE_MODULES = YES; CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; + DEVELOPMENT_TEAM = 88NVGSJ5N3; ENABLE_BITCODE = NO; INFOPLIST_FILE = Runner/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -1172,6 +1175,7 @@ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CLANG_ENABLE_MODULES = YES; CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; + DEVELOPMENT_TEAM = 88NVGSJ5N3; ENABLE_BITCODE = NO; INFOPLIST_FILE = Runner/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -1268,6 +1272,7 @@ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CLANG_ENABLE_MODULES = YES; CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; + DEVELOPMENT_TEAM = 88NVGSJ5N3; ENABLE_BITCODE = NO; INFOPLIST_FILE = Runner/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -1360,6 +1365,7 @@ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CLANG_ENABLE_MODULES = YES; CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; + DEVELOPMENT_TEAM = 88NVGSJ5N3; ENABLE_BITCODE = NO; INFOPLIST_FILE = Runner/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -1585,6 +1591,7 @@ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CLANG_ENABLE_MODULES = YES; CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; + DEVELOPMENT_TEAM = 88NVGSJ5N3; ENABLE_BITCODE = NO; INFOPLIST_FILE = Runner/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -1703,6 +1710,7 @@ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CLANG_ENABLE_MODULES = YES; CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; + DEVELOPMENT_TEAM = 88NVGSJ5N3; ENABLE_BITCODE = NO; INFOPLIST_FILE = Runner/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -1816,6 +1824,7 @@ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CLANG_ENABLE_MODULES = YES; CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; + DEVELOPMENT_TEAM = 88NVGSJ5N3; ENABLE_BITCODE = NO; INFOPLIST_FILE = Runner/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -2126,6 +2135,7 @@ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CLANG_ENABLE_MODULES = YES; CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; + DEVELOPMENT_TEAM = 88NVGSJ5N3; ENABLE_BITCODE = NO; INFOPLIST_FILE = Runner/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -2266,6 +2276,7 @@ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CLANG_ENABLE_MODULES = YES; CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; + DEVELOPMENT_TEAM = 88NVGSJ5N3; ENABLE_BITCODE = NO; INFOPLIST_FILE = Runner/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -2400,6 +2411,7 @@ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CLANG_ENABLE_MODULES = YES; CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; + DEVELOPMENT_TEAM = 88NVGSJ5N3; ENABLE_BITCODE = NO; INFOPLIST_FILE = Runner/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( diff --git a/macos/packaging/pkg/make_config.yaml b/macos/packaging/pkg/make_config.yaml new file mode 100644 index 00000000..06d92076 --- /dev/null +++ b/macos/packaging/pkg/make_config.yaml @@ -0,0 +1 @@ +install-path: /Applications From 6351306f87e2ffe273e8b1eb614ebb7a3d7db0e9 Mon Sep 17 00:00:00 2001 From: Kingkor Roy Tirtho Date: Wed, 24 Jan 2024 22:12:13 +0600 Subject: [PATCH 123/195] cd: downgrade upload and download artifact to v3 for merging --- .github/workflows/spotube-release-binary.yml | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/.github/workflows/spotube-release-binary.yml b/.github/workflows/spotube-release-binary.yml index 27ae683e..2b16148f 100644 --- a/.github/workflows/spotube-release-binary.yml +++ b/.github/workflows/spotube-release-binary.yml @@ -89,7 +89,7 @@ jobs: - name: Upload Artifact - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@v3 with: if-no-files-found: error name: Spotube-Release-Binaries @@ -180,7 +180,7 @@ jobs: mv dist/**/spotube-*-linux.rpm dist/Spotube-linux-x86_64.rpm - - uses: actions/upload-artifact@v4 + - uses: actions/upload-artifact@v3 with: if-no-files-found: error name: Spotube-Release-Binaries @@ -257,7 +257,7 @@ jobs: mv build/app/outputs/bundle/${{ inputs.channel }}Release/app-${{ inputs.channel }}-release.aab build/Spotube-playstore-all-arch.aab - - uses: actions/upload-artifact@v4 + - uses: actions/upload-artifact@v3 with: if-no-files-found: error name: Spotube-Release-Binaries @@ -323,7 +323,7 @@ jobs: flutter_distributor package --platform=macos --targets pkg --skip-clean mv dist/**/spotube-*-macos.pkg build/Spotube-macos-universal.pkg - - uses: actions/upload-artifact@v4 + - uses: actions/upload-artifact@v3 with: if-no-files-found: error name: Spotube-Release-Binaries @@ -378,7 +378,7 @@ jobs: ln -sf ./build/ios/iphoneos Payload zip -r9 Spotube-iOS.ipa Payload/${{ inputs.channel }}.app - - uses: actions/upload-artifact@v4 + - uses: actions/upload-artifact@v3 with: if-no-files-found: error name: Spotube-Release-Binaries @@ -401,7 +401,7 @@ jobs: - macos - iOS steps: - - uses: actions/download-artifact@v4 + - uses: actions/download-artifact@v3 with: name: Spotube-Release-Binaries path: ./Spotube-Release-Binaries @@ -416,7 +416,7 @@ jobs: sha256sum Spotube-Release-Binaries/* >> RELEASE.sha256sum sed -i 's|Spotube-Release-Binaries/||' RELEASE.sha256sum RELEASE.md5sum - - uses: actions/upload-artifact@v4 + - uses: actions/upload-artifact@v3 with: if-no-files-found: error name: Spotube-Release-Binaries From 14d8ea582cd8c362f33dee821d92084a76dd7c4e Mon Sep 17 00:00:00 2001 From: Kingkor Roy Tirtho Date: Wed, 24 Jan 2024 22:25:15 +0600 Subject: [PATCH 124/195] cd: add flutter_distributor for macos --- .github/workflows/spotube-release-binary.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/spotube-release-binary.yml b/.github/workflows/spotube-release-binary.yml index 2b16148f..dd20ca5d 100644 --- a/.github/workflows/spotube-release-binary.yml +++ b/.github/workflows/spotube-release-binary.yml @@ -304,8 +304,8 @@ jobs: - name: Generate Secrets run: | + dart pub global activate flutter_distributor flutter pub get - flutter pub remove media_kit_native_event_loop dart run build_runner build --delete-conflicting-outputs --enable-experiment=records,patterns - name: Build Macos App From 62fde50442f04f93255b5b1b1dcca23d116a13ec Mon Sep 17 00:00:00 2001 From: Kingkor Roy Tirtho Date: Sat, 27 Jan 2024 20:59:50 +0600 Subject: [PATCH 125/195] fix: alternative source doesn't persist on next restart #840 --- lib/components/root/sidebar.dart | 3 +++ lib/services/sourced_track/sources/jiosaavn.dart | 10 ++++++++++ lib/services/sourced_track/sources/piped.dart | 10 ++++++++++ lib/services/sourced_track/sources/youtube.dart | 10 ++++++++++ macos/Runner.xcodeproj/project.pbxproj | 11 ++++++++++- macos/Runner/RunnerDebug.entitlements | 6 ++++++ 6 files changed, 49 insertions(+), 1 deletion(-) diff --git a/lib/components/root/sidebar.dart b/lib/components/root/sidebar.dart index 9b3fd3ed..a55ef947 100644 --- a/lib/components/root/sidebar.dart +++ b/lib/components/root/sidebar.dart @@ -182,6 +182,9 @@ class Sidebar extends HookConsumerWidget { ), itemTextPadding: const EdgeInsets.only(left: 10), selectedItemTextPadding: const EdgeInsets.only(left: 10), + hoverTextStyle: theme.textTheme.bodyMedium?.copyWith( + color: theme.colorScheme.primary, + ), ), ), ), diff --git a/lib/services/sourced_track/sources/jiosaavn.dart b/lib/services/sourced_track/sources/jiosaavn.dart index 281be998..7455f4d7 100644 --- a/lib/services/sourced_track/sources/jiosaavn.dart +++ b/lib/services/sourced_track/sources/jiosaavn.dart @@ -185,6 +185,16 @@ class JioSaavnSourcedTrack extends SourcedTrack { final (:info, :source) = toSiblingType(item); + await SourceMatch.box.put( + id!, + SourceMatch( + id: id!, + sourceType: SourceType.jiosaavn, + createdAt: DateTime.now(), + sourceId: info.id, + ), + ); + return JioSaavnSourcedTrack( ref: ref, siblings: newSiblings, diff --git a/lib/services/sourced_track/sources/piped.dart b/lib/services/sourced_track/sources/piped.dart index f9e4368d..52364ce8 100644 --- a/lib/services/sourced_track/sources/piped.dart +++ b/lib/services/sourced_track/sources/piped.dart @@ -263,6 +263,16 @@ class PipedSourcedTrack extends SourcedTrack { final manifest = await pipedClient.streams(newSourceInfo.id); + await SourceMatch.box.put( + id!, + SourceMatch( + id: id!, + sourceType: SourceType.jiosaavn, + createdAt: DateTime.now(), + sourceId: newSourceInfo.id, + ), + ); + return PipedSourcedTrack( ref: ref, siblings: newSiblings, diff --git a/lib/services/sourced_track/sources/youtube.dart b/lib/services/sourced_track/sources/youtube.dart index c4105d75..8708fc03 100644 --- a/lib/services/sourced_track/sources/youtube.dart +++ b/lib/services/sourced_track/sources/youtube.dart @@ -246,6 +246,16 @@ class YoutubeSourcedTrack extends SourcedTrack { final manifest = await youtubeClient.videos.streamsClient.getManifest(newSourceInfo.id); + await SourceMatch.box.put( + id!, + SourceMatch( + id: id!, + sourceType: SourceType.jiosaavn, + createdAt: DateTime.now(), + sourceId: newSourceInfo.id, + ), + ); + return YoutubeSourcedTrack( ref: ref, siblings: newSiblings, diff --git a/macos/Runner.xcodeproj/project.pbxproj b/macos/Runner.xcodeproj/project.pbxproj index 16e242c7..e2e72334 100644 --- a/macos/Runner.xcodeproj/project.pbxproj +++ b/macos/Runner.xcodeproj/project.pbxproj @@ -228,7 +228,7 @@ }; }; buildConfigurationList = 33CC10E82044A3C60003C045 /* Build configuration list for PBXProject "Runner" */; - compatibilityVersion = "Xcode 9.3"; + compatibilityVersion = "Xcode 12.0"; developmentRegion = en; hasScannedForEncodings = 0; knownRegions = ( @@ -427,7 +427,10 @@ CODE_SIGN_ENTITLEMENTS = Runner/DebugProfile.entitlements; CODE_SIGN_STYLE = Automatic; COMBINE_HIDPI_IMAGES = YES; + DEVELOPMENT_TEAM = 88NVGSJ5N3; INFOPLIST_FILE = Runner/Info.plist; + INFOPLIST_KEY_CFBundleDisplayName = Spotube; + INFOPLIST_KEY_LSApplicationCategoryType = "public.app-category.music"; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/../Frameworks", @@ -554,7 +557,10 @@ CODE_SIGN_ENTITLEMENTS = Runner/RunnerDebug.entitlements; CODE_SIGN_STYLE = Automatic; COMBINE_HIDPI_IMAGES = YES; + DEVELOPMENT_TEAM = 88NVGSJ5N3; INFOPLIST_FILE = Runner/Info.plist; + INFOPLIST_KEY_CFBundleDisplayName = Spotube; + INFOPLIST_KEY_LSApplicationCategoryType = "public.app-category.music"; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/../Frameworks", @@ -575,7 +581,10 @@ CODE_SIGN_ENTITLEMENTS = Runner/Release.entitlements; CODE_SIGN_STYLE = Automatic; COMBINE_HIDPI_IMAGES = YES; + DEVELOPMENT_TEAM = 88NVGSJ5N3; INFOPLIST_FILE = Runner/Info.plist; + INFOPLIST_KEY_CFBundleDisplayName = Spotube; + INFOPLIST_KEY_LSApplicationCategoryType = "public.app-category.music"; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/../Frameworks", diff --git a/macos/Runner/RunnerDebug.entitlements b/macos/Runner/RunnerDebug.entitlements index 3ba6c126..e9de2261 100644 --- a/macos/Runner/RunnerDebug.entitlements +++ b/macos/Runner/RunnerDebug.entitlements @@ -4,8 +4,14 @@ com.apple.security.app-sandbox + com.apple.security.assets.music.read-write + com.apple.security.cs.allow-jit + com.apple.security.files.downloads.read-write + + com.apple.security.files.user-selected.read-write + com.apple.security.network.client com.apple.security.network.server From 5fa56387fddc2fbf062126839bf5fdfc9176e7d5 Mon Sep 17 00:00:00 2001 From: Kingkor Roy Tirtho Date: Sat, 27 Jan 2024 21:18:13 +0600 Subject: [PATCH 126/195] chore: move friends above new releases Because friends matters more than Elton John's 69th album (joking) --- lib/pages/home/home.dart | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/lib/pages/home/home.dart b/lib/pages/home/home.dart index 2994eac3..dbec0564 100644 --- a/lib/pages/home/home.dart +++ b/lib/pages/home/home.dart @@ -1,4 +1,6 @@ +import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; +import 'package:flutter/widgets.dart'; import 'package:flutter_desktop_tools/flutter_desktop_tools.dart'; import 'package:flutter_hooks/flutter_hooks.dart'; import 'package:gap/gap.dart'; @@ -30,13 +32,9 @@ class HomePage extends HookConsumerWidget { if (DesktopTools.platform.isMacOS || DesktopTools.platform.isWeb) const SliverGap(20), const HomeGenresSection(), - SliverList.list( - children: const [ - HomeFeaturedSection(), - HomeNewReleasesSection(), - ], - ), + const SliverToBoxAdapter(child: HomeFeaturedSection()), const HomePageFriendsSection(), + const SliverToBoxAdapter(child: HomeNewReleasesSection()), const SliverSafeArea(sliver: HomeMadeForUserSection()), ], ), From 8184555ee89fd30aaf886af9fc1d52c142fdebb0 Mon Sep 17 00:00:00 2001 From: Kingkor Roy Tirtho Date: Sat, 27 Jan 2024 21:48:38 +0600 Subject: [PATCH 127/195] feat: improve youtube/piped matching by suffixing "- Topic" --- lib/provider/piped_instances_provider.dart | 10 ++++++++-- lib/services/sourced_track/sources/piped.dart | 2 +- lib/services/sourced_track/sources/youtube.dart | 2 +- 3 files changed, 10 insertions(+), 4 deletions(-) diff --git a/lib/provider/piped_instances_provider.dart b/lib/provider/piped_instances_provider.dart index 264b7048..d571f730 100644 --- a/lib/provider/piped_instances_provider.dart +++ b/lib/provider/piped_instances_provider.dart @@ -1,11 +1,17 @@ +import 'package:catcher_2/catcher_2.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:piped_client/piped_client.dart'; import 'package:spotube/services/sourced_track/sources/piped.dart'; final pipedInstancesFutureProvider = FutureProvider>( (ref) async { - final pipedClient = ref.watch(pipedProvider); + try { + final pipedClient = ref.watch(pipedProvider); - return await pipedClient.instanceList(); + return await pipedClient.instanceList(); + } catch (e, stack) { + Catcher2.reportCheckedError(e, stack); + return []; + } }, ); diff --git a/lib/services/sourced_track/sources/piped.dart b/lib/services/sourced_track/sources/piped.dart index 52364ce8..8a1ec1bc 100644 --- a/lib/services/sourced_track/sources/piped.dart +++ b/lib/services/sourced_track/sources/piped.dart @@ -160,7 +160,7 @@ class PipedSourcedTrack extends SourcedTrack { final query = SourcedTrack.getSearchTerm(track); final PipedSearchResult(items: searchResults) = await pipedClient.search( - query, + "$query - Topic", preference.searchMode == SearchMode.youtube ? PipedFilter.video : PipedFilter.musicSongs, diff --git a/lib/services/sourced_track/sources/youtube.dart b/lib/services/sourced_track/sources/youtube.dart index 8708fc03..f363937c 100644 --- a/lib/services/sourced_track/sources/youtube.dart +++ b/lib/services/sourced_track/sources/youtube.dart @@ -210,7 +210,7 @@ class YoutubeSourcedTrack extends SourcedTrack { final query = SourcedTrack.getSearchTerm(track); final searchResults = await youtubeClient.search.search( - query, + "$query - Topic", filter: TypeFilters.video, ); From 2168a640af3104a43139c303d78e2c2326a1bda7 Mon Sep 17 00:00:00 2001 From: Kingkor Roy Tirtho Date: Sat, 27 Jan 2024 21:59:10 +0600 Subject: [PATCH 128/195] feat: add create playlist button in add playlist dialog --- .../dialogs/playlist_add_track_dialog.dart | 16 +++++++++++++++- lib/services/mutations/playlist.dart | 6 +++--- 2 files changed, 18 insertions(+), 4 deletions(-) diff --git a/lib/components/shared/dialogs/playlist_add_track_dialog.dart b/lib/components/shared/dialogs/playlist_add_track_dialog.dart index 1c8e5aaa..51b77c76 100644 --- a/lib/components/shared/dialogs/playlist_add_track_dialog.dart +++ b/lib/components/shared/dialogs/playlist_add_track_dialog.dart @@ -1,9 +1,11 @@ import 'package:fl_query_hooks/fl_query_hooks.dart'; import 'package:flutter/material.dart'; import 'package:flutter_hooks/flutter_hooks.dart'; +import 'package:gap/gap.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:spotify/spotify.dart'; +import 'package:spotube/components/playlist/playlist_create_dialog.dart'; import 'package:spotube/components/shared/image/universal_image.dart'; import 'package:spotube/extensions/context.dart'; import 'package:spotube/provider/spotify_provider.dart'; @@ -22,6 +24,7 @@ class PlaylistAddTrackDialog extends HookConsumerWidget { @override Widget build(BuildContext context, ref) { + final ThemeData(:textTheme) = Theme.of(context); final spotify = ref.watch(spotifyProvider); final userPlaylists = useQueries.playlist.ofMineAll(ref); @@ -69,7 +72,18 @@ class PlaylistAddTrackDialog extends HookConsumerWidget { } return AlertDialog( - title: Text(context.l10n.add_to_playlist), + insetPadding: EdgeInsets.zero, + title: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Text( + context.l10n.add_to_playlist, + style: textTheme.titleMedium, + ), + const Gap(20), + const PlaylistCreateDialogButton(), + ], + ), actions: [ OutlinedButton( child: Text(context.l10n.cancel), diff --git a/lib/services/mutations/playlist.dart b/lib/services/mutations/playlist.dart index 077fff06..f480c565 100644 --- a/lib/services/mutations/playlist.dart +++ b/lib/services/mutations/playlist.dart @@ -94,9 +94,8 @@ class PlaylistMutations { return playlist; }, - refreshInfiniteQueries: [ - "current-user-playlists", - ], + refreshInfiniteQueries: ["current-user-playlists"], + refreshQueries: ["current-user-all-playlists"], ref: ref, onError: (error, recoveryData) { onError?.call(error); @@ -135,6 +134,7 @@ class PlaylistMutations { "playlist/$playlistId", "current-user-playlists", ], + refreshQueries: ["current-user-all-playlists"], ref: ref, onError: (error, recoveryData) { onError?.call(error); From bcba45fbd1def38d1e2d34ba2169bc062be33a11 Mon Sep 17 00:00:00 2001 From: Kingkor Roy Tirtho Date: Sat, 27 Jan 2024 22:27:27 +0600 Subject: [PATCH 129/195] chore: bump version and add changelogs --- CHANGELOG.md | 33 ++++++++++ README.md | 14 ++--- lib/l10n/app_ar.arb | 6 +- lib/l10n/app_bn.arb | 6 +- lib/l10n/app_ca.arb | 6 +- lib/l10n/app_de.arb | 6 +- lib/l10n/app_es.arb | 6 +- lib/l10n/app_fa.arb | 6 +- lib/l10n/app_fr.arb | 6 +- lib/l10n/app_hi.arb | 6 +- lib/l10n/app_it.arb | 6 +- lib/l10n/app_ja.arb | 6 +- lib/l10n/app_ne.arb | 6 +- lib/l10n/app_nl.arb | 6 +- lib/l10n/app_pl.arb | 6 +- lib/l10n/app_pt.arb | 6 +- lib/l10n/app_ru.arb | 6 +- lib/l10n/app_tr.arb | 6 +- lib/l10n/app_uk.arb | 6 +- lib/l10n/app_zh.arb | 6 +- pubspec.yaml | 2 +- untranslated_messages.json | 126 +------------------------------------ 22 files changed, 131 insertions(+), 152 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index ea429caa..9d784485 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,39 @@ All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines. +## [3.5.0](https://personal.github.com/krtirtho/spotube/compare/v3.4.0...v3.5.0) (2024-01-27) + + +### Features + +* add create playlist button in add playlist dialog ([2168a64](https://personal.github.com/krtirtho/spotube/commit/2168a640af3104a43139c303d78e2c2326a1bda7)) +* add spotify friends activity ([#1130](https://personal.github.com/krtirtho/spotube/issues/1130)) ([7983932](https://personal.github.com/krtirtho/spotube/commit/79839329b0970acccb0c566a31eee508adbc8557)) +* **deep-link:** add track opening page ([988a975](https://personal.github.com/krtirtho/spotube/commit/988a975bf1a675df0cfc7b17776bcec74c67f1f2)) +* haptic feedback on long press and reordering actions ([6242200](https://personal.github.com/krtirtho/spotube/commit/624220090572eb643dce37ca8ffd85d2b3f5c9df)) +* improve youtube/piped matching by suffixing "- Topic" ([8184555](https://personal.github.com/krtirtho/spotube/commit/8184555ee89fd30aaf886af9fc1d52c142fdebb0)) +* **translations:** add Nepali (नेपाली) translations ([#1111](https://personal.github.com/krtirtho/spotube/issues/1111)) ([c3ebf56](https://personal.github.com/krtirtho/spotube/commit/c3ebf56ac149b0af8815a5533fe6c386df743440)), closes [#1074](https://personal.github.com/krtirtho/spotube/issues/1074) [#1100](https://personal.github.com/krtirtho/spotube/issues/1100) + + +### Bug Fixes + +* alternative searched sources doesn't play [#1059](https://personal.github.com/krtirtho/spotube/issues/1059) ([a8e9b82](https://personal.github.com/krtirtho/spotube/commit/a8e9b824f33add8f6a83f0d147e889eb6beeb442)) +* alternative source doesn't persist on next restart [#840](https://personal.github.com/krtirtho/spotube/issues/840) ([62fde50](https://personal.github.com/krtirtho/spotube/commit/62fde50442f04f93255b5b1b1dcca23d116a13ec)) +* **android:** download failing for permission issues [#1015](https://personal.github.com/krtirtho/spotube/issues/1015) ([5509cae](https://personal.github.com/krtirtho/spotube/commit/5509cae91c8b1f5cb9fac179060f477397a4a27f)) +* artist page error [#1018](https://personal.github.com/krtirtho/spotube/issues/1018) ([8cd650b](https://personal.github.com/krtirtho/spotube/commit/8cd650b07e5f4c4c2f296bf4374e5ee67fb3eb50)) +* audio resumes after a phone call even if it was paused before [#926](https://personal.github.com/krtirtho/spotube/issues/926) ([fd1899f](https://personal.github.com/krtirtho/spotube/commit/fd1899f162395752142d7aa7320d1c39b0995070)) +* better error message for failing to find lyrics [#1085](https://personal.github.com/krtirtho/spotube/issues/1085) ([e58e18d](https://personal.github.com/krtirtho/spotube/commit/e58e18de33d7bc6fb0e4ddd7ccf6ea14472642b1)) +* Black window flash when starting the app ([#1003](https://personal.github.com/krtirtho/spotube/issues/1003)) ([02e44fc](https://personal.github.com/krtirtho/spotube/commit/02e44fc6b849a873adad382f5d46ed8caf32359f)) +* **linux:** crash after login ([0dfd401](https://personal.github.com/krtirtho/spotube/commit/0dfd40153714b7a4b83ac30f0c56830bc0c05ffd)) +* **macos:** backbutton and window button overlap and unused empty space on home ([b9417ca](https://personal.github.com/krtirtho/spotube/commit/b9417ca3575992673357230dab49e0124dd576b1)) +* **macos:** download folder unchangeable ([9d74cf5](https://personal.github.com/krtirtho/spotube/commit/9d74cf5fc250a6a143321d49b8e045519b4c2872)) +* **macos:** Respect Minimize to tray option ([#1001](https://personal.github.com/krtirtho/spotube/issues/1001)) ([69559ba](https://personal.github.com/krtirtho/spotube/commit/69559ba24285636e42b2f2231f956c31388c5cf3)) +* **macos:** system tray shows name and sidebar weird gap [#1083](https://personal.github.com/krtirtho/spotube/issues/1083) ([27057ea](https://personal.github.com/krtirtho/spotube/commit/27057ea0c8d83c9701057c18b473f1af4e4e82be)) +* releases section is empty when user doesn't follow any artists [#1104](https://personal.github.com/krtirtho/spotube/issues/1104) ([682e88e](https://personal.github.com/krtirtho/spotube/commit/682e88e0c55bc0f4708bc0b4681b129e5c61c999)) +* search page vertical scrollbar moves on horizontal scroll [#1017](https://personal.github.com/krtirtho/spotube/issues/1017) ([c203ac6](https://personal.github.com/krtirtho/spotube/commit/c203ac69ee74ba8722dae3da4b47761cd8d59c34)) +* songs doesn't play when sources with preferred audio codec is empty ([#976](https://personal.github.com/krtirtho/spotube/issues/976)) ([ba4e11a](https://personal.github.com/krtirtho/spotube/commit/ba4e11a40ab18308437a05333a46eace6f8eeb5a)) +* track index not showing after 200 ([a752cf4](https://personal.github.com/krtirtho/spotube/commit/a752cf4c978d1b05851aabb6c84c7862de551320)) +* track pad horizontal scrolling not working ([59e0e6b](https://personal.github.com/krtirtho/spotube/commit/59e0e6bb659b70831f6e0ae064100381c57f149c)) + ## [3.4.0](https://github.com/KRTirtho/spotube/compare/v3.3.0...v3.4.0) (2023-12-30) diff --git a/README.md b/README.md index 791d5da0..18eb55aa 100644 --- a/README.md +++ b/README.md @@ -209,7 +209,7 @@ If you are concerned, you can [read the reason of choosing this license](https:/ 1. [auto_size_text](https://github.com/leisim/auto_size_text) - Flutter widget that automatically resizes text to fit perfectly within its bounds. 1. [buttons_tabbar](https://afonsoraposo.com) - A Flutter package that implements a TabBar where each label is a toggle button. 1. [cached_network_image](https://github.com/Baseflow/flutter_cached_network_image) - Flutter library to load and cache network images. Can also be used with placeholder and error widgets. -1. [catcher_2](https://github.com/ThexXTURBOXx/catcher_2) - Plugin for error catching which provides multiple handlers for dealing with errors when they are not caught by the developer. +1. [catcher_2](https://github.com/ThexXTURBOXx/catcher_2) - Plugin for error catching which provides multiple handlers for dealing with errors when they are not caught by the developer. 1. [collection](https://pub.dev/packages/collection) - Collections and utilities functions and classes related to collections. 1. [cupertino_icons](https://pub.dev/packages/cupertino_icons) - Default icons asset for Cupertino widgets based on Apple styled icons 1. [curved_navigation_bar](https://github.com/rafalbednarczuk/curved_navigation_bar) - Stunning Animating Curved Shape Navigation Bar. Adjustable color, background color, animation curve, animation duration. @@ -222,9 +222,9 @@ If you are concerned, you can [read the reason of choosing this license](https:/ 1. [envied](https://github.com/petercinibulk/envied) - Explicitly reads environment variables into a dart file from a .env file for more security and faster start up times. 1. [file_selector](https://pub.dev/packages/file_selector) - Flutter plugin for opening and saving files, or selecting directories, using native file selection UI. 1. [fl_query](https://fl-query.krtirtho.dev) - Asynchronous data caching, refetching & invalidation library for Flutter -1. [fl_query_hooks](https://fl-query.krtirtho.dev) - Elite flutter_hooks compatible library for fl_query, the Asynchronous data caching, refetching & invalidation library for Flutter +1. [fl_query_hooks](https://fl-query.krtirtho.dev) - Elite flutter_hooks compatible library for fl_query, the Asynchronous data caching, refetching & invalidation library for Flutter 1. [fl_query_devtools](https://fl-query.krtirtho.dev) - Devtools support for Fl-Query -1. [fluentui_system_icons](https://github.com/microsoft/fluentui-system-icons/tree/main) - Fluent UI System Icons are a collection of familiar, friendly and modern icons from Microsoft. +1. [fluentui_system_icons](https://github.com/microsoft/fluentui-system-icons/tree/main) - Fluent UI System Icons are a collection of familiar, friendly and modern icons from Microsoft. 1. [flutter_cache_manager](https://github.com/Baseflow/flutter_cache_manager/tree/develop/flutter_cache_manager) - Generic cache manager for flutter. Saves web files on the storages of the device and saves the cache info using sqflite. 1. [flutter_displaymode](https://github.com/ajinasokan/flutter_displaymode) - A Flutter plugin to set display mode (resolution, refresh rate) on Android platform. Allows to enable high refresh rate on supported devices. 1. [flutter_feather_icons](https://github.com/muj-programmer/flutter_feather_icons) - Feather is a collection of simply beautiful open source icons. Each icon is designed on a 24x24 grid with an emphasis on simplicity, consistency and usability. @@ -235,9 +235,9 @@ If you are concerned, you can [read the reason of choosing this license](https:/ 1. [flutter_secure_storage](https://pub.dev/packages/flutter_secure_storage) - Flutter Secure Storage provides API to store data in secure storage. Keychain is used in iOS, KeyStore based solution is used in Android. 1. [flutter_svg](https://pub.dev/packages/flutter_svg) - An SVG rendering and widget library for Flutter, which allows painting and displaying Scalable Vector Graphics 1.1 files. 1. [form_validator](https://github.com/TheMisir/form-validator) - Simplest form validation library for flutter's form field widgets -1. [fuzzywuzzy](https://github.com/sphericalkat/dart-fuzzywuzzy) - An implementation of the popular fuzzywuzzy package in Dart, to suit all your fuzzy string matching/searching needs! -1. [google_fonts](https://pub.dev/packages/google_fonts) - A Flutter package to use fonts from fonts.google.com. Supports HTTP fetching, caching, and asset bundling. +1. [fuzzywuzzy](https://github.com/sphericalkat/dart-fuzzywuzzy) - An implementation of the popular fuzzywuzzy package in Dart, to suit all your fuzzy string matching/searching needs! 1. [go_router](https://pub.dev/packages/go_router) - A declarative router for Flutter based on Navigation 2 supporting deep linking, data-driven routes and more +1. [google_fonts](https://pub.dev/packages/google_fonts) - A Flutter package to use fonts from fonts.google.com. Supports HTTP fetching, caching, and asset bundling. 1. [hive](https://github.com/hivedb/hive/tree/master/hive) - Lightweight and blazing fast key-value database written in pure Dart. Strongly encrypted using AES-256. 1. [hive_flutter](https://github.com/hivedb/hive/tree/master/hive_flutter) - Extension for Hive. Makes it easier to use Hive in Flutter apps. 1. [hooks_riverpod](https://riverpod.dev) - A simple way to access state from anywhere in your application while robust and testable. @@ -255,13 +255,13 @@ If you are concerned, you can [read the reason of choosing this license](https:/ 1. [package_info_plus](https://plus.fluttercommunity.dev/) - Flutter plugin for querying information about the application package, such as CFBundleVersion on iOS or versionCode on Android. 1. [palette_generator](https://pub.dev/packages/palette_generator) - Flutter package for generating palette colors from a source image. 1. [path](https://pub.dev/packages/path) - A string-based path manipulation library. All of the path operations you know and love, with solid support for Windows, POSIX (Linux and Mac OS X), and the web. -1. [path_provider](https://pub.dev/packages/path_provider) - Flutter plugin for getting commonly used locations on host platform file systems, such as the temp and app data directories. +1. [path_provider](https://pub.dev/packages/path_provider) - Flutter plugin for getting commonly used locations on host platform file systems, such as the temp and app data directories. 1. [permission_handler](https://pub.dev/packages/permission_handler) - Permission plugin for Flutter. This plugin provides a cross-platform (iOS, Android) API to request and check permissions. 1. [piped_client](https://github.com/KRTirtho/piped_client) - API Client for piped.video 1. [popover](https://github.com/minikin/popover) - A popover is a transient view that appears above other content onscreen when you tap a control or in an area. 1. [scroll_to_index](https://github.com/quire-io/scroll-to-index) - Scroll to a specific child of any scrollable widget in Flutter -1. [shared_preferences](https://pub.dev/packages/shared_preferences) - Flutter plugin for reading and writing simple key-value pairs. Wraps NSUserDefaults on iOS and SharedPreferences on Android. 1. [sidebarx](https://github.com/Frezyx/sidebarx) - flutter multiplatform navigation sidebar / side navigationbar / drawer widget +1. [shared_preferences](https://pub.dev/packages/shared_preferences) - Flutter plugin for reading and writing simple key-value pairs. Wraps NSUserDefaults on iOS and SharedPreferences on Android. 1. [skeleton_text](https://github.com/101Loop/Skeleton-Text) - A package that provides an easy way to add skeleton text loading animation in Flutter project. This project is a part of 101Loop community. 1. [smtc_windows](https://github.com/KRTirtho/smtc_windows) - Windows `SystemMediaTransportControls` implementation for Flutter giving access to Windows OS Media Control applet. 1. [spotify](https://github.com/rinukkusu/spotify-dart) - An incomplete dart library for interfacing with the Spotify Web API. diff --git a/lib/l10n/app_ar.arb b/lib/l10n/app_ar.arb index 20b6a47c..eebede99 100644 --- a/lib/l10n/app_ar.arb +++ b/lib/l10n/app_ar.arb @@ -282,5 +282,9 @@ "discord_rich_presence": "وجود ديسكورد الغني", "browse_all": "تصفح الكل", "genres": "الأنواع الموسيقية", - "explore_genres": "استكشاف الأنواع" + "explore_genres": "استكشاف الأنواع", + "step_3_steps": "انسخ قيمة الكوكي \"sp_dc\"", + "step_4_steps": "الصق قيمة \"sp_dc\" المنسوخة", + "friends": "أصدقاء", + "no_lyrics_available": "عذرًا، تعذر العثور على كلمات الأغنية لهذه العنصر" } \ No newline at end of file diff --git a/lib/l10n/app_bn.arb b/lib/l10n/app_bn.arb index 74dc200d..2711f8d2 100644 --- a/lib/l10n/app_bn.arb +++ b/lib/l10n/app_bn.arb @@ -282,5 +282,9 @@ "discord_rich_presence": "وجود ديسكورد الغني", "browse_all": "تصفح الكل", "genres": "الأنواع الموسيقية", - "explore_genres": "استكشاف الأنواع" + "explore_genres": "استكشاف الأنواع", + "step_3_steps": "কুকি \"sp_dc\" এর মানটি কপি করুন", + "step_4_steps": "কপি করা \"sp_dc\" মানটি পেস্ট করুন", + "friends": "বন্ধু", + "no_lyrics_available": "দুঃখিত, এই ট্র্যাকের জন্য কথা খুঁজে পাওয়া গেলনা" } \ No newline at end of file diff --git a/lib/l10n/app_ca.arb b/lib/l10n/app_ca.arb index 2c952457..f46cfae4 100644 --- a/lib/l10n/app_ca.arb +++ b/lib/l10n/app_ca.arb @@ -282,5 +282,9 @@ "discord_rich_presence": "Presència rica de Discord", "browse_all": "Navega per tot", "genres": "Gèneres", - "explore_genres": "Explora els gèneres" + "explore_genres": "Explora els gèneres", + "step_3_steps": "Copia el valor de la cookie \"sp_dc\"", + "step_4_steps": "Pega el valor copiado de \"sp_dc\"", + "friends": "Amics", + "no_lyrics_available": "Ho sentim, no es poden trobar les lletres d'aquesta pista" } \ No newline at end of file diff --git a/lib/l10n/app_de.arb b/lib/l10n/app_de.arb index 59f832ea..ebaa0329 100644 --- a/lib/l10n/app_de.arb +++ b/lib/l10n/app_de.arb @@ -282,5 +282,9 @@ "discord_rich_presence": "Discord Rich Presence", "browse_all": "Alles durchsuchen", "genres": "Genres", - "explore_genres": "Genres erkunden" + "explore_genres": "Genres erkunden", + "step_3_steps": "Kopiere den Wert des Cookies \"sp_dc\"", + "step_4_steps": "Füge den kopierten Wert von \"sp_dc\" ein", + "friends": "Freunde", + "no_lyrics_available": "Entschuldigung, Texte für diesen Track konnten nicht gefunden werden" } \ No newline at end of file diff --git a/lib/l10n/app_es.arb b/lib/l10n/app_es.arb index e04b4798..476056cb 100644 --- a/lib/l10n/app_es.arb +++ b/lib/l10n/app_es.arb @@ -282,5 +282,9 @@ "discord_rich_presence": "Presencia rica en Discord", "browse_all": "Explorar todo", "genres": "Géneros", - "explore_genres": "Explorar géneros" + "explore_genres": "Explorar géneros", + "step_3_steps": "Copia el valor de la cookie \"sp_dc\"", + "step_4_steps": "Pega el valor copiado de \"sp_dc\"", + "friends": "Amigos", + "no_lyrics_available": "Lo siento, no se pueden encontrar las letras de esta pista" } \ No newline at end of file diff --git a/lib/l10n/app_fa.arb b/lib/l10n/app_fa.arb index c9586cde..3a2bcb4b 100644 --- a/lib/l10n/app_fa.arb +++ b/lib/l10n/app_fa.arb @@ -282,5 +282,9 @@ "discord_rich_presence": "حضور غنی دیسکورد", "browse_all": "مرور همه", "genres": "ژانرها", - "explore_genres": "استکشاف ژانرها" + "explore_genres": "استکشاف ژانرها", + "step_3_steps": "مقدار کوکی \"sp_dc\" را کپی کنید", + "step_4_steps": "مقدار کپی شده \"sp_dc\" را الصاق کنید", + "friends": "دوستان", + "no_lyrics_available": "متاسفیم، قادر به یافتن متن این قطعه نیستیم" } \ No newline at end of file diff --git a/lib/l10n/app_fr.arb b/lib/l10n/app_fr.arb index 0c3eb653..5c24d0fe 100644 --- a/lib/l10n/app_fr.arb +++ b/lib/l10n/app_fr.arb @@ -282,5 +282,9 @@ "discord_rich_presence": "Présence riche de Discord", "browse_all": "Parcourir tout", "genres": "Genres", - "explore_genres": "Explorer les genres" + "explore_genres": "Explorer les genres", + "step_3_steps": "Copiez la valeur du cookie \"sp_dc\"", + "step_4_steps": "Collez la valeur copiée de \"sp_dc\"", + "friends": "Amis", + "no_lyrics_available": "Désolé, impossible de trouver les paroles de cette piste" } \ No newline at end of file diff --git a/lib/l10n/app_hi.arb b/lib/l10n/app_hi.arb index dd27dabf..1cf62398 100644 --- a/lib/l10n/app_hi.arb +++ b/lib/l10n/app_hi.arb @@ -282,5 +282,9 @@ "discord_rich_presence": "डिस्कॉर्ड रिच प्रेजेंस", "browse_all": "सभी को ब्राउज़ करें", "genres": "शैलियाँ", - "explore_genres": "शैलियों का अन्वेषण करें" + "explore_genres": "शैलियों का अन्वेषण करें", + "step_3_steps": "\"sp_dc\" कुकी का मूल्य कॉपी करें", + "step_4_steps": "कॉपी किए गए \"sp_dc\" मूल्य को पेस्ट करें", + "friends": "दोस्त", + "no_lyrics_available": "क्षमा करें, इस ट्रैक के लिए गाने नहीं मिल सके" } \ No newline at end of file diff --git a/lib/l10n/app_it.arb b/lib/l10n/app_it.arb index 3680933a..ec76b914 100644 --- a/lib/l10n/app_it.arb +++ b/lib/l10n/app_it.arb @@ -283,5 +283,9 @@ "discord_rich_presence": "Presenza ricca di Discord", "browse_all": "Esplora tutto", "genres": "Generi", - "explore_genres": "Esplora generi" + "explore_genres": "Esplora generi", + "step_3_steps": "Copia il valore del cookie \"sp_dc\"", + "step_4_steps": "Incolla il valore copiato di \"sp_dc\"", + "friends": "Amici", + "no_lyrics_available": "Spiacente, impossibile trovare il testo di questa traccia" } \ No newline at end of file diff --git a/lib/l10n/app_ja.arb b/lib/l10n/app_ja.arb index 39e0dad8..d16708d7 100644 --- a/lib/l10n/app_ja.arb +++ b/lib/l10n/app_ja.arb @@ -282,5 +282,9 @@ "discord_rich_presence": "ディスコードリッチプレゼンス", "browse_all": "すべてを閲覧", "genres": "ジャンル", - "explore_genres": "ジャンルを探索" + "explore_genres": "ジャンルを探索", + "step_3_steps": "\"sp_dc\" Cookieの値をコピー", + "step_4_steps": "コピーした\"sp_dc\"の値を貼り付け", + "friends": "友達", + "no_lyrics_available": "申し訳ありませんが、このトラックの歌詞を見つけることができません" } \ No newline at end of file diff --git a/lib/l10n/app_ne.arb b/lib/l10n/app_ne.arb index 9fca9ea4..2d20fc9c 100644 --- a/lib/l10n/app_ne.arb +++ b/lib/l10n/app_ne.arb @@ -115,7 +115,7 @@ "language": "भाषा", "system_default": "सिस्टम पूर्वनिर्धारित", "market_place_region": "बजार स्थान", - "recommendation_country":"सिफारिस गरिएको देश", + "recommendation_country": "सिफारिस गरिएको देश", "appearance": "दृष्टिकोण", "layout_mode": "लेआउट मोड", "override_layout_settings": "अनुकूलित प्रतिकृयात्मक लेआउट मोड सेटिङ्गहरू", @@ -284,5 +284,7 @@ "discord_rich_presence": "डिस्कर्ड धनी उपस्थिति", "browse_all": "सबै हेर्नुहोस्", "genres": "शैलीहरू", - "explore_genres": "शैलीहरू अन्वेषण गर्नुहोस्" + "explore_genres": "शैलीहरू अन्वेषण गर्नुहोस्", + "friends": "साथीहरू", + "no_lyrics_available": "क्षमा गर्दैछौं, यस ट्र्याकका लागि गीतका शब्दहरू फेला परेन" } \ No newline at end of file diff --git a/lib/l10n/app_nl.arb b/lib/l10n/app_nl.arb index 23eee51b..bf819c57 100644 --- a/lib/l10n/app_nl.arb +++ b/lib/l10n/app_nl.arb @@ -283,5 +283,9 @@ "discord_rich_presence": "Discord Rich Presence", "browse_all": "Alles bekijken", "genres": "Genres", - "explore_genres": "Verken genres" + "explore_genres": "Verken genres", + "step_3_steps": "Kopieer de waarde van de \"sp_dc\"-cookie", + "step_4_steps": "Plak de gekopieerde waarde van \"sp_dc\"", + "friends": "Vrienden", + "no_lyrics_available": "Sorry, kan geen teksten vinden voor deze track" } \ No newline at end of file diff --git a/lib/l10n/app_pl.arb b/lib/l10n/app_pl.arb index 4ae48338..b7ce8923 100644 --- a/lib/l10n/app_pl.arb +++ b/lib/l10n/app_pl.arb @@ -282,5 +282,9 @@ "discord_rich_presence": "Obecność na Discordzie", "browse_all": "Przeglądaj wszystko", "genres": "Gatunki muzyczne", - "explore_genres": "Eksploruj gatunki" + "explore_genres": "Eksploruj gatunki", + "step_3_steps": "Skopiuj wartość ciasteczka \"sp_dc\"", + "step_4_steps": "Wklej skopiowaną wartość \"sp_dc\"", + "friends": "Przyjaciele", + "no_lyrics_available": "Przepraszamy, nie można znaleźć tekstu dla tego utworu" } \ No newline at end of file diff --git a/lib/l10n/app_pt.arb b/lib/l10n/app_pt.arb index 5ea4cca0..1c75f734 100644 --- a/lib/l10n/app_pt.arb +++ b/lib/l10n/app_pt.arb @@ -282,5 +282,9 @@ "discord_rich_presence": "Presença rica no Discord", "browse_all": "Navegar por tudo", "genres": "Gêneros", - "explore_genres": "Explorar gêneros" + "explore_genres": "Explorar gêneros", + "step_3_steps": "Copie o valor do cookie \"sp_dc\"", + "step_4_steps": "Cole o valor copiado de \"sp_dc\"", + "friends": "Amigos", + "no_lyrics_available": "Desculpe, não foi possível encontrar a letra desta faixa" } \ No newline at end of file diff --git a/lib/l10n/app_ru.arb b/lib/l10n/app_ru.arb index 24120d62..7ed67f4f 100644 --- a/lib/l10n/app_ru.arb +++ b/lib/l10n/app_ru.arb @@ -282,5 +282,9 @@ "discord_rich_presence": "Богатое присутствие в Discord", "browse_all": "Просмотреть все", "genres": "Жанры", - "explore_genres": "Исследовать жанры" + "explore_genres": "Исследовать жанры", + "step_3_steps": "Скопируйте значение файла cookie \"sp_dc\"", + "step_4_steps": "Вставьте скопированное значение \"sp_dc\"", + "friends": "Друзья", + "no_lyrics_available": "Извините, не удается найти текст для этого трека" } \ No newline at end of file diff --git a/lib/l10n/app_tr.arb b/lib/l10n/app_tr.arb index e6b0ce34..4d9066fd 100644 --- a/lib/l10n/app_tr.arb +++ b/lib/l10n/app_tr.arb @@ -282,5 +282,9 @@ "discord_rich_presence": "Discord Zengin Varlık", "browse_all": "Tümünü Gözat", "genres": "Müzik Türleri", - "explore_genres": "Türleri Keşfet" + "explore_genres": "Türleri Keşfet", + "step_3_steps": "\"sp_dc\" Çerezinin değerini kopyala", + "step_4_steps": "Kopyalanan \"sp_dc\" değerini yapıştır", + "friends": "Arkadaşlar", + "no_lyrics_available": "Üzgünüz, bu parça için şarkı sözleri bulunamıyor" } \ No newline at end of file diff --git a/lib/l10n/app_uk.arb b/lib/l10n/app_uk.arb index a5199a04..a4586a5e 100644 --- a/lib/l10n/app_uk.arb +++ b/lib/l10n/app_uk.arb @@ -282,5 +282,9 @@ "discord_rich_presence": "Багата присутність у Discord", "browse_all": "Переглянути все", "genres": "Жанри", - "explore_genres": "Досліджувати жанри" + "explore_genres": "Досліджувати жанри", + "step_3_steps": "Скопіюйте значення cookie \"sp_dc\"", + "step_4_steps": "Вставте скопійоване значення \"sp_dc\"", + "friends": "Друзі", + "no_lyrics_available": "Вибачте, не вдалося знайти текст для цього треку" } \ No newline at end of file diff --git a/lib/l10n/app_zh.arb b/lib/l10n/app_zh.arb index 30f4a82c..20fdb329 100644 --- a/lib/l10n/app_zh.arb +++ b/lib/l10n/app_zh.arb @@ -282,5 +282,9 @@ "discord_rich_presence": "Discord 丰富展现", "browse_all": "浏览全部", "genres": "音乐类型", - "explore_genres": "探索音乐类型" + "explore_genres": "探索音乐类型", + "step_3_steps": "复制\"sp_dc\" Cookie的值", + "step_4_steps": "粘贴复制的\"sp_dc\"值", + "friends": "朋友", + "no_lyrics_available": "抱歉,无法找到此曲的歌词" } \ No newline at end of file diff --git a/pubspec.yaml b/pubspec.yaml index f9da61d2..daeaa234 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -3,7 +3,7 @@ description: Open source Spotify client that doesn't require Premium nor uses El publish_to: "none" -version: 3.4.0+27 +version: 3.5.0+28 homepage: https://spotube.krtirtho.dev repository: https://github.com/KRTirtho/spotube diff --git a/untranslated_messages.json b/untranslated_messages.json index ae05dfeb..9e26dfee 100644 --- a/untranslated_messages.json +++ b/untranslated_messages.json @@ -1,125 +1 @@ -{ - "ar": [ - "step_3_steps", - "step_4_steps", - "friends", - "no_lyrics_available" - ], - - "bn": [ - "step_3_steps", - "step_4_steps", - "friends", - "no_lyrics_available" - ], - - "ca": [ - "step_3_steps", - "step_4_steps", - "friends", - "no_lyrics_available" - ], - - "de": [ - "step_3_steps", - "step_4_steps", - "friends", - "no_lyrics_available" - ], - - "es": [ - "step_3_steps", - "step_4_steps", - "friends", - "no_lyrics_available" - ], - - "fa": [ - "step_3_steps", - "step_4_steps", - "friends", - "no_lyrics_available" - ], - - "fr": [ - "step_3_steps", - "step_4_steps", - "friends", - "no_lyrics_available" - ], - - "hi": [ - "step_3_steps", - "step_4_steps", - "friends", - "no_lyrics_available" - ], - - "it": [ - "step_3_steps", - "step_4_steps", - "friends", - "no_lyrics_available" - ], - - "ja": [ - "step_3_steps", - "step_4_steps", - "friends", - "no_lyrics_available" - ], - - "ne": [ - "friends", - "no_lyrics_available" - ], - - "nl": [ - "step_3_steps", - "step_4_steps", - "friends", - "no_lyrics_available" - ], - - "pl": [ - "step_3_steps", - "step_4_steps", - "friends", - "no_lyrics_available" - ], - - "pt": [ - "step_3_steps", - "step_4_steps", - "friends", - "no_lyrics_available" - ], - - "ru": [ - "step_3_steps", - "step_4_steps", - "friends", - "no_lyrics_available" - ], - - "tr": [ - "step_3_steps", - "step_4_steps", - "friends", - "no_lyrics_available" - ], - - "uk": [ - "step_3_steps", - "step_4_steps", - "friends", - "no_lyrics_available" - ], - - "zh": [ - "step_3_steps", - "step_4_steps", - "friends", - "no_lyrics_available" - ] -} +{} \ No newline at end of file From 5d0b5e69a5e43b17561656160fd963de4ff0f833 Mon Sep 17 00:00:00 2001 From: Kingkor Roy Tirtho Date: Sat, 27 Jan 2024 22:39:05 +0600 Subject: [PATCH 130/195] chore: adjust the version --- .github/workflows/spotube-release-binary.yml | 2 +- CHANGELOG.md | 2 +- pubspec.yaml | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/spotube-release-binary.yml b/.github/workflows/spotube-release-binary.yml index dd20ca5d..3ef0ff61 100644 --- a/.github/workflows/spotube-release-binary.yml +++ b/.github/workflows/spotube-release-binary.yml @@ -4,7 +4,7 @@ on: inputs: version: description: Version to release (x.x.x) - default: 3.4.0 + default: 3.4.1 required: true channel: type: choice diff --git a/CHANGELOG.md b/CHANGELOG.md index 9d784485..8f48b39e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,7 +2,7 @@ All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines. -## [3.5.0](https://personal.github.com/krtirtho/spotube/compare/v3.4.0...v3.5.0) (2024-01-27) +## [3.4.1](https://personal.github.com/krtirtho/spotube/compare/v3.4.0...v3.4.1) (2024-01-27) ### Features diff --git a/pubspec.yaml b/pubspec.yaml index daeaa234..1b3d15b0 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -3,7 +3,7 @@ description: Open source Spotify client that doesn't require Premium nor uses El publish_to: "none" -version: 3.5.0+28 +version: 3.4.1+28 homepage: https://spotube.krtirtho.dev repository: https://github.com/KRTirtho/spotube From 4defeefe7e5947aa00a2afb2a06577ec141cdc52 Mon Sep 17 00:00:00 2001 From: Kingkor Roy Tirtho Date: Wed, 31 Jan 2024 16:33:50 +0600 Subject: [PATCH 131/195] feat: start radio support --- lib/collections/spotube_icons.dart | 1 + .../shared/track_tile/track_options.dart | 79 ++++++++++++- lib/l10n/app_en.arb | 5 +- lib/services/queries/search.dart | 70 +++++++---- untranslated_messages.json | 110 +++++++++++++++++- 5 files changed, 238 insertions(+), 27 deletions(-) diff --git a/lib/collections/spotube_icons.dart b/lib/collections/spotube_icons.dart index 65e6c1a0..c00643ce 100644 --- a/lib/collections/spotube_icons.dart +++ b/lib/collections/spotube_icons.dart @@ -111,4 +111,5 @@ abstract class SpotubeIcons { static const wikipedia = SimpleIcons.wikipedia; static const discord = SimpleIcons.discord; static const youtube = SimpleIcons.youtube; + static const radio = FeatherIcons.radio; } diff --git a/lib/components/shared/track_tile/track_options.dart b/lib/components/shared/track_tile/track_options.dart index 724bc029..515d42b5 100644 --- a/lib/components/shared/track_tile/track_options.dart +++ b/lib/components/shared/track_tile/track_options.dart @@ -1,6 +1,7 @@ import 'dart:io'; -import 'package:flutter/material.dart'; +import 'package:fl_query/fl_query.dart'; +import 'package:flutter/material.dart' hide Page; import 'package:flutter/services.dart'; import 'package:flutter_hooks/flutter_hooks.dart'; import 'package:go_router/go_router.dart'; @@ -10,6 +11,7 @@ import 'package:spotube/collections/spotube_icons.dart'; import 'package:spotube/components/library/user_local_tracks.dart'; import 'package:spotube/components/shared/adaptive/adaptive_pop_sheet_list.dart'; import 'package:spotube/components/shared/dialogs/playlist_add_track_dialog.dart'; +import 'package:spotube/components/shared/dialogs/prompt_dialog.dart'; import 'package:spotube/components/shared/dialogs/track_details_dialog.dart'; import 'package:spotube/components/shared/heart_button.dart'; import 'package:spotube/components/shared/image/universal_image.dart'; @@ -20,7 +22,9 @@ import 'package:spotube/provider/authentication_provider.dart'; import 'package:spotube/provider/blacklist_provider.dart'; import 'package:spotube/provider/download_manager_provider.dart'; import 'package:spotube/provider/proxy_playlist/proxy_playlist_provider.dart'; +import 'package:spotube/provider/spotify_provider.dart'; import 'package:spotube/services/mutations/mutations.dart'; +import 'package:spotube/services/queries/search.dart'; import 'package:spotube/utils/type_conversion_utils.dart'; enum TrackOptionValue { @@ -36,6 +40,7 @@ enum TrackOptionValue { favorite, details, download, + startRadio, } class TrackOptions extends HookConsumerWidget { @@ -82,6 +87,67 @@ class TrackOptions extends HookConsumerWidget { ); } + void actionStartRadio( + BuildContext context, + WidgetRef ref, + Track track, + ) async { + final playback = ref.read(ProxyPlaylistNotifier.notifier); + final playlist = ref.read(ProxyPlaylistNotifier.provider); + final spotify = ref.read(spotifyProvider); + final pages = await QueryClient.of(context) + .fetchInfiniteQueryJob, dynamic, int, SearchParams>( + job: SearchQueries.queryJob(SearchType.playlist.name), + args: ( + spotify: spotify, + searchType: SearchType.playlist, + query: "${track.name} Radio" + ), + ) ?? + []; + + final radios = pages.expand((e) => e.items ?? []).toList(); + + final artists = track.artists!.map((e) => e.name); + + final radio = radios.firstWhere( + (e) => + e.name == "${track.name} Radio" && + artists.where((a) => e.name!.contains(a!)).length >= 2, + orElse: () => radios.first, + ); + + bool replaceQueue = false; + + if (context.mounted && playlist.tracks.isNotEmpty) { + replaceQueue = await showPromptDialog( + context: context, + title: context.l10n.how_to_start_radio, + message: context.l10n.replace_queue_question, + okText: context.l10n.replace, + cancelText: context.l10n.add_to_queue, + ); + } + + if (replaceQueue) { + await playback.stop(); + await playback.load([track], autoPlay: true); + } else { + await playback.addTrack(track); + } + + final tracks = + await spotify.playlists.getTracksByPlaylistId(radio.id!).all(); + + await playback.addTracks( + tracks.toList() + ..removeWhere((e) { + final isDuplicate = playlist.tracks.any((t) => t.id == e.id); + return e.id == track.id || isDuplicate; + }), + ); + } + @override Widget build(BuildContext context, ref) { final scaffoldMessenger = ScaffoldMessenger.of(context); @@ -207,6 +273,9 @@ class TrackOptions extends HookConsumerWidget { case TrackOptionValue.download: await downloadManager.addToQueue(track); break; + case TrackOptionValue.startRadio: + actionStartRadio(context, ref, track); + break; } }, icon: icon ?? const Icon(SpotubeIcons.moreHorizontal), @@ -287,12 +356,18 @@ class TrackOptions extends HookConsumerWidget { : context.l10n.save_as_favorite, ), ), - if (auth != null) + if (auth != null) ...[ + PopSheetEntry( + value: TrackOptionValue.startRadio, + leading: const Icon(SpotubeIcons.radio), + title: Text(context.l10n.start_a_radio), + ), PopSheetEntry( value: TrackOptionValue.addToPlaylist, leading: const Icon(SpotubeIcons.playlistAdd), title: Text(context.l10n.add_to_playlist), ), + ], if (userPlaylist && auth != null) PopSheetEntry( value: TrackOptionValue.removeFromPlaylist, diff --git a/lib/l10n/app_en.arb b/lib/l10n/app_en.arb index 07df5f06..f79090ae 100644 --- a/lib/l10n/app_en.arb +++ b/lib/l10n/app_en.arb @@ -286,5 +286,8 @@ "genres": "Genres", "explore_genres": "Explore Genres", "friends": "Friends", - "no_lyrics_available": "Sorry, unable find lyrics for this track" + "no_lyrics_available": "Sorry, unable find lyrics for this track", + "start_a_radio": "Start a Radio", + "how_to_start_radio": "How do you want to start the radio?", + "replace_queue_question": "Do you want to replace the current queue or append to it?" } \ No newline at end of file diff --git a/lib/services/queries/search.dart b/lib/services/queries/search.dart index f11f4399..3c6ee064 100644 --- a/lib/services/queries/search.dart +++ b/lib/services/queries/search.dart @@ -1,36 +1,60 @@ import 'package:fl_query/fl_query.dart'; +import 'package:fl_query_hooks/fl_query_hooks.dart'; +import 'package:flutter_hooks/flutter_hooks.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:spotify/spotify.dart'; -import 'package:spotube/hooks/spotify/use_spotify_infinite_query.dart'; +import 'package:spotube/provider/spotify_provider.dart'; + +typedef SearchParams = ({ + SpotifyApi spotify, + SearchType searchType, + String query +}); class SearchQueries { const SearchQueries(); + + static final queryJob = + InfiniteQueryJob.withVariableKey, dynamic, int, SearchParams>( + baseQueryKey: "search-query", + task: (variableKey, page, args) => args!.spotify.search.get( + args.query, + types: [args.searchType], + ).getPage(10, page), + initialPage: 0, + nextPage: (lastPage, lastPageData) { + if (lastPageData.isEmpty) return null; + if ((lastPageData.first.isLast || + (lastPageData.first.items ?? []).length < 10)) { + return null; + } + return lastPageData.first.nextOffset; + }, + enabled: false, + ); + InfiniteQuery, dynamic, int> query( WidgetRef ref, - String query, + String queryStr, SearchType searchType, ) { - return useSpotifyInfiniteQuery, dynamic, int>( - "search-query/${searchType.name}", - (page, spotify) { - if (query.trim().isEmpty) return []; - final queryString = query; - return spotify.search.get( - queryString, - types: [searchType], - ).getPage(10, page); - }, - enabled: false, - ref: ref, - initialPage: 0, - nextPage: (lastPage, lastPageData) { - if (lastPageData.isEmpty) return null; - if ((lastPageData.first.isLast || - (lastPageData.first.items ?? []).length < 10)) { - return null; - } - return lastPageData.first.nextOffset; - }, + final spotify = ref.watch(spotifyProvider); + final query = useInfiniteQueryJob, dynamic, int, SearchParams>( + job: queryJob(searchType.name), + args: (spotify: spotify, searchType: searchType, query: queryStr), ); + + useEffect(() { + return ref.listenManual( + spotifyProvider, + (previous, next) { + if (previous != next) { + query.refreshAll(); + } + }, + ).close; + }, [query]); + + return query; } } diff --git a/untranslated_messages.json b/untranslated_messages.json index 9e26dfee..748a9906 100644 --- a/untranslated_messages.json +++ b/untranslated_messages.json @@ -1 +1,109 @@ -{} \ No newline at end of file +{ + "ar": [ + "start_a_radio", + "how_to_start_radio", + "replace_queue_question" + ], + + "bn": [ + "start_a_radio", + "how_to_start_radio", + "replace_queue_question" + ], + + "ca": [ + "start_a_radio", + "how_to_start_radio", + "replace_queue_question" + ], + + "de": [ + "start_a_radio", + "how_to_start_radio", + "replace_queue_question" + ], + + "es": [ + "start_a_radio", + "how_to_start_radio", + "replace_queue_question" + ], + + "fa": [ + "start_a_radio", + "how_to_start_radio", + "replace_queue_question" + ], + + "fr": [ + "start_a_radio", + "how_to_start_radio", + "replace_queue_question" + ], + + "hi": [ + "start_a_radio", + "how_to_start_radio", + "replace_queue_question" + ], + + "it": [ + "start_a_radio", + "how_to_start_radio", + "replace_queue_question" + ], + + "ja": [ + "start_a_radio", + "how_to_start_radio", + "replace_queue_question" + ], + + "ne": [ + "start_a_radio", + "how_to_start_radio", + "replace_queue_question" + ], + + "nl": [ + "start_a_radio", + "how_to_start_radio", + "replace_queue_question" + ], + + "pl": [ + "start_a_radio", + "how_to_start_radio", + "replace_queue_question" + ], + + "pt": [ + "start_a_radio", + "how_to_start_radio", + "replace_queue_question" + ], + + "ru": [ + "start_a_radio", + "how_to_start_radio", + "replace_queue_question" + ], + + "tr": [ + "start_a_radio", + "how_to_start_radio", + "replace_queue_question" + ], + + "uk": [ + "start_a_radio", + "how_to_start_radio", + "replace_queue_question" + ], + + "zh": [ + "start_a_radio", + "how_to_start_radio", + "replace_queue_question" + ] +} From 9dfd49ca04f0e915e333e205b17ac70456873f6e Mon Sep 17 00:00:00 2001 From: Kingkor Roy Tirtho Date: Wed, 31 Jan 2024 18:00:54 +0600 Subject: [PATCH 132/195] feat: add endless playback support #285 --- analysis_options.yaml | 4 +- .../shared/track_tile/track_options.dart | 21 +- .../configurators/use_endless_playback.dart | 102 +++ lib/l10n/app_en.arb | 3 +- lib/pages/root/root_app.dart | 3 + lib/pages/settings/sections/playback.dart | 6 + .../user_preferences_provider.dart | 4 + .../user_preferences_state.dart | 234 ++---- .../user_preferences_state.freezed.dart | 697 ++++++++++++++++++ .../user_preferences_state.g.dart | 69 +- pubspec.lock | 10 +- pubspec.yaml | 2 + untranslated_messages.json | 54 +- 13 files changed, 956 insertions(+), 253 deletions(-) create mode 100644 lib/hooks/configurators/use_endless_playback.dart create mode 100644 lib/provider/user_preferences/user_preferences_state.freezed.dart diff --git a/analysis_options.yaml b/analysis_options.yaml index 4f0718e4..5f2cbbe1 100644 --- a/analysis_options.yaml +++ b/analysis_options.yaml @@ -31,4 +31,6 @@ linter: analyzer: enable-experiment: - records - - patterns \ No newline at end of file + - patterns + errors: + invalid_annotation_target: ignore diff --git a/lib/components/shared/track_tile/track_options.dart b/lib/components/shared/track_tile/track_options.dart index 515d42b5..d0d081ff 100644 --- a/lib/components/shared/track_tile/track_options.dart +++ b/lib/components/shared/track_tile/track_options.dart @@ -106,14 +106,22 @@ class TrackOptions extends HookConsumerWidget { ) ?? []; - final radios = pages.expand((e) => e.items ?? []).toList(); + final radios = pages + .expand((e) => e.items?.toList() ?? []) + .toList() + .cast(); final artists = track.artists!.map((e) => e.name); final radio = radios.firstWhere( - (e) => - e.name == "${track.name} Radio" && - artists.where((a) => e.name!.contains(a!)).length >= 2, + (e) { + final validPlaylists = + artists.where((a) => e.description!.contains(a!)); + return e.name == "${track.name} Radio" && + (validPlaylists.length >= 2 || + validPlaylists.length == artists.length) && + e.owner?.displayName == "Spotify"; + }, orElse: () => radios.first, ); @@ -129,9 +137,12 @@ class TrackOptions extends HookConsumerWidget { ); } - if (replaceQueue) { + if (replaceQueue || playlist.tracks.isEmpty) { await playback.stop(); await playback.load([track], autoPlay: true); + + // we don't have to add those tracks as useEndlessPlayback will do it for us + return; } else { await playback.addTrack(track); } diff --git a/lib/hooks/configurators/use_endless_playback.dart b/lib/hooks/configurators/use_endless_playback.dart new file mode 100644 index 00000000..ffbb6991 --- /dev/null +++ b/lib/hooks/configurators/use_endless_playback.dart @@ -0,0 +1,102 @@ +import 'package:catcher_2/catcher_2.dart'; +import 'package:fl_query_hooks/fl_query_hooks.dart'; +import 'package:flutter_hooks/flutter_hooks.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; +import 'package:spotify/spotify.dart'; +import 'package:spotube/provider/authentication_provider.dart'; +import 'package:spotube/provider/proxy_playlist/proxy_playlist_provider.dart'; +import 'package:spotube/provider/spotify_provider.dart'; +import 'package:spotube/provider/user_preferences/user_preferences_provider.dart'; +import 'package:spotube/services/audio_player/audio_player.dart'; +import 'package:spotube/services/queries/search.dart'; + +void useEndlessPlayback(WidgetRef ref) { + final auth = ref.watch(AuthenticationNotifier.provider); + final playback = ref.watch(ProxyPlaylistNotifier.notifier); + final playlist = ref.watch(ProxyPlaylistNotifier.provider); + final spotify = ref.watch(spotifyProvider); + final endlessPlayback = + ref.watch(userPreferencesProvider.select((s) => s.endlessPlayback)); + + final queryClient = useQueryClient(); + + useEffect( + () { + if (!endlessPlayback || auth == null) return null; + + void listener(int index) async { + try { + final playlist = ref.read(ProxyPlaylistNotifier.provider); + if (index != playlist.tracks.length - 1) return; + + final track = playlist.tracks.last; + + final pages = await queryClient.fetchInfiniteQueryJob, + dynamic, int, SearchParams>( + job: SearchQueries.queryJob(SearchType.playlist.name), + args: ( + spotify: spotify, + searchType: SearchType.playlist, + query: "${track.name} Radio" + ), + ) ?? + []; + + final radios = pages + .expand((e) => e.items?.toList() ?? []) + .toList() + .cast(); + + final artists = track.artists!.map((e) => e.name); + + final radio = radios.firstWhere( + (e) { + final validPlaylists = + artists.where((a) => e.description!.contains(a!)); + return e.name == "${track.name} Radio" && + (validPlaylists.length >= 2 || + validPlaylists.length == artists.length) && + e.owner?.displayName != "Spotify"; + }, + orElse: () => radios.first, + ); + + final tracks = + await spotify.playlists.getTracksByPlaylistId(radio.id!).all(); + + await playback.addTracks( + tracks.toList() + ..removeWhere((e) { + final playlist = ref.read(ProxyPlaylistNotifier.provider); + final isDuplicate = playlist.tracks.any((t) => t.id == e.id); + return e.id == track.id || isDuplicate; + }), + ); + } catch (e, stack) { + Catcher2.reportCheckedError(e, stack); + } + } + + // Sometimes user can change settings for which the currentIndexChanged + // might not be called. So we need to check if the current track is the + // last track and if it is then we need to call the listener manually. + if (playlist.active == playlist.tracks.length - 1 && + audioPlayer.isPlaying) { + listener(playlist.active!); + } + + final subscription = + audioPlayer.currentIndexChangedStream.listen(listener); + + return subscription.cancel; + }, + [ + spotify, + playback, + queryClient, + playlist.tracks, + endlessPlayback, + auth, + ], + ); +} diff --git a/lib/l10n/app_en.arb b/lib/l10n/app_en.arb index f79090ae..0628cc43 100644 --- a/lib/l10n/app_en.arb +++ b/lib/l10n/app_en.arb @@ -289,5 +289,6 @@ "no_lyrics_available": "Sorry, unable find lyrics for this track", "start_a_radio": "Start a Radio", "how_to_start_radio": "How do you want to start the radio?", - "replace_queue_question": "Do you want to replace the current queue or append to it?" + "replace_queue_question": "Do you want to replace the current queue or append to it?", + "endless_playback": "Endless Playback" } \ No newline at end of file diff --git a/lib/pages/root/root_app.dart b/lib/pages/root/root_app.dart index 87be587c..2ff49737 100644 --- a/lib/pages/root/root_app.dart +++ b/lib/pages/root/root_app.dart @@ -15,6 +15,7 @@ import 'package:spotube/components/root/bottom_player.dart'; import 'package:spotube/components/root/sidebar.dart'; import 'package:spotube/components/root/spotube_navigation_bar.dart'; import 'package:spotube/extensions/context.dart'; +import 'package:spotube/hooks/configurators/use_endless_playback.dart'; import 'package:spotube/hooks/configurators/use_update_checker.dart'; import 'package:spotube/provider/download_manager_provider.dart'; import 'package:spotube/utils/persisted_state_notifier.dart'; @@ -134,6 +135,8 @@ class RootApp extends HookConsumerWidget { // checks for latest version of the application useUpdateChecker(ref); + useEndlessPlayback(ref); + final backgroundColor = Theme.of(context).scaffoldBackgroundColor; useEffect(() { diff --git a/lib/pages/settings/sections/playback.dart b/lib/pages/settings/sections/playback.dart index d36e0713..bd2e33b9 100644 --- a/lib/pages/settings/sections/playback.dart +++ b/lib/pages/settings/sections/playback.dart @@ -221,6 +221,12 @@ class SettingsPlaybackSection extends HookConsumerWidget { preferencesNotifier.setDownloadMusicCodec(value); }, ), + SwitchListTile( + secondary: const Icon(SpotubeIcons.repeat), + title: Text(context.l10n.endless_playback), + value: preferences.endlessPlayback, + onChanged: preferencesNotifier.setEndlessPlayback, + ), ], ); } diff --git a/lib/provider/user_preferences/user_preferences_provider.dart b/lib/provider/user_preferences/user_preferences_provider.dart index 46569269..875f36cc 100644 --- a/lib/provider/user_preferences/user_preferences_provider.dart +++ b/lib/provider/user_preferences/user_preferences_provider.dart @@ -123,6 +123,10 @@ class UserPreferencesNotifier extends PersistedStateNotifier { audioPlayer.setAudioNormalization(normalize); } + void setEndlessPlayback(bool endless) { + state = state.copyWith(endlessPlayback: endless); + } + Future _getDefaultDownloadDirectory() async { if (kIsAndroid) return "/storage/emulated/0/Download/Spotube"; diff --git a/lib/provider/user_preferences/user_preferences_state.dart b/lib/provider/user_preferences/user_preferences_state.dart index 4244ca67..cf6c0597 100644 --- a/lib/provider/user_preferences/user_preferences_state.dart +++ b/lib/provider/user_preferences/user_preferences_state.dart @@ -1,12 +1,13 @@ import 'dart:convert'; import 'package:flutter/material.dart'; -import 'package:json_annotation/json_annotation.dart'; +import 'package:freezed_annotation/freezed_annotation.dart'; import 'package:spotify/spotify.dart'; import 'package:spotube/components/settings/color_scheme_picker_dialog.dart'; import 'package:spotube/services/sourced_track/enums.dart'; part 'user_preferences_state.g.dart'; +part 'user_preferences_state.freezed.dart'; @JsonEnum() enum LayoutMode { @@ -53,40 +54,48 @@ enum SearchMode { } } -@JsonSerializable() -final class UserPreferences { - @JsonKey( - defaultValue: SourceQualities.high, - unknownEnumValue: SourceQualities.high, - ) - final SourceQualities audioQuality; +@freezed +class UserPreferences with _$UserPreferences { + const factory UserPreferences({ + @Default(SourceQualities.high) SourceQualities audioQuality, + @Default(true) bool albumColorSync, + @Default(false) bool amoledDarkTheme, + @Default(true) bool checkUpdate, + @Default(false) bool normalizeAudio, + @Default(true) bool showSystemTrayIcon, + @Default(false) bool skipNonMusic, + @Default(false) bool systemTitleBar, + @Default(CloseBehavior.minimizeToTray) CloseBehavior closeBehavior, + @Default(SpotubeColor(0xFF2196F3, name: "Blue")) + @JsonKey( + fromJson: UserPreferences._accentColorSchemeFromJson, + toJson: UserPreferences._accentColorSchemeToJson, + readValue: UserPreferences._accentColorSchemeReadValue, + ) + SpotubeColor accentColorScheme, + @Default(LayoutMode.adaptive) LayoutMode layoutMode, + @Default(Locale("system", "system")) + @JsonKey( + fromJson: UserPreferences._localeFromJson, + toJson: UserPreferences._localeToJson, + readValue: UserPreferences._localeReadValue, + ) + Locale locale, + @Default(Market.US) Market recommendationMarket, + @Default(SearchMode.youtube) SearchMode searchMode, + @Default("") String downloadLocation, + @Default("https://pipedapi.kavin.rocks") String pipedInstance, + @Default(ThemeMode.system) ThemeMode themeMode, + @Default(AudioSource.youtube) AudioSource audioSource, + @Default(SourceCodecs.weba) SourceCodecs streamMusicCodec, + @Default(SourceCodecs.m4a) SourceCodecs downloadMusicCodec, + @Default(true) bool discordPresence, + @Default(true) bool endlessPlayback, + }) = _UserPreferences; + factory UserPreferences.fromJson(Map json) => + _$UserPreferencesFromJson(json); - @JsonKey(defaultValue: true) - final bool albumColorSync; - - @JsonKey(defaultValue: false) - final bool amoledDarkTheme; - - @JsonKey(defaultValue: true) - final bool checkUpdate; - - @JsonKey(defaultValue: false) - final bool normalizeAudio; - - @JsonKey(defaultValue: true) - final bool showSystemTrayIcon; - - @JsonKey(defaultValue: true) - final bool skipNonMusic; - - @JsonKey(defaultValue: false) - final bool systemTitleBar; - - @JsonKey( - defaultValue: CloseBehavior.minimizeToTray, - unknownEnumValue: CloseBehavior.minimizeToTray, - ) - final CloseBehavior closeBehavior; + factory UserPreferences.withDefaults() => UserPreferences.fromJson({}); static SpotubeColor _accentColorSchemeFromJson(Map json) { return SpotubeColor.fromString(json["color"]); @@ -105,23 +114,6 @@ final class UserPreferences { return {"color": color.toString()}; } - static SpotubeColor _defaultAccentColorScheme() => - const SpotubeColor(0xFF2196F3, name: "Blue"); - - @JsonKey( - defaultValue: UserPreferences._defaultAccentColorScheme, - fromJson: UserPreferences._accentColorSchemeFromJson, - toJson: UserPreferences._accentColorSchemeToJson, - readValue: UserPreferences._accentColorSchemeReadValue, - ) - final SpotubeColor accentColorScheme; - - @JsonKey( - defaultValue: LayoutMode.adaptive, - unknownEnumValue: LayoutMode.adaptive, - ) - final LayoutMode layoutMode; - static Locale _localeFromJson(Map json) { return Locale(json["languageCode"], json["countryCode"]); } @@ -145,144 +137,4 @@ final class UserPreferences { return json[key] as Map?; } - - static Locale _defaultLocaleValue() => const Locale("system", "system"); - - @JsonKey( - defaultValue: UserPreferences._defaultLocaleValue, - toJson: UserPreferences._localeToJson, - fromJson: UserPreferences._localeFromJson, - readValue: UserPreferences._localeReadValue, - ) - final Locale locale; - - @JsonKey( - defaultValue: Market.US, - unknownEnumValue: Market.US, - ) - final Market recommendationMarket; - - @JsonKey( - defaultValue: SearchMode.youtube, - unknownEnumValue: SearchMode.youtube, - ) - final SearchMode searchMode; - - @JsonKey(defaultValue: "") - final String downloadLocation; - - @JsonKey(defaultValue: "https://pipedapi.kavin.rocks") - final String pipedInstance; - - @JsonKey( - defaultValue: ThemeMode.system, - unknownEnumValue: ThemeMode.system, - ) - final ThemeMode themeMode; - - @JsonKey( - defaultValue: AudioSource.youtube, - unknownEnumValue: AudioSource.youtube, - ) - final AudioSource audioSource; - - @JsonKey( - defaultValue: SourceCodecs.weba, - unknownEnumValue: SourceCodecs.weba, - ) - final SourceCodecs streamMusicCodec; - - @JsonKey( - defaultValue: SourceCodecs.m4a, - unknownEnumValue: SourceCodecs.m4a, - ) - final SourceCodecs downloadMusicCodec; - - @JsonKey(defaultValue: true) - final bool discordPresence; - - UserPreferences({ - required this.audioQuality, - required this.albumColorSync, - required this.amoledDarkTheme, - required this.checkUpdate, - required this.normalizeAudio, - required this.showSystemTrayIcon, - required this.skipNonMusic, - required this.systemTitleBar, - required this.closeBehavior, - required this.accentColorScheme, - required this.layoutMode, - required this.locale, - required this.recommendationMarket, - required this.searchMode, - required this.downloadLocation, - required this.pipedInstance, - required this.themeMode, - required this.audioSource, - required this.streamMusicCodec, - required this.downloadMusicCodec, - required this.discordPresence, - }); - - factory UserPreferences.withDefaults() { - return UserPreferences.fromJson({}); - } - - factory UserPreferences.fromJson(Map json) { - return _$UserPreferencesFromJson(json); - } - - Map toJson() { - return _$UserPreferencesToJson(this); - } - - UserPreferences copyWith({ - ThemeMode? themeMode, - SpotubeColor? accentColorScheme, - bool? albumColorSync, - bool? checkUpdate, - SourceQualities? audioQuality, - String? downloadLocation, - LayoutMode? layoutMode, - CloseBehavior? closeBehavior, - bool? showSystemTrayIcon, - Locale? locale, - String? pipedInstance, - SearchMode? searchMode, - bool? skipNonMusic, - AudioSource? audioSource, - Market? recommendationMarket, - bool? saveTrackLyrics, - bool? amoledDarkTheme, - bool? normalizeAudio, - SourceCodecs? downloadMusicCodec, - SourceCodecs? streamMusicCodec, - bool? systemTitleBar, - bool? discordPresence, - }) { - return UserPreferences( - themeMode: themeMode ?? this.themeMode, - accentColorScheme: accentColorScheme ?? this.accentColorScheme, - albumColorSync: albumColorSync ?? this.albumColorSync, - checkUpdate: checkUpdate ?? this.checkUpdate, - audioQuality: audioQuality ?? this.audioQuality, - downloadLocation: downloadLocation ?? this.downloadLocation, - layoutMode: layoutMode ?? this.layoutMode, - closeBehavior: closeBehavior ?? this.closeBehavior, - showSystemTrayIcon: showSystemTrayIcon ?? this.showSystemTrayIcon, - locale: locale ?? this.locale, - pipedInstance: pipedInstance ?? this.pipedInstance, - searchMode: searchMode ?? this.searchMode, - skipNonMusic: skipNonMusic ?? this.skipNonMusic, - audioSource: audioSource ?? this.audioSource, - recommendationMarket: recommendationMarket ?? this.recommendationMarket, - amoledDarkTheme: amoledDarkTheme ?? this.amoledDarkTheme, - downloadMusicCodec: downloadMusicCodec ?? this.downloadMusicCodec, - normalizeAudio: normalizeAudio ?? this.normalizeAudio, - streamMusicCodec: streamMusicCodec ?? this.streamMusicCodec, - systemTitleBar: systemTitleBar ?? this.systemTitleBar, - discordPresence: discordPresence ?? this.discordPresence, - ); - } } diff --git a/lib/provider/user_preferences/user_preferences_state.freezed.dart b/lib/provider/user_preferences/user_preferences_state.freezed.dart new file mode 100644 index 00000000..4d08d1a9 --- /dev/null +++ b/lib/provider/user_preferences/user_preferences_state.freezed.dart @@ -0,0 +1,697 @@ +// coverage:ignore-file +// GENERATED CODE - DO NOT MODIFY BY HAND +// ignore_for_file: type=lint +// ignore_for_file: unused_element, deprecated_member_use, deprecated_member_use_from_same_package, use_function_type_syntax_for_parameters, unnecessary_const, avoid_init_to_null, invalid_override_different_default_values_named, prefer_expression_function_bodies, annotate_overrides, invalid_annotation_target, unnecessary_question_mark + +part of 'user_preferences_state.dart'; + +// ************************************************************************** +// FreezedGenerator +// ************************************************************************** + +T _$identity(T value) => value; + +final _privateConstructorUsedError = UnsupportedError( + 'It seems like you constructed your class using `MyClass._()`. This constructor is only meant to be used by freezed and you are not supposed to need it nor use it.\nPlease check the documentation here for more information: https://github.com/rrousselGit/freezed#custom-getters-and-methods'); + +UserPreferences _$UserPreferencesFromJson(Map json) { + return _UserPreferences.fromJson(json); +} + +/// @nodoc +mixin _$UserPreferences { + SourceQualities get audioQuality => throw _privateConstructorUsedError; + bool get albumColorSync => throw _privateConstructorUsedError; + bool get amoledDarkTheme => throw _privateConstructorUsedError; + bool get checkUpdate => throw _privateConstructorUsedError; + bool get normalizeAudio => throw _privateConstructorUsedError; + bool get showSystemTrayIcon => throw _privateConstructorUsedError; + bool get skipNonMusic => throw _privateConstructorUsedError; + bool get systemTitleBar => throw _privateConstructorUsedError; + CloseBehavior get closeBehavior => throw _privateConstructorUsedError; + @JsonKey( + fromJson: UserPreferences._accentColorSchemeFromJson, + toJson: UserPreferences._accentColorSchemeToJson, + readValue: UserPreferences._accentColorSchemeReadValue) + SpotubeColor get accentColorScheme => throw _privateConstructorUsedError; + LayoutMode get layoutMode => throw _privateConstructorUsedError; + @JsonKey( + fromJson: UserPreferences._localeFromJson, + toJson: UserPreferences._localeToJson, + readValue: UserPreferences._localeReadValue) + Locale get locale => throw _privateConstructorUsedError; + Market get recommendationMarket => throw _privateConstructorUsedError; + SearchMode get searchMode => throw _privateConstructorUsedError; + String get downloadLocation => throw _privateConstructorUsedError; + String get pipedInstance => throw _privateConstructorUsedError; + ThemeMode get themeMode => throw _privateConstructorUsedError; + AudioSource get audioSource => throw _privateConstructorUsedError; + SourceCodecs get streamMusicCodec => throw _privateConstructorUsedError; + SourceCodecs get downloadMusicCodec => throw _privateConstructorUsedError; + bool get discordPresence => throw _privateConstructorUsedError; + bool get endlessPlayback => throw _privateConstructorUsedError; + + Map toJson() => throw _privateConstructorUsedError; + @JsonKey(ignore: true) + $UserPreferencesCopyWith get copyWith => + throw _privateConstructorUsedError; +} + +/// @nodoc +abstract class $UserPreferencesCopyWith<$Res> { + factory $UserPreferencesCopyWith( + UserPreferences value, $Res Function(UserPreferences) then) = + _$UserPreferencesCopyWithImpl<$Res, UserPreferences>; + @useResult + $Res call( + {SourceQualities audioQuality, + bool albumColorSync, + bool amoledDarkTheme, + bool checkUpdate, + bool normalizeAudio, + bool showSystemTrayIcon, + bool skipNonMusic, + bool systemTitleBar, + CloseBehavior closeBehavior, + @JsonKey( + fromJson: UserPreferences._accentColorSchemeFromJson, + toJson: UserPreferences._accentColorSchemeToJson, + readValue: UserPreferences._accentColorSchemeReadValue) + SpotubeColor accentColorScheme, + LayoutMode layoutMode, + @JsonKey( + fromJson: UserPreferences._localeFromJson, + toJson: UserPreferences._localeToJson, + readValue: UserPreferences._localeReadValue) + Locale locale, + Market recommendationMarket, + SearchMode searchMode, + String downloadLocation, + String pipedInstance, + ThemeMode themeMode, + AudioSource audioSource, + SourceCodecs streamMusicCodec, + SourceCodecs downloadMusicCodec, + bool discordPresence, + bool endlessPlayback}); +} + +/// @nodoc +class _$UserPreferencesCopyWithImpl<$Res, $Val extends UserPreferences> + implements $UserPreferencesCopyWith<$Res> { + _$UserPreferencesCopyWithImpl(this._value, this._then); + + // ignore: unused_field + final $Val _value; + // ignore: unused_field + final $Res Function($Val) _then; + + @pragma('vm:prefer-inline') + @override + $Res call({ + Object? audioQuality = null, + Object? albumColorSync = null, + Object? amoledDarkTheme = null, + Object? checkUpdate = null, + Object? normalizeAudio = null, + Object? showSystemTrayIcon = null, + Object? skipNonMusic = null, + Object? systemTitleBar = null, + Object? closeBehavior = null, + Object? accentColorScheme = null, + Object? layoutMode = null, + Object? locale = null, + Object? recommendationMarket = null, + Object? searchMode = null, + Object? downloadLocation = null, + Object? pipedInstance = null, + Object? themeMode = null, + Object? audioSource = null, + Object? streamMusicCodec = null, + Object? downloadMusicCodec = null, + Object? discordPresence = null, + Object? endlessPlayback = null, + }) { + return _then(_value.copyWith( + audioQuality: null == audioQuality + ? _value.audioQuality + : audioQuality // ignore: cast_nullable_to_non_nullable + as SourceQualities, + albumColorSync: null == albumColorSync + ? _value.albumColorSync + : albumColorSync // ignore: cast_nullable_to_non_nullable + as bool, + amoledDarkTheme: null == amoledDarkTheme + ? _value.amoledDarkTheme + : amoledDarkTheme // ignore: cast_nullable_to_non_nullable + as bool, + checkUpdate: null == checkUpdate + ? _value.checkUpdate + : checkUpdate // ignore: cast_nullable_to_non_nullable + as bool, + normalizeAudio: null == normalizeAudio + ? _value.normalizeAudio + : normalizeAudio // ignore: cast_nullable_to_non_nullable + as bool, + showSystemTrayIcon: null == showSystemTrayIcon + ? _value.showSystemTrayIcon + : showSystemTrayIcon // ignore: cast_nullable_to_non_nullable + as bool, + skipNonMusic: null == skipNonMusic + ? _value.skipNonMusic + : skipNonMusic // ignore: cast_nullable_to_non_nullable + as bool, + systemTitleBar: null == systemTitleBar + ? _value.systemTitleBar + : systemTitleBar // ignore: cast_nullable_to_non_nullable + as bool, + closeBehavior: null == closeBehavior + ? _value.closeBehavior + : closeBehavior // ignore: cast_nullable_to_non_nullable + as CloseBehavior, + accentColorScheme: null == accentColorScheme + ? _value.accentColorScheme + : accentColorScheme // ignore: cast_nullable_to_non_nullable + as SpotubeColor, + layoutMode: null == layoutMode + ? _value.layoutMode + : layoutMode // ignore: cast_nullable_to_non_nullable + as LayoutMode, + locale: null == locale + ? _value.locale + : locale // ignore: cast_nullable_to_non_nullable + as Locale, + recommendationMarket: null == recommendationMarket + ? _value.recommendationMarket + : recommendationMarket // ignore: cast_nullable_to_non_nullable + as Market, + searchMode: null == searchMode + ? _value.searchMode + : searchMode // ignore: cast_nullable_to_non_nullable + as SearchMode, + downloadLocation: null == downloadLocation + ? _value.downloadLocation + : downloadLocation // ignore: cast_nullable_to_non_nullable + as String, + pipedInstance: null == pipedInstance + ? _value.pipedInstance + : pipedInstance // ignore: cast_nullable_to_non_nullable + as String, + themeMode: null == themeMode + ? _value.themeMode + : themeMode // ignore: cast_nullable_to_non_nullable + as ThemeMode, + audioSource: null == audioSource + ? _value.audioSource + : audioSource // ignore: cast_nullable_to_non_nullable + as AudioSource, + streamMusicCodec: null == streamMusicCodec + ? _value.streamMusicCodec + : streamMusicCodec // ignore: cast_nullable_to_non_nullable + as SourceCodecs, + downloadMusicCodec: null == downloadMusicCodec + ? _value.downloadMusicCodec + : downloadMusicCodec // ignore: cast_nullable_to_non_nullable + as SourceCodecs, + discordPresence: null == discordPresence + ? _value.discordPresence + : discordPresence // ignore: cast_nullable_to_non_nullable + as bool, + endlessPlayback: null == endlessPlayback + ? _value.endlessPlayback + : endlessPlayback // ignore: cast_nullable_to_non_nullable + as bool, + ) as $Val); + } +} + +/// @nodoc +abstract class _$$UserPreferencesImplCopyWith<$Res> + implements $UserPreferencesCopyWith<$Res> { + factory _$$UserPreferencesImplCopyWith(_$UserPreferencesImpl value, + $Res Function(_$UserPreferencesImpl) then) = + __$$UserPreferencesImplCopyWithImpl<$Res>; + @override + @useResult + $Res call( + {SourceQualities audioQuality, + bool albumColorSync, + bool amoledDarkTheme, + bool checkUpdate, + bool normalizeAudio, + bool showSystemTrayIcon, + bool skipNonMusic, + bool systemTitleBar, + CloseBehavior closeBehavior, + @JsonKey( + fromJson: UserPreferences._accentColorSchemeFromJson, + toJson: UserPreferences._accentColorSchemeToJson, + readValue: UserPreferences._accentColorSchemeReadValue) + SpotubeColor accentColorScheme, + LayoutMode layoutMode, + @JsonKey( + fromJson: UserPreferences._localeFromJson, + toJson: UserPreferences._localeToJson, + readValue: UserPreferences._localeReadValue) + Locale locale, + Market recommendationMarket, + SearchMode searchMode, + String downloadLocation, + String pipedInstance, + ThemeMode themeMode, + AudioSource audioSource, + SourceCodecs streamMusicCodec, + SourceCodecs downloadMusicCodec, + bool discordPresence, + bool endlessPlayback}); +} + +/// @nodoc +class __$$UserPreferencesImplCopyWithImpl<$Res> + extends _$UserPreferencesCopyWithImpl<$Res, _$UserPreferencesImpl> + implements _$$UserPreferencesImplCopyWith<$Res> { + __$$UserPreferencesImplCopyWithImpl( + _$UserPreferencesImpl _value, $Res Function(_$UserPreferencesImpl) _then) + : super(_value, _then); + + @pragma('vm:prefer-inline') + @override + $Res call({ + Object? audioQuality = null, + Object? albumColorSync = null, + Object? amoledDarkTheme = null, + Object? checkUpdate = null, + Object? normalizeAudio = null, + Object? showSystemTrayIcon = null, + Object? skipNonMusic = null, + Object? systemTitleBar = null, + Object? closeBehavior = null, + Object? accentColorScheme = null, + Object? layoutMode = null, + Object? locale = null, + Object? recommendationMarket = null, + Object? searchMode = null, + Object? downloadLocation = null, + Object? pipedInstance = null, + Object? themeMode = null, + Object? audioSource = null, + Object? streamMusicCodec = null, + Object? downloadMusicCodec = null, + Object? discordPresence = null, + Object? endlessPlayback = null, + }) { + return _then(_$UserPreferencesImpl( + audioQuality: null == audioQuality + ? _value.audioQuality + : audioQuality // ignore: cast_nullable_to_non_nullable + as SourceQualities, + albumColorSync: null == albumColorSync + ? _value.albumColorSync + : albumColorSync // ignore: cast_nullable_to_non_nullable + as bool, + amoledDarkTheme: null == amoledDarkTheme + ? _value.amoledDarkTheme + : amoledDarkTheme // ignore: cast_nullable_to_non_nullable + as bool, + checkUpdate: null == checkUpdate + ? _value.checkUpdate + : checkUpdate // ignore: cast_nullable_to_non_nullable + as bool, + normalizeAudio: null == normalizeAudio + ? _value.normalizeAudio + : normalizeAudio // ignore: cast_nullable_to_non_nullable + as bool, + showSystemTrayIcon: null == showSystemTrayIcon + ? _value.showSystemTrayIcon + : showSystemTrayIcon // ignore: cast_nullable_to_non_nullable + as bool, + skipNonMusic: null == skipNonMusic + ? _value.skipNonMusic + : skipNonMusic // ignore: cast_nullable_to_non_nullable + as bool, + systemTitleBar: null == systemTitleBar + ? _value.systemTitleBar + : systemTitleBar // ignore: cast_nullable_to_non_nullable + as bool, + closeBehavior: null == closeBehavior + ? _value.closeBehavior + : closeBehavior // ignore: cast_nullable_to_non_nullable + as CloseBehavior, + accentColorScheme: null == accentColorScheme + ? _value.accentColorScheme + : accentColorScheme // ignore: cast_nullable_to_non_nullable + as SpotubeColor, + layoutMode: null == layoutMode + ? _value.layoutMode + : layoutMode // ignore: cast_nullable_to_non_nullable + as LayoutMode, + locale: null == locale + ? _value.locale + : locale // ignore: cast_nullable_to_non_nullable + as Locale, + recommendationMarket: null == recommendationMarket + ? _value.recommendationMarket + : recommendationMarket // ignore: cast_nullable_to_non_nullable + as Market, + searchMode: null == searchMode + ? _value.searchMode + : searchMode // ignore: cast_nullable_to_non_nullable + as SearchMode, + downloadLocation: null == downloadLocation + ? _value.downloadLocation + : downloadLocation // ignore: cast_nullable_to_non_nullable + as String, + pipedInstance: null == pipedInstance + ? _value.pipedInstance + : pipedInstance // ignore: cast_nullable_to_non_nullable + as String, + themeMode: null == themeMode + ? _value.themeMode + : themeMode // ignore: cast_nullable_to_non_nullable + as ThemeMode, + audioSource: null == audioSource + ? _value.audioSource + : audioSource // ignore: cast_nullable_to_non_nullable + as AudioSource, + streamMusicCodec: null == streamMusicCodec + ? _value.streamMusicCodec + : streamMusicCodec // ignore: cast_nullable_to_non_nullable + as SourceCodecs, + downloadMusicCodec: null == downloadMusicCodec + ? _value.downloadMusicCodec + : downloadMusicCodec // ignore: cast_nullable_to_non_nullable + as SourceCodecs, + discordPresence: null == discordPresence + ? _value.discordPresence + : discordPresence // ignore: cast_nullable_to_non_nullable + as bool, + endlessPlayback: null == endlessPlayback + ? _value.endlessPlayback + : endlessPlayback // ignore: cast_nullable_to_non_nullable + as bool, + )); + } +} + +/// @nodoc +@JsonSerializable() +class _$UserPreferencesImpl implements _UserPreferences { + const _$UserPreferencesImpl( + {this.audioQuality = SourceQualities.high, + this.albumColorSync = true, + this.amoledDarkTheme = false, + this.checkUpdate = true, + this.normalizeAudio = false, + this.showSystemTrayIcon = true, + this.skipNonMusic = false, + this.systemTitleBar = false, + this.closeBehavior = CloseBehavior.minimizeToTray, + @JsonKey( + fromJson: UserPreferences._accentColorSchemeFromJson, + toJson: UserPreferences._accentColorSchemeToJson, + readValue: UserPreferences._accentColorSchemeReadValue) + this.accentColorScheme = const SpotubeColor(0xFF2196F3, name: "Blue"), + this.layoutMode = LayoutMode.adaptive, + @JsonKey( + fromJson: UserPreferences._localeFromJson, + toJson: UserPreferences._localeToJson, + readValue: UserPreferences._localeReadValue) + this.locale = const Locale("system", "system"), + this.recommendationMarket = Market.US, + this.searchMode = SearchMode.youtube, + this.downloadLocation = "", + this.pipedInstance = "https://pipedapi.kavin.rocks", + this.themeMode = ThemeMode.system, + this.audioSource = AudioSource.youtube, + this.streamMusicCodec = SourceCodecs.weba, + this.downloadMusicCodec = SourceCodecs.m4a, + this.discordPresence = true, + this.endlessPlayback = true}); + + factory _$UserPreferencesImpl.fromJson(Map json) => + _$$UserPreferencesImplFromJson(json); + + @override + @JsonKey() + final SourceQualities audioQuality; + @override + @JsonKey() + final bool albumColorSync; + @override + @JsonKey() + final bool amoledDarkTheme; + @override + @JsonKey() + final bool checkUpdate; + @override + @JsonKey() + final bool normalizeAudio; + @override + @JsonKey() + final bool showSystemTrayIcon; + @override + @JsonKey() + final bool skipNonMusic; + @override + @JsonKey() + final bool systemTitleBar; + @override + @JsonKey() + final CloseBehavior closeBehavior; + @override + @JsonKey( + fromJson: UserPreferences._accentColorSchemeFromJson, + toJson: UserPreferences._accentColorSchemeToJson, + readValue: UserPreferences._accentColorSchemeReadValue) + final SpotubeColor accentColorScheme; + @override + @JsonKey() + final LayoutMode layoutMode; + @override + @JsonKey( + fromJson: UserPreferences._localeFromJson, + toJson: UserPreferences._localeToJson, + readValue: UserPreferences._localeReadValue) + final Locale locale; + @override + @JsonKey() + final Market recommendationMarket; + @override + @JsonKey() + final SearchMode searchMode; + @override + @JsonKey() + final String downloadLocation; + @override + @JsonKey() + final String pipedInstance; + @override + @JsonKey() + final ThemeMode themeMode; + @override + @JsonKey() + final AudioSource audioSource; + @override + @JsonKey() + final SourceCodecs streamMusicCodec; + @override + @JsonKey() + final SourceCodecs downloadMusicCodec; + @override + @JsonKey() + final bool discordPresence; + @override + @JsonKey() + final bool endlessPlayback; + + @override + String toString() { + return 'UserPreferences(audioQuality: $audioQuality, albumColorSync: $albumColorSync, amoledDarkTheme: $amoledDarkTheme, checkUpdate: $checkUpdate, normalizeAudio: $normalizeAudio, showSystemTrayIcon: $showSystemTrayIcon, skipNonMusic: $skipNonMusic, systemTitleBar: $systemTitleBar, closeBehavior: $closeBehavior, accentColorScheme: $accentColorScheme, layoutMode: $layoutMode, locale: $locale, recommendationMarket: $recommendationMarket, searchMode: $searchMode, downloadLocation: $downloadLocation, pipedInstance: $pipedInstance, themeMode: $themeMode, audioSource: $audioSource, streamMusicCodec: $streamMusicCodec, downloadMusicCodec: $downloadMusicCodec, discordPresence: $discordPresence, endlessPlayback: $endlessPlayback)'; + } + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other.runtimeType == runtimeType && + other is _$UserPreferencesImpl && + (identical(other.audioQuality, audioQuality) || + other.audioQuality == audioQuality) && + (identical(other.albumColorSync, albumColorSync) || + other.albumColorSync == albumColorSync) && + (identical(other.amoledDarkTheme, amoledDarkTheme) || + other.amoledDarkTheme == amoledDarkTheme) && + (identical(other.checkUpdate, checkUpdate) || + other.checkUpdate == checkUpdate) && + (identical(other.normalizeAudio, normalizeAudio) || + other.normalizeAudio == normalizeAudio) && + (identical(other.showSystemTrayIcon, showSystemTrayIcon) || + other.showSystemTrayIcon == showSystemTrayIcon) && + (identical(other.skipNonMusic, skipNonMusic) || + other.skipNonMusic == skipNonMusic) && + (identical(other.systemTitleBar, systemTitleBar) || + other.systemTitleBar == systemTitleBar) && + (identical(other.closeBehavior, closeBehavior) || + other.closeBehavior == closeBehavior) && + (identical(other.accentColorScheme, accentColorScheme) || + other.accentColorScheme == accentColorScheme) && + (identical(other.layoutMode, layoutMode) || + other.layoutMode == layoutMode) && + (identical(other.locale, locale) || other.locale == locale) && + (identical(other.recommendationMarket, recommendationMarket) || + other.recommendationMarket == recommendationMarket) && + (identical(other.searchMode, searchMode) || + other.searchMode == searchMode) && + (identical(other.downloadLocation, downloadLocation) || + other.downloadLocation == downloadLocation) && + (identical(other.pipedInstance, pipedInstance) || + other.pipedInstance == pipedInstance) && + (identical(other.themeMode, themeMode) || + other.themeMode == themeMode) && + (identical(other.audioSource, audioSource) || + other.audioSource == audioSource) && + (identical(other.streamMusicCodec, streamMusicCodec) || + other.streamMusicCodec == streamMusicCodec) && + (identical(other.downloadMusicCodec, downloadMusicCodec) || + other.downloadMusicCodec == downloadMusicCodec) && + (identical(other.discordPresence, discordPresence) || + other.discordPresence == discordPresence) && + (identical(other.endlessPlayback, endlessPlayback) || + other.endlessPlayback == endlessPlayback)); + } + + @JsonKey(ignore: true) + @override + int get hashCode => Object.hashAll([ + runtimeType, + audioQuality, + albumColorSync, + amoledDarkTheme, + checkUpdate, + normalizeAudio, + showSystemTrayIcon, + skipNonMusic, + systemTitleBar, + closeBehavior, + accentColorScheme, + layoutMode, + locale, + recommendationMarket, + searchMode, + downloadLocation, + pipedInstance, + themeMode, + audioSource, + streamMusicCodec, + downloadMusicCodec, + discordPresence, + endlessPlayback + ]); + + @JsonKey(ignore: true) + @override + @pragma('vm:prefer-inline') + _$$UserPreferencesImplCopyWith<_$UserPreferencesImpl> get copyWith => + __$$UserPreferencesImplCopyWithImpl<_$UserPreferencesImpl>( + this, _$identity); + + @override + Map toJson() { + return _$$UserPreferencesImplToJson( + this, + ); + } +} + +abstract class _UserPreferences implements UserPreferences { + const factory _UserPreferences( + {final SourceQualities audioQuality, + final bool albumColorSync, + final bool amoledDarkTheme, + final bool checkUpdate, + final bool normalizeAudio, + final bool showSystemTrayIcon, + final bool skipNonMusic, + final bool systemTitleBar, + final CloseBehavior closeBehavior, + @JsonKey( + fromJson: UserPreferences._accentColorSchemeFromJson, + toJson: UserPreferences._accentColorSchemeToJson, + readValue: UserPreferences._accentColorSchemeReadValue) + final SpotubeColor accentColorScheme, + final LayoutMode layoutMode, + @JsonKey( + fromJson: UserPreferences._localeFromJson, + toJson: UserPreferences._localeToJson, + readValue: UserPreferences._localeReadValue) + final Locale locale, + final Market recommendationMarket, + final SearchMode searchMode, + final String downloadLocation, + final String pipedInstance, + final ThemeMode themeMode, + final AudioSource audioSource, + final SourceCodecs streamMusicCodec, + final SourceCodecs downloadMusicCodec, + final bool discordPresence, + final bool endlessPlayback}) = _$UserPreferencesImpl; + + factory _UserPreferences.fromJson(Map json) = + _$UserPreferencesImpl.fromJson; + + @override + SourceQualities get audioQuality; + @override + bool get albumColorSync; + @override + bool get amoledDarkTheme; + @override + bool get checkUpdate; + @override + bool get normalizeAudio; + @override + bool get showSystemTrayIcon; + @override + bool get skipNonMusic; + @override + bool get systemTitleBar; + @override + CloseBehavior get closeBehavior; + @override + @JsonKey( + fromJson: UserPreferences._accentColorSchemeFromJson, + toJson: UserPreferences._accentColorSchemeToJson, + readValue: UserPreferences._accentColorSchemeReadValue) + SpotubeColor get accentColorScheme; + @override + LayoutMode get layoutMode; + @override + @JsonKey( + fromJson: UserPreferences._localeFromJson, + toJson: UserPreferences._localeToJson, + readValue: UserPreferences._localeReadValue) + Locale get locale; + @override + Market get recommendationMarket; + @override + SearchMode get searchMode; + @override + String get downloadLocation; + @override + String get pipedInstance; + @override + ThemeMode get themeMode; + @override + AudioSource get audioSource; + @override + SourceCodecs get streamMusicCodec; + @override + SourceCodecs get downloadMusicCodec; + @override + bool get discordPresence; + @override + bool get endlessPlayback; + @override + @JsonKey(ignore: true) + _$$UserPreferencesImplCopyWith<_$UserPreferencesImpl> get copyWith => + throw _privateConstructorUsedError; +} diff --git a/lib/provider/user_preferences/user_preferences_state.g.dart b/lib/provider/user_preferences/user_preferences_state.g.dart index 59043601..ce488247 100644 --- a/lib/provider/user_preferences/user_preferences_state.g.dart +++ b/lib/provider/user_preferences/user_preferences_state.g.dart @@ -6,67 +6,63 @@ part of 'user_preferences_state.dart'; // JsonSerializableGenerator // ************************************************************************** -UserPreferences _$UserPreferencesFromJson(Map json) => - UserPreferences( - audioQuality: $enumDecodeNullable( - _$SourceQualitiesEnumMap, json['audioQuality'], - unknownValue: SourceQualities.high) ?? - SourceQualities.high, +_$UserPreferencesImpl _$$UserPreferencesImplFromJson( + Map json) => + _$UserPreferencesImpl( + audioQuality: + $enumDecodeNullable(_$SourceQualitiesEnumMap, json['audioQuality']) ?? + SourceQualities.high, albumColorSync: json['albumColorSync'] as bool? ?? true, amoledDarkTheme: json['amoledDarkTheme'] as bool? ?? false, checkUpdate: json['checkUpdate'] as bool? ?? true, normalizeAudio: json['normalizeAudio'] as bool? ?? false, showSystemTrayIcon: json['showSystemTrayIcon'] as bool? ?? true, - skipNonMusic: json['skipNonMusic'] as bool? ?? true, + skipNonMusic: json['skipNonMusic'] as bool? ?? false, systemTitleBar: json['systemTitleBar'] as bool? ?? false, - closeBehavior: $enumDecodeNullable( - _$CloseBehaviorEnumMap, json['closeBehavior'], - unknownValue: CloseBehavior.minimizeToTray) ?? - CloseBehavior.minimizeToTray, + closeBehavior: + $enumDecodeNullable(_$CloseBehaviorEnumMap, json['closeBehavior']) ?? + CloseBehavior.minimizeToTray, accentColorScheme: UserPreferences._accentColorSchemeReadValue( json, 'accentColorScheme') == null - ? UserPreferences._defaultAccentColorScheme() + ? const SpotubeColor(0xFF2196F3, name: "Blue") : UserPreferences._accentColorSchemeFromJson( UserPreferences._accentColorSchemeReadValue( json, 'accentColorScheme') as Map), - layoutMode: $enumDecodeNullable(_$LayoutModeEnumMap, json['layoutMode'], - unknownValue: LayoutMode.adaptive) ?? - LayoutMode.adaptive, + layoutMode: + $enumDecodeNullable(_$LayoutModeEnumMap, json['layoutMode']) ?? + LayoutMode.adaptive, locale: UserPreferences._localeReadValue(json, 'locale') == null - ? UserPreferences._defaultLocaleValue() + ? const Locale("system", "system") : UserPreferences._localeFromJson( UserPreferences._localeReadValue(json, 'locale') as Map), - recommendationMarket: $enumDecodeNullable( - _$MarketEnumMap, json['recommendationMarket'], - unknownValue: Market.US) ?? - Market.US, - searchMode: $enumDecodeNullable(_$SearchModeEnumMap, json['searchMode'], - unknownValue: SearchMode.youtube) ?? - SearchMode.youtube, - downloadLocation: json['downloadLocation'] as String? ?? '', + recommendationMarket: + $enumDecodeNullable(_$MarketEnumMap, json['recommendationMarket']) ?? + Market.US, + searchMode: + $enumDecodeNullable(_$SearchModeEnumMap, json['searchMode']) ?? + SearchMode.youtube, + downloadLocation: json['downloadLocation'] as String? ?? "", pipedInstance: - json['pipedInstance'] as String? ?? 'https://pipedapi.kavin.rocks', - themeMode: $enumDecodeNullable(_$ThemeModeEnumMap, json['themeMode'], - unknownValue: ThemeMode.system) ?? + json['pipedInstance'] as String? ?? "https://pipedapi.kavin.rocks", + themeMode: $enumDecodeNullable(_$ThemeModeEnumMap, json['themeMode']) ?? ThemeMode.system, - audioSource: $enumDecodeNullable( - _$AudioSourceEnumMap, json['audioSource'], - unknownValue: AudioSource.youtube) ?? - AudioSource.youtube, + audioSource: + $enumDecodeNullable(_$AudioSourceEnumMap, json['audioSource']) ?? + AudioSource.youtube, streamMusicCodec: $enumDecodeNullable( - _$SourceCodecsEnumMap, json['streamMusicCodec'], - unknownValue: SourceCodecs.weba) ?? + _$SourceCodecsEnumMap, json['streamMusicCodec']) ?? SourceCodecs.weba, downloadMusicCodec: $enumDecodeNullable( - _$SourceCodecsEnumMap, json['downloadMusicCodec'], - unknownValue: SourceCodecs.m4a) ?? + _$SourceCodecsEnumMap, json['downloadMusicCodec']) ?? SourceCodecs.m4a, discordPresence: json['discordPresence'] as bool? ?? true, + endlessPlayback: json['endlessPlayback'] as bool? ?? true, ); -Map _$UserPreferencesToJson(UserPreferences instance) => +Map _$$UserPreferencesImplToJson( + _$UserPreferencesImpl instance) => { 'audioQuality': _$SourceQualitiesEnumMap[instance.audioQuality]!, 'albumColorSync': instance.albumColorSync, @@ -90,6 +86,7 @@ Map _$UserPreferencesToJson(UserPreferences instance) => 'streamMusicCodec': _$SourceCodecsEnumMap[instance.streamMusicCodec]!, 'downloadMusicCodec': _$SourceCodecsEnumMap[instance.downloadMusicCodec]!, 'discordPresence': instance.discordPresence, + 'endlessPlayback': instance.endlessPlayback, }; const _$SourceQualitiesEnumMap = { diff --git a/pubspec.lock b/pubspec.lock index 1a95f20e..0d1b2993 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -957,8 +957,16 @@ packages: url: "https://pub.dev" source: hosted version: "2.1.1" + freezed: + dependency: "direct dev" + description: + name: freezed + sha256: "6c5031daae12c7072b3a87eff98983076434b4889ef2a44384d0cae3f82372ba" + url: "https://pub.dev" + source: hosted + version: "2.4.6" freezed_annotation: - dependency: transitive + dependency: "direct main" description: name: freezed_annotation sha256: c3fd9336eb55a38cc1bbd79ab17573113a8deccd0ecbbf926cca3c62803b5c2d diff --git a/pubspec.yaml b/pubspec.yaml index 1b3d15b0..d3fb5630 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -122,6 +122,7 @@ dependencies: app_links: ^3.5.0 win32_registry: ^1.1.2 flutter_sharing_intent: ^1.1.0 + freezed_annotation: ^2.4.1 dev_dependencies: build_runner: ^2.3.2 @@ -138,6 +139,7 @@ dev_dependencies: json_serializable: ^6.6.2 pub_api_client: ^2.4.0 pubspec_parse: ^1.2.2 + freezed: ^2.4.6 dependency_overrides: http: ^1.1.0 diff --git a/untranslated_messages.json b/untranslated_messages.json index 748a9906..4240c8c0 100644 --- a/untranslated_messages.json +++ b/untranslated_messages.json @@ -2,108 +2,126 @@ "ar": [ "start_a_radio", "how_to_start_radio", - "replace_queue_question" + "replace_queue_question", + "endless_playback" ], "bn": [ "start_a_radio", "how_to_start_radio", - "replace_queue_question" + "replace_queue_question", + "endless_playback" ], "ca": [ "start_a_radio", "how_to_start_radio", - "replace_queue_question" + "replace_queue_question", + "endless_playback" ], "de": [ "start_a_radio", "how_to_start_radio", - "replace_queue_question" + "replace_queue_question", + "endless_playback" ], "es": [ "start_a_radio", "how_to_start_radio", - "replace_queue_question" + "replace_queue_question", + "endless_playback" ], "fa": [ "start_a_radio", "how_to_start_radio", - "replace_queue_question" + "replace_queue_question", + "endless_playback" ], "fr": [ "start_a_radio", "how_to_start_radio", - "replace_queue_question" + "replace_queue_question", + "endless_playback" ], "hi": [ "start_a_radio", "how_to_start_radio", - "replace_queue_question" + "replace_queue_question", + "endless_playback" ], "it": [ "start_a_radio", "how_to_start_radio", - "replace_queue_question" + "replace_queue_question", + "endless_playback" ], "ja": [ "start_a_radio", "how_to_start_radio", - "replace_queue_question" + "replace_queue_question", + "endless_playback" ], "ne": [ "start_a_radio", "how_to_start_radio", - "replace_queue_question" + "replace_queue_question", + "endless_playback" ], "nl": [ "start_a_radio", "how_to_start_radio", - "replace_queue_question" + "replace_queue_question", + "endless_playback" ], "pl": [ "start_a_radio", "how_to_start_radio", - "replace_queue_question" + "replace_queue_question", + "endless_playback" ], "pt": [ "start_a_radio", "how_to_start_radio", - "replace_queue_question" + "replace_queue_question", + "endless_playback" ], "ru": [ "start_a_radio", "how_to_start_radio", - "replace_queue_question" + "replace_queue_question", + "endless_playback" ], "tr": [ "start_a_radio", "how_to_start_radio", - "replace_queue_question" + "replace_queue_question", + "endless_playback" ], "uk": [ "start_a_radio", "how_to_start_radio", - "replace_queue_question" + "replace_queue_question", + "endless_playback" ], "zh": [ "start_a_radio", "how_to_start_radio", - "replace_queue_question" + "replace_queue_question", + "endless_playback" ] } From 5ad5d16683b22d47d3967111b429588626696f91 Mon Sep 17 00:00:00 2001 From: Kingkor Roy Tirtho Date: Wed, 31 Jan 2024 18:07:40 +0600 Subject: [PATCH 133/195] chore: use query as key name for endless playback radio search --- lib/components/shared/track_tile/track_options.dart | 5 +++-- lib/hooks/configurators/use_endless_playback.dart | 5 +++-- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/lib/components/shared/track_tile/track_options.dart b/lib/components/shared/track_tile/track_options.dart index d0d081ff..419f61a4 100644 --- a/lib/components/shared/track_tile/track_options.dart +++ b/lib/components/shared/track_tile/track_options.dart @@ -95,13 +95,14 @@ class TrackOptions extends HookConsumerWidget { final playback = ref.read(ProxyPlaylistNotifier.notifier); final playlist = ref.read(ProxyPlaylistNotifier.provider); final spotify = ref.read(spotifyProvider); + final query = "${track.name} Radio"; final pages = await QueryClient.of(context) .fetchInfiniteQueryJob, dynamic, int, SearchParams>( - job: SearchQueries.queryJob(SearchType.playlist.name), + job: SearchQueries.queryJob(query), args: ( spotify: spotify, searchType: SearchType.playlist, - query: "${track.name} Radio" + query: query, ), ) ?? []; diff --git a/lib/hooks/configurators/use_endless_playback.dart b/lib/hooks/configurators/use_endless_playback.dart index ffbb6991..f5d11829 100644 --- a/lib/hooks/configurators/use_endless_playback.dart +++ b/lib/hooks/configurators/use_endless_playback.dart @@ -31,13 +31,14 @@ void useEndlessPlayback(WidgetRef ref) { final track = playlist.tracks.last; + final query = "${track.name} Radio"; final pages = await queryClient.fetchInfiniteQueryJob, dynamic, int, SearchParams>( - job: SearchQueries.queryJob(SearchType.playlist.name), + job: SearchQueries.queryJob(query), args: ( spotify: spotify, searchType: SearchType.playlist, - query: "${track.name} Radio" + query: query ), ) ?? []; From 9b9822cc3c7321f069ead85251e2b836d1455a75 Mon Sep 17 00:00:00 2001 From: Kingkor Roy Tirtho Date: Wed, 31 Jan 2024 21:56:47 +0600 Subject: [PATCH 134/195] chore: add ios development team --- ios/Runner.xcodeproj/project.pbxproj | 36 ++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/ios/Runner.xcodeproj/project.pbxproj b/ios/Runner.xcodeproj/project.pbxproj index 6edf52e3..dbcdd7a6 100644 --- a/ios/Runner.xcodeproj/project.pbxproj +++ b/ios/Runner.xcodeproj/project.pbxproj @@ -1056,6 +1056,7 @@ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CLANG_ENABLE_MODULES = YES; CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; + DEVELOPMENT_TEAM = 88NVGSJ5N3; ENABLE_BITCODE = NO; INFOPLIST_FILE = "stable-Info.plist"; LD_RUNPATH_SEARCH_PATHS = ( @@ -1078,6 +1079,7 @@ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CLANG_ENABLE_MODULES = YES; CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; + DEVELOPMENT_TEAM = 88NVGSJ5N3; ENABLE_BITCODE = NO; INFOPLIST_FILE = "stable-Info.plist"; LD_RUNPATH_SEARCH_PATHS = ( @@ -1099,6 +1101,7 @@ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CLANG_ENABLE_MODULES = YES; CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; + DEVELOPMENT_TEAM = 88NVGSJ5N3; ENABLE_BITCODE = NO; INFOPLIST_FILE = "stable-Info.plist"; LD_RUNPATH_SEARCH_PATHS = ( @@ -1198,6 +1201,7 @@ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CLANG_ENABLE_MODULES = YES; CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; + DEVELOPMENT_TEAM = 88NVGSJ5N3; ENABLE_BITCODE = NO; INFOPLIST_FILE = "stable-Info.plist"; LD_RUNPATH_SEARCH_PATHS = ( @@ -1294,6 +1298,7 @@ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CLANG_ENABLE_MODULES = YES; CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; + DEVELOPMENT_TEAM = 88NVGSJ5N3; ENABLE_BITCODE = NO; INFOPLIST_FILE = "stable-Info.plist"; LD_RUNPATH_SEARCH_PATHS = ( @@ -1387,6 +1392,7 @@ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CLANG_ENABLE_MODULES = YES; CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; + DEVELOPMENT_TEAM = 88NVGSJ5N3; ENABLE_BITCODE = NO; INFOPLIST_FILE = "stable-Info.plist"; LD_RUNPATH_SEARCH_PATHS = ( @@ -1408,6 +1414,7 @@ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CLANG_ENABLE_MODULES = YES; CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; + DEVELOPMENT_TEAM = 88NVGSJ5N3; ENABLE_BITCODE = NO; INFOPLIST_FILE = "dev-Info.plist"; LD_RUNPATH_SEARCH_PATHS = ( @@ -1430,6 +1437,7 @@ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CLANG_ENABLE_MODULES = YES; CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; + DEVELOPMENT_TEAM = 88NVGSJ5N3; ENABLE_BITCODE = NO; INFOPLIST_FILE = "dev-Info.plist"; LD_RUNPATH_SEARCH_PATHS = ( @@ -1452,6 +1460,7 @@ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CLANG_ENABLE_MODULES = YES; CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; + DEVELOPMENT_TEAM = 88NVGSJ5N3; ENABLE_BITCODE = NO; INFOPLIST_FILE = "dev-Info.plist"; LD_RUNPATH_SEARCH_PATHS = ( @@ -1473,6 +1482,7 @@ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CLANG_ENABLE_MODULES = YES; CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; + DEVELOPMENT_TEAM = 88NVGSJ5N3; ENABLE_BITCODE = NO; INFOPLIST_FILE = "dev-Info.plist"; LD_RUNPATH_SEARCH_PATHS = ( @@ -1494,6 +1504,7 @@ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CLANG_ENABLE_MODULES = YES; CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; + DEVELOPMENT_TEAM = 88NVGSJ5N3; ENABLE_BITCODE = NO; INFOPLIST_FILE = "dev-Info.plist"; LD_RUNPATH_SEARCH_PATHS = ( @@ -1515,6 +1526,7 @@ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CLANG_ENABLE_MODULES = YES; CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; + DEVELOPMENT_TEAM = 88NVGSJ5N3; ENABLE_BITCODE = NO; INFOPLIST_FILE = "dev-Info.plist"; LD_RUNPATH_SEARCH_PATHS = ( @@ -1614,6 +1626,7 @@ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CLANG_ENABLE_MODULES = YES; CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; + DEVELOPMENT_TEAM = 88NVGSJ5N3; ENABLE_BITCODE = NO; INFOPLIST_FILE = "stable-Info.plist"; LD_RUNPATH_SEARCH_PATHS = ( @@ -1636,6 +1649,7 @@ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CLANG_ENABLE_MODULES = YES; CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; + DEVELOPMENT_TEAM = 88NVGSJ5N3; ENABLE_BITCODE = NO; INFOPLIST_FILE = "dev-Info.plist"; LD_RUNPATH_SEARCH_PATHS = ( @@ -1732,6 +1746,7 @@ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CLANG_ENABLE_MODULES = YES; CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; + DEVELOPMENT_TEAM = 88NVGSJ5N3; ENABLE_BITCODE = NO; INFOPLIST_FILE = "stable-Info.plist"; LD_RUNPATH_SEARCH_PATHS = ( @@ -1753,6 +1768,7 @@ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CLANG_ENABLE_MODULES = YES; CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; + DEVELOPMENT_TEAM = 88NVGSJ5N3; ENABLE_BITCODE = NO; INFOPLIST_FILE = "dev-Info.plist"; LD_RUNPATH_SEARCH_PATHS = ( @@ -1846,6 +1862,7 @@ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CLANG_ENABLE_MODULES = YES; CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; + DEVELOPMENT_TEAM = 88NVGSJ5N3; ENABLE_BITCODE = NO; INFOPLIST_FILE = "stable-Info.plist"; LD_RUNPATH_SEARCH_PATHS = ( @@ -1867,6 +1884,7 @@ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CLANG_ENABLE_MODULES = YES; CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; + DEVELOPMENT_TEAM = 88NVGSJ5N3; ENABLE_BITCODE = NO; INFOPLIST_FILE = "dev-Info.plist"; LD_RUNPATH_SEARCH_PATHS = ( @@ -1888,6 +1906,7 @@ ASSETCATALOG_COMPILER_APPICON_NAME = "AppIcon-nightly"; CLANG_ENABLE_MODULES = YES; CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; + DEVELOPMENT_TEAM = 88NVGSJ5N3; ENABLE_BITCODE = NO; INFOPLIST_FILE = "nightly-Info.plist"; LD_RUNPATH_SEARCH_PATHS = ( @@ -1910,6 +1929,7 @@ ASSETCATALOG_COMPILER_APPICON_NAME = "AppIcon-nightly"; CLANG_ENABLE_MODULES = YES; CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; + DEVELOPMENT_TEAM = 88NVGSJ5N3; ENABLE_BITCODE = NO; INFOPLIST_FILE = "nightly-Info.plist"; LD_RUNPATH_SEARCH_PATHS = ( @@ -1932,6 +1952,7 @@ ASSETCATALOG_COMPILER_APPICON_NAME = "AppIcon-nightly"; CLANG_ENABLE_MODULES = YES; CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; + DEVELOPMENT_TEAM = 88NVGSJ5N3; ENABLE_BITCODE = NO; INFOPLIST_FILE = "nightly-Info.plist"; LD_RUNPATH_SEARCH_PATHS = ( @@ -1954,6 +1975,7 @@ ASSETCATALOG_COMPILER_APPICON_NAME = "AppIcon-nightly"; CLANG_ENABLE_MODULES = YES; CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; + DEVELOPMENT_TEAM = 88NVGSJ5N3; ENABLE_BITCODE = NO; INFOPLIST_FILE = "nightly-Info.plist"; LD_RUNPATH_SEARCH_PATHS = ( @@ -1975,6 +1997,7 @@ ASSETCATALOG_COMPILER_APPICON_NAME = "AppIcon-nightly"; CLANG_ENABLE_MODULES = YES; CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; + DEVELOPMENT_TEAM = 88NVGSJ5N3; ENABLE_BITCODE = NO; INFOPLIST_FILE = "nightly-Info.plist"; LD_RUNPATH_SEARCH_PATHS = ( @@ -1996,6 +2019,7 @@ ASSETCATALOG_COMPILER_APPICON_NAME = "AppIcon-nightly"; CLANG_ENABLE_MODULES = YES; CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; + DEVELOPMENT_TEAM = 88NVGSJ5N3; ENABLE_BITCODE = NO; INFOPLIST_FILE = "nightly-Info.plist"; LD_RUNPATH_SEARCH_PATHS = ( @@ -2017,6 +2041,7 @@ ASSETCATALOG_COMPILER_APPICON_NAME = "AppIcon-nightly"; CLANG_ENABLE_MODULES = YES; CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; + DEVELOPMENT_TEAM = 88NVGSJ5N3; ENABLE_BITCODE = NO; INFOPLIST_FILE = "nightly-Info.plist"; LD_RUNPATH_SEARCH_PATHS = ( @@ -2038,6 +2063,7 @@ ASSETCATALOG_COMPILER_APPICON_NAME = "AppIcon-nightly"; CLANG_ENABLE_MODULES = YES; CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; + DEVELOPMENT_TEAM = 88NVGSJ5N3; ENABLE_BITCODE = NO; INFOPLIST_FILE = "nightly-Info.plist"; LD_RUNPATH_SEARCH_PATHS = ( @@ -2059,6 +2085,7 @@ ASSETCATALOG_COMPILER_APPICON_NAME = "AppIcon-nightly"; CLANG_ENABLE_MODULES = YES; CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; + DEVELOPMENT_TEAM = 88NVGSJ5N3; ENABLE_BITCODE = NO; INFOPLIST_FILE = "nightly-Info.plist"; LD_RUNPATH_SEARCH_PATHS = ( @@ -2158,6 +2185,7 @@ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CLANG_ENABLE_MODULES = YES; CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; + DEVELOPMENT_TEAM = 88NVGSJ5N3; ENABLE_BITCODE = NO; INFOPLIST_FILE = "stable-Info.plist"; LD_RUNPATH_SEARCH_PATHS = ( @@ -2180,6 +2208,7 @@ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CLANG_ENABLE_MODULES = YES; CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; + DEVELOPMENT_TEAM = 88NVGSJ5N3; ENABLE_BITCODE = NO; INFOPLIST_FILE = "dev-Info.plist"; LD_RUNPATH_SEARCH_PATHS = ( @@ -2202,6 +2231,7 @@ ASSETCATALOG_COMPILER_APPICON_NAME = "AppIcon-nightly"; CLANG_ENABLE_MODULES = YES; CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; + DEVELOPMENT_TEAM = 88NVGSJ5N3; ENABLE_BITCODE = NO; INFOPLIST_FILE = "nightly-Info.plist"; LD_RUNPATH_SEARCH_PATHS = ( @@ -2298,6 +2328,7 @@ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CLANG_ENABLE_MODULES = YES; CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; + DEVELOPMENT_TEAM = 88NVGSJ5N3; ENABLE_BITCODE = NO; INFOPLIST_FILE = "stable-Info.plist"; LD_RUNPATH_SEARCH_PATHS = ( @@ -2319,6 +2350,7 @@ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CLANG_ENABLE_MODULES = YES; CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; + DEVELOPMENT_TEAM = 88NVGSJ5N3; ENABLE_BITCODE = NO; INFOPLIST_FILE = "dev-Info.plist"; LD_RUNPATH_SEARCH_PATHS = ( @@ -2340,6 +2372,7 @@ ASSETCATALOG_COMPILER_APPICON_NAME = "AppIcon-nightly"; CLANG_ENABLE_MODULES = YES; CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; + DEVELOPMENT_TEAM = 88NVGSJ5N3; ENABLE_BITCODE = NO; INFOPLIST_FILE = "nightly-Info.plist"; LD_RUNPATH_SEARCH_PATHS = ( @@ -2433,6 +2466,7 @@ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CLANG_ENABLE_MODULES = YES; CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; + DEVELOPMENT_TEAM = 88NVGSJ5N3; ENABLE_BITCODE = NO; INFOPLIST_FILE = "stable-Info.plist"; LD_RUNPATH_SEARCH_PATHS = ( @@ -2454,6 +2488,7 @@ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CLANG_ENABLE_MODULES = YES; CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; + DEVELOPMENT_TEAM = 88NVGSJ5N3; ENABLE_BITCODE = NO; INFOPLIST_FILE = "dev-Info.plist"; LD_RUNPATH_SEARCH_PATHS = ( @@ -2475,6 +2510,7 @@ ASSETCATALOG_COMPILER_APPICON_NAME = "AppIcon-nightly"; CLANG_ENABLE_MODULES = YES; CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; + DEVELOPMENT_TEAM = 88NVGSJ5N3; ENABLE_BITCODE = NO; INFOPLIST_FILE = "nightly-Info.plist"; LD_RUNPATH_SEARCH_PATHS = ( From 46830d212203de84b452eeae4a96475a41ed100f Mon Sep 17 00:00:00 2001 From: Vishwas Saini <85990875+VishwasSaini25@users.noreply.github.com> Date: Fri, 9 Feb 2024 09:25:27 +0530 Subject: [PATCH 135/195] website: Website enhancement (#1203) --- website/pages/index.tsx | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/website/pages/index.tsx b/website/pages/index.tsx index 770ffc41..b0032c18 100755 --- a/website/pages/index.tsx +++ b/website/pages/index.tsx @@ -32,7 +32,7 @@ const Root = () => { md: "transparent", }} > - + Spotube @@ -44,7 +44,7 @@ const Root = () => { {/* */} - + { /> { }} color="gray.800" > - Access all your Spotify Music & Playlists + Access all your Spotify Music & Playlists You can use all your Spotify tracks & playlists here. Everything will be in Sync & some action taken from Spotube will also @@ -111,7 +112,7 @@ const Root = () => { display: "block", height: "100%", width: "100%", - background: "url('/headline-2b.png') rgba(0, 0, 0, 0.9)", + background: "url('/headline-2b.png') rgba(0, 0, 0, 0)", bgSize: "contain", bgRepeat: "no-repeat", bgPos: "center", @@ -130,7 +131,7 @@ const Root = () => { From 8167963212eeb5dfb0b4fb2eadf81d466659a9f1 Mon Sep 17 00:00:00 2001 From: Stephan Paternotte Date: Fri, 9 Feb 2024 04:59:15 +0100 Subject: [PATCH 136/195] fix(translations): Update app_nl.arb (#1168) I made a couple of improvements to the Dutch translation, which I hope the original translator will appreciate. --- lib/l10n/app_nl.arb | 185 ++++++++++++++++++++++---------------------- 1 file changed, 92 insertions(+), 93 deletions(-) diff --git a/lib/l10n/app_nl.arb b/lib/l10n/app_nl.arb index bf819c57..3bece8be 100644 --- a/lib/l10n/app_nl.arb +++ b/lib/l10n/app_nl.arb @@ -1,107 +1,107 @@ { "guest": "Gast", "browse": "Bladeren", - "search": "Zoek op", + "search": "Zoeken", "library": "Bibliotheek", - "lyrics": "Liedteksten", + "lyrics": "Teksten", "settings": "Instellingen", - "genre_categories_filter": "Categorieën of genres filteren...", + "genre_categories_filter": "Categorieën of genres filteren…", "genre": "Genre", "personalized": "Gepersonaliseerd", "featured": "Aanbevolen", "new_releases": "Nieuwe uitgaves", "songs": "Liedjes", "playing_track": "{track} afspelen", - "queue_clear_alert": "Dit zal de huidige wachtrij wissen. {track_length} tracks worden verwijderd\nWilt u doorgaan?", + "queue_clear_alert": "Dit zal de huidige wachtrij wissen. {track_length} nummers worden verwijderd\nWil je doorgaan?", "load_more": "Meer laden", "playlists": "Afspeellijsten", - "artists": "Kunstenaars", + "artists": "Artiesten", "albums": "Albums", "tracks": "Nummers", "downloads": "Downloads", - "filter_playlists": "Filter uw afspeellijsten...", + "filter_playlists": "Afspeellijsten filteren…", "liked_tracks": "Geliefde tracks", "liked_tracks_description": "Al je favoriete nummers", - "create_playlist": "Afspeellijst maken", - "create_a_playlist": "Een afspeellijst maken", + "create_playlist": "Afspeellijst aanmaken", + "create_a_playlist": "Een afspeellijst aanmaken", "update_playlist": "Afspeellijst bijwerken", - "create": "Maak", + "create": "Aanmaken", "cancel": "Annuleren", "update": "Bijwerken", - "playlist_name": "Afspeellijstnaam", + "playlist_name": "Naam afspeellijst", "name_of_playlist": "Naam van de afspeellijst", "description": "Beschrijving", "public": "Openbaar", "collaborative": "Samenwerkend", - "search_local_tracks": "Lokale nummers zoeken...", - "play": "Speel", + "search_local_tracks": "Lokale nummers zoeken…", + "play": "Afspelen", "delete": "Wissen", "none": "Geen", "sort_a_z": "Sorteren op A-Z", "sort_z_a": "Sorteren op Z-A", - "sort_artist": "Sorteren op kunstenaar", + "sort_artist": "Sorteren op artiest", "sort_album": "Sorteren op album", "sort_tracks": "Nummers sorteren", "currently_downloading": "Momenteel aan het downloaden ({tracks_length})", "cancel_all": "Alle annuleren", - "filter_artist": "Kunstenaars filteren...", + "filter_artist": "Artiesten filteren…", "followers": "{followers} volgers", - "add_artist_to_blacklist": "Kunstenaar toevoegen aan zwarte lijst", + "add_artist_to_blacklist": "Artiest toevoegen aan zwarte lijst", "top_tracks": "Topsporen", "fans_also_like": "Liefhebbers willen ook", - "loading": "Aan het laden...", - "artist": "Kunstenaar", - "blacklisted": "Op de zwarte lijst", - "following": "Op volg", + "loading": "Laden…", + "artist": "Artiest", + "blacklisted": "Zwarte lijst", + "following": "Volgen", "follow": "Volgen", "artist_url_copied": "URL artiest gekopieerd naar klembord", - "added_to_queue": "{tracks} tracks toegevoegd aan wachtrij", - "filter_albums": "Albums filteren...", + "added_to_queue": "{tracks} nummers toegevoegd aan wachtrij", + "filter_albums": "Albums filteren…", "synced": "Gesynchroniseerd", "plain": "Eenvoudig", - "shuffle": "Schuifelen", - "search_tracks": "Zoek nummers...", - "released": "Vrijgegeven", + "shuffle": "Willekeurig", + "search_tracks": "Nummers zoeken…", + "released": "Uitgegeven", "error": "Fout {error}", "title": "Titel", "time": "Tijd", "more_actions": "Meer acties", "download_count": "({count}) downloads", - "add_count_to_playlist": "Voeg ({count}) toe aan afspeellijst", - "add_count_to_queue": "Voeg ({count}) toe aan wachtrij", - "play_count_next": "Speel ({count}) volgende", + "add_count_to_playlist": "({count}) aan afspeellijst toevoegen", + "add_count_to_queue": "({count}) aan wachtrij toevoegen", + "play_count_next": "Volgende ({count}) afspelen", "album": "Album", "copied_to_clipboard": "{data} naar klembord gekopieerd", - "add_to_following_playlists": "Voeg {track} toe aan volgende afspeellijsten", + "add_to_following_playlists": "{track} aan volgende afspeellijsten toevoegen", "add": "Toevoegen", - "added_track_to_queue": "{track} toegevoegd aan wachtrij", + "added_track_to_queue": "{track} aan wachtrij toegevoegd", "add_to_queue": "Toevoegen aan wachtrij", - "track_will_play_next": "{track} zal hierna spelen", + "track_will_play_next": "{track} wordt hierna afgespeeld", "play_next": "Volgende afspelen", - "removed_track_from_queue": "{track} uit wachtrij verwijderd", - "remove_from_queue": "Verwijderen uit wachtrij", - "remove_from_favorites": "Verwijderen uit favorieten", + "removed_track_from_queue": "{track} van wachtrij verwijderd", + "remove_from_queue": "Van wachtrij verwijderen", + "remove_from_favorites": "Van favorieten verwijderen", "save_as_favorite": "Opslaan als favoriet", - "add_to_playlist": "Toevoegen aan afspeellijst", - "remove_from_playlist": "Verwijderen uit afspeellijst", - "add_to_blacklist": "Toevoegen aan zwarte lijst", - "remove_from_blacklist": "Verwijderen uit zwarte lijst", + "add_to_playlist": "Aan afspeellijst toevoegen", + "remove_from_playlist": "Van afspeellijst verwijderen", + "add_to_blacklist": "Aan zwarte lijst toevoegen", + "remove_from_blacklist": "Van zwarte lijst verwijderen", "share": "Delen", "mini_player": "Minispeler", - "slide_to_seek": "Schuif om vooruit of achteruit te zoeken", + "slide_to_seek": "Schuiven om vooruit of achteruit te zoeken", "shuffle_playlist": "Afspeellijst schuifelen", "unshuffle_playlist": "Afspeellijst onschuifelen", "previous_track": "Vorige nummer", "next_track": "Volgende nummer", - "pause_playback": "Weergave pauzeren", - "resume_playback": "Weergave hervatten", - "loop_track": "Nummer loopen", + "pause_playback": "Afspelen pauzeren", + "resume_playback": "Afspelen hervatten", + "loop_track": "Nummer herhalen", "repeat_playlist": "Afspeellijst herhalen", "queue": "Wachtrij", "alternative_track_sources": "Alternatieve nummerbronnen", "download_track": "Nummer downloaden", - "tracks_in_queue": "{tracks} tracks in wachtrij", - "clear_all": "Wis alles", + "tracks_in_queue": "{tracks} nummers in wachtrij", + "clear_all": "Alles wissen", "show_hide_ui_on_hover": "UI tonen/verbergen bij zweven", "always_on_top": "Altijd bovenaan", "exit_mini_player": "Minispeler afsluiten", @@ -111,7 +111,7 @@ "connect_with_spotify": "Verbinden met Spotify", "logout": "Afmelden", "logout_of_this_account": "Afmelden van dit account", - "language_region": "Taal & Regio", + "language_region": "Taal & regio", "language": "Taal", "system_default": "Systeemstandaard", "market_place_region": "Marktplaats-regio", @@ -119,76 +119,78 @@ "appearance": "Uiterlijk", "layout_mode": "Opmaakmodus", "override_layout_settings": "Instellingen voor responsieve opmaakmodus opheffen", - "adaptive": "Aanpassingsgericht", + "adaptive": "Adaptief", "compact": "Compact", - "extended": "Uitgebreide", + "extended": "Uitgebreid", "theme": "Thema", "dark": "Donker", "light": "Licht", "system": "Systeem", "accent_color": "Accentkleur", "sync_album_color": "Albumkleur synchroniseren", - "sync_album_color_description": "Gebruikt de overheersende kleur van het albumartikel als accentkleur", + "sync_album_color_description": "Gebruikt de overheersende kleur van het album als accentkleur", "playback": "Weergave", "audio_quality": "Audiokwaliteit", "high": "Hoog", "low": "Laag", - "pre_download_play": "Vooraf downloaden en spelen", + "pre_download_play": "Vooraf downloaden en afspelen", "pre_download_play_description": "In plaats van audio te streamen, kun je bytes downloaden en afspelen (aanbevolen voor gebruikers met een hogere bandbreedte)", "skip_non_music": "Niet-muzieksegmenten overslaan (SponsorBlock)", "blacklist_description": "Nummers en artiesten op de zwarte lijst", "wait_for_download_to_finish": "Wacht tot de huidige download is voltooid", "desktop": "Bureaublad", "close_behavior": "Sluitgedrag", - "close": "Sluit af", - "minimize_to_tray": "Minimaliseren naar lade", + "close": "Afsluiten", + "minimize_to_tray": "Minimaliseren naar systeemvak", "show_tray_icon": "Systeemvakpictogram tonen", "about": "Over", - "u_love_spotube": "We weten dat jullie van Spotube houden", + "u_love_spotube": "We weten dat je van Spotube houd", "check_for_updates": "Controleren op updates", "about_spotube": "Over Spotube", "blacklist": "Zwarte lijst", "please_sponsor": "Sponsor/Doneer a.u.b.", "spotube_description": "Spotube, een lichtgewicht, cross-platform, vrij-voor-alles Spotify-client", "version": "Versie", - "build_number": "Beeldnummer", - "founder": "Stichter", + "build_number": "Bouwnummer", + "founder": "Grondlegger", "repository": "Opslagplaats", "bug_issues": "Bug+problemen", - "made_with": "Gemaakt met ❤️ in Bangladesh🇧🇩", + "made_with": "Met ❤️ gemaakt in Bangladesh🇧🇩", "kingkor_roy_tirtho": "Kingkor Roy Tirtho", "copyright": "© 2021-{current_year} Kingkor Roy Tirtho", "license": "Licentie", - "add_spotify_credentials": "Voeg je spotify-referenties toe om te beginnen", - "credentials_will_not_be_shared_disclaimer": "Maakt u geen zorgen, uw gegevens worden niet verzameld of gedeeld met anderen.", - "know_how_to_login": "Weet u niet hoe u dit moet doen?", - "follow_step_by_step_guide": "Volg de stap voor stap gids", + "add_spotify_credentials": "Voeg om te beginnen je spotify-aanmeldgegevens toe", + "credentials_will_not_be_shared_disclaimer": "Maak je geen zorgen, je gegevens worden niet verzameld of gedeeld met anderen.", + "know_how_to_login": "Weet je niet hoe je dit moet doen?", + "follow_step_by_step_guide": "Volg de stapsgewijze handleiding", "spotify_cookie": "Spotify {name} Cookie", "cookie_name_cookie": "{name} Cookie", "fill_in_all_fields": "Vul alle velden in a.u.b.", "submit": "Verzenden", - "exit": "Ga weg", + "exit": "Afronden", "previous": "Vorige", "next": "Volgende", "done": "Klaar", "step_1": "Stap 1", "first_go_to": "Ga eerst naar", - "login_if_not_logged_in": "en Inloggen/Aanmelden als u niet bent ingelogd", + "login_if_not_logged_in": "en Inloggen/Aanmelden als je niet bent ingelogd", "step_2": "Stap 2", "step_2_steps": "1. Zodra je bent aangemeld, druk je op F12 of klik je met de rechtermuisknop > Inspect om de Browser devtools te openen.\n2. Ga vervolgens naar het tabblad \"Toepassing\" (Chrome, Edge, Brave enz..) of naar het tabblad \"Opslag\" (Firefox, Palemoon enz..).\n3. Ga naar de sectie \"Cookies\" en vervolgens naar de subsectie \"https://accounts.spotify.com\".", "step_3": "Stap 3", + "step_3_steps": "De waarde van cookie \"sp_dc\" kopiëren", "success_emoji": "Succes🥳", - "success_message": "Je bent nu succesvol ingelogd met je Spotify account. Goed gedaan, maat!", + "success_message": "Je bent nu ingelogd met je Spotify account. Goed gedaan!", "step_4": "Stap 4", + "step_4_steps": "De gekopieerde waarde \"sp_dc\" plakken", "something_went_wrong": "Er ging iets mis", "piped_instance": "Piped-serverinstantie", - "piped_description": "De Piped-serverinstantie die moet worden gebruikt voor het matchen van sporen", + "piped_description": "De Piped-serverinstantie die moet worden gebruikt voor overeenkomstige nummers", "piped_warning": "Sommige werken misschien niet goed. Dus gebruik ze op eigen risico", "generate_playlist": "Afspeellijst genereren", "track_exists": "Nummer {track} bestaat al", "replace_downloaded_tracks": "Alle gedownloade nummers vervangen", "skip_download_tracks": "Downloaden van alle gedownloade nummers overslaan", - "do_you_want_to_replace": "Wil je de bestaande nummer vervangen?", + "do_you_want_to_replace": "Wil je het bestaande nummer vervangen?", "replace": "Vervangen", "skip": "Overslaan", "select_up_to_count_type": "Selecteer tot {count} {type}", @@ -196,13 +198,13 @@ "add_genres": "Genres toevoegen", "country": "Land", "number_of_tracks_generate": "Aantal nummers om te genereren", - "acousticness": "Akoesticiteit", + "acousticness": "Akoestiek", "danceability": "Dansbaarheid", "energy": "Energie", "instrumentalness": "Instrumentaliteit", "liveness": "Levendigheid", "loudness": "Luidheid", - "speechiness": "Sprakeligheid", + "speechiness": "Spraak", "valence": "Valentie", "popularity": "Populariteit", "key": "Sleutel", @@ -217,16 +219,16 @@ "max": "Max", "target": "Doel", "moderate": "Matig", - "deselect_all": "Alles deselecteren", + "deselect_all": "Selectie opheffen", "select_all": "Alles selecteren", "are_you_sure": "Weet je het zeker?", - "generating_playlist": "Je aangepaste afspeellijst genereren...", + "generating_playlist": "Aangepaste afspeellijst genereren…", "selected_count_tracks": "{count} nummers geselecteerd", - "download_warning": "Als je alle Tracks in bulk downloadt, ben je duidelijk bezig met muziekpiraterij en breng je schade toe aan de creatieve muziekmaatschappij. Ik hoop dat je je hiervan bewust bent. Probeer altijd het harde werk van artiesten te respecteren en te steunen.", - "download_ip_ban_warning": "BTW, je IP-adres kan worden geblokkeerd op YouTube als gevolg van buitensporige downloadverzoeken dan normaal. IP blokkering betekent dat je YouTube niet kunt gebruiken (zelfs als je ingelogd bent) voor tenminste 2-3 maanden vanaf dat IP apparaat. Spotube is niet verantwoordelijk als dit ooit gebeurt.", + "download_warning": "Als je alle nummers in bulk downloadt, ben je duidelijk bezig met muziekpiraterij en breng je schade toe aan de creatieve muziekmaatschappij. Ik hoop dat je je hiervan bewust bent. Probeer altijd het harde werk van artiesten te respecteren en te steunen.", + "download_ip_ban_warning": "BTW, je IP-adres kan worden geblokkeerd op YouTube als gevolg van buitensporige downloadverzoeken. IP-blokkering betekent dat je YouTube niet kunt gebruiken (zelfs als je ingelogd bent) voor tenminste 2-3 maanden vanaf dat IP-apparaat. Spotube is niet verantwoordelijk als dit ooit gebeurt.", "by_clicking_accept_terms": "Door op 'accepteren' te klikken ga je akkoord met de volgende voorwaarden:", - "download_agreement_1": "Ik weet dat ik muziek illegaal verveel. Ik ben en crimineel.", - "download_agreement_2": "Ik steun de kunstenaar waar ik kan en ik doe dit alleen omdat ik geen geld heb om hun kunst te kopen.", + "download_agreement_1": "Ik weet dat ik muziek illegaal donload. Ik ben slecht.", + "download_agreement_2": "Ik steun de artiest waar ik kan en ik doe dit alleen omdat ik geen geld heb om hun kunst te kopen.", "download_agreement_3": "Ik ben me er volledig van bewust dat mijn IP geblokkeerd kan worden op YouTube & ik houd Spotube of zijn eigenaars/contributeurs niet verantwoordelijk voor ongelukken die veroorzaakt worden door mijn huidige actie.", "decline": "Weigeren", "accept": "Accepteren", @@ -247,45 +249,42 @@ "custom_hours": "Aangepaste uren", "logs": "Logboeken", "developers": "Ontwikkelaars", - "not_logged_in": "U bent niet aangemeld", + "not_logged_in": "Je bent niet aangemeld", "search_mode": "Zoekmodus", "youtube_api_type": "API-type", "ok": "Oké", "failed_to_encrypt": "Versleuteling mislukt", - "encryption_failed_warning": "Spotube gebruikt encryptie om je gegevens veilig op te slaan. Maar dat is niet gelukt. Dus zal het terugvallen op onveilige opslag.\nAls je linux gebruikt, zorg er dan voor dat je een geheim-dienst (gnome-keyring, kde-wallet, keepassxc etc) hebt geïnstalleerd.", - "querying_info": "Info opvragen...", + "encryption_failed_warning": "Spotube gebruikt versleuteling om je gegevens veilig op te slaan. Maar dat is niet gelukt. Dus zal het terugvallen op onveilige opslag.\nAls je linux gebruikt, zorg er dan voor dat je een geheim-dienst (gnome-keyring, kde-wallet, keepassxc etc) hebt geïnstalleerd.", + "querying_info": "Info opvragen…", "piped_api_down": "Piped API is uit", "piped_down_error_instructions": "De Piped-instantie {pipedInstance} is momenteel uitgevallen\n\nVerander de instantie of verander het 'API-type' naar de officiële YouTube API.\n\nZorg ervoor dat u de app herstart na de wijziging", - "you_are_offline": "U bent momenteel offline", - "connection_restored": "Uw internetverbinding is hersteld", + "you_are_offline": "Je bent momenteel offline", + "connection_restored": "Je internetverbinding is hersteld", "use_system_title_bar": "Systeemtitelbalk gebruiken", - "crunching_results": "Resultaten kraken...", - "search_to_get_results": "Zoek om resultaten te krijgen", + "crunching_results": "Resultaten verwerken…", + "search_to_get_results": "Zoeken naar resultaten", "use_amoled_mode": "Pikzwart donkerthema", "pitch_dark_theme": "AMOLED-modus", "normalize_audio": "Audio normaliseren", - "change_cover": "Dekking wijzigen", - "add_cover": "Dekking toevoegen", + "change_cover": "Hoes aanpassen", + "add_cover": "Hoes toevoegen", "restore_defaults": "Standaardwaarden herstellen", - "download_music_codec": "Muziek-codec downloaden", - "streaming_music_codec": "Muziek-codec streamen", - "login_with_lastfm": "Aanmelden met Last.fm", + "download_music_codec": "Download-codec", + "streaming_music_codec": "Streaming-codec", + "login_with_lastfm": "Inloggen met Last.fm", "connect": "Verbinden", "disconnect_lastfm": "Last.fm verbreken", - "disconnect": "Ontkoppelen", + "disconnect": "Verbeken", "username": "Gebruikersnaam", "password": "Wachtwoord", "login": "Inloggen", - "login_with_your_lastfm": "Inloggen met uw Last.fm account", - "scrobble_to_lastfm": "Scrobbel naar Last.fm", - "audio_source": "Audiobron", + "login_with_your_lastfm": "Inloggen met je Last.fm account", + "scrobble_to_lastfm": "Scrobbelen naar Last.fm", "go_to_album": "Ga naar album", "discord_rich_presence": "Discord Rich Presence", - "browse_all": "Alles bekijken", + "browse_all": "Alles doorbladeren", "genres": "Genres", - "explore_genres": "Verken genres", - "step_3_steps": "Kopieer de waarde van de \"sp_dc\"-cookie", - "step_4_steps": "Plak de gekopieerde waarde van \"sp_dc\"", + "explore_genres": "Genres verkennen", "friends": "Vrienden", - "no_lyrics_available": "Sorry, kan geen teksten vinden voor deze track" -} \ No newline at end of file + "no_lyrics_available": "Sorry, geen teksten gevonden voor dit nummer" +} From 0737a362d88e7d4d98e9b848d051b5e09bd455fc Mon Sep 17 00:00:00 2001 From: Stephan Paternotte Date: Fri, 9 Feb 2024 05:00:09 +0100 Subject: [PATCH 137/195] chore: Add 2nd dutch translator (#1170) 2nd Dutch translator added --- lib/l10n/l10n.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/l10n/l10n.dart b/lib/l10n/l10n.dart index 335be545..51d4ef7c 100644 --- a/lib/l10n/l10n.dart +++ b/lib/l10n/l10n.dart @@ -8,7 +8,7 @@ /// yuri-val@github => Ukrainian /// energywave@github, ncvescera@github, OpenCode@github => Italian /// mdksec@github => Turkish -/// SecularSteve@github => Dutch +/// Stephan-P@github, SecularSteve@github => Dutch import 'package:flutter/material.dart'; class L10n { From 8ed65bfa179000607397f3170c057d34afe37a56 Mon Sep 17 00:00:00 2001 From: Kingkor Roy Tirtho Date: Sat, 17 Feb 2024 13:45:54 +0600 Subject: [PATCH 138/195] chore: add folders to git ignore --- website/.gitignore | 3 +++ 1 file changed, 3 insertions(+) diff --git a/website/.gitignore b/website/.gitignore index 737d8721..ee4209a0 100755 --- a/website/.gitignore +++ b/website/.gitignore @@ -33,3 +33,6 @@ yarn-error.log* # typescript *.tsbuildinfo + +/.svelte-kit +/.netlify From cd669e22c12679ae328fdefdb460cc16dc2e88d0 Mon Sep 17 00:00:00 2001 From: Kingkor Roy Tirtho Date: Sat, 17 Feb 2024 13:48:27 +0600 Subject: [PATCH 139/195] website: new sveltekit based website (#1239) * feat: initialize website project * feat: add initial homepage with download links * feat: initial download page * fix: linux icon color * feat: add mobile nav and github star button * feat: add older and nightly downloads page * feat: add supporters and footer * feat: add author details in about page * feat: add darkmode toggle for website * feat: add playstore and flathub download buttons and contribution button * feat: add blogs support * feat: remove netlify deploy config and add cloudflare config and favicons + manifest * chore: add robots.txt * feat: add spotube logo in navbar and fix build errors * chore: add gap --- website/.eslintignore | 13 + website/.eslintrc.cjs | 31 + website/.eslintrc.json | 6 - website/.gitignore | 45 +- website/.node-version | 1 + website/.npmrc | 1 + website/.prettierignore | 4 + website/.prettierrc | 10 +- website/.vscode/settings.json | 120 + website/README.md | 50 +- website/components/AdDetector.tsx | 133 - website/components/ArticleCard.tsx | 138 - website/components/CodeBlock.tsx | 25 - website/components/DownloadButton.tsx | 118 - website/components/Footer.tsx | 88 - website/components/Navbar.tsx | 218 - website/components/UserDetailedCard.tsx | 153 - website/components/special.tsx | 72 - website/configurations/gtag.ts | 17 - website/configurations/ocotokit.ts | 3 - website/hooks/usePlatform.ts | 26 - website/misc/MarkdownComponentDefs.tsx | 43 - website/next-env.d.ts | 5 - website/next.config.js | 7 - website/package-lock.json | 6391 +++++++++++++++++ website/package.json | 92 +- website/pages/_app.tsx | 138 - website/pages/about/index.tsx | 68 - website/pages/blog/[slug].tsx | 119 - website/pages/blog/index.tsx | 66 - website/pages/index.tsx | 181 - website/pages/other-downloads/index.tsx | 109 - .../other-downloads/nightly-downloads.tsx | 118 - .../pages/other-downloads/package-manager.tsx | 117 - .../other-downloads/stable-downloads.tsx | 195 - website/playwright.config.ts | 12 + website/pnpm-lock.yaml | 4502 ------------ website/postcss.config.cjs | 6 + website/posts/getting-started-with-spotube.md | 84 - website/posts/images/.gitkeep | 0 website/posts/spotube-basics.md | 41 + website/public/android-chrome-192x192.png | Bin 25999 -> 0 bytes website/public/android-chrome-512x512.png | Bin 25999 -> 0 bytes website/public/apple-touch-icon.png | Bin 26572 -> 0 bytes website/public/favicon-16x16.png | Bin 1627 -> 0 bytes website/public/favicon-32x32.png | Bin 2682 -> 0 bytes website/public/favicon.ico | Bin 1150 -> 0 bytes website/public/google7d445d7199e703dc.html | 1 - website/public/headline-1.png | Bin 344416 -> 0 bytes website/public/headline-2a.svg | 1 - website/public/headline-2b.png | Bin 1167053 -> 0 bytes website/public/headline-3.svg | 1 - website/public/site.webmanifest | 1 - website/public/spotube-screenshot-web.jpg | Bin 330295 -> 0 bytes website/src/app.d.ts | 22 + website/src/app.html | 23 + website/src/app.postcss | 11 + .../downloads/download-items.svelte | 25 + .../src/lib/components/markdown/layout.svelte | 3 + .../components/navbar/darkmode-toggle.svelte | 32 + .../src/lib/components/navbar/navbar.svelte | 57 + .../lib/components/navdrawer/navdrawer.svelte | 37 + website/src/lib/index.ts | 61 + website/src/lib/persisted-store.ts | 106 + website/src/lib/posts.ts | 41 + website/src/routes/+layout.svelte | 71 + website/src/routes/+page.svelte | 110 + website/src/routes/+page.ts | 34 + website/src/routes/about/+page.svelte | 22 + website/src/routes/api/posts/+server.ts | 9 + website/src/routes/blog/+page.svelte | 32 + website/src/routes/blog/+page.ts | 11 + website/src/routes/blog/[slug]/+page.svelte | 26 + website/src/routes/blog/[slug]/+page.ts | 23 + website/src/routes/downloads/+page.svelte | 39 + .../src/routes/downloads/nightly/+page.svelte | 33 + .../src/routes/downloads/older/+page.svelte | 138 + website/src/routes/downloads/older/+page.ts | 14 + .../src/routes/downloads/packages/+page.svx | 70 + website/static/android-chrome-192x192.png | Bin 0 -> 12127 bytes website/static/android-chrome-512x512.png | Bin 0 -> 64675 bytes website/static/apple-touch-icon.png | Bin 0 -> 10898 bytes website/static/favicon-16x16.png | Bin 0 -> 390 bytes website/static/favicon-32x32.png | Bin 0 -> 777 bytes website/static/favicon.ico | Bin 0 -> 15406 bytes website/static/fonts/AbrilFatface.ttf | Bin 0 -> 58448 bytes website/static/images/spotube-logo.png | Bin 0 -> 91271 bytes .../images}/spotube-logo.svg | 0 website/static/manifest.json | 19 + website/static/robots.txt | 1 + website/styles/globals.css | 16 - website/svelte.config.js | 55 + website/tailwind.config.ts | 28 + website/tests/test.ts | 6 + website/tsconfig.json | 31 +- website/vite.config.ts | 22 + 96 files changed, 7913 insertions(+), 6885 deletions(-) create mode 100644 website/.eslintignore create mode 100644 website/.eslintrc.cjs delete mode 100755 website/.eslintrc.json mode change 100755 => 100644 website/.gitignore create mode 100644 website/.node-version create mode 100644 website/.npmrc create mode 100644 website/.prettierignore create mode 100644 website/.vscode/settings.json mode change 100755 => 100644 website/README.md delete mode 100644 website/components/AdDetector.tsx delete mode 100644 website/components/ArticleCard.tsx delete mode 100644 website/components/CodeBlock.tsx delete mode 100644 website/components/DownloadButton.tsx delete mode 100644 website/components/Footer.tsx delete mode 100644 website/components/Navbar.tsx delete mode 100644 website/components/UserDetailedCard.tsx delete mode 100644 website/components/special.tsx delete mode 100644 website/configurations/gtag.ts delete mode 100644 website/configurations/ocotokit.ts delete mode 100644 website/hooks/usePlatform.ts delete mode 100644 website/misc/MarkdownComponentDefs.tsx delete mode 100755 website/next-env.d.ts delete mode 100755 website/next.config.js create mode 100644 website/package-lock.json delete mode 100755 website/pages/_app.tsx delete mode 100644 website/pages/about/index.tsx delete mode 100644 website/pages/blog/[slug].tsx delete mode 100644 website/pages/blog/index.tsx delete mode 100755 website/pages/index.tsx delete mode 100644 website/pages/other-downloads/index.tsx delete mode 100644 website/pages/other-downloads/nightly-downloads.tsx delete mode 100644 website/pages/other-downloads/package-manager.tsx delete mode 100644 website/pages/other-downloads/stable-downloads.tsx create mode 100644 website/playwright.config.ts delete mode 100644 website/pnpm-lock.yaml create mode 100644 website/postcss.config.cjs delete mode 100644 website/posts/getting-started-with-spotube.md create mode 100644 website/posts/images/.gitkeep create mode 100644 website/posts/spotube-basics.md delete mode 100644 website/public/android-chrome-192x192.png delete mode 100644 website/public/android-chrome-512x512.png delete mode 100644 website/public/apple-touch-icon.png delete mode 100644 website/public/favicon-16x16.png delete mode 100644 website/public/favicon-32x32.png delete mode 100644 website/public/favicon.ico delete mode 100644 website/public/google7d445d7199e703dc.html delete mode 100644 website/public/headline-1.png delete mode 100644 website/public/headline-2a.svg delete mode 100644 website/public/headline-2b.png delete mode 100644 website/public/headline-3.svg delete mode 100644 website/public/site.webmanifest delete mode 100644 website/public/spotube-screenshot-web.jpg create mode 100644 website/src/app.d.ts create mode 100644 website/src/app.html create mode 100644 website/src/app.postcss create mode 100644 website/src/lib/components/downloads/download-items.svelte create mode 100644 website/src/lib/components/markdown/layout.svelte create mode 100644 website/src/lib/components/navbar/darkmode-toggle.svelte create mode 100644 website/src/lib/components/navbar/navbar.svelte create mode 100644 website/src/lib/components/navdrawer/navdrawer.svelte create mode 100644 website/src/lib/index.ts create mode 100644 website/src/lib/persisted-store.ts create mode 100644 website/src/lib/posts.ts create mode 100644 website/src/routes/+layout.svelte create mode 100644 website/src/routes/+page.svelte create mode 100644 website/src/routes/+page.ts create mode 100644 website/src/routes/about/+page.svelte create mode 100644 website/src/routes/api/posts/+server.ts create mode 100644 website/src/routes/blog/+page.svelte create mode 100644 website/src/routes/blog/+page.ts create mode 100644 website/src/routes/blog/[slug]/+page.svelte create mode 100644 website/src/routes/blog/[slug]/+page.ts create mode 100644 website/src/routes/downloads/+page.svelte create mode 100644 website/src/routes/downloads/nightly/+page.svelte create mode 100644 website/src/routes/downloads/older/+page.svelte create mode 100644 website/src/routes/downloads/older/+page.ts create mode 100644 website/src/routes/downloads/packages/+page.svx create mode 100644 website/static/android-chrome-192x192.png create mode 100644 website/static/android-chrome-512x512.png create mode 100644 website/static/apple-touch-icon.png create mode 100644 website/static/favicon-16x16.png create mode 100644 website/static/favicon-32x32.png create mode 100644 website/static/favicon.ico create mode 100644 website/static/fonts/AbrilFatface.ttf create mode 100644 website/static/images/spotube-logo.png rename website/{public => static/images}/spotube-logo.svg (100%) create mode 100644 website/static/manifest.json create mode 100644 website/static/robots.txt delete mode 100755 website/styles/globals.css create mode 100644 website/svelte.config.js create mode 100644 website/tailwind.config.ts create mode 100644 website/tests/test.ts mode change 100755 => 100644 website/tsconfig.json create mode 100644 website/vite.config.ts diff --git a/website/.eslintignore b/website/.eslintignore new file mode 100644 index 00000000..38972655 --- /dev/null +++ b/website/.eslintignore @@ -0,0 +1,13 @@ +.DS_Store +node_modules +/build +/.svelte-kit +/package +.env +.env.* +!.env.example + +# Ignore files for PNPM, NPM and YARN +pnpm-lock.yaml +package-lock.json +yarn.lock diff --git a/website/.eslintrc.cjs b/website/.eslintrc.cjs new file mode 100644 index 00000000..0b757582 --- /dev/null +++ b/website/.eslintrc.cjs @@ -0,0 +1,31 @@ +/** @type { import("eslint").Linter.Config } */ +module.exports = { + root: true, + extends: [ + 'eslint:recommended', + 'plugin:@typescript-eslint/recommended', + 'plugin:svelte/recommended', + 'prettier' + ], + parser: '@typescript-eslint/parser', + plugins: ['@typescript-eslint'], + parserOptions: { + sourceType: 'module', + ecmaVersion: 2020, + extraFileExtensions: ['.svelte'] + }, + env: { + browser: true, + es2017: true, + node: true + }, + overrides: [ + { + files: ['*.svelte'], + parser: 'svelte-eslint-parser', + parserOptions: { + parser: '@typescript-eslint/parser' + } + } + ] +}; diff --git a/website/.eslintrc.json b/website/.eslintrc.json deleted file mode 100755 index 22c30ebe..00000000 --- a/website/.eslintrc.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "extends": [ - "next/core-web-vitals", - "prettier" - ] -} \ No newline at end of file diff --git a/website/.gitignore b/website/.gitignore old mode 100755 new mode 100644 index ee4209a0..c1f6d69f --- a/website/.gitignore +++ b/website/.gitignore @@ -1,38 +1,11 @@ -# See https://help.github.com/articles/ignoring-files/ for more about ignoring files. - -# dependencies -/node_modules -/.pnp -.pnp.js - -# testing -/coverage - -# next.js -/.next/ -/out/ - -# production -/build - -# misc .DS_Store -*.pem - -# debug -npm-debug.log* -yarn-debug.log* -yarn-error.log* -.pnpm-debug.log* - -# local env files -.env*.local - -# vercel -.vercel - -# typescript -*.tsbuildinfo - +node_modules +/build /.svelte-kit -/.netlify +/package +.env +.env.* +!.env.example +vite.config.js.timestamp-* +vite.config.ts.timestamp-* +.netlify diff --git a/website/.node-version b/website/.node-version new file mode 100644 index 00000000..18c28417 --- /dev/null +++ b/website/.node-version @@ -0,0 +1 @@ +20.11.0 \ No newline at end of file diff --git a/website/.npmrc b/website/.npmrc new file mode 100644 index 00000000..b6f27f13 --- /dev/null +++ b/website/.npmrc @@ -0,0 +1 @@ +engine-strict=true diff --git a/website/.prettierignore b/website/.prettierignore new file mode 100644 index 00000000..cc41cea9 --- /dev/null +++ b/website/.prettierignore @@ -0,0 +1,4 @@ +# Ignore files for PNPM, NPM and YARN +pnpm-lock.yaml +package-lock.json +yarn.lock diff --git a/website/.prettierrc b/website/.prettierrc index 78760076..95730232 100644 --- a/website/.prettierrc +++ b/website/.prettierrc @@ -1,4 +1,8 @@ { - "singleQuote": false, - "useTabs": false -} \ No newline at end of file + "useTabs": true, + "singleQuote": true, + "trailingComma": "none", + "printWidth": 100, + "plugins": ["prettier-plugin-svelte"], + "overrides": [{ "files": "*.svelte", "options": { "parser": "svelte" } }] +} diff --git a/website/.vscode/settings.json b/website/.vscode/settings.json new file mode 100644 index 00000000..e5c5673c --- /dev/null +++ b/website/.vscode/settings.json @@ -0,0 +1,120 @@ +{ + "prettier.documentSelectors": [ + "**/*.svelte" + ], + "tailwindCSS.classAttributes": [ + "class", + "accent", + "active", + "animIndeterminate", + "aspectRatio", + "background", + "badge", + "bgBackdrop", + "bgDark", + "bgDrawer", + "bgLight", + "blur", + "border", + "button", + "buttonAction", + "buttonBack", + "buttonClasses", + "buttonComplete", + "buttonDismiss", + "buttonNeutral", + "buttonNext", + "buttonPositive", + "buttonTextCancel", + "buttonTextConfirm", + "buttonTextFirst", + "buttonTextLast", + "buttonTextNext", + "buttonTextPrevious", + "buttonTextSubmit", + "caretClosed", + "caretOpen", + "chips", + "color", + "controlSeparator", + "controlVariant", + "cursor", + "display", + "element", + "fill", + "fillDark", + "fillLight", + "flex", + "flexDirection", + "gap", + "gridColumns", + "height", + "hover", + "inactive", + "indent", + "justify", + "meter", + "padding", + "position", + "regionAnchor", + "regionBackdrop", + "regionBody", + "regionCaption", + "regionCaret", + "regionCell", + "regionChildren", + "regionChipList", + "regionChipWrapper", + "regionCone", + "regionContent", + "regionControl", + "regionDefault", + "regionDrawer", + "regionFoot", + "regionFootCell", + "regionFooter", + "regionHead", + "regionHeadCell", + "regionHeader", + "regionIcon", + "regionInput", + "regionInterface", + "regionInterfaceText", + "regionLabel", + "regionLead", + "regionLegend", + "regionList", + "regionListItem", + "regionNavigation", + "regionPage", + "regionPanel", + "regionRowHeadline", + "regionRowMain", + "regionSummary", + "regionSymbol", + "regionTab", + "regionTrail", + "ring", + "rounded", + "select", + "shadow", + "slotDefault", + "slotFooter", + "slotHeader", + "slotLead", + "slotMessage", + "slotMeta", + "slotPageContent", + "slotPageFooter", + "slotPageHeader", + "slotSidebarLeft", + "slotSidebarRight", + "slotTrail", + "spacing", + "text", + "track", + "transition", + "width", + "zIndex" + ] +} \ No newline at end of file diff --git a/website/README.md b/website/README.md old mode 100755 new mode 100644 index c87e0421..5ce67661 --- a/website/README.md +++ b/website/README.md @@ -1,34 +1,38 @@ -This is a [Next.js](https://nextjs.org/) project bootstrapped with [`create-next-app`](https://github.com/vercel/next.js/tree/canary/packages/create-next-app). +# create-svelte -## Getting Started +Everything you need to build a Svelte project, powered by [`create-svelte`](https://github.com/sveltejs/kit/tree/main/packages/create-svelte). -First, run the development server: +## Creating a project + +If you're seeing this, you've probably already done this step. Congrats! + +```bash +# create a new project in the current directory +npm create svelte@latest + +# create a new project in my-app +npm create svelte@latest my-app +``` + +## Developing + +Once you've created a project and installed dependencies with `npm install` (or `pnpm install` or `yarn`), start a development server: ```bash npm run dev -# or -yarn dev + +# or start the server and open the app in a new browser tab +npm run dev -- --open ``` -Open [http://localhost:3000](http://localhost:3000) with your browser to see the result. +## Building -You can start editing the page by modifying `pages/index.tsx`. The page auto-updates as you edit the file. +To create a production version of your app: -[API routes](https://nextjs.org/docs/api-routes/introduction) can be accessed on [http://localhost:3000/api/hello](http://localhost:3000/api/hello). This endpoint can be edited in `pages/api/hello.ts`. +```bash +npm run build +``` -The `pages/api` directory is mapped to `/api/*`. Files in this directory are treated as [API routes](https://nextjs.org/docs/api-routes/introduction) instead of React pages. +You can preview the production build with `npm run preview`. -## Learn More - -To learn more about Next.js, take a look at the following resources: - -- [Next.js Documentation](https://nextjs.org/docs) - learn about Next.js features and API. -- [Learn Next.js](https://nextjs.org/learn) - an interactive Next.js tutorial. - -You can check out [the Next.js GitHub repository](https://github.com/vercel/next.js/) - your feedback and contributions are welcome! - -## Deploy on Vercel - -The easiest way to deploy your Next.js app is to use the [Vercel Platform](https://vercel.com/new?utm_medium=default-template&filter=next.js&utm_source=create-next-app&utm_campaign=create-next-app-readme) from the creators of Next.js. - -Check out our [Next.js deployment documentation](https://nextjs.org/docs/deployment) for more details. +> To deploy your app, you may need to install an [adapter](https://kit.svelte.dev/docs/adapters) for your target environment. diff --git a/website/components/AdDetector.tsx b/website/components/AdDetector.tsx deleted file mode 100644 index 33de86ec..00000000 --- a/website/components/AdDetector.tsx +++ /dev/null @@ -1,133 +0,0 @@ -import { - Button, - CloseButton, - Heading, - Modal, - ModalBody, - ModalContent, - ModalFooter, - ModalHeader, - ModalOverlay, - Stack, - Text, - Tooltip, - useDisclosure, - VStack, -} from "@chakra-ui/react"; -import { FC, ReactNode, useEffect, useState } from "react"; - -const AdDetector: FC<{ children: ReactNode }> = ({ children }) => { - const [adBlockEnabled, setAdBlockEnabled] = useState(false); - const { isOpen, onOpen, onClose } = useDisclosure(); - const [joke, setJoke] = useState>({}); - - useEffect(() => { - (async () => { - const googleAdUrl = - "https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js"; - try { - await fetch(new Request(googleAdUrl)); - } catch (e) { - setAdBlockEnabled(true); - setJoke( - await ( - await fetch( - "https://v2.jokeapi.dev/joke/Any?blacklistFlags=racist,sexist" - ) - ).json() - ); - onOpen(); - } - })(); - // eslint-disable-next-line react-hooks/exhaustive-deps - }, []); - - return ( - <> - - - - Support the Creator💚 - -

    - Open source developers work really hard to provide the best, - secure & efficient software experience for you & people all around - the world. Most of the time we work without any wages at all but - we need minimum support to live & these Ads Helps Us earn - the minimum wage that we need to live.{" "} - - So, please support Spotube by disabling the AdBlocker on this - page or by sponsoring or donating to our collectives directly - -

    -
    - - - -
    -
    - {!adBlockEnabled ? ( - children - ) : ( - - - setAdBlockEnabled(false)} - /> - - - Here's something interesting: - - {joke.joke ?? ( - <> -

    {joke.setup}

    -

    {joke.delivery}

    - - )} -
    -
    - - - Be grateful for all the favors you get. But don't let it - become a pile of debt. Try returning them as soon as you can. - You'll feel relieved - - - - Kingkor Roy Tirtho - - -
    - )} - - ); -}; - -export default AdDetector; diff --git a/website/components/ArticleCard.tsx b/website/components/ArticleCard.tsx deleted file mode 100644 index 0bef6f51..00000000 --- a/website/components/ArticleCard.tsx +++ /dev/null @@ -1,138 +0,0 @@ -import { Link, Flex, Box, chakra, Image, Button, Text } from "@chakra-ui/react"; -import { BlogPost } from "pages/blog"; -import { FC } from "react"; -import NavLink from "next/link"; - -const ArticleCard: FC = ({ - metadata: { - author, - author_avatar_url, - cover_image, - tags, - title, - summary, - date, - }, - slug, -}) => { - return ( - - - - - - {tags.map((tag, i) => { - return ( - - {tag} - - ); - })} - - - {title} - - - - {summary} - - - - - - - - - {author} - - - {date} - - - - - - - - - - ); -}; - -export default ArticleCard; diff --git a/website/components/CodeBlock.tsx b/website/components/CodeBlock.tsx deleted file mode 100644 index 111a2011..00000000 --- a/website/components/CodeBlock.tsx +++ /dev/null @@ -1,25 +0,0 @@ -import { chakra } from "@chakra-ui/react"; -import { FC, ReactNode } from "react"; - -type Props = { - children: ReactNode; -}; - -export const CodeBlock: FC = ({ children }) => { - return ( - - {children} - - ); -}; diff --git a/website/components/DownloadButton.tsx b/website/components/DownloadButton.tsx deleted file mode 100644 index 1aa43e70..00000000 --- a/website/components/DownloadButton.tsx +++ /dev/null @@ -1,118 +0,0 @@ -import { - Menu, - ButtonGroup, - Button, - MenuButton, - IconButton, - MenuList, - MenuItem, - Link as Anchor, -} from "@chakra-ui/react"; -import { Platform, usePlatform } from "hooks/usePlatform"; -import React from "react"; -import { - FaApple, - FaCaretDown, - FaUbuntu, - FaLinux, - FaWindows, - FaAndroid, -} from "react-icons/fa"; -import { MdOutlineFileDownload } from "react-icons/md"; - -const baseURL = "https://github.com/KRTirtho/spotube/releases/latest/download/"; - -const DownloadLinks = Object.freeze({ - [Platform.linux]: [ - { - name: "deb", - url: baseURL + "Spotube-linux-x86_64.deb", - icon: , - }, - { - name: "tar", - url: baseURL + "Spotube-linux-x86_64.tar.xz", - icon: , - }, - { - name: "AppImage", - url: baseURL + "Spotube-linux-x86_64.AppImage", - icon: , - }, - ], - [Platform.android]: [ - { - name: "apk", - url: baseURL + "Spotube-android-all-arch.apk", - icon: , - }, - ], - [Platform.mac]: [ - { - name: "dmg", - url: baseURL + "Spotube-macos-universal.dmg", - icon: , - }, - ], - [Platform.windows]: [ - { - name: "exe", - url: baseURL + "Spotube-windows-x86_64-setup.exe", - icon: , - }, - { - name: "nupkg", - url: baseURL + "Spotube-windows-x86_64.nupkg ", - icon: , - }, - ], -}); - -const DownloadButton = () => { - const platform = usePlatform(); - - const allPlatforms = Object.entries(Platform) - .map(([, value]) => { - return DownloadLinks[value].map((s) => ({ - ...s, - name: `${value} (.${s.name})`, - })); - }) - .flat(1); - - const currentPlatform = DownloadLinks[platform][0]; - return ( - - - - } - /> - - - {allPlatforms.map(({ name, url, icon }) => { - return ( - - {name} - - ); - })} - - - ); -}; - -export default DownloadButton; diff --git a/website/components/Footer.tsx b/website/components/Footer.tsx deleted file mode 100644 index a51cf0a2..00000000 --- a/website/components/Footer.tsx +++ /dev/null @@ -1,88 +0,0 @@ -import { Flex, chakra, Link, IconButton } from "@chakra-ui/react"; - -import { FaGithub, FaRedditAlien } from "react-icons/fa"; -import { FiTwitter } from "react-icons/fi"; - -const Footer = () => { - return ( - - - Spotube - - - - © {new Date().getFullYear()}, Spotube. All rights reserved - - - - } - variant="link" - /> - } - variant="link" - /> - } - variant="link" - /> - - - ); -}; - -export default Footer; diff --git a/website/components/Navbar.tsx b/website/components/Navbar.tsx deleted file mode 100644 index 7084b917..00000000 --- a/website/components/Navbar.tsx +++ /dev/null @@ -1,218 +0,0 @@ -import { - Box, - Button, - chakra, - CloseButton, - Flex, - Heading, - HStack, - IconButton, - Link, - useColorMode, - useColorModeValue, - useDisclosure, - VisuallyHidden, - VStack, -} from "@chakra-ui/react"; -import NavLink from "next/link"; -import { GoLightBulb } from "react-icons/go"; -import { FiGithub, FiSun } from "react-icons/fi"; -import Image from "next/image"; -import React from "react"; -import { AiOutlineMenu } from "react-icons/ai"; -import { BsHeartFill } from "react-icons/bs"; - -const Navbar = () => { - const bg = useColorModeValue("white", "gray.800"); - const mobileNav = useDisclosure(); - const { colorMode, toggleColorMode } = useColorMode(); - return ( - - - - - - - - Spotube - - - Spotube - - - - - - - - - - - - - - - - - - : } - aria-label="Dark Mode Toggle" - onClick={() => { - toggleColorMode(); - }} - /> - - } - onClick={mobileNav.onOpen} - /> - - - - - - - - - - - - - - - - - - - - ); -}; - -export default Navbar; diff --git a/website/components/UserDetailedCard.tsx b/website/components/UserDetailedCard.tsx deleted file mode 100644 index fee3bdbd..00000000 --- a/website/components/UserDetailedCard.tsx +++ /dev/null @@ -1,153 +0,0 @@ -import { - Flex, - Box, - Icon, - chakra, - Image, - HStack, - IconButton, - Link, - CircularProgress, -} from "@chakra-ui/react"; -import { MdEmail, MdLocationOn } from "react-icons/md"; -import { BsFillBriefcaseFill } from "react-icons/bs"; -import { FC } from "react"; -import { FaGithub } from "react-icons/fa"; -import { FiTwitter } from "react-icons/fi"; -import { octokit } from "configurations/ocotokit"; -import useSWR from "swr"; - -interface UserDetailedCardProps { - username: string; - emoji: string; -} - -const UserDetailedCard: FC = ({ username, emoji }) => { - const { data } = useSWR(`user-${username}}`, () => - octokit.users.getByUsername({ username }) - ); - - if (!data) { - return ; - } - - return ( - - - - - {emoji} - - {data.data.name ?? data.data.login} - - - - - - {data.data.bio} - - - {data.data.company && ( - - - - - {data.data.company} - - - )} - - {data.data.location && ( - - - - - {data.data.location} - - - )} - {data.data.email && ( - - - - {data.data.email} - - - )} - - } - variant="link" - /> - {data.data.twitter_username && ( - } - variant="link" - /> - )} - - - - ); -}; - -export default UserDetailedCard; diff --git a/website/components/special.tsx b/website/components/special.tsx deleted file mode 100644 index 93b2d565..00000000 --- a/website/components/special.tsx +++ /dev/null @@ -1,72 +0,0 @@ -import Script from "next/script"; -import { FC, useId } from "react"; - -type AdComponent = FC<{ - slot: string; -}>; - -export const DisplayAd: AdComponent = ({ slot }) => { - const id = useId(); - return ( - <> - - - - ); -}; - -export const GridMultiplexAd: AdComponent = ({ slot }) => { - const id = useId(); - return ( - <> - - - - ); -}; - -export const InFeedAd = () => { - const id = useId(); - return ( - <> - - - - ); -}; diff --git a/website/configurations/gtag.ts b/website/configurations/gtag.ts deleted file mode 100644 index 01dcba50..00000000 --- a/website/configurations/gtag.ts +++ /dev/null @@ -1,17 +0,0 @@ -export const GA_TRACKING_ID = process.env.NEXT_PUBLIC_GA_ID; - -// https://developers.google.com/analytics/devguides/collection/gtagjs/pages -export const pageview = (url: any) => { - (window as any).gtag("config", GA_TRACKING_ID, { - page_path: url, - }); -}; - -// https://developers.google.com/analytics/devguides/collection/gtagjs/events -export const event = ({ action, category, label, value }: any) => { - (window as any).gtag("event", action, { - event_category: category, - event_label: label, - value: value, - }); -}; diff --git a/website/configurations/ocotokit.ts b/website/configurations/ocotokit.ts deleted file mode 100644 index b50fb197..00000000 --- a/website/configurations/ocotokit.ts +++ /dev/null @@ -1,3 +0,0 @@ -import { Octokit } from "@octokit/rest"; - -export const octokit: Octokit = new Octokit(); \ No newline at end of file diff --git a/website/hooks/usePlatform.ts b/website/hooks/usePlatform.ts deleted file mode 100644 index a502e4cd..00000000 --- a/website/hooks/usePlatform.ts +++ /dev/null @@ -1,26 +0,0 @@ -import { useEffect, useState } from "react"; -import { detectOS } from "detect-browser"; - -export enum Platform { - linux = "Linux", - windows = "Windows", - mac = "Mac", - android = "Android", -} - -export function usePlatform(): Platform { - const [platform, setPlatform] = useState(Platform.linux); - - useEffect(() => { - const detectedPlatform = detectOS(navigator.userAgent)?.toLowerCase(); - - if (!detectedPlatform) return; - - if (detectedPlatform.includes("windows")) setPlatform(Platform.windows); - else if (detectedPlatform.includes("mac")) setPlatform(Platform.mac); - else if (detectedPlatform.includes("android")) - setPlatform(Platform.android); - }, []); - - return platform; -} diff --git a/website/misc/MarkdownComponentDefs.tsx b/website/misc/MarkdownComponentDefs.tsx deleted file mode 100644 index f3c901ca..00000000 --- a/website/misc/MarkdownComponentDefs.tsx +++ /dev/null @@ -1,43 +0,0 @@ -import { - Link as Anchor, - Heading, - Text, - chakra, - Code, - HStack, - Divider, - Box, -} from "@chakra-ui/react"; -import { Options } from "react-markdown"; - -export const MarkdownComponentDefs: Options["components"] = { - a: (props: any) => , - h1: (props: any) => , - h2: (props: any) => , - h3: (props: any) => , - h4: (props: any) => , - h5: (props: any) => , - h6: (props: any) => , - p: (props: any) => , - li: (props: any) => , - code: (props) => ( - - ), - blockquote: (props) => { - return ( - - - - {props.children} - - - - ); - }, -}; diff --git a/website/next-env.d.ts b/website/next-env.d.ts deleted file mode 100755 index 4f11a03d..00000000 --- a/website/next-env.d.ts +++ /dev/null @@ -1,5 +0,0 @@ -/// -/// - -// NOTE: This file should not be edited -// see https://nextjs.org/docs/basic-features/typescript for more information. diff --git a/website/next.config.js b/website/next.config.js deleted file mode 100755 index ae887958..00000000 --- a/website/next.config.js +++ /dev/null @@ -1,7 +0,0 @@ -/** @type {import('next').NextConfig} */ -const nextConfig = { - reactStrictMode: true, - swcMinify: true, -} - -module.exports = nextConfig diff --git a/website/package-lock.json b/website/package-lock.json new file mode 100644 index 00000000..89323983 --- /dev/null +++ b/website/package-lock.json @@ -0,0 +1,6391 @@ +{ + "name": "website", + "version": "0.0.1", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "website", + "version": "0.0.1", + "dependencies": { + "@floating-ui/dom": "1.6.1", + "@fortawesome/free-brands-svg-icons": "^6.5.1", + "@octokit/openapi-types": "^19.1.0", + "@octokit/rest": "^20.0.2", + "date-fns": "^3.3.1", + "highlight.js": "11.9.0", + "lucide-svelte": "^0.323.0", + "mdsvex-relative-images": "^1.0.3", + "rehype-autolink-headings": "^7.1.0", + "rehype-slug": "^6.0.0", + "remark-container": "^0.1.2", + "remark-external-links": "^9.0.1", + "remark-gfm": "^4.0.0", + "remark-github": "^12.0.0", + "remark-reading-time": "^1.0.1", + "svelte-fa": "^4.0.2", + "svelte-markdown": "^0.4.1" + }, + "devDependencies": { + "@playwright/test": "^1.28.1", + "@skeletonlabs/skeleton": "2.8.0", + "@skeletonlabs/tw-plugin": "0.3.1", + "@sveltejs/adapter-cloudflare": "^4.1.0", + "@sveltejs/kit": "^2.0.0", + "@sveltejs/vite-plugin-svelte": "^3.0.0", + "@tailwindcss/typography": "0.5.10", + "@types/eslint": "8.56.0", + "@types/node": "^20.11.16", + "@typescript-eslint/eslint-plugin": "^6.0.0", + "@typescript-eslint/parser": "^6.0.0", + "autoprefixer": "10.4.17", + "eslint": "^8.56.0", + "eslint-config-prettier": "^9.1.0", + "eslint-plugin-svelte": "^2.35.1", + "mdsvex": "^0.11.0", + "postcss": "8.4.35", + "prettier": "^3.1.1", + "prettier-plugin-svelte": "^3.1.2", + "svelte": "^4.2.7", + "svelte-check": "^3.6.0", + "tailwindcss": "3.4.1", + "tslib": "^2.4.1", + "typescript": "^5.0.0", + "vite": "^5.0.3", + "vite-plugin-tailwind-purgecss": "0.2.0" + } + }, + "node_modules/@aashutoshrathi/word-wrap": { + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/@aashutoshrathi/word-wrap/-/word-wrap-1.2.6.tgz", + "integrity": "sha512-1Yjs2SvM8TflER/OD3cOjhWWOZb58A2t7wpE2S9XfBYTiIl+XFhQG2bjy4Pu1I+EAlCNUzRDYDdFwFYUKvXcIA==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/@alloc/quick-lru": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/@alloc/quick-lru/-/quick-lru-5.2.0.tgz", + "integrity": "sha512-UrcABB+4bUrFABwbluTIBErXwvbsU/V7TZWfmbgJfbkwiBuziS9gxdODUyuiecfdGQ85jglMW6juS3+z5TsKLw==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@ampproject/remapping": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.2.1.tgz", + "integrity": "sha512-lFMjJTrFL3j7L9yBxwYfCq2k6qqwHyzuUl/XBnif78PWTJYyL/dfowQHWE3sp6U6ZzqWiiIZnpTMO96zhkjwtg==", + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.0", + "@jridgewell/trace-mapping": "^0.3.9" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@cloudflare/workers-types": { + "version": "4.20240208.0", + "resolved": "https://registry.npmjs.org/@cloudflare/workers-types/-/workers-types-4.20240208.0.tgz", + "integrity": "sha512-MVGTTjZpJu4kJONvai5SdJzWIhOJbuweVZ3goI7FNyG+JdoQH41OoB+nMhLsX626vPLZVWGPIWsiSo/WZHzgQw==", + "dev": true + }, + "node_modules/@esbuild/aix-ppc64": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.19.12.tgz", + "integrity": "sha512-bmoCYyWdEL3wDQIVbcyzRyeKLgk2WtWLTWz1ZIAZF/EGbNOwSA6ew3PftJ1PqMiOOGu0OyFMzG53L0zqIpPeNA==", + "cpu": [ + "ppc64" + ], + "dev": true, + "optional": true, + "os": [ + "aix" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/android-arm": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.19.12.tgz", + "integrity": "sha512-qg/Lj1mu3CdQlDEEiWrlC4eaPZ1KztwGJ9B6J+/6G+/4ewxJg7gqj8eVYWvao1bXrqGiW2rsBZFSX3q2lcW05w==", + "cpu": [ + "arm" + ], + "dev": true, + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/android-arm64": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.19.12.tgz", + "integrity": "sha512-P0UVNGIienjZv3f5zq0DP3Nt2IE/3plFzuaS96vihvD0Hd6H/q4WXUGpCxD/E8YrSXfNyRPbpTq+T8ZQioSuPA==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/android-x64": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.19.12.tgz", + "integrity": "sha512-3k7ZoUW6Q6YqhdhIaq/WZ7HwBpnFBlW905Fa4s4qWJyiNOgT1dOqDiVAQFwBH7gBRZr17gLrlFCRzF6jFh7Kew==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/darwin-arm64": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.19.12.tgz", + "integrity": "sha512-B6IeSgZgtEzGC42jsI+YYu9Z3HKRxp8ZT3cqhvliEHovq8HSX2YX8lNocDn79gCKJXOSaEot9MVYky7AKjCs8g==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/darwin-x64": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.19.12.tgz", + "integrity": "sha512-hKoVkKzFiToTgn+41qGhsUJXFlIjxI/jSYeZf3ugemDYZldIXIxhvwN6erJGlX4t5h417iFuheZ7l+YVn05N3A==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/freebsd-arm64": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.19.12.tgz", + "integrity": "sha512-4aRvFIXmwAcDBw9AueDQ2YnGmz5L6obe5kmPT8Vd+/+x/JMVKCgdcRwH6APrbpNXsPz+K653Qg8HB/oXvXVukA==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/freebsd-x64": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.19.12.tgz", + "integrity": "sha512-EYoXZ4d8xtBoVN7CEwWY2IN4ho76xjYXqSXMNccFSx2lgqOG/1TBPW0yPx1bJZk94qu3tX0fycJeeQsKovA8gg==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-arm": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.19.12.tgz", + "integrity": "sha512-J5jPms//KhSNv+LO1S1TX1UWp1ucM6N6XuL6ITdKWElCu8wXP72l9MM0zDTzzeikVyqFE6U8YAV9/tFyj0ti+w==", + "cpu": [ + "arm" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-arm64": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.19.12.tgz", + "integrity": "sha512-EoTjyYyLuVPfdPLsGVVVC8a0p1BFFvtpQDB/YLEhaXyf/5bczaGeN15QkR+O4S5LeJ92Tqotve7i1jn35qwvdA==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-ia32": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.19.12.tgz", + "integrity": "sha512-Thsa42rrP1+UIGaWz47uydHSBOgTUnwBwNq59khgIwktK6x60Hivfbux9iNR0eHCHzOLjLMLfUMLCypBkZXMHA==", + "cpu": [ + "ia32" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-loong64": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.19.12.tgz", + "integrity": "sha512-LiXdXA0s3IqRRjm6rV6XaWATScKAXjI4R4LoDlvO7+yQqFdlr1Bax62sRwkVvRIrwXxvtYEHHI4dm50jAXkuAA==", + "cpu": [ + "loong64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-mips64el": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.19.12.tgz", + "integrity": "sha512-fEnAuj5VGTanfJ07ff0gOA6IPsvrVHLVb6Lyd1g2/ed67oU1eFzL0r9WL7ZzscD+/N6i3dWumGE1Un4f7Amf+w==", + "cpu": [ + "mips64el" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-ppc64": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.19.12.tgz", + "integrity": "sha512-nYJA2/QPimDQOh1rKWedNOe3Gfc8PabU7HT3iXWtNUbRzXS9+vgB0Fjaqr//XNbd82mCxHzik2qotuI89cfixg==", + "cpu": [ + "ppc64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-riscv64": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.19.12.tgz", + "integrity": "sha512-2MueBrlPQCw5dVJJpQdUYgeqIzDQgw3QtiAHUC4RBz9FXPrskyyU3VI1hw7C0BSKB9OduwSJ79FTCqtGMWqJHg==", + "cpu": [ + "riscv64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-s390x": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.19.12.tgz", + "integrity": "sha512-+Pil1Nv3Umes4m3AZKqA2anfhJiVmNCYkPchwFJNEJN5QxmTs1uzyy4TvmDrCRNT2ApwSari7ZIgrPeUx4UZDg==", + "cpu": [ + "s390x" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-x64": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.19.12.tgz", + "integrity": "sha512-B71g1QpxfwBvNrfyJdVDexenDIt1CiDN1TIXLbhOw0KhJzE78KIFGX6OJ9MrtC0oOqMWf+0xop4qEU8JrJTwCg==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/netbsd-x64": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.19.12.tgz", + "integrity": "sha512-3ltjQ7n1owJgFbuC61Oj++XhtzmymoCihNFgT84UAmJnxJfm4sYCiSLTXZtE00VWYpPMYc+ZQmB6xbSdVh0JWA==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/openbsd-x64": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.19.12.tgz", + "integrity": "sha512-RbrfTB9SWsr0kWmb9srfF+L933uMDdu9BIzdA7os2t0TXhCRjrQyCeOt6wVxr79CKD4c+p+YhCj31HBkYcXebw==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/sunos-x64": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.19.12.tgz", + "integrity": "sha512-HKjJwRrW8uWtCQnQOz9qcU3mUZhTUQvi56Q8DPTLLB+DawoiQdjsYq+j+D3s9I8VFtDr+F9CjgXKKC4ss89IeA==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/win32-arm64": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.19.12.tgz", + "integrity": "sha512-URgtR1dJnmGvX864pn1B2YUYNzjmXkuJOIqG2HdU62MVS4EHpU2946OZoTMnRUHklGtJdJZ33QfzdjGACXhn1A==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/win32-ia32": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.19.12.tgz", + "integrity": "sha512-+ZOE6pUkMOJfmxmBZElNOx72NKpIa/HFOMGzu8fqzQJ5kgf6aTGrcJaFsNiVMH4JKpMipyK+7k0n2UXN7a8YKQ==", + "cpu": [ + "ia32" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/win32-x64": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.19.12.tgz", + "integrity": "sha512-T1QyPSDCyMXaO3pzBkF96E8xMkiRYbUEZADd29SyPGabqxMViNoii+NcK7eWJAEoU6RZyEm5lVSIjTmcdoB9HA==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@eslint-community/eslint-utils": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz", + "integrity": "sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA==", + "dev": true, + "dependencies": { + "eslint-visitor-keys": "^3.3.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "peerDependencies": { + "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" + } + }, + "node_modules/@eslint-community/regexpp": { + "version": "4.10.0", + "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.10.0.tgz", + "integrity": "sha512-Cu96Sd2By9mCNTx2iyKOmq10v22jUVQv0lQnlGNy16oE9589yE+QADPbrMGCkA51cKZSg3Pu/aTJVTGfL/qjUA==", + "dev": true, + "engines": { + "node": "^12.0.0 || ^14.0.0 || >=16.0.0" + } + }, + "node_modules/@eslint/eslintrc": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.1.4.tgz", + "integrity": "sha512-269Z39MS6wVJtsoUl10L60WdkhJVdPG24Q4eZTH3nnF6lpvSShEK3wQjDX9JRWAUPvPh7COouPpU9IrqaZFvtQ==", + "dev": true, + "dependencies": { + "ajv": "^6.12.4", + "debug": "^4.3.2", + "espree": "^9.6.0", + "globals": "^13.19.0", + "ignore": "^5.2.0", + "import-fresh": "^3.2.1", + "js-yaml": "^4.1.0", + "minimatch": "^3.1.2", + "strip-json-comments": "^3.1.1" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/@eslint/eslintrc/node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/@eslint/eslintrc/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/@eslint/js": { + "version": "8.56.0", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.56.0.tgz", + "integrity": "sha512-gMsVel9D7f2HLkBma9VbtzZRehRogVRfbr++f06nL2vnCGCNlzOD+/MUov/F4p8myyAHspEhVobgjpX64q5m6A==", + "dev": true, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + } + }, + "node_modules/@floating-ui/core": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/@floating-ui/core/-/core-1.6.0.tgz", + "integrity": "sha512-PcF++MykgmTj3CIyOQbKA/hDzOAiqI3mhuoN44WRCopIs1sgoDoU4oty4Jtqaj/y3oDU6fnVSm4QG0a3t5i0+g==", + "dependencies": { + "@floating-ui/utils": "^0.2.1" + } + }, + "node_modules/@floating-ui/dom": { + "version": "1.6.1", + "resolved": "https://registry.npmjs.org/@floating-ui/dom/-/dom-1.6.1.tgz", + "integrity": "sha512-iA8qE43/H5iGozC3W0YSnVSW42Vh522yyM1gj+BqRwVsTNOyr231PsXDaV04yT39PsO0QL2QpbI/M0ZaLUQgRQ==", + "dependencies": { + "@floating-ui/core": "^1.6.0", + "@floating-ui/utils": "^0.2.1" + } + }, + "node_modules/@floating-ui/utils": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/@floating-ui/utils/-/utils-0.2.1.tgz", + "integrity": "sha512-9TANp6GPoMtYzQdt54kfAyMmz1+osLlXdg2ENroU7zzrtflTLrrC/lgrIfaSe+Wu0b89GKccT7vxXA0MoAIO+Q==" + }, + "node_modules/@fortawesome/fontawesome-common-types": { + "version": "6.5.1", + "resolved": "https://registry.npmjs.org/@fortawesome/fontawesome-common-types/-/fontawesome-common-types-6.5.1.tgz", + "integrity": "sha512-GkWzv+L6d2bI5f/Vk6ikJ9xtl7dfXtoRu3YGE6nq0p/FFqA1ebMOAWg3XgRyb0I6LYyYkiAo+3/KrwuBp8xG7A==", + "hasInstallScript": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/@fortawesome/free-brands-svg-icons": { + "version": "6.5.1", + "resolved": "https://registry.npmjs.org/@fortawesome/free-brands-svg-icons/-/free-brands-svg-icons-6.5.1.tgz", + "integrity": "sha512-093l7DAkx0aEtBq66Sf19MgoZewv1zeY9/4C7vSKPO4qMwEsW/2VYTUTpBtLwfb9T2R73tXaRDPmE4UqLCYHfg==", + "hasInstallScript": true, + "dependencies": { + "@fortawesome/fontawesome-common-types": "6.5.1" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/@humanwhocodes/config-array": { + "version": "0.11.14", + "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.14.tgz", + "integrity": "sha512-3T8LkOmg45BV5FICb15QQMsyUSWrQ8AygVfC7ZG32zOalnqrilm018ZVCw0eapXux8FtA33q8PSRSstjee3jSg==", + "dev": true, + "dependencies": { + "@humanwhocodes/object-schema": "^2.0.2", + "debug": "^4.3.1", + "minimatch": "^3.0.5" + }, + "engines": { + "node": ">=10.10.0" + } + }, + "node_modules/@humanwhocodes/config-array/node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/@humanwhocodes/config-array/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/@humanwhocodes/module-importer": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", + "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==", + "dev": true, + "engines": { + "node": ">=12.22" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" + } + }, + "node_modules/@humanwhocodes/object-schema": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-2.0.2.tgz", + "integrity": "sha512-6EwiSjwWYP7pTckG6I5eyFANjPhmPjUX9JRLUSfNPC7FX7zK9gyZAfUEaECL6ALTpGX5AjnBq3C9XmVWPitNpw==", + "dev": true + }, + "node_modules/@isaacs/cliui": { + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz", + "integrity": "sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==", + "dev": true, + "dependencies": { + "string-width": "^5.1.2", + "string-width-cjs": "npm:string-width@^4.2.0", + "strip-ansi": "^7.0.1", + "strip-ansi-cjs": "npm:strip-ansi@^6.0.1", + "wrap-ansi": "^8.1.0", + "wrap-ansi-cjs": "npm:wrap-ansi@^7.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/@isaacs/cliui/node_modules/ansi-regex": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz", + "integrity": "sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" + } + }, + "node_modules/@isaacs/cliui/node_modules/strip-ansi": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", + "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", + "dev": true, + "dependencies": { + "ansi-regex": "^6.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" + } + }, + "node_modules/@jridgewell/gen-mapping": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.3.tgz", + "integrity": "sha512-HLhSWOLRi875zjjMG/r+Nv0oCW8umGb0BgEhyX3dDX3egwZtB8PqLnjz3yedt8R5StBrzcg4aBpnh8UA9D1BoQ==", + "dependencies": { + "@jridgewell/set-array": "^1.0.1", + "@jridgewell/sourcemap-codec": "^1.4.10", + "@jridgewell/trace-mapping": "^0.3.9" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/resolve-uri": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.1.tgz", + "integrity": "sha512-dSYZh7HhCDtCKm4QakX0xFpsRDqjjtZf/kjI/v3T3Nwt5r8/qz/M19F9ySyOqU94SXBmeG9ttTul+YnR4LOxFA==", + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/set-array": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.1.2.tgz", + "integrity": "sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==", + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.4.15", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz", + "integrity": "sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==" + }, + "node_modules/@jridgewell/trace-mapping": { + "version": "0.3.22", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.22.tgz", + "integrity": "sha512-Wf963MzWtA2sjrNt+g18IAln9lKnlRp+K2eH4jjIoF1wYeq3aMREpG09xhlhdzS0EjwU7qmUJYangWa+151vZw==", + "dependencies": { + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" + } + }, + "node_modules/@nodelib/fs.scandir": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", + "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", + "dev": true, + "dependencies": { + "@nodelib/fs.stat": "2.0.5", + "run-parallel": "^1.1.9" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.stat": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", + "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", + "dev": true, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.walk": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", + "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", + "dev": true, + "dependencies": { + "@nodelib/fs.scandir": "2.1.5", + "fastq": "^1.6.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@octokit/auth-token": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@octokit/auth-token/-/auth-token-4.0.0.tgz", + "integrity": "sha512-tY/msAuJo6ARbK6SPIxZrPBms3xPbfwBrulZe0Wtr/DIY9lje2HeV1uoebShn6mx7SjCHif6EjMvoREj+gZ+SA==", + "engines": { + "node": ">= 18" + } + }, + "node_modules/@octokit/core": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/@octokit/core/-/core-5.1.0.tgz", + "integrity": "sha512-BDa2VAMLSh3otEiaMJ/3Y36GU4qf6GI+VivQ/P41NC6GHcdxpKlqV0ikSZ5gdQsmS3ojXeRx5vasgNTinF0Q4g==", + "dependencies": { + "@octokit/auth-token": "^4.0.0", + "@octokit/graphql": "^7.0.0", + "@octokit/request": "^8.0.2", + "@octokit/request-error": "^5.0.0", + "@octokit/types": "^12.0.0", + "before-after-hook": "^2.2.0", + "universal-user-agent": "^6.0.0" + }, + "engines": { + "node": ">= 18" + } + }, + "node_modules/@octokit/endpoint": { + "version": "9.0.4", + "resolved": "https://registry.npmjs.org/@octokit/endpoint/-/endpoint-9.0.4.tgz", + "integrity": "sha512-DWPLtr1Kz3tv8L0UvXTDP1fNwM0S+z6EJpRcvH66orY6Eld4XBMCSYsaWp4xIm61jTWxK68BrR7ibO+vSDnZqw==", + "dependencies": { + "@octokit/types": "^12.0.0", + "universal-user-agent": "^6.0.0" + }, + "engines": { + "node": ">= 18" + } + }, + "node_modules/@octokit/graphql": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/@octokit/graphql/-/graphql-7.0.2.tgz", + "integrity": "sha512-OJ2iGMtj5Tg3s6RaXH22cJcxXRi7Y3EBqbHTBRq+PQAqfaS8f/236fUrWhfSn8P4jovyzqucxme7/vWSSZBX2Q==", + "dependencies": { + "@octokit/request": "^8.0.1", + "@octokit/types": "^12.0.0", + "universal-user-agent": "^6.0.0" + }, + "engines": { + "node": ">= 18" + } + }, + "node_modules/@octokit/openapi-types": { + "version": "19.1.0", + "resolved": "https://registry.npmjs.org/@octokit/openapi-types/-/openapi-types-19.1.0.tgz", + "integrity": "sha512-6G+ywGClliGQwRsjvqVYpklIfa7oRPA0vyhPQG/1Feh+B+wU0vGH1JiJ5T25d3g1JZYBHzR2qefLi9x8Gt+cpw==" + }, + "node_modules/@octokit/plugin-paginate-rest": { + "version": "9.1.5", + "resolved": "https://registry.npmjs.org/@octokit/plugin-paginate-rest/-/plugin-paginate-rest-9.1.5.tgz", + "integrity": "sha512-WKTQXxK+bu49qzwv4qKbMMRXej1DU2gq017euWyKVudA6MldaSSQuxtz+vGbhxV4CjxpUxjZu6rM2wfc1FiWVg==", + "dependencies": { + "@octokit/types": "^12.4.0" + }, + "engines": { + "node": ">= 18" + }, + "peerDependencies": { + "@octokit/core": ">=5" + } + }, + "node_modules/@octokit/plugin-request-log": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@octokit/plugin-request-log/-/plugin-request-log-4.0.0.tgz", + "integrity": "sha512-2uJI1COtYCq8Z4yNSnM231TgH50bRkheQ9+aH8TnZanB6QilOnx8RMD2qsnamSOXtDj0ilxvevf5fGsBhBBzKA==", + "engines": { + "node": ">= 18" + }, + "peerDependencies": { + "@octokit/core": ">=5" + } + }, + "node_modules/@octokit/plugin-rest-endpoint-methods": { + "version": "10.2.0", + "resolved": "https://registry.npmjs.org/@octokit/plugin-rest-endpoint-methods/-/plugin-rest-endpoint-methods-10.2.0.tgz", + "integrity": "sha512-ePbgBMYtGoRNXDyKGvr9cyHjQ163PbwD0y1MkDJCpkO2YH4OeXX40c4wYHKikHGZcpGPbcRLuy0unPUuafco8Q==", + "dependencies": { + "@octokit/types": "^12.3.0" + }, + "engines": { + "node": ">= 18" + }, + "peerDependencies": { + "@octokit/core": ">=5" + } + }, + "node_modules/@octokit/request": { + "version": "8.1.6", + "resolved": "https://registry.npmjs.org/@octokit/request/-/request-8.1.6.tgz", + "integrity": "sha512-YhPaGml3ncZC1NfXpP3WZ7iliL1ap6tLkAp6MvbK2fTTPytzVUyUesBBogcdMm86uRYO5rHaM1xIWxigWZ17MQ==", + "dependencies": { + "@octokit/endpoint": "^9.0.0", + "@octokit/request-error": "^5.0.0", + "@octokit/types": "^12.0.0", + "universal-user-agent": "^6.0.0" + }, + "engines": { + "node": ">= 18" + } + }, + "node_modules/@octokit/request-error": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/@octokit/request-error/-/request-error-5.0.1.tgz", + "integrity": "sha512-X7pnyTMV7MgtGmiXBwmO6M5kIPrntOXdyKZLigNfQWSEQzVxR4a4vo49vJjTWX70mPndj8KhfT4Dx+2Ng3vnBQ==", + "dependencies": { + "@octokit/types": "^12.0.0", + "deprecation": "^2.0.0", + "once": "^1.4.0" + }, + "engines": { + "node": ">= 18" + } + }, + "node_modules/@octokit/rest": { + "version": "20.0.2", + "resolved": "https://registry.npmjs.org/@octokit/rest/-/rest-20.0.2.tgz", + "integrity": "sha512-Ux8NDgEraQ/DMAU1PlAohyfBBXDwhnX2j33Z1nJNziqAfHi70PuxkFYIcIt8aIAxtRE7KVuKp8lSR8pA0J5iOQ==", + "dependencies": { + "@octokit/core": "^5.0.0", + "@octokit/plugin-paginate-rest": "^9.0.0", + "@octokit/plugin-request-log": "^4.0.0", + "@octokit/plugin-rest-endpoint-methods": "^10.0.0" + }, + "engines": { + "node": ">= 18" + } + }, + "node_modules/@octokit/types": { + "version": "12.4.0", + "resolved": "https://registry.npmjs.org/@octokit/types/-/types-12.4.0.tgz", + "integrity": "sha512-FLWs/AvZllw/AGVs+nJ+ELCDZZJk+kY0zMen118xhL2zD0s1etIUHm1odgjP7epxYU1ln7SZxEUWYop5bhsdgQ==", + "dependencies": { + "@octokit/openapi-types": "^19.1.0" + } + }, + "node_modules/@pkgjs/parseargs": { + "version": "0.11.0", + "resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz", + "integrity": "sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==", + "dev": true, + "optional": true, + "engines": { + "node": ">=14" + } + }, + "node_modules/@playwright/test": { + "version": "1.41.2", + "resolved": "https://registry.npmjs.org/@playwright/test/-/test-1.41.2.tgz", + "integrity": "sha512-qQB9h7KbibJzrDpkXkYvsmiDJK14FULCCZgEcoe2AvFAS64oCirWTwzTlAYEbKaRxWs5TFesE1Na6izMv3HfGg==", + "dev": true, + "dependencies": { + "playwright": "1.41.2" + }, + "bin": { + "playwright": "cli.js" + }, + "engines": { + "node": ">=16" + } + }, + "node_modules/@polka/url": { + "version": "1.0.0-next.24", + "resolved": "https://registry.npmjs.org/@polka/url/-/url-1.0.0-next.24.tgz", + "integrity": "sha512-2LuNTFBIO0m7kKIQvvPHN6UE63VjpmL9rnEEaOOaiSPbZK+zUOYIzBAWcED+3XYzhYsd/0mD57VdxAEqqV52CQ==", + "dev": true + }, + "node_modules/@rollup/rollup-android-arm-eabi": { + "version": "4.9.6", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.9.6.tgz", + "integrity": "sha512-MVNXSSYN6QXOulbHpLMKYi60ppyO13W9my1qogeiAqtjb2yR4LSmfU2+POvDkLzhjYLXz9Rf9+9a3zFHW1Lecg==", + "cpu": [ + "arm" + ], + "dev": true, + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@rollup/rollup-android-arm64": { + "version": "4.9.6", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.9.6.tgz", + "integrity": "sha512-T14aNLpqJ5wzKNf5jEDpv5zgyIqcpn1MlwCrUXLrwoADr2RkWA0vOWP4XxbO9aiO3dvMCQICZdKeDrFl7UMClw==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@rollup/rollup-darwin-arm64": { + "version": "4.9.6", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.9.6.tgz", + "integrity": "sha512-CqNNAyhRkTbo8VVZ5R85X73H3R5NX9ONnKbXuHisGWC0qRbTTxnF1U4V9NafzJbgGM0sHZpdO83pLPzq8uOZFw==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@rollup/rollup-darwin-x64": { + "version": "4.9.6", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.9.6.tgz", + "integrity": "sha512-zRDtdJuRvA1dc9Mp6BWYqAsU5oeLixdfUvkTHuiYOHwqYuQ4YgSmi6+/lPvSsqc/I0Omw3DdICx4Tfacdzmhog==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@rollup/rollup-linux-arm-gnueabihf": { + "version": "4.9.6", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.9.6.tgz", + "integrity": "sha512-oNk8YXDDnNyG4qlNb6is1ojTOGL/tRhbbKeE/YuccItzerEZT68Z9gHrY3ROh7axDc974+zYAPxK5SH0j/G+QQ==", + "cpu": [ + "arm" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm64-gnu": { + "version": "4.9.6", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.9.6.tgz", + "integrity": "sha512-Z3O60yxPtuCYobrtzjo0wlmvDdx2qZfeAWTyfOjEDqd08kthDKexLpV97KfAeUXPosENKd8uyJMRDfFMxcYkDQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm64-musl": { + "version": "4.9.6", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.9.6.tgz", + "integrity": "sha512-gpiG0qQJNdYEVad+1iAsGAbgAnZ8j07FapmnIAQgODKcOTjLEWM9sRb+MbQyVsYCnA0Im6M6QIq6ax7liws6eQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-riscv64-gnu": { + "version": "4.9.6", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.9.6.tgz", + "integrity": "sha512-+uCOcvVmFUYvVDr27aiyun9WgZk0tXe7ThuzoUTAukZJOwS5MrGbmSlNOhx1j80GdpqbOty05XqSl5w4dQvcOA==", + "cpu": [ + "riscv64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-x64-gnu": { + "version": "4.9.6", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.9.6.tgz", + "integrity": "sha512-HUNqM32dGzfBKuaDUBqFB7tP6VMN74eLZ33Q9Y1TBqRDn+qDonkAUyKWwF9BR9unV7QUzffLnz9GrnKvMqC/fw==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-x64-musl": { + "version": "4.9.6", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.9.6.tgz", + "integrity": "sha512-ch7M+9Tr5R4FK40FHQk8VnML0Szi2KRujUgHXd/HjuH9ifH72GUmw6lStZBo3c3GB82vHa0ZoUfjfcM7JiiMrQ==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-win32-arm64-msvc": { + "version": "4.9.6", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.9.6.tgz", + "integrity": "sha512-VD6qnR99dhmTQ1mJhIzXsRcTBvTjbfbGGwKAHcu+52cVl15AC/kplkhxzW/uT0Xl62Y/meBKDZvoJSJN+vTeGA==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-ia32-msvc": { + "version": "4.9.6", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.9.6.tgz", + "integrity": "sha512-J9AFDq/xiRI58eR2NIDfyVmTYGyIZmRcvcAoJ48oDld/NTR8wyiPUu2X/v1navJ+N/FGg68LEbX3Ejd6l8B7MQ==", + "cpu": [ + "ia32" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-x64-msvc": { + "version": "4.9.6", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.9.6.tgz", + "integrity": "sha512-jqzNLhNDvIZOrt69Ce4UjGRpXJBzhUBzawMwnaDAwyHriki3XollsewxWzOzz+4yOFDkuJHtTsZFwMxhYJWmLQ==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@skeletonlabs/skeleton": { + "version": "2.8.0", + "resolved": "https://registry.npmjs.org/@skeletonlabs/skeleton/-/skeleton-2.8.0.tgz", + "integrity": "sha512-R6spSJSyW9MA6cnVQ8IV7uoYSXxHmP/oWJ9IHdGDU9epPZaZMmOXUHJSzA1gngccB2jFaA/6jXfS1O1CsIlGMg==", + "dev": true, + "dependencies": { + "esm-env": "1.0.0" + }, + "peerDependencies": { + "svelte": "^3.56.0 || ^4.0.0" + } + }, + "node_modules/@skeletonlabs/tw-plugin": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/@skeletonlabs/tw-plugin/-/tw-plugin-0.3.1.tgz", + "integrity": "sha512-DjjeOHN3HhFQf6gYPT2MUZMkIdw1jeB9mbuKC8etQxUlOR4XitfC7hssRWFJ8RJsvrrN0myCBbdWkVG1JVA96g==", + "dev": true, + "peerDependencies": { + "tailwindcss": ">=3.0.0" + } + }, + "node_modules/@sveltejs/adapter-cloudflare": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/@sveltejs/adapter-cloudflare/-/adapter-cloudflare-4.1.0.tgz", + "integrity": "sha512-AQQdZAZpcFDcBiMEmxbMYhn4yKZYoPZrKUrYpVejjbO+9obIGIuj/jWjVzAEkHqZMZuoRRqPbq+Zq+AWRm4x1Q==", + "dev": true, + "dependencies": { + "@cloudflare/workers-types": "^4.20231121.0", + "esbuild": "^0.19.11", + "worktop": "0.8.0-next.18" + }, + "peerDependencies": { + "@sveltejs/kit": "^2.0.0" + } + }, + "node_modules/@sveltejs/kit": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/@sveltejs/kit/-/kit-2.5.0.tgz", + "integrity": "sha512-1uyXvzC2Lu1FZa30T4y5jUAC21R309ZMRG0TPt+PPPbNUoDpy8zSmSNVWYaBWxYDqLGQ5oPNWvjvvF2IjJ1jmA==", + "dev": true, + "hasInstallScript": true, + "dependencies": { + "@types/cookie": "^0.6.0", + "cookie": "^0.6.0", + "devalue": "^4.3.2", + "esm-env": "^1.0.0", + "import-meta-resolve": "^4.0.0", + "kleur": "^4.1.5", + "magic-string": "^0.30.5", + "mrmime": "^2.0.0", + "sade": "^1.8.1", + "set-cookie-parser": "^2.6.0", + "sirv": "^2.0.4", + "tiny-glob": "^0.2.9" + }, + "bin": { + "svelte-kit": "svelte-kit.js" + }, + "engines": { + "node": ">=18.13" + }, + "peerDependencies": { + "@sveltejs/vite-plugin-svelte": "^3.0.0", + "svelte": "^4.0.0 || ^5.0.0-next.0", + "vite": "^5.0.3" + } + }, + "node_modules/@sveltejs/vite-plugin-svelte": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@sveltejs/vite-plugin-svelte/-/vite-plugin-svelte-3.0.2.tgz", + "integrity": "sha512-MpmF/cju2HqUls50WyTHQBZUV3ovV/Uk8k66AN2gwHogNAG8wnW8xtZDhzNBsFJJuvmq1qnzA5kE7YfMJNFv2Q==", + "dev": true, + "dependencies": { + "@sveltejs/vite-plugin-svelte-inspector": "^2.0.0", + "debug": "^4.3.4", + "deepmerge": "^4.3.1", + "kleur": "^4.1.5", + "magic-string": "^0.30.5", + "svelte-hmr": "^0.15.3", + "vitefu": "^0.2.5" + }, + "engines": { + "node": "^18.0.0 || >=20" + }, + "peerDependencies": { + "svelte": "^4.0.0 || ^5.0.0-next.0", + "vite": "^5.0.0" + } + }, + "node_modules/@sveltejs/vite-plugin-svelte-inspector": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@sveltejs/vite-plugin-svelte-inspector/-/vite-plugin-svelte-inspector-2.0.0.tgz", + "integrity": "sha512-gjr9ZFg1BSlIpfZ4PRewigrvYmHWbDrq2uvvPB1AmTWKuM+dI1JXQSUu2pIrYLb/QncyiIGkFDFKTwJ0XqQZZg==", + "dev": true, + "dependencies": { + "debug": "^4.3.4" + }, + "engines": { + "node": "^18.0.0 || >=20" + }, + "peerDependencies": { + "@sveltejs/vite-plugin-svelte": "^3.0.0", + "svelte": "^4.0.0 || ^5.0.0-next.0", + "vite": "^5.0.0" + } + }, + "node_modules/@tailwindcss/typography": { + "version": "0.5.10", + "resolved": "https://registry.npmjs.org/@tailwindcss/typography/-/typography-0.5.10.tgz", + "integrity": "sha512-Pe8BuPJQJd3FfRnm6H0ulKIGoMEQS+Vq01R6M5aCrFB/ccR/shT+0kXLjouGC1gFLm9hopTFN+DMP0pfwRWzPw==", + "dev": true, + "dependencies": { + "lodash.castarray": "^4.4.0", + "lodash.isplainobject": "^4.0.6", + "lodash.merge": "^4.6.2", + "postcss-selector-parser": "6.0.10" + }, + "peerDependencies": { + "tailwindcss": ">=3.0.0 || insiders" + } + }, + "node_modules/@types/cookie": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/@types/cookie/-/cookie-0.6.0.tgz", + "integrity": "sha512-4Kh9a6B2bQciAhf7FSuMRRkUWecJgJu9nPnx3yzpsfXX/c50REIqpHY4C82bXP90qrLtXtkDxTZosYO3UpOwlA==", + "dev": true + }, + "node_modules/@types/debug": { + "version": "4.1.12", + "resolved": "https://registry.npmjs.org/@types/debug/-/debug-4.1.12.tgz", + "integrity": "sha512-vIChWdVG3LG1SMxEvI/AK+FWJthlrqlTu7fbrlywTkkaONwk/UAGaULXRlf8vkzFBLVm0zkMdCquhL5aOjhXPQ==", + "dependencies": { + "@types/ms": "*" + } + }, + "node_modules/@types/eslint": { + "version": "8.56.0", + "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-8.56.0.tgz", + "integrity": "sha512-FlsN0p4FhuYRjIxpbdXovvHQhtlG05O1GG/RNWvdAxTboR438IOTwmrY/vLA+Xfgg06BTkP045M3vpFwTMv1dg==", + "dev": true, + "dependencies": { + "@types/estree": "*", + "@types/json-schema": "*" + } + }, + "node_modules/@types/estree": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.5.tgz", + "integrity": "sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw==" + }, + "node_modules/@types/hast": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@types/hast/-/hast-3.0.4.tgz", + "integrity": "sha512-WPs+bbQw5aCj+x6laNGWLH3wviHtoCv/P3+otBhbOhJgG8qtpdAMlTCxLtsTWA7LH1Oh/bFCHsBn0TPS5m30EQ==", + "dependencies": { + "@types/unist": "*" + } + }, + "node_modules/@types/json-schema": { + "version": "7.0.15", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz", + "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==", + "dev": true + }, + "node_modules/@types/marked": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/@types/marked/-/marked-5.0.2.tgz", + "integrity": "sha512-OucS4KMHhFzhz27KxmWg7J+kIYqyqoW5kdIEI319hqARQQUTqhao3M/F+uFnDXD0Rg72iDDZxZNxq5gvctmLlg==" + }, + "node_modules/@types/mdast": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/@types/mdast/-/mdast-4.0.3.tgz", + "integrity": "sha512-LsjtqsyF+d2/yFOYaN22dHZI1Cpwkrj+g06G8+qtUKlhovPW89YhqSnfKtMbkgmEtYpH2gydRNULd6y8mciAFg==", + "dependencies": { + "@types/unist": "*" + } + }, + "node_modules/@types/ms": { + "version": "0.7.34", + "resolved": "https://registry.npmjs.org/@types/ms/-/ms-0.7.34.tgz", + "integrity": "sha512-nG96G3Wp6acyAgJqGasjODb+acrI7KltPiRxzHPXnP3NgI28bpQDRv53olbqGXbfcgF5aiiHmO3xpwEpS5Ld9g==" + }, + "node_modules/@types/node": { + "version": "20.11.16", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.11.16.tgz", + "integrity": "sha512-gKb0enTmRCzXSSUJDq6/sPcqrfCv2mkkG6Jt/clpn5eiCbKTY+SgZUxo+p8ZKMof5dCp9vHQUAB7wOUTod22wQ==", + "dev": true, + "dependencies": { + "undici-types": "~5.26.4" + } + }, + "node_modules/@types/pug": { + "version": "2.0.10", + "resolved": "https://registry.npmjs.org/@types/pug/-/pug-2.0.10.tgz", + "integrity": "sha512-Sk/uYFOBAB7mb74XcpizmH0KOR2Pv3D2Hmrh1Dmy5BmK3MpdSa5kqZcg6EKBdklU0bFXX9gCfzvpnyUehrPIuA==", + "dev": true + }, + "node_modules/@types/semver": { + "version": "7.5.6", + "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.5.6.tgz", + "integrity": "sha512-dn1l8LaMea/IjDoHNd9J52uBbInB796CDffS6VdIxvqYCPSG0V0DzHp76GpaWnlhg88uYyPbXCDIowa86ybd5A==", + "dev": true + }, + "node_modules/@types/unist": { + "version": "2.0.10", + "resolved": "https://registry.npmjs.org/@types/unist/-/unist-2.0.10.tgz", + "integrity": "sha512-IfYcSBWE3hLpBg8+X2SEa8LVkJdJEkT2Ese2aaLs3ptGdVtABxndrMaxuFlQ1qdFf9Q5rDvDpxI3WwgvKFAsQA==" + }, + "node_modules/@typescript-eslint/eslint-plugin": { + "version": "6.21.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-6.21.0.tgz", + "integrity": "sha512-oy9+hTPCUFpngkEZUSzbf9MxI65wbKFoQYsgPdILTfbUldp5ovUuphZVe4i30emU9M/kP+T64Di0mxl7dSw3MA==", + "dev": true, + "dependencies": { + "@eslint-community/regexpp": "^4.5.1", + "@typescript-eslint/scope-manager": "6.21.0", + "@typescript-eslint/type-utils": "6.21.0", + "@typescript-eslint/utils": "6.21.0", + "@typescript-eslint/visitor-keys": "6.21.0", + "debug": "^4.3.4", + "graphemer": "^1.4.0", + "ignore": "^5.2.4", + "natural-compare": "^1.4.0", + "semver": "^7.5.4", + "ts-api-utils": "^1.0.1" + }, + "engines": { + "node": "^16.0.0 || >=18.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "@typescript-eslint/parser": "^6.0.0 || ^6.0.0-alpha", + "eslint": "^7.0.0 || ^8.0.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/parser": { + "version": "6.21.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-6.21.0.tgz", + "integrity": "sha512-tbsV1jPne5CkFQCgPBcDOt30ItF7aJoZL997JSF7MhGQqOeT3svWRYxiqlfA5RUdlHN6Fi+EI9bxqbdyAUZjYQ==", + "dev": true, + "dependencies": { + "@typescript-eslint/scope-manager": "6.21.0", + "@typescript-eslint/types": "6.21.0", + "@typescript-eslint/typescript-estree": "6.21.0", + "@typescript-eslint/visitor-keys": "6.21.0", + "debug": "^4.3.4" + }, + "engines": { + "node": "^16.0.0 || >=18.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^7.0.0 || ^8.0.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/scope-manager": { + "version": "6.21.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-6.21.0.tgz", + "integrity": "sha512-OwLUIWZJry80O99zvqXVEioyniJMa+d2GrqpUTqi5/v5D5rOrppJVBPa0yKCblcigC0/aYAzxxqQ1B+DS2RYsg==", + "dev": true, + "dependencies": { + "@typescript-eslint/types": "6.21.0", + "@typescript-eslint/visitor-keys": "6.21.0" + }, + "engines": { + "node": "^16.0.0 || >=18.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/type-utils": { + "version": "6.21.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-6.21.0.tgz", + "integrity": "sha512-rZQI7wHfao8qMX3Rd3xqeYSMCL3SoiSQLBATSiVKARdFGCYSRvmViieZjqc58jKgs8Y8i9YvVVhRbHSTA4VBag==", + "dev": true, + "dependencies": { + "@typescript-eslint/typescript-estree": "6.21.0", + "@typescript-eslint/utils": "6.21.0", + "debug": "^4.3.4", + "ts-api-utils": "^1.0.1" + }, + "engines": { + "node": "^16.0.0 || >=18.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^7.0.0 || ^8.0.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/types": { + "version": "6.21.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-6.21.0.tgz", + "integrity": "sha512-1kFmZ1rOm5epu9NZEZm1kckCDGj5UJEf7P1kliH4LKu/RkwpsfqqGmY2OOcUs18lSlQBKLDYBOGxRVtrMN5lpg==", + "dev": true, + "engines": { + "node": "^16.0.0 || >=18.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/typescript-estree": { + "version": "6.21.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-6.21.0.tgz", + "integrity": "sha512-6npJTkZcO+y2/kr+z0hc4HwNfrrP4kNYh57ek7yCNlrBjWQ1Y0OS7jiZTkgumrvkX5HkEKXFZkkdFNkaW2wmUQ==", + "dev": true, + "dependencies": { + "@typescript-eslint/types": "6.21.0", + "@typescript-eslint/visitor-keys": "6.21.0", + "debug": "^4.3.4", + "globby": "^11.1.0", + "is-glob": "^4.0.3", + "minimatch": "9.0.3", + "semver": "^7.5.4", + "ts-api-utils": "^1.0.1" + }, + "engines": { + "node": "^16.0.0 || >=18.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/utils": { + "version": "6.21.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-6.21.0.tgz", + "integrity": "sha512-NfWVaC8HP9T8cbKQxHcsJBY5YE1O33+jpMwN45qzWWaPDZgLIbo12toGMWnmhvCpd3sIxkpDw3Wv1B3dYrbDQQ==", + "dev": true, + "dependencies": { + "@eslint-community/eslint-utils": "^4.4.0", + "@types/json-schema": "^7.0.12", + "@types/semver": "^7.5.0", + "@typescript-eslint/scope-manager": "6.21.0", + "@typescript-eslint/types": "6.21.0", + "@typescript-eslint/typescript-estree": "6.21.0", + "semver": "^7.5.4" + }, + "engines": { + "node": "^16.0.0 || >=18.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^7.0.0 || ^8.0.0" + } + }, + "node_modules/@typescript-eslint/visitor-keys": { + "version": "6.21.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-6.21.0.tgz", + "integrity": "sha512-JJtkDduxLi9bivAB+cYOVMtbkqdPOhZ+ZI5LC47MIRrDV4Yn2o+ZnW10Nkmr28xRpSpdJ6Sm42Hjf2+REYXm0A==", + "dev": true, + "dependencies": { + "@typescript-eslint/types": "6.21.0", + "eslint-visitor-keys": "^3.4.1" + }, + "engines": { + "node": "^16.0.0 || >=18.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@ungap/structured-clone": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.2.0.tgz", + "integrity": "sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ==" + }, + "node_modules/acorn": { + "version": "8.11.3", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.11.3.tgz", + "integrity": "sha512-Y9rRfJG5jcKOE0CLisYbojUjIrIEE7AGMzA/Sm4BslANhbS+cDMpgBdcPT91oJ7OuJ9hYJBx59RjbhxVnrF8Xg==", + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/acorn-jsx": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", + "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", + "dev": true, + "peerDependencies": { + "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" + } + }, + "node_modules/ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dev": true, + "dependencies": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/any-promise": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/any-promise/-/any-promise-1.3.0.tgz", + "integrity": "sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A==", + "dev": true + }, + "node_modules/anymatch": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", + "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", + "dev": true, + "dependencies": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/arg": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/arg/-/arg-5.0.2.tgz", + "integrity": "sha512-PYjyFOLKQ9y57JvQ6QLo8dAgNqswh8M1RMJYdQduT6xbWSgK36P/Z/v+p888pM69jMMfS8Xd8F6I1kQ/I9HUGg==", + "dev": true + }, + "node_modules/argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "dev": true + }, + "node_modules/aria-query": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/aria-query/-/aria-query-5.3.0.tgz", + "integrity": "sha512-b0P0sZPKtyu8HkeRAfCq0IfURZK+SuwMjY1UXGBU27wpAiTwQAIlq56IbIO+ytk/JjS1fMR14ee5WBBfKi5J6A==", + "dependencies": { + "dequal": "^2.0.3" + } + }, + "node_modules/array-union": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", + "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/autoprefixer": { + "version": "10.4.17", + "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.4.17.tgz", + "integrity": "sha512-/cpVNRLSfhOtcGflT13P2794gVSgmPgTR+erw5ifnMLZb0UnSlkK4tquLmkd3BhA+nLo5tX8Cu0upUsGKvKbmg==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/autoprefixer" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "dependencies": { + "browserslist": "^4.22.2", + "caniuse-lite": "^1.0.30001578", + "fraction.js": "^4.3.7", + "normalize-range": "^0.1.2", + "picocolors": "^1.0.0", + "postcss-value-parser": "^4.2.0" + }, + "bin": { + "autoprefixer": "bin/autoprefixer" + }, + "engines": { + "node": "^10 || ^12 || >=14" + }, + "peerDependencies": { + "postcss": "^8.1.0" + } + }, + "node_modules/axobject-query": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/axobject-query/-/axobject-query-4.0.0.tgz", + "integrity": "sha512-+60uv1hiVFhHZeO+Lz0RYzsVHy5Wr1ayX0mwda9KPDVLNJgZ1T9Ny7VmFbLDzxsH0D87I86vgj3gFrjTJUYznw==", + "dependencies": { + "dequal": "^2.0.3" + } + }, + "node_modules/bail": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/bail/-/bail-2.0.2.tgz", + "integrity": "sha512-0xO6mYd7JB2YesxDKplafRpsiOzPt9V02ddPCLbY1xYGPOX24NTyN50qnUxgCPcSoYMhKpAuBTjQoRZCAkUDRw==", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "dev": true + }, + "node_modules/before-after-hook": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/before-after-hook/-/before-after-hook-2.2.3.tgz", + "integrity": "sha512-NzUnlZexiaH/46WDhANlyR2bXRopNg4F/zuSA3OpZnllCUgRaOF2znDioDWrmbNVsuZk6l9pMquQB38cfBZwkQ==" + }, + "node_modules/binary-extensions": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz", + "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/braces": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", + "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", + "dev": true, + "dependencies": { + "fill-range": "^7.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/browserslist": { + "version": "4.22.3", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.22.3.tgz", + "integrity": "sha512-UAp55yfwNv0klWNapjs/ktHoguxuQNGnOzxYmfnXIS+8AsRDZkSDxg7R1AX3GKzn078SBI5dzwzj/Yx0Or0e3A==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "dependencies": { + "caniuse-lite": "^1.0.30001580", + "electron-to-chromium": "^1.4.648", + "node-releases": "^2.0.14", + "update-browserslist-db": "^1.0.13" + }, + "bin": { + "browserslist": "cli.js" + }, + "engines": { + "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" + } + }, + "node_modules/buffer-crc32": { + "version": "0.2.13", + "resolved": "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-0.2.13.tgz", + "integrity": "sha512-VO9Ht/+p3SN7SKWqcrgEzjGbRSJYTx+Q1pTQC0wrWqHx0vpJraQ6GtHx8tvcg1rlK1byhU5gccxgOgj7B0TDkQ==", + "dev": true, + "engines": { + "node": "*" + } + }, + "node_modules/callsites": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/camelcase-css": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/camelcase-css/-/camelcase-css-2.0.1.tgz", + "integrity": "sha512-QOSvevhslijgYwRx6Rv7zKdMF8lbRmx+uQGx2+vDc+KI/eBnsy9kit5aj23AgGu3pa4t9AgwbnXWqS+iOY+2aA==", + "dev": true, + "engines": { + "node": ">= 6" + } + }, + "node_modules/caniuse-lite": { + "version": "1.0.30001585", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001585.tgz", + "integrity": "sha512-yr2BWR1yLXQ8fMpdS/4ZZXpseBgE7o4g41x3a6AJOqZuOi+iE/WdJYAuZ6Y95i4Ohd2Y+9MzIWRR+uGABH4s3Q==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/caniuse-lite" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ] + }, + "node_modules/ccount": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/ccount/-/ccount-2.0.1.tgz", + "integrity": "sha512-eyrF0jiFpY+3drT6383f1qhkbGsLSifNAjA61IUjZjmLCWjItY6LB9ft9YhoDgwfmclB2zhu51Lc7+95b8NRAg==", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/character-entities": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/character-entities/-/character-entities-2.0.2.tgz", + "integrity": "sha512-shx7oQ0Awen/BRIdkjkvz54PnEEI/EjwXDSIZp86/KKdbafHh1Df/RYGBhn4hbe2+uKC9FnT5UCEdyPz3ai9hQ==", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/chokidar": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz", + "integrity": "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==", + "dev": true, + "dependencies": { + "anymatch": "~3.1.2", + "braces": "~3.0.2", + "glob-parent": "~5.1.2", + "is-binary-path": "~2.1.0", + "is-glob": "~4.0.1", + "normalize-path": "~3.0.0", + "readdirp": "~3.6.0" + }, + "engines": { + "node": ">= 8.10.0" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + }, + "optionalDependencies": { + "fsevents": "~2.3.2" + } + }, + "node_modules/chokidar/node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/code-red": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/code-red/-/code-red-1.0.4.tgz", + "integrity": "sha512-7qJWqItLA8/VPVlKJlFXU+NBlo/qyfs39aJcuMT/2ere32ZqvF5OSxgdM5xOfJJ7O429gg2HM47y8v9P+9wrNw==", + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.4.15", + "@types/estree": "^1.0.1", + "acorn": "^8.10.0", + "estree-walker": "^3.0.3", + "periscopic": "^3.1.0" + } + }, + "node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "node_modules/commander": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/commander/-/commander-4.1.1.tgz", + "integrity": "sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==", + "dev": true, + "engines": { + "node": ">= 6" + } + }, + "node_modules/concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", + "dev": true + }, + "node_modules/cookie": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.6.0.tgz", + "integrity": "sha512-U71cyTamuh1CRNCfpGY6to28lxvNwPG4Guz/EVjgf3Jmzv0vlDp1atT9eS5dDjMYHucpHbWns6Lwf3BKz6svdw==", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/cross-spawn": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", + "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", + "dev": true, + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/css-tree": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/css-tree/-/css-tree-2.3.1.tgz", + "integrity": "sha512-6Fv1DV/TYw//QF5IzQdqsNDjx/wc8TrMBZsqjL9eW01tWb7R7k/mq+/VXfJCl7SoD5emsJop9cOByJZfs8hYIw==", + "dependencies": { + "mdn-data": "2.0.30", + "source-map-js": "^1.0.1" + }, + "engines": { + "node": "^10 || ^12.20.0 || ^14.13.0 || >=15.0.0" + } + }, + "node_modules/cssesc": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz", + "integrity": "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==", + "dev": true, + "bin": { + "cssesc": "bin/cssesc" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/date-fns": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/date-fns/-/date-fns-3.3.1.tgz", + "integrity": "sha512-y8e109LYGgoQDveiEBD3DYXKba1jWf5BA8YU1FL5Tvm0BTdEfy54WLCwnuYWZNnzzvALy/QQ4Hov+Q9RVRv+Zw==", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/kossnocorp" + } + }, + "node_modules/debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/decode-named-character-reference": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/decode-named-character-reference/-/decode-named-character-reference-1.0.2.tgz", + "integrity": "sha512-O8x12RzrUF8xyVcY0KJowWsmaJxQbmy0/EtnNtHRpsOcT7dFk5W598coHqBVpmWo1oQQfsCqfCmkZN5DJrZVdg==", + "dependencies": { + "character-entities": "^2.0.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/deep-is": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", + "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", + "dev": true + }, + "node_modules/deepmerge": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.3.1.tgz", + "integrity": "sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/deprecation": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/deprecation/-/deprecation-2.3.1.tgz", + "integrity": "sha512-xmHIy4F3scKVwMsQ4WnVaS8bHOx0DmVwRywosKhaILI0ywMDWPtBSku2HNxRvF7jtwDRsoEwYQSfbxj8b7RlJQ==" + }, + "node_modules/dequal": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/dequal/-/dequal-2.0.3.tgz", + "integrity": "sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==", + "engines": { + "node": ">=6" + } + }, + "node_modules/detect-indent": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/detect-indent/-/detect-indent-6.1.0.tgz", + "integrity": "sha512-reYkTUJAZb9gUuZ2RvVCNhVHdg62RHnJ7WJl8ftMi4diZ6NWlciOzQN88pUhSELEwflJht4oQDv0F0BMlwaYtA==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/devalue": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/devalue/-/devalue-4.3.2.tgz", + "integrity": "sha512-KqFl6pOgOW+Y6wJgu80rHpo2/3H07vr8ntR9rkkFIRETewbf5GaYYcakYfiKz89K+sLsuPkQIZaXDMjUObZwWg==", + "dev": true + }, + "node_modules/devlop": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/devlop/-/devlop-1.1.0.tgz", + "integrity": "sha512-RWmIqhcFf1lRYBvNmr7qTNuyCt/7/ns2jbpp1+PalgE/rDQcBT0fioSMUpJ93irlUhC5hrg4cYqe6U+0ImW0rA==", + "dependencies": { + "dequal": "^2.0.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/didyoumean": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/didyoumean/-/didyoumean-1.2.2.tgz", + "integrity": "sha512-gxtyfqMg7GKyhQmb056K7M3xszy/myH8w+B4RT+QXBQsvAOdc3XymqDDPHx1BgPgsdAA5SIifona89YtRATDzw==", + "dev": true + }, + "node_modules/dir-glob": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", + "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==", + "dev": true, + "dependencies": { + "path-type": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/dlv": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/dlv/-/dlv-1.1.3.tgz", + "integrity": "sha512-+HlytyjlPKnIG8XuRG8WvmBP8xs8P71y+SKKS6ZXWoEgLuePxtDoUEiH7WkdePWrQ5JBpE6aoVqfZfJUQkjXwA==", + "dev": true + }, + "node_modules/doctrine": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", + "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", + "dev": true, + "dependencies": { + "esutils": "^2.0.2" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/eastasianwidth": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz", + "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==", + "dev": true + }, + "node_modules/electron-to-chromium": { + "version": "1.4.661", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.661.tgz", + "integrity": "sha512-AFg4wDHSOk5F+zA8aR+SVIOabu7m0e7BiJnigCvPXzIGy731XENw/lmNxTySpVFtkFEy+eyt4oHhh5FF3NjQNw==", + "dev": true + }, + "node_modules/emoji-regex": { + "version": "9.2.2", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", + "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==", + "dev": true + }, + "node_modules/es6-promise": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/es6-promise/-/es6-promise-3.3.1.tgz", + "integrity": "sha512-SOp9Phqvqn7jtEUxPWdWfWoLmyt2VaJ6MpvP9Comy1MceMXqE6bxvaTu4iaxpYYPzhny28Lc+M87/c2cPK6lDg==", + "dev": true + }, + "node_modules/esbuild": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.19.12.tgz", + "integrity": "sha512-aARqgq8roFBj054KvQr5f1sFu0D65G+miZRCuJyJ0G13Zwx7vRar5Zhn2tkQNzIXcBrNVsv/8stehpj+GAjgbg==", + "dev": true, + "hasInstallScript": true, + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=12" + }, + "optionalDependencies": { + "@esbuild/aix-ppc64": "0.19.12", + "@esbuild/android-arm": "0.19.12", + "@esbuild/android-arm64": "0.19.12", + "@esbuild/android-x64": "0.19.12", + "@esbuild/darwin-arm64": "0.19.12", + "@esbuild/darwin-x64": "0.19.12", + "@esbuild/freebsd-arm64": "0.19.12", + "@esbuild/freebsd-x64": "0.19.12", + "@esbuild/linux-arm": "0.19.12", + "@esbuild/linux-arm64": "0.19.12", + "@esbuild/linux-ia32": "0.19.12", + "@esbuild/linux-loong64": "0.19.12", + "@esbuild/linux-mips64el": "0.19.12", + "@esbuild/linux-ppc64": "0.19.12", + "@esbuild/linux-riscv64": "0.19.12", + "@esbuild/linux-s390x": "0.19.12", + "@esbuild/linux-x64": "0.19.12", + "@esbuild/netbsd-x64": "0.19.12", + "@esbuild/openbsd-x64": "0.19.12", + "@esbuild/sunos-x64": "0.19.12", + "@esbuild/win32-arm64": "0.19.12", + "@esbuild/win32-ia32": "0.19.12", + "@esbuild/win32-x64": "0.19.12" + } + }, + "node_modules/escalade": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.2.tgz", + "integrity": "sha512-ErCHMCae19vR8vQGe50xIsVomy19rg6gFu3+r3jkEO46suLMWBksvVyoGgQV+jOfl84ZSOSlmv6Gxa89PmTGmA==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint": { + "version": "8.56.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.56.0.tgz", + "integrity": "sha512-Go19xM6T9puCOWntie1/P997aXxFsOi37JIHRWI514Hc6ZnaHGKY9xFhrU65RT6CcBEzZoGG1e6Nq+DT04ZtZQ==", + "dev": true, + "dependencies": { + "@eslint-community/eslint-utils": "^4.2.0", + "@eslint-community/regexpp": "^4.6.1", + "@eslint/eslintrc": "^2.1.4", + "@eslint/js": "8.56.0", + "@humanwhocodes/config-array": "^0.11.13", + "@humanwhocodes/module-importer": "^1.0.1", + "@nodelib/fs.walk": "^1.2.8", + "@ungap/structured-clone": "^1.2.0", + "ajv": "^6.12.4", + "chalk": "^4.0.0", + "cross-spawn": "^7.0.2", + "debug": "^4.3.2", + "doctrine": "^3.0.0", + "escape-string-regexp": "^4.0.0", + "eslint-scope": "^7.2.2", + "eslint-visitor-keys": "^3.4.3", + "espree": "^9.6.1", + "esquery": "^1.4.2", + "esutils": "^2.0.2", + "fast-deep-equal": "^3.1.3", + "file-entry-cache": "^6.0.1", + "find-up": "^5.0.0", + "glob-parent": "^6.0.2", + "globals": "^13.19.0", + "graphemer": "^1.4.0", + "ignore": "^5.2.0", + "imurmurhash": "^0.1.4", + "is-glob": "^4.0.0", + "is-path-inside": "^3.0.3", + "js-yaml": "^4.1.0", + "json-stable-stringify-without-jsonify": "^1.0.1", + "levn": "^0.4.1", + "lodash.merge": "^4.6.2", + "minimatch": "^3.1.2", + "natural-compare": "^1.4.0", + "optionator": "^0.9.3", + "strip-ansi": "^6.0.1", + "text-table": "^0.2.0" + }, + "bin": { + "eslint": "bin/eslint.js" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint-compat-utils": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/eslint-compat-utils/-/eslint-compat-utils-0.1.2.tgz", + "integrity": "sha512-Jia4JDldWnFNIru1Ehx1H5s9/yxiRHY/TimCuUc0jNexew3cF1gI6CYZil1ociakfWO3rRqFjl1mskBblB3RYg==", + "dev": true, + "engines": { + "node": ">=12" + }, + "peerDependencies": { + "eslint": ">=6.0.0" + } + }, + "node_modules/eslint-config-prettier": { + "version": "9.1.0", + "resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-9.1.0.tgz", + "integrity": "sha512-NSWl5BFQWEPi1j4TjVNItzYV7dZXZ+wP6I6ZhrBGpChQhZRUaElihE9uRRkcbRnNb76UMKDF3r+WTmNcGPKsqw==", + "dev": true, + "bin": { + "eslint-config-prettier": "bin/cli.js" + }, + "peerDependencies": { + "eslint": ">=7.0.0" + } + }, + "node_modules/eslint-plugin-svelte": { + "version": "2.35.1", + "resolved": "https://registry.npmjs.org/eslint-plugin-svelte/-/eslint-plugin-svelte-2.35.1.tgz", + "integrity": "sha512-IF8TpLnROSGy98Z3NrsKXWDSCbNY2ReHDcrYTuXZMbfX7VmESISR78TWgO9zdg4Dht1X8coub5jKwHzP0ExRug==", + "dev": true, + "dependencies": { + "@eslint-community/eslint-utils": "^4.2.0", + "@jridgewell/sourcemap-codec": "^1.4.14", + "debug": "^4.3.1", + "eslint-compat-utils": "^0.1.2", + "esutils": "^2.0.3", + "known-css-properties": "^0.29.0", + "postcss": "^8.4.5", + "postcss-load-config": "^3.1.4", + "postcss-safe-parser": "^6.0.0", + "postcss-selector-parser": "^6.0.11", + "semver": "^7.5.3", + "svelte-eslint-parser": ">=0.33.0 <1.0.0" + }, + "engines": { + "node": "^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/ota-meshi" + }, + "peerDependencies": { + "eslint": "^7.0.0 || ^8.0.0-0", + "svelte": "^3.37.0 || ^4.0.0" + }, + "peerDependenciesMeta": { + "svelte": { + "optional": true + } + } + }, + "node_modules/eslint-plugin-svelte/node_modules/postcss-selector-parser": { + "version": "6.0.15", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.0.15.tgz", + "integrity": "sha512-rEYkQOMUCEMhsKbK66tbEU9QVIxbhN18YiniAwA7XQYTVBqrBy+P2p5JcdqsHgKM2zWylp8d7J6eszocfds5Sw==", + "dev": true, + "dependencies": { + "cssesc": "^3.0.0", + "util-deprecate": "^1.0.2" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/eslint-scope": { + "version": "7.2.2", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.2.2.tgz", + "integrity": "sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg==", + "dev": true, + "dependencies": { + "esrecurse": "^4.3.0", + "estraverse": "^5.2.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint-visitor-keys": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", + "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", + "dev": true, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint/node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/eslint/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/esm-env": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/esm-env/-/esm-env-1.0.0.tgz", + "integrity": "sha512-Cf6VksWPsTuW01vU9Mk/3vRue91Zevka5SjyNf3nEpokFRuqt/KjUQoGAwq9qMmhpLTHmXzSIrFRw8zxWzmFBA==", + "dev": true + }, + "node_modules/espree": { + "version": "9.6.1", + "resolved": "https://registry.npmjs.org/espree/-/espree-9.6.1.tgz", + "integrity": "sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==", + "dev": true, + "dependencies": { + "acorn": "^8.9.0", + "acorn-jsx": "^5.3.2", + "eslint-visitor-keys": "^3.4.1" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/esquery": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.5.0.tgz", + "integrity": "sha512-YQLXUplAwJgCydQ78IMJywZCceoqk1oH01OERdSAJc/7U2AylwjhSCLDEtqwg811idIS/9fIU5GjG73IgjKMVg==", + "dev": true, + "dependencies": { + "estraverse": "^5.1.0" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/esrecurse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", + "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", + "dev": true, + "dependencies": { + "estraverse": "^5.2.0" + }, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/estree-walker": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-3.0.3.tgz", + "integrity": "sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==", + "dependencies": { + "@types/estree": "^1.0.0" + } + }, + "node_modules/esutils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/extend": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", + "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==" + }, + "node_modules/fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", + "dev": true + }, + "node_modules/fast-glob": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.2.tgz", + "integrity": "sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow==", + "dev": true, + "dependencies": { + "@nodelib/fs.stat": "^2.0.2", + "@nodelib/fs.walk": "^1.2.3", + "glob-parent": "^5.1.2", + "merge2": "^1.3.0", + "micromatch": "^4.0.4" + }, + "engines": { + "node": ">=8.6.0" + } + }, + "node_modules/fast-glob/node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/fast-json-stable-stringify": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", + "dev": true + }, + "node_modules/fast-levenshtein": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", + "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", + "dev": true + }, + "node_modules/fastq": { + "version": "1.17.1", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.17.1.tgz", + "integrity": "sha512-sRVD3lWVIXWg6By68ZN7vho9a1pQcN/WBFaAAsDDFzlJjvoGx0P8z7V1t72grFJfJhu3YPZBuu25f7Kaw2jN1w==", + "dev": true, + "dependencies": { + "reusify": "^1.0.4" + } + }, + "node_modules/file-entry-cache": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", + "integrity": "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==", + "dev": true, + "dependencies": { + "flat-cache": "^3.0.4" + }, + "engines": { + "node": "^10.12.0 || >=12.0.0" + } + }, + "node_modules/fill-range": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", + "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", + "dev": true, + "dependencies": { + "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/find-up": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", + "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", + "dev": true, + "dependencies": { + "locate-path": "^6.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/flat-cache": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.2.0.tgz", + "integrity": "sha512-CYcENa+FtcUKLmhhqyctpclsq7QF38pKjZHsGNiSQF5r4FtoKDWabFDl3hzaEQMvT1LHEysw5twgLvpYYb4vbw==", + "dev": true, + "dependencies": { + "flatted": "^3.2.9", + "keyv": "^4.5.3", + "rimraf": "^3.0.2" + }, + "engines": { + "node": "^10.12.0 || >=12.0.0" + } + }, + "node_modules/flatted": { + "version": "3.2.9", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.2.9.tgz", + "integrity": "sha512-36yxDn5H7OFZQla0/jFJmbIKTdZAQHngCedGxiMmpNfEZM0sdEeT+WczLQrjK6D7o2aiyLYDnkw0R3JK0Qv1RQ==", + "dev": true + }, + "node_modules/foreground-child": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.1.1.tgz", + "integrity": "sha512-TMKDUnIte6bfb5nWv7V/caI169OHgvwjb7V4WkeUvbQQdjr5rWKqHFiKWb/fcOwB+CzBT+qbWjvj+DVwRskpIg==", + "dev": true, + "dependencies": { + "cross-spawn": "^7.0.0", + "signal-exit": "^4.0.1" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/fraction.js": { + "version": "4.3.7", + "resolved": "https://registry.npmjs.org/fraction.js/-/fraction.js-4.3.7.tgz", + "integrity": "sha512-ZsDfxO51wGAXREY55a7la9LScWpwv9RxIrYABrlvOFBlH/ShPnrtsXeuUIfXKKOVicNxQ+o8JTbJvjS4M89yew==", + "dev": true, + "engines": { + "node": "*" + }, + "funding": { + "type": "patreon", + "url": "https://github.com/sponsors/rawify" + } + }, + "node_modules/fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", + "dev": true + }, + "node_modules/fsevents": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", + "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", + "dev": true, + "hasInstallScript": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/function-bind": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", + "dev": true, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/github-slugger": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/github-slugger/-/github-slugger-2.0.0.tgz", + "integrity": "sha512-IaOQ9puYtjrkq7Y0Ygl9KDZnrf/aiUJYUpVf89y8kyaxbRG7Y1SrX/jaumrv81vc61+kiMempujsM3Yw7w5qcw==" + }, + "node_modules/glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "dev": true, + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/glob-parent": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", + "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", + "dev": true, + "dependencies": { + "is-glob": "^4.0.3" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/glob/node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/glob/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/globals": { + "version": "13.24.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.24.0.tgz", + "integrity": "sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==", + "dev": true, + "dependencies": { + "type-fest": "^0.20.2" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/globalyzer": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/globalyzer/-/globalyzer-0.1.0.tgz", + "integrity": "sha512-40oNTM9UfG6aBmuKxk/giHn5nQ8RVz/SS4Ir6zgzOv9/qC3kKZ9v4etGTcJbEl/NyVQH7FGU7d+X1egr57Md2Q==", + "dev": true + }, + "node_modules/globby": { + "version": "11.1.0", + "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz", + "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==", + "dev": true, + "dependencies": { + "array-union": "^2.1.0", + "dir-glob": "^3.0.1", + "fast-glob": "^3.2.9", + "ignore": "^5.2.0", + "merge2": "^1.4.1", + "slash": "^3.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/globrex": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/globrex/-/globrex-0.1.2.tgz", + "integrity": "sha512-uHJgbwAMwNFf5mLst7IWLNg14x1CkeqglJb/K3doi4dw6q2IvAAmM/Y81kevy83wP+Sst+nutFTYOGg3d1lsxg==", + "dev": true + }, + "node_modules/graceful-fs": { + "version": "4.2.11", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", + "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", + "dev": true + }, + "node_modules/graphemer": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/graphemer/-/graphemer-1.4.0.tgz", + "integrity": "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==", + "dev": true + }, + "node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/hasown": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.0.tgz", + "integrity": "sha512-vUptKVTpIJhcczKBbgnS+RtcuYMB8+oNzPK2/Hp3hanz8JmpATdmmgLgSaadVREkDm+e2giHwY3ZRkyjSIDDFA==", + "dev": true, + "dependencies": { + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/hast-util-heading-rank": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/hast-util-heading-rank/-/hast-util-heading-rank-3.0.0.tgz", + "integrity": "sha512-EJKb8oMUXVHcWZTDepnr+WNbfnXKFNf9duMesmr4S8SXTJBJ9M4Yok08pu9vxdJwdlGRhVumk9mEhkEvKGifwA==", + "dependencies": { + "@types/hast": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/hast-util-is-element": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/hast-util-is-element/-/hast-util-is-element-3.0.0.tgz", + "integrity": "sha512-Val9mnv2IWpLbNPqc/pUem+a7Ipj2aHacCwgNfTiK0vJKl0LF+4Ba4+v1oPHFpf3bLYmreq0/l3Gud9S5OH42g==", + "dependencies": { + "@types/hast": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/hast-util-to-string": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/hast-util-to-string/-/hast-util-to-string-3.0.0.tgz", + "integrity": "sha512-OGkAxX1Ua3cbcW6EJ5pT/tslVb90uViVkcJ4ZZIMW/R33DX/AkcJcRrPebPwJkHYwlDHXz4aIwvAAaAdtrACFA==", + "dependencies": { + "@types/hast": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/highlight.js": { + "version": "11.9.0", + "resolved": "https://registry.npmjs.org/highlight.js/-/highlight.js-11.9.0.tgz", + "integrity": "sha512-fJ7cW7fQGCYAkgv4CPfwFHrfd/cLS4Hau96JuJ+ZTOWhjnhoeN1ub1tFmALm/+lW5z4WCAuAV9bm05AP0mS6Gw==", + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/ignore": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.1.tgz", + "integrity": "sha512-5Fytz/IraMjqpwfd34ke28PTVMjZjJG2MPn5t7OE4eUCUNf8BAa7b5WUS9/Qvr6mwOQS7Mk6vdsMno5he+T8Xw==", + "dev": true, + "engines": { + "node": ">= 4" + } + }, + "node_modules/import-fresh": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", + "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", + "dev": true, + "dependencies": { + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/import-meta-resolve": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/import-meta-resolve/-/import-meta-resolve-4.0.0.tgz", + "integrity": "sha512-okYUR7ZQPH+efeuMJGlq4f8ubUgO50kByRPyt/Cy1Io4PSRsPjxME+YlVaCOx+NIToW7hCsZNFJyTPFFKepRSA==", + "dev": true, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", + "dev": true, + "engines": { + "node": ">=0.8.19" + } + }, + "node_modules/inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", + "dev": true, + "dependencies": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "node_modules/inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "dev": true + }, + "node_modules/is-absolute-url": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/is-absolute-url/-/is-absolute-url-4.0.1.tgz", + "integrity": "sha512-/51/TKE88Lmm7Gc4/8btclNXWS+g50wXhYJq8HWIBAGUBnoAdRu1aXeh364t/O7wXDAcTJDP8PNuNKWUDWie+A==", + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-binary-path": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", + "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", + "dev": true, + "dependencies": { + "binary-extensions": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-buffer": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-2.0.5.tgz", + "integrity": "sha512-i2R6zNFDwgEHJyQUtJEk0XFi1i0dPFn/oqjK3/vPCcDeJvW5NQ83V8QbicfF1SupOaB0h8ntgBC2YiE7dfyctQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "engines": { + "node": ">=4" + } + }, + "node_modules/is-core-module": { + "version": "2.13.1", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.13.1.tgz", + "integrity": "sha512-hHrIjvZsftOsvKSn2TRYl63zvxsgE0K+0mYMoH6gD4omR5IWB2KynivBQczo3+wF1cCkjzvptnI9Q0sPU66ilw==", + "dev": true, + "dependencies": { + "hasown": "^2.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "dev": true, + "dependencies": { + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "dev": true, + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/is-path-inside": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz", + "integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-reference": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/is-reference/-/is-reference-3.0.2.tgz", + "integrity": "sha512-v3rht/LgVcsdZa3O2Nqs+NMowLOxeOm7Ay9+/ARQ2F+qEoANRcqrjAZKGN0v8ymUetZGgkp26LTnGT7H0Qo9Pg==", + "dependencies": { + "@types/estree": "*" + } + }, + "node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "dev": true + }, + "node_modules/jackspeak": { + "version": "2.3.6", + "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-2.3.6.tgz", + "integrity": "sha512-N3yCS/NegsOBokc8GAdM8UcmfsKiSS8cipheD/nivzr700H+nsMOxJjQnvwOcRYVuFkdH0wGUvW2WbXGmrZGbQ==", + "dev": true, + "dependencies": { + "@isaacs/cliui": "^8.0.2" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + }, + "optionalDependencies": { + "@pkgjs/parseargs": "^0.11.0" + } + }, + "node_modules/jiti": { + "version": "1.21.0", + "resolved": "https://registry.npmjs.org/jiti/-/jiti-1.21.0.tgz", + "integrity": "sha512-gFqAIbuKyyso/3G2qhiO2OM6shY6EPP/R0+mkDbyspxKazh8BXDC5FiFsUjlczgdNz/vfra0da2y+aHrusLG/Q==", + "dev": true, + "bin": { + "jiti": "bin/jiti.js" + } + }, + "node_modules/js-yaml": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", + "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", + "dev": true, + "dependencies": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/json-buffer": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", + "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==", + "dev": true + }, + "node_modules/json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true + }, + "node_modules/json-stable-stringify-without-jsonify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", + "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", + "dev": true + }, + "node_modules/just-camel-case": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/just-camel-case/-/just-camel-case-4.0.2.tgz", + "integrity": "sha512-df6QI/EIq+6uHe/wtaa9Qq7/pp4wr4pJC/r1+7XhVL6m5j03G6h9u9/rIZr8rDASX7CxwDPQnZjffCo2e6PRLw==" + }, + "node_modules/keyv": { + "version": "4.5.4", + "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", + "integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==", + "dev": true, + "dependencies": { + "json-buffer": "3.0.1" + } + }, + "node_modules/kleur": { + "version": "4.1.5", + "resolved": "https://registry.npmjs.org/kleur/-/kleur-4.1.5.tgz", + "integrity": "sha512-o+NO+8WrRiQEE4/7nwRJhN1HWpVmJm511pBHUxPLtp0BUISzlBplORYSmTclCnJvQq2tKu/sgl3xVpkc7ZWuQQ==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/known-css-properties": { + "version": "0.29.0", + "resolved": "https://registry.npmjs.org/known-css-properties/-/known-css-properties-0.29.0.tgz", + "integrity": "sha512-Ne7wqW7/9Cz54PDt4I3tcV+hAyat8ypyOGzYRJQfdxnnjeWsTxt1cy8pjvvKeI5kfXuyvULyeeAvwvvtAX3ayQ==", + "dev": true + }, + "node_modules/levn": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", + "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", + "dev": true, + "dependencies": { + "prelude-ls": "^1.2.1", + "type-check": "~0.4.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/lilconfig": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-2.1.0.tgz", + "integrity": "sha512-utWOt/GHzuUxnLKxB6dk81RoOeoNeHgbrXiuGk4yyF5qlRz+iIVWu56E2fqGHFrXz0QNUhLB/8nKqvRH66JKGQ==", + "dev": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/lines-and-columns": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", + "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==", + "dev": true + }, + "node_modules/locate-character": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/locate-character/-/locate-character-3.0.0.tgz", + "integrity": "sha512-SW13ws7BjaeJ6p7Q6CO2nchbYEc3X3J6WrmTTDto7yMPqVSZTUyY5Tjbid+Ab8gLnATtygYtiDIJGQRRn2ZOiA==" + }, + "node_modules/locate-path": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", + "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", + "dev": true, + "dependencies": { + "p-locate": "^5.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/lodash.castarray": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/lodash.castarray/-/lodash.castarray-4.4.0.tgz", + "integrity": "sha512-aVx8ztPv7/2ULbArGJ2Y42bG1mEQ5mGjpdvrbJcJFU3TbYybe+QlLS4pst9zV52ymy2in1KpFPiZnAOATxD4+Q==", + "dev": true + }, + "node_modules/lodash.isplainobject": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz", + "integrity": "sha512-oSXzaWypCMHkPC3NvBEaPHf0KsA5mvPrOPgQWDsbg8n7orZ290M0BmC/jgRZ4vcJ6DTAhjrsSYgdsW/F+MFOBA==", + "dev": true + }, + "node_modules/lodash.merge": { + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", + "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", + "dev": true + }, + "node_modules/longest-streak": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/longest-streak/-/longest-streak-3.1.0.tgz", + "integrity": "sha512-9Ri+o0JYgehTaVBBDoMqIl8GXtbWg711O3srftcHhZ0dqnETqLaoIK0x17fUw9rFSlK/0NlsKe0Ahhyl5pXE2g==", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "dev": true, + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/lucide-svelte": { + "version": "0.323.0", + "resolved": "https://registry.npmjs.org/lucide-svelte/-/lucide-svelte-0.323.0.tgz", + "integrity": "sha512-3GEFk1vCwB8BtHTHZTocFJfX6AtTLQw9a74JSuihAGx+MzhxqeWk8W1TkM4WUlvE0x9UdONM2rJGRyx9IyjkJg==", + "peerDependencies": { + "svelte": "^3 || ^4 || ^5.0.0-next.42" + } + }, + "node_modules/magic-string": { + "version": "0.30.7", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.7.tgz", + "integrity": "sha512-8vBuFF/I/+OSLRmdf2wwFCJCz+nSn0m6DPvGH1fS/KiQoSaR+sETbov0eIk9KhEKy8CYqIkIAnbohxT/4H0kuA==", + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.4.15" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/markdown-table": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/markdown-table/-/markdown-table-3.0.3.tgz", + "integrity": "sha512-Z1NL3Tb1M9wH4XESsCDEksWoKTdlUafKc4pt0GRwjUyXaCFZ+dc3g2erqB6zm3szA2IUSi7VnPI+o/9jnxh9hw==", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/marked": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/marked/-/marked-5.1.2.tgz", + "integrity": "sha512-ahRPGXJpjMjwSOlBoTMZAK7ATXkli5qCPxZ21TG44rx1KEo44bii4ekgTDQPNRQ4Kh7JMb9Ub1PVk1NxRSsorg==", + "bin": { + "marked": "bin/marked.js" + }, + "engines": { + "node": ">= 16" + } + }, + "node_modules/mdast-util-definitions": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/mdast-util-definitions/-/mdast-util-definitions-5.1.2.tgz", + "integrity": "sha512-8SVPMuHqlPME/z3gqVwWY4zVXn8lqKv/pAhC57FuJ40ImXyBpmO5ukh98zB2v7Blql2FiHjHv9LVztSIqjY+MA==", + "dependencies": { + "@types/mdast": "^3.0.0", + "@types/unist": "^2.0.0", + "unist-util-visit": "^4.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-definitions/node_modules/@types/mdast": { + "version": "3.0.15", + "resolved": "https://registry.npmjs.org/@types/mdast/-/mdast-3.0.15.tgz", + "integrity": "sha512-LnwD+mUEfxWMa1QpDraczIn6k0Ee3SMicuYSSzS6ZYl2gKS09EClnJYGd8Du6rfc5r/GZEk5o1mRb8TaTj03sQ==", + "dependencies": { + "@types/unist": "^2" + } + }, + "node_modules/mdast-util-definitions/node_modules/unist-util-is": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/unist-util-is/-/unist-util-is-5.2.1.tgz", + "integrity": "sha512-u9njyyfEh43npf1M+yGKDGVPbY/JWEemg5nH05ncKPfi+kBbKBJoTdsogMu33uhytuLlv9y0O7GH7fEdwLdLQw==", + "dependencies": { + "@types/unist": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-definitions/node_modules/unist-util-visit": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/unist-util-visit/-/unist-util-visit-4.1.2.tgz", + "integrity": "sha512-MSd8OUGISqHdVvfY9TPhyK2VdUrPgxkUtWSuMHF6XAAFuL4LokseigBnZtPnJMu+FbynTkFNnFlyjxpVKujMRg==", + "dependencies": { + "@types/unist": "^2.0.0", + "unist-util-is": "^5.0.0", + "unist-util-visit-parents": "^5.1.1" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-definitions/node_modules/unist-util-visit-parents": { + "version": "5.1.3", + "resolved": "https://registry.npmjs.org/unist-util-visit-parents/-/unist-util-visit-parents-5.1.3.tgz", + "integrity": "sha512-x6+y8g7wWMyQhL1iZfhIPhDAs7Xwbn9nRosDXl7qoPTSCy0yNxnKc+hWokFifWQIDGi154rdUqKvbCa4+1kLhg==", + "dependencies": { + "@types/unist": "^2.0.0", + "unist-util-is": "^5.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-find-and-replace": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/mdast-util-find-and-replace/-/mdast-util-find-and-replace-3.0.1.tgz", + "integrity": "sha512-SG21kZHGC3XRTSUhtofZkBzZTJNM5ecCi0SK2IMKmSXR8vO3peL+kb1O0z7Zl83jKtutG4k5Wv/W7V3/YHvzPA==", + "dependencies": { + "@types/mdast": "^4.0.0", + "escape-string-regexp": "^5.0.0", + "unist-util-is": "^6.0.0", + "unist-util-visit-parents": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-find-and-replace/node_modules/escape-string-regexp": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-5.0.0.tgz", + "integrity": "sha512-/veY75JbMK4j1yjvuUxuVsiS/hr/4iHs9FTT6cgTexxdE0Ly/glccBAkloH/DofkjRbZU3bnoj38mOmhkZ0lHw==", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/mdast-util-from-markdown": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/mdast-util-from-markdown/-/mdast-util-from-markdown-2.0.0.tgz", + "integrity": "sha512-n7MTOr/z+8NAX/wmhhDji8O3bRvPTV/U0oTCaZJkjhPSKTPhS3xufVhKGF8s1pJ7Ox4QgoIU7KHseh09S+9rTA==", + "dependencies": { + "@types/mdast": "^4.0.0", + "@types/unist": "^3.0.0", + "decode-named-character-reference": "^1.0.0", + "devlop": "^1.0.0", + "mdast-util-to-string": "^4.0.0", + "micromark": "^4.0.0", + "micromark-util-decode-numeric-character-reference": "^2.0.0", + "micromark-util-decode-string": "^2.0.0", + "micromark-util-normalize-identifier": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0", + "unist-util-stringify-position": "^4.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-from-markdown/node_modules/@types/unist": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@types/unist/-/unist-3.0.2.tgz", + "integrity": "sha512-dqId9J8K/vGi5Zr7oo212BGii5m3q5Hxlkwy3WpYuKPklmBEvsbMYYyLxAQpSffdLl/gdW0XUpKWFvYmyoWCoQ==" + }, + "node_modules/mdast-util-from-markdown/node_modules/unist-util-stringify-position": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/unist-util-stringify-position/-/unist-util-stringify-position-4.0.0.tgz", + "integrity": "sha512-0ASV06AAoKCDkS2+xw5RXJywruurpbC4JZSm7nr7MOt1ojAzvyyaO+UxZf18j8FCF6kmzCZKcAgN/yu2gm2XgQ==", + "dependencies": { + "@types/unist": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-gfm": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/mdast-util-gfm/-/mdast-util-gfm-3.0.0.tgz", + "integrity": "sha512-dgQEX5Amaq+DuUqf26jJqSK9qgixgd6rYDHAv4aTBuA92cTknZlKpPfa86Z/s8Dj8xsAQpFfBmPUHWJBWqS4Bw==", + "dependencies": { + "mdast-util-from-markdown": "^2.0.0", + "mdast-util-gfm-autolink-literal": "^2.0.0", + "mdast-util-gfm-footnote": "^2.0.0", + "mdast-util-gfm-strikethrough": "^2.0.0", + "mdast-util-gfm-table": "^2.0.0", + "mdast-util-gfm-task-list-item": "^2.0.0", + "mdast-util-to-markdown": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-gfm-autolink-literal": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/mdast-util-gfm-autolink-literal/-/mdast-util-gfm-autolink-literal-2.0.0.tgz", + "integrity": "sha512-FyzMsduZZHSc3i0Px3PQcBT4WJY/X/RCtEJKuybiC6sjPqLv7h1yqAkmILZtuxMSsUyaLUWNp71+vQH2zqp5cg==", + "dependencies": { + "@types/mdast": "^4.0.0", + "ccount": "^2.0.0", + "devlop": "^1.0.0", + "mdast-util-find-and-replace": "^3.0.0", + "micromark-util-character": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-gfm-footnote": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/mdast-util-gfm-footnote/-/mdast-util-gfm-footnote-2.0.0.tgz", + "integrity": "sha512-5jOT2boTSVkMnQ7LTrd6n/18kqwjmuYqo7JUPe+tRCY6O7dAuTFMtTPauYYrMPpox9hlN0uOx/FL8XvEfG9/mQ==", + "dependencies": { + "@types/mdast": "^4.0.0", + "devlop": "^1.1.0", + "mdast-util-from-markdown": "^2.0.0", + "mdast-util-to-markdown": "^2.0.0", + "micromark-util-normalize-identifier": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-gfm-strikethrough": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/mdast-util-gfm-strikethrough/-/mdast-util-gfm-strikethrough-2.0.0.tgz", + "integrity": "sha512-mKKb915TF+OC5ptj5bJ7WFRPdYtuHv0yTRxK2tJvi+BDqbkiG7h7u/9SI89nRAYcmap2xHQL9D+QG/6wSrTtXg==", + "dependencies": { + "@types/mdast": "^4.0.0", + "mdast-util-from-markdown": "^2.0.0", + "mdast-util-to-markdown": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-gfm-table": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/mdast-util-gfm-table/-/mdast-util-gfm-table-2.0.0.tgz", + "integrity": "sha512-78UEvebzz/rJIxLvE7ZtDd/vIQ0RHv+3Mh5DR96p7cS7HsBhYIICDBCu8csTNWNO6tBWfqXPWekRuj2FNOGOZg==", + "dependencies": { + "@types/mdast": "^4.0.0", + "devlop": "^1.0.0", + "markdown-table": "^3.0.0", + "mdast-util-from-markdown": "^2.0.0", + "mdast-util-to-markdown": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-gfm-task-list-item": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/mdast-util-gfm-task-list-item/-/mdast-util-gfm-task-list-item-2.0.0.tgz", + "integrity": "sha512-IrtvNvjxC1o06taBAVJznEnkiHxLFTzgonUdy8hzFVeDun0uTjxxrRGVaNFqkU1wJR3RBPEfsxmU6jDWPofrTQ==", + "dependencies": { + "@types/mdast": "^4.0.0", + "devlop": "^1.0.0", + "mdast-util-from-markdown": "^2.0.0", + "mdast-util-to-markdown": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-phrasing": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/mdast-util-phrasing/-/mdast-util-phrasing-4.1.0.tgz", + "integrity": "sha512-TqICwyvJJpBwvGAMZjj4J2n0X8QWp21b9l0o7eXyVJ25YNWYbJDVIyD1bZXE6WtV6RmKJVYmQAKWa0zWOABz2w==", + "dependencies": { + "@types/mdast": "^4.0.0", + "unist-util-is": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-to-markdown": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/mdast-util-to-markdown/-/mdast-util-to-markdown-2.1.0.tgz", + "integrity": "sha512-SR2VnIEdVNCJbP6y7kVTJgPLifdr8WEU440fQec7qHoHOUz/oJ2jmNRqdDQ3rbiStOXb2mCDGTuwsK5OPUgYlQ==", + "dependencies": { + "@types/mdast": "^4.0.0", + "@types/unist": "^3.0.0", + "longest-streak": "^3.0.0", + "mdast-util-phrasing": "^4.0.0", + "mdast-util-to-string": "^4.0.0", + "micromark-util-decode-string": "^2.0.0", + "unist-util-visit": "^5.0.0", + "zwitch": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdast-util-to-markdown/node_modules/@types/unist": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@types/unist/-/unist-3.0.2.tgz", + "integrity": "sha512-dqId9J8K/vGi5Zr7oo212BGii5m3q5Hxlkwy3WpYuKPklmBEvsbMYYyLxAQpSffdLl/gdW0XUpKWFvYmyoWCoQ==" + }, + "node_modules/mdast-util-to-string": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/mdast-util-to-string/-/mdast-util-to-string-4.0.0.tgz", + "integrity": "sha512-0H44vDimn51F0YwvxSJSm0eCDOJTRlmN0R1yBh4HLj9wiV1Dn0QoXGbvFAWj2hSItVTlCmBF1hqKlIyUBVFLPg==", + "dependencies": { + "@types/mdast": "^4.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdn-data": { + "version": "2.0.30", + "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.0.30.tgz", + "integrity": "sha512-GaqWWShW4kv/G9IEucWScBx9G1/vsFZZJUO+tD26M8J8z3Kw5RDQjaoZe03YAClgeS/SWPOcb4nkFBTEi5DUEA==" + }, + "node_modules/mdsvex": { + "version": "0.11.0", + "resolved": "https://registry.npmjs.org/mdsvex/-/mdsvex-0.11.0.tgz", + "integrity": "sha512-gJF1s0N2nCmdxcKn8HDn0LKrN8poStqAicp6bBcsKFd/zkUBGLP5e7vnxu+g0pjBbDFOscUyI1mtHz+YK2TCDw==", + "dev": true, + "dependencies": { + "@types/unist": "^2.0.3", + "prism-svelte": "^0.4.7", + "prismjs": "^1.17.1", + "vfile-message": "^2.0.4" + }, + "peerDependencies": { + "svelte": ">=3 <5" + } + }, + "node_modules/mdsvex-relative-images": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/mdsvex-relative-images/-/mdsvex-relative-images-1.0.3.tgz", + "integrity": "sha512-3XvpnaguRAhC5gchpqCH+A5Yl28xG9WDPylVla0+k90c5LT+QqSM+hwHd1v5C7gB2cAT0AIhuMsY/g6aCw+WDg==", + "dependencies": { + "just-camel-case": "^4.0.2", + "unist-util-visit": "^3.1.0" + } + }, + "node_modules/mdsvex-relative-images/node_modules/unist-util-is": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/unist-util-is/-/unist-util-is-5.2.1.tgz", + "integrity": "sha512-u9njyyfEh43npf1M+yGKDGVPbY/JWEemg5nH05ncKPfi+kBbKBJoTdsogMu33uhytuLlv9y0O7GH7fEdwLdLQw==", + "dependencies": { + "@types/unist": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdsvex-relative-images/node_modules/unist-util-visit": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/unist-util-visit/-/unist-util-visit-3.1.0.tgz", + "integrity": "sha512-Szoh+R/Ll68QWAyQyZZpQzZQm2UPbxibDvaY8Xc9SUtYgPsDzx5AWSk++UUt2hJuow8mvwR+rG+LQLw+KsuAKA==", + "dependencies": { + "@types/unist": "^2.0.0", + "unist-util-is": "^5.0.0", + "unist-util-visit-parents": "^4.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/mdsvex-relative-images/node_modules/unist-util-visit-parents": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/unist-util-visit-parents/-/unist-util-visit-parents-4.1.1.tgz", + "integrity": "sha512-1xAFJXAKpnnJl8G7K5KgU7FY55y3GcLIXqkzUj5QF/QVP7biUm0K0O2oqVkYsdjzJKifYeWn9+o6piAK2hGSHw==", + "dependencies": { + "@types/unist": "^2.0.0", + "unist-util-is": "^5.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/merge2": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", + "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", + "dev": true, + "engines": { + "node": ">= 8" + } + }, + "node_modules/micromark": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/micromark/-/micromark-4.0.0.tgz", + "integrity": "sha512-o/sd0nMof8kYff+TqcDx3VSrgBTcZpSvYcAHIfHhv5VAuNmisCxjhx6YmxS8PFEpb9z5WKWKPdzf0jM23ro3RQ==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "dependencies": { + "@types/debug": "^4.0.0", + "debug": "^4.0.0", + "decode-named-character-reference": "^1.0.0", + "devlop": "^1.0.0", + "micromark-core-commonmark": "^2.0.0", + "micromark-factory-space": "^2.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-chunked": "^2.0.0", + "micromark-util-combine-extensions": "^2.0.0", + "micromark-util-decode-numeric-character-reference": "^2.0.0", + "micromark-util-encode": "^2.0.0", + "micromark-util-normalize-identifier": "^2.0.0", + "micromark-util-resolve-all": "^2.0.0", + "micromark-util-sanitize-uri": "^2.0.0", + "micromark-util-subtokenize": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-core-commonmark": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/micromark-core-commonmark/-/micromark-core-commonmark-2.0.0.tgz", + "integrity": "sha512-jThOz/pVmAYUtkroV3D5c1osFXAMv9e0ypGDOIZuCeAe91/sD6BoE2Sjzt30yuXtwOYUmySOhMas/PVyh02itA==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "dependencies": { + "decode-named-character-reference": "^1.0.0", + "devlop": "^1.0.0", + "micromark-factory-destination": "^2.0.0", + "micromark-factory-label": "^2.0.0", + "micromark-factory-space": "^2.0.0", + "micromark-factory-title": "^2.0.0", + "micromark-factory-whitespace": "^2.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-chunked": "^2.0.0", + "micromark-util-classify-character": "^2.0.0", + "micromark-util-html-tag-name": "^2.0.0", + "micromark-util-normalize-identifier": "^2.0.0", + "micromark-util-resolve-all": "^2.0.0", + "micromark-util-subtokenize": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-extension-gfm": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/micromark-extension-gfm/-/micromark-extension-gfm-3.0.0.tgz", + "integrity": "sha512-vsKArQsicm7t0z2GugkCKtZehqUm31oeGBV/KVSorWSy8ZlNAv7ytjFhvaryUiCUJYqs+NoE6AFhpQvBTM6Q4w==", + "dependencies": { + "micromark-extension-gfm-autolink-literal": "^2.0.0", + "micromark-extension-gfm-footnote": "^2.0.0", + "micromark-extension-gfm-strikethrough": "^2.0.0", + "micromark-extension-gfm-table": "^2.0.0", + "micromark-extension-gfm-tagfilter": "^2.0.0", + "micromark-extension-gfm-task-list-item": "^2.0.0", + "micromark-util-combine-extensions": "^2.0.0", + "micromark-util-types": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/micromark-extension-gfm-autolink-literal": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/micromark-extension-gfm-autolink-literal/-/micromark-extension-gfm-autolink-literal-2.0.0.tgz", + "integrity": "sha512-rTHfnpt/Q7dEAK1Y5ii0W8bhfJlVJFnJMHIPisfPK3gpVNuOP0VnRl96+YJ3RYWV/P4gFeQoGKNlT3RhuvpqAg==", + "dependencies": { + "micromark-util-character": "^2.0.0", + "micromark-util-sanitize-uri": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/micromark-extension-gfm-footnote": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/micromark-extension-gfm-footnote/-/micromark-extension-gfm-footnote-2.0.0.tgz", + "integrity": "sha512-6Rzu0CYRKDv3BfLAUnZsSlzx3ak6HAoI85KTiijuKIz5UxZxbUI+pD6oHgw+6UtQuiRwnGRhzMmPRv4smcz0fg==", + "dependencies": { + "devlop": "^1.0.0", + "micromark-core-commonmark": "^2.0.0", + "micromark-factory-space": "^2.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-normalize-identifier": "^2.0.0", + "micromark-util-sanitize-uri": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/micromark-extension-gfm-strikethrough": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/micromark-extension-gfm-strikethrough/-/micromark-extension-gfm-strikethrough-2.0.0.tgz", + "integrity": "sha512-c3BR1ClMp5fxxmwP6AoOY2fXO9U8uFMKs4ADD66ahLTNcwzSCyRVU4k7LPV5Nxo/VJiR4TdzxRQY2v3qIUceCw==", + "dependencies": { + "devlop": "^1.0.0", + "micromark-util-chunked": "^2.0.0", + "micromark-util-classify-character": "^2.0.0", + "micromark-util-resolve-all": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/micromark-extension-gfm-table": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/micromark-extension-gfm-table/-/micromark-extension-gfm-table-2.0.0.tgz", + "integrity": "sha512-PoHlhypg1ItIucOaHmKE8fbin3vTLpDOUg8KAr8gRCF1MOZI9Nquq2i/44wFvviM4WuxJzc3demT8Y3dkfvYrw==", + "dependencies": { + "devlop": "^1.0.0", + "micromark-factory-space": "^2.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/micromark-extension-gfm-tagfilter": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/micromark-extension-gfm-tagfilter/-/micromark-extension-gfm-tagfilter-2.0.0.tgz", + "integrity": "sha512-xHlTOmuCSotIA8TW1mDIM6X2O1SiX5P9IuDtqGonFhEK0qgRI4yeC6vMxEV2dgyr2TiD+2PQ10o+cOhdVAcwfg==", + "dependencies": { + "micromark-util-types": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/micromark-extension-gfm-task-list-item": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-extension-gfm-task-list-item/-/micromark-extension-gfm-task-list-item-2.0.1.tgz", + "integrity": "sha512-cY5PzGcnULaN5O7T+cOzfMoHjBW7j+T9D2sucA5d/KbsBTPcYdebm9zUd9zzdgJGCwahV+/W78Z3nbulBYVbTw==", + "dependencies": { + "devlop": "^1.0.0", + "micromark-factory-space": "^2.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/micromark-factory-destination": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/micromark-factory-destination/-/micromark-factory-destination-2.0.0.tgz", + "integrity": "sha512-j9DGrQLm/Uhl2tCzcbLhy5kXsgkHUrjJHg4fFAeoMRwJmJerT9aw4FEhIbZStWN8A3qMwOp1uzHr4UL8AInxtA==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "dependencies": { + "micromark-util-character": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-factory-label": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/micromark-factory-label/-/micromark-factory-label-2.0.0.tgz", + "integrity": "sha512-RR3i96ohZGde//4WSe/dJsxOX6vxIg9TimLAS3i4EhBAFx8Sm5SmqVfR8E87DPSR31nEAjZfbt91OMZWcNgdZw==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "dependencies": { + "devlop": "^1.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-factory-space": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/micromark-factory-space/-/micromark-factory-space-2.0.0.tgz", + "integrity": "sha512-TKr+LIDX2pkBJXFLzpyPyljzYK3MtmllMUMODTQJIUfDGncESaqB90db9IAUcz4AZAJFdd8U9zOp9ty1458rxg==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "dependencies": { + "micromark-util-character": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-factory-title": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/micromark-factory-title/-/micromark-factory-title-2.0.0.tgz", + "integrity": "sha512-jY8CSxmpWLOxS+t8W+FG3Xigc0RDQA9bKMY/EwILvsesiRniiVMejYTE4wumNc2f4UbAa4WsHqe3J1QS1sli+A==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "dependencies": { + "micromark-factory-space": "^2.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-factory-whitespace": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/micromark-factory-whitespace/-/micromark-factory-whitespace-2.0.0.tgz", + "integrity": "sha512-28kbwaBjc5yAI1XadbdPYHX/eDnqaUFVikLwrO7FDnKG7lpgxnvk/XGRhX/PN0mOZ+dBSZ+LgunHS+6tYQAzhA==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "dependencies": { + "micromark-factory-space": "^2.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-util-character": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/micromark-util-character/-/micromark-util-character-2.1.0.tgz", + "integrity": "sha512-KvOVV+X1yLBfs9dCBSopq/+G1PcgT3lAK07mC4BzXi5E7ahzMAF8oIupDDJ6mievI6F+lAATkbQQlQixJfT3aQ==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "dependencies": { + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-util-chunked": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/micromark-util-chunked/-/micromark-util-chunked-2.0.0.tgz", + "integrity": "sha512-anK8SWmNphkXdaKgz5hJvGa7l00qmcaUQoMYsBwDlSKFKjc6gjGXPDw3FNL3Nbwq5L8gE+RCbGqTw49FK5Qyvg==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "dependencies": { + "micromark-util-symbol": "^2.0.0" + } + }, + "node_modules/micromark-util-classify-character": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/micromark-util-classify-character/-/micromark-util-classify-character-2.0.0.tgz", + "integrity": "sha512-S0ze2R9GH+fu41FA7pbSqNWObo/kzwf8rN/+IGlW/4tC6oACOs8B++bh+i9bVyNnwCcuksbFwsBme5OCKXCwIw==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "dependencies": { + "micromark-util-character": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-util-combine-extensions": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/micromark-util-combine-extensions/-/micromark-util-combine-extensions-2.0.0.tgz", + "integrity": "sha512-vZZio48k7ON0fVS3CUgFatWHoKbbLTK/rT7pzpJ4Bjp5JjkZeasRfrS9wsBdDJK2cJLHMckXZdzPSSr1B8a4oQ==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "dependencies": { + "micromark-util-chunked": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-util-decode-numeric-character-reference": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/micromark-util-decode-numeric-character-reference/-/micromark-util-decode-numeric-character-reference-2.0.1.tgz", + "integrity": "sha512-bmkNc7z8Wn6kgjZmVHOX3SowGmVdhYS7yBpMnuMnPzDq/6xwVA604DuOXMZTO1lvq01g+Adfa0pE2UKGlxL1XQ==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "dependencies": { + "micromark-util-symbol": "^2.0.0" + } + }, + "node_modules/micromark-util-decode-string": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/micromark-util-decode-string/-/micromark-util-decode-string-2.0.0.tgz", + "integrity": "sha512-r4Sc6leeUTn3P6gk20aFMj2ntPwn6qpDZqWvYmAG6NgvFTIlj4WtrAudLi65qYoaGdXYViXYw2pkmn7QnIFasA==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "dependencies": { + "decode-named-character-reference": "^1.0.0", + "micromark-util-character": "^2.0.0", + "micromark-util-decode-numeric-character-reference": "^2.0.0", + "micromark-util-symbol": "^2.0.0" + } + }, + "node_modules/micromark-util-encode": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/micromark-util-encode/-/micromark-util-encode-2.0.0.tgz", + "integrity": "sha512-pS+ROfCXAGLWCOc8egcBvT0kf27GoWMqtdarNfDcjb6YLuV5cM3ioG45Ys2qOVqeqSbjaKg72vU+Wby3eddPsA==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ] + }, + "node_modules/micromark-util-html-tag-name": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/micromark-util-html-tag-name/-/micromark-util-html-tag-name-2.0.0.tgz", + "integrity": "sha512-xNn4Pqkj2puRhKdKTm8t1YHC/BAjx6CEwRFXntTaRf/x16aqka6ouVoutm+QdkISTlT7e2zU7U4ZdlDLJd2Mcw==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ] + }, + "node_modules/micromark-util-normalize-identifier": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/micromark-util-normalize-identifier/-/micromark-util-normalize-identifier-2.0.0.tgz", + "integrity": "sha512-2xhYT0sfo85FMrUPtHcPo2rrp1lwbDEEzpx7jiH2xXJLqBuy4H0GgXk5ToU8IEwoROtXuL8ND0ttVa4rNqYK3w==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "dependencies": { + "micromark-util-symbol": "^2.0.0" + } + }, + "node_modules/micromark-util-resolve-all": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/micromark-util-resolve-all/-/micromark-util-resolve-all-2.0.0.tgz", + "integrity": "sha512-6KU6qO7DZ7GJkaCgwBNtplXCvGkJToU86ybBAUdavvgsCiG8lSSvYxr9MhwmQ+udpzywHsl4RpGJsYWG1pDOcA==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "dependencies": { + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-util-sanitize-uri": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/micromark-util-sanitize-uri/-/micromark-util-sanitize-uri-2.0.0.tgz", + "integrity": "sha512-WhYv5UEcZrbAtlsnPuChHUAsu/iBPOVaEVsntLBIdpibO0ddy8OzavZz3iL2xVvBZOpolujSliP65Kq0/7KIYw==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "dependencies": { + "micromark-util-character": "^2.0.0", + "micromark-util-encode": "^2.0.0", + "micromark-util-symbol": "^2.0.0" + } + }, + "node_modules/micromark-util-subtokenize": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/micromark-util-subtokenize/-/micromark-util-subtokenize-2.0.0.tgz", + "integrity": "sha512-vc93L1t+gpR3p8jxeVdaYlbV2jTYteDje19rNSS/H5dlhxUYll5Fy6vJ2cDwP8RnsXi818yGty1ayP55y3W6fg==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ], + "dependencies": { + "devlop": "^1.0.0", + "micromark-util-chunked": "^2.0.0", + "micromark-util-symbol": "^2.0.0", + "micromark-util-types": "^2.0.0" + } + }, + "node_modules/micromark-util-symbol": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/micromark-util-symbol/-/micromark-util-symbol-2.0.0.tgz", + "integrity": "sha512-8JZt9ElZ5kyTnO94muPxIGS8oyElRJaiJO8EzV6ZSyGQ1Is8xwl4Q45qU5UOg+bGH4AikWziz0iN4sFLWs8PGw==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ] + }, + "node_modules/micromark-util-types": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/micromark-util-types/-/micromark-util-types-2.0.0.tgz", + "integrity": "sha512-oNh6S2WMHWRZrmutsRmDDfkzKtxF+bc2VxLC9dvtrDIRFln627VsFP6fLMgTryGDljgLPjkrzQSDcPrjPyDJ5w==", + "funding": [ + { + "type": "GitHub Sponsors", + "url": "https://github.com/sponsors/unifiedjs" + }, + { + "type": "OpenCollective", + "url": "https://opencollective.com/unified" + } + ] + }, + "node_modules/micromatch": { + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz", + "integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==", + "dev": true, + "dependencies": { + "braces": "^3.0.2", + "picomatch": "^2.3.1" + }, + "engines": { + "node": ">=8.6" + } + }, + "node_modules/min-indent": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/min-indent/-/min-indent-1.0.1.tgz", + "integrity": "sha512-I9jwMn07Sy/IwOj3zVkVik2JTvgpaykDZEigL6Rx6N9LbMywwUSMtxET+7lVoDLLd3O3IXwJwvuuns8UB/HeAg==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/minimatch": { + "version": "9.0.3", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.3.tgz", + "integrity": "sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg==", + "dev": true, + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/minimist": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", + "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", + "dev": true, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/minipass": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.0.4.tgz", + "integrity": "sha512-jYofLM5Dam9279rdkWzqHozUo4ybjdZmCsDHePy5V/PbBcVMiSZR97gmAy45aqi8CK1lG2ECd356FU86avfwUQ==", + "dev": true, + "engines": { + "node": ">=16 || 14 >=14.17" + } + }, + "node_modules/mkdirp": { + "version": "0.5.6", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.6.tgz", + "integrity": "sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==", + "dev": true, + "dependencies": { + "minimist": "^1.2.6" + }, + "bin": { + "mkdirp": "bin/cmd.js" + } + }, + "node_modules/mri": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/mri/-/mri-1.2.0.tgz", + "integrity": "sha512-tzzskb3bG8LvYGFF/mDTpq3jpI6Q9wc3LEmBaghu+DdCssd1FakN7Bc0hVNmEyGq1bq3RgfkCb3cmQLpNPOroA==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/mrmime": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/mrmime/-/mrmime-2.0.0.tgz", + "integrity": "sha512-eu38+hdgojoyq63s+yTpN4XMBdt5l8HhMhc4VKLO9KM5caLIBvUm4thi7fFaxyTmCKeNnXZ5pAlBwCUnhA09uw==", + "dev": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" + }, + "node_modules/mz": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/mz/-/mz-2.7.0.tgz", + "integrity": "sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q==", + "dev": true, + "dependencies": { + "any-promise": "^1.0.0", + "object-assign": "^4.0.1", + "thenify-all": "^1.0.0" + } + }, + "node_modules/nanoid": { + "version": "3.3.7", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.7.tgz", + "integrity": "sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "bin": { + "nanoid": "bin/nanoid.cjs" + }, + "engines": { + "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" + } + }, + "node_modules/natural-compare": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", + "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", + "dev": true + }, + "node_modules/node-releases": { + "version": "2.0.14", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.14.tgz", + "integrity": "sha512-y10wOWt8yZpqXmOgRo77WaHEmhYQYGNA6y421PKsKYWEK8aW+cqAphborZDhqfyKrbZEN92CN1X2KbafY2s7Yw==", + "dev": true + }, + "node_modules/normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/normalize-range": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/normalize-range/-/normalize-range-0.1.2.tgz", + "integrity": "sha512-bdok/XvKII3nUpklnV6P2hxtMNrCboOjAcyBuQnWEhO665FwrSNRxU+AqpsyvO6LgGYPspN+lu5CLtw4jPRKNA==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/object-assign": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/object-hash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/object-hash/-/object-hash-3.0.0.tgz", + "integrity": "sha512-RSn9F68PjH9HqtltsSnqYC1XXoWe9Bju5+213R98cNGttag9q9yAOTzdbsqvIa7aNm5WffBZFpWYr2aWrklWAw==", + "dev": true, + "engines": { + "node": ">= 6" + } + }, + "node_modules/once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", + "dependencies": { + "wrappy": "1" + } + }, + "node_modules/optionator": { + "version": "0.9.3", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.3.tgz", + "integrity": "sha512-JjCoypp+jKn1ttEFExxhetCKeJt9zhAgAve5FXHixTvFDW/5aEktX9bufBKLRRMdU7bNtpLfcGu94B3cdEJgjg==", + "dev": true, + "dependencies": { + "@aashutoshrathi/word-wrap": "^1.2.3", + "deep-is": "^0.1.3", + "fast-levenshtein": "^2.0.6", + "levn": "^0.4.1", + "prelude-ls": "^1.2.1", + "type-check": "^0.4.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/p-limit": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", + "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", + "dev": true, + "dependencies": { + "yocto-queue": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-locate": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", + "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", + "dev": true, + "dependencies": { + "p-limit": "^3.0.2" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/parent-module": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", + "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", + "dev": true, + "dependencies": { + "callsites": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/path-parse": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", + "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", + "dev": true + }, + "node_modules/path-scurry": { + "version": "1.10.1", + "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.10.1.tgz", + "integrity": "sha512-MkhCqzzBEpPvxxQ71Md0b1Kk51W01lrYvlMzSUaIzNsODdd7mqhiimSZlr+VegAz5Z6Vzt9Xg2ttE//XBhH3EQ==", + "dev": true, + "dependencies": { + "lru-cache": "^9.1.1 || ^10.0.0", + "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/path-scurry/node_modules/lru-cache": { + "version": "10.2.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.2.0.tgz", + "integrity": "sha512-2bIM8x+VAf6JT4bKAljS1qUWgMsqZRPGJS6FSahIMPVvctcNhyVp7AJu7quxOW9jwkryBReKZY5tY5JYv2n/7Q==", + "dev": true, + "engines": { + "node": "14 || >=16.14" + } + }, + "node_modules/path-type": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", + "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/periscopic": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/periscopic/-/periscopic-3.1.0.tgz", + "integrity": "sha512-vKiQ8RRtkl9P+r/+oefh25C3fhybptkHKCZSPlcXiJux2tJF55GnEj3BVn4A5gKfq9NWWXXrxkHBwVPUfH0opw==", + "dependencies": { + "@types/estree": "^1.0.0", + "estree-walker": "^3.0.0", + "is-reference": "^3.0.0" + } + }, + "node_modules/picocolors": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", + "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==", + "dev": true + }, + "node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "dev": true, + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/pify": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", + "integrity": "sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/pirates": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.6.tgz", + "integrity": "sha512-saLsH7WeYYPiD25LDuLRRY/i+6HaPYr6G1OUlN39otzkSTxKnubR9RTxS3/Kk50s1g2JTgFwWQDQyplC5/SHZg==", + "dev": true, + "engines": { + "node": ">= 6" + } + }, + "node_modules/playwright": { + "version": "1.41.2", + "resolved": "https://registry.npmjs.org/playwright/-/playwright-1.41.2.tgz", + "integrity": "sha512-v0bOa6H2GJChDL8pAeLa/LZC4feoAMbSQm1/jF/ySsWWoaNItvrMP7GEkvEEFyCTUYKMxjQKaTSg5up7nR6/8A==", + "dev": true, + "dependencies": { + "playwright-core": "1.41.2" + }, + "bin": { + "playwright": "cli.js" + }, + "engines": { + "node": ">=16" + }, + "optionalDependencies": { + "fsevents": "2.3.2" + } + }, + "node_modules/playwright-core": { + "version": "1.41.2", + "resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.41.2.tgz", + "integrity": "sha512-VaTvwCA4Y8kxEe+kfm2+uUUw5Lubf38RxF7FpBxLPmGe5sdNkSg5e3ChEigaGrX7qdqT3pt2m/98LiyvU2x6CA==", + "dev": true, + "bin": { + "playwright-core": "cli.js" + }, + "engines": { + "node": ">=16" + } + }, + "node_modules/postcss": { + "version": "8.4.35", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.35.tgz", + "integrity": "sha512-u5U8qYpBCpN13BsiEB0CbR1Hhh4Gc0zLFuedrHJKMctHCHAGrMdG0PRM/KErzAL3CU6/eckEtmHNB3x6e3c0vA==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/postcss" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "dependencies": { + "nanoid": "^3.3.7", + "picocolors": "^1.0.0", + "source-map-js": "^1.0.2" + }, + "engines": { + "node": "^10 || ^12 || >=14" + } + }, + "node_modules/postcss-import": { + "version": "15.1.0", + "resolved": "https://registry.npmjs.org/postcss-import/-/postcss-import-15.1.0.tgz", + "integrity": "sha512-hpr+J05B2FVYUAXHeK1YyI267J/dDDhMU6B6civm8hSY1jYJnBXxzKDKDswzJmtLHryrjhnDjqqp/49t8FALew==", + "dev": true, + "dependencies": { + "postcss-value-parser": "^4.0.0", + "read-cache": "^1.0.0", + "resolve": "^1.1.7" + }, + "engines": { + "node": ">=14.0.0" + }, + "peerDependencies": { + "postcss": "^8.0.0" + } + }, + "node_modules/postcss-js": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/postcss-js/-/postcss-js-4.0.1.tgz", + "integrity": "sha512-dDLF8pEO191hJMtlHFPRa8xsizHaM82MLfNkUHdUtVEV3tgTp5oj+8qbEqYM57SLfc74KSbw//4SeJma2LRVIw==", + "dev": true, + "dependencies": { + "camelcase-css": "^2.0.1" + }, + "engines": { + "node": "^12 || ^14 || >= 16" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + "peerDependencies": { + "postcss": "^8.4.21" + } + }, + "node_modules/postcss-load-config": { + "version": "3.1.4", + "resolved": "https://registry.npmjs.org/postcss-load-config/-/postcss-load-config-3.1.4.tgz", + "integrity": "sha512-6DiM4E7v4coTE4uzA8U//WhtPwyhiim3eyjEMFCnUpzbrkK9wJHgKDT2mR+HbtSrd/NubVaYTOpSpjUl8NQeRg==", + "dev": true, + "dependencies": { + "lilconfig": "^2.0.5", + "yaml": "^1.10.2" + }, + "engines": { + "node": ">= 10" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + "peerDependencies": { + "postcss": ">=8.0.9", + "ts-node": ">=9.0.0" + }, + "peerDependenciesMeta": { + "postcss": { + "optional": true + }, + "ts-node": { + "optional": true + } + } + }, + "node_modules/postcss-nested": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/postcss-nested/-/postcss-nested-6.0.1.tgz", + "integrity": "sha512-mEp4xPMi5bSWiMbsgoPfcP74lsWLHkQbZc3sY+jWYd65CUwXrUaTp0fmNpa01ZcETKlIgUdFN/MpS2xZtqL9dQ==", + "dev": true, + "dependencies": { + "postcss-selector-parser": "^6.0.11" + }, + "engines": { + "node": ">=12.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + "peerDependencies": { + "postcss": "^8.2.14" + } + }, + "node_modules/postcss-nested/node_modules/postcss-selector-parser": { + "version": "6.0.15", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.0.15.tgz", + "integrity": "sha512-rEYkQOMUCEMhsKbK66tbEU9QVIxbhN18YiniAwA7XQYTVBqrBy+P2p5JcdqsHgKM2zWylp8d7J6eszocfds5Sw==", + "dev": true, + "dependencies": { + "cssesc": "^3.0.0", + "util-deprecate": "^1.0.2" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/postcss-safe-parser": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/postcss-safe-parser/-/postcss-safe-parser-6.0.0.tgz", + "integrity": "sha512-FARHN8pwH+WiS2OPCxJI8FuRJpTVnn6ZNFiqAM2aeW2LwTHWWmWgIyKC6cUo0L8aeKiF/14MNvnpls6R2PBeMQ==", + "dev": true, + "engines": { + "node": ">=12.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + "peerDependencies": { + "postcss": "^8.3.3" + } + }, + "node_modules/postcss-scss": { + "version": "4.0.9", + "resolved": "https://registry.npmjs.org/postcss-scss/-/postcss-scss-4.0.9.tgz", + "integrity": "sha512-AjKOeiwAitL/MXxQW2DliT28EKukvvbEWx3LBmJIRN8KfBGZbRTxNYW0kSqi1COiTZ57nZ9NW06S6ux//N1c9A==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/postcss-scss" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "engines": { + "node": ">=12.0" + }, + "peerDependencies": { + "postcss": "^8.4.29" + } + }, + "node_modules/postcss-selector-parser": { + "version": "6.0.10", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.0.10.tgz", + "integrity": "sha512-IQ7TZdoaqbT+LCpShg46jnZVlhWD2w6iQYAcYXfHARZ7X1t/UGhhceQDs5X0cGqKvYlHNOuv7Oa1xmb0oQuA3w==", + "dev": true, + "dependencies": { + "cssesc": "^3.0.0", + "util-deprecate": "^1.0.2" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/postcss-value-parser": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz", + "integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==", + "dev": true + }, + "node_modules/prelude-ls": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", + "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", + "dev": true, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/prettier": { + "version": "3.2.5", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.2.5.tgz", + "integrity": "sha512-3/GWa9aOC0YeD7LUfvOG2NiDyhOWRvt1k+rcKhOuYnMY24iiCphgneUfJDyFXd6rZCAnuLBv6UeAULtrhT/F4A==", + "dev": true, + "bin": { + "prettier": "bin/prettier.cjs" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/prettier/prettier?sponsor=1" + } + }, + "node_modules/prettier-plugin-svelte": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/prettier-plugin-svelte/-/prettier-plugin-svelte-3.1.2.tgz", + "integrity": "sha512-7xfMZtwgAWHMT0iZc8jN4o65zgbAQ3+O32V6W7pXrqNvKnHnkoyQCGCbKeUyXKZLbYE0YhFRnamfxfkEGxm8qA==", + "dev": true, + "peerDependencies": { + "prettier": "^3.0.0", + "svelte": "^3.2.0 || ^4.0.0-next.0 || ^5.0.0-next.0" + } + }, + "node_modules/prism-svelte": { + "version": "0.4.7", + "resolved": "https://registry.npmjs.org/prism-svelte/-/prism-svelte-0.4.7.tgz", + "integrity": "sha512-yABh19CYbM24V7aS7TuPYRNMqthxwbvx6FF/Rw920YbyBWO3tnyPIqRMgHuSVsLmuHkkBS1Akyof463FVdkeDQ==", + "dev": true + }, + "node_modules/prismjs": { + "version": "1.29.0", + "resolved": "https://registry.npmjs.org/prismjs/-/prismjs-1.29.0.tgz", + "integrity": "sha512-Kx/1w86q/epKcmte75LNrEoT+lX8pBpavuAbvJWRXar7Hz8jrtF+e3vY751p0R8H9HdArwaCTNDDzHg/ScJK1Q==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/punycode": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", + "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/purgecss": { + "version": "6.0.0-alpha.0", + "resolved": "https://registry.npmjs.org/purgecss/-/purgecss-6.0.0-alpha.0.tgz", + "integrity": "sha512-UC7d7uIyZsky+srEsSXny9BkbTcVn3ZtBCNX3rW3DsqJKhvUXFRpufA4ktcHzWF0+JLZgmsqjUm/8R82x9bHpw==", + "dev": true, + "dependencies": { + "commander": "^10.0.0", + "glob": "^8.0.3", + "postcss": "^8.4.4", + "postcss-selector-parser": "^6.0.7" + }, + "bin": { + "purgecss": "bin/purgecss.js" + } + }, + "node_modules/purgecss/node_modules/commander": { + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/commander/-/commander-10.0.1.tgz", + "integrity": "sha512-y4Mg2tXshplEbSGzx7amzPwKKOCGuoSRP/CjEdwwk0FOGlUbq6lKuoyDZTNZkmxHdJtp54hdfY/JUrdL7Xfdug==", + "dev": true, + "engines": { + "node": ">=14" + } + }, + "node_modules/purgecss/node_modules/glob": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/glob/-/glob-8.1.0.tgz", + "integrity": "sha512-r8hpEjiQEYlF2QU0df3dS+nxxSIreXQS1qRhMJM0Q5NDdR386C7jb7Hwwod8Fgiuex+k0GFjgft18yvxm5XoCQ==", + "dev": true, + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^5.0.1", + "once": "^1.3.0" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/purgecss/node_modules/minimatch": { + "version": "5.1.6", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.6.tgz", + "integrity": "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==", + "dev": true, + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/queue-microtask": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", + "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/read-cache": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/read-cache/-/read-cache-1.0.0.tgz", + "integrity": "sha512-Owdv/Ft7IjOgm/i0xvNDZ1LrRANRfew4b2prF3OWMQLxLfu3bS8FVhCsrSCMK4lR56Y9ya+AThoTpDCTxCmpRA==", + "dev": true, + "dependencies": { + "pify": "^2.3.0" + } + }, + "node_modules/readdirp": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", + "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", + "dev": true, + "dependencies": { + "picomatch": "^2.2.1" + }, + "engines": { + "node": ">=8.10.0" + } + }, + "node_modules/reading-time": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/reading-time/-/reading-time-1.5.0.tgz", + "integrity": "sha512-onYyVhBNr4CmAxFsKS7bz+uTLRakypIe4R+5A824vBSkQy/hB3fZepoVEf8OVAxzLvK+H/jm9TzpI3ETSm64Kg==" + }, + "node_modules/regexparam": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/regexparam/-/regexparam-3.0.0.tgz", + "integrity": "sha512-RSYAtP31mvYLkAHrOlh25pCNQ5hWnT106VukGaaFfuJrZFkGRX5GhUAdPqpSDXxOhA2c4akmRuplv1mRqnBn6Q==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/rehype-autolink-headings": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/rehype-autolink-headings/-/rehype-autolink-headings-7.1.0.tgz", + "integrity": "sha512-rItO/pSdvnvsP4QRB1pmPiNHUskikqtPojZKJPPPAVx9Hj8i8TwMBhofrrAYRhYOOBZH9tgmG5lPqDLuIWPWmw==", + "dependencies": { + "@types/hast": "^3.0.0", + "@ungap/structured-clone": "^1.0.0", + "hast-util-heading-rank": "^3.0.0", + "hast-util-is-element": "^3.0.0", + "unified": "^11.0.0", + "unist-util-visit": "^5.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/rehype-slug": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/rehype-slug/-/rehype-slug-6.0.0.tgz", + "integrity": "sha512-lWyvf/jwu+oS5+hL5eClVd3hNdmwM1kAC0BUvEGD19pajQMIzcNUd/k9GsfQ+FfECvX+JE+e9/btsKH0EjJT6A==", + "dependencies": { + "@types/hast": "^3.0.0", + "github-slugger": "^2.0.0", + "hast-util-heading-rank": "^3.0.0", + "hast-util-to-string": "^3.0.0", + "unist-util-visit": "^5.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/remark-container": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/remark-container/-/remark-container-0.1.2.tgz", + "integrity": "sha512-E+G7dSALm3aMqyi15N4DxnRFQmBbHwxVc+9GrbijqwbdHzagUDvi2A3oI27y/PwLkSDRjwMfoc1rCIZayZ2PFg==" + }, + "node_modules/remark-external-links": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/remark-external-links/-/remark-external-links-9.0.1.tgz", + "integrity": "sha512-EYw+p8Zqy5oT5+W8iSKzInfRLY+zeKWHCf0ut+Q5SwnaSIDGXd2zzvp4SWqyAuVbinNmZ0zjMrDKaExWZnTYqQ==", + "dependencies": { + "@types/hast": "^2.3.2", + "@types/mdast": "^3.0.0", + "extend": "^3.0.0", + "is-absolute-url": "^4.0.0", + "mdast-util-definitions": "^5.0.0", + "space-separated-tokens": "^2.0.0", + "unified": "^10.0.0", + "unist-util-visit": "^4.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/remark-external-links/node_modules/@types/hast": { + "version": "2.3.10", + "resolved": "https://registry.npmjs.org/@types/hast/-/hast-2.3.10.tgz", + "integrity": "sha512-McWspRw8xx8J9HurkVBfYj0xKoE25tOFlHGdx4MJ5xORQrMGZNqJhVQWaIbm6Oyla5kYOXtDiopzKRJzEOkwJw==", + "dependencies": { + "@types/unist": "^2" + } + }, + "node_modules/remark-external-links/node_modules/@types/mdast": { + "version": "3.0.15", + "resolved": "https://registry.npmjs.org/@types/mdast/-/mdast-3.0.15.tgz", + "integrity": "sha512-LnwD+mUEfxWMa1QpDraczIn6k0Ee3SMicuYSSzS6ZYl2gKS09EClnJYGd8Du6rfc5r/GZEk5o1mRb8TaTj03sQ==", + "dependencies": { + "@types/unist": "^2" + } + }, + "node_modules/remark-external-links/node_modules/is-plain-obj": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-4.1.0.tgz", + "integrity": "sha512-+Pgi+vMuUNkJyExiMBt5IlFoMyKnr5zhJ4Uspz58WOhBF5QoIZkFyNHIbBAtHwzVAgk5RtndVNsDRN61/mmDqg==", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/remark-external-links/node_modules/unified": { + "version": "10.1.2", + "resolved": "https://registry.npmjs.org/unified/-/unified-10.1.2.tgz", + "integrity": "sha512-pUSWAi/RAnVy1Pif2kAoeWNBa3JVrx0MId2LASj8G+7AiHWoKZNTomq6LG326T68U7/e263X6fTdcXIy7XnF7Q==", + "dependencies": { + "@types/unist": "^2.0.0", + "bail": "^2.0.0", + "extend": "^3.0.0", + "is-buffer": "^2.0.0", + "is-plain-obj": "^4.0.0", + "trough": "^2.0.0", + "vfile": "^5.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/remark-external-links/node_modules/unist-util-is": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/unist-util-is/-/unist-util-is-5.2.1.tgz", + "integrity": "sha512-u9njyyfEh43npf1M+yGKDGVPbY/JWEemg5nH05ncKPfi+kBbKBJoTdsogMu33uhytuLlv9y0O7GH7fEdwLdLQw==", + "dependencies": { + "@types/unist": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/remark-external-links/node_modules/unist-util-stringify-position": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/unist-util-stringify-position/-/unist-util-stringify-position-3.0.3.tgz", + "integrity": "sha512-k5GzIBZ/QatR8N5X2y+drfpWG8IDBzdnVj6OInRNWm1oXrzydiaAT2OQiA8DPRRZyAKb9b6I2a6PxYklZD0gKg==", + "dependencies": { + "@types/unist": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/remark-external-links/node_modules/unist-util-visit": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/unist-util-visit/-/unist-util-visit-4.1.2.tgz", + "integrity": "sha512-MSd8OUGISqHdVvfY9TPhyK2VdUrPgxkUtWSuMHF6XAAFuL4LokseigBnZtPnJMu+FbynTkFNnFlyjxpVKujMRg==", + "dependencies": { + "@types/unist": "^2.0.0", + "unist-util-is": "^5.0.0", + "unist-util-visit-parents": "^5.1.1" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/remark-external-links/node_modules/unist-util-visit-parents": { + "version": "5.1.3", + "resolved": "https://registry.npmjs.org/unist-util-visit-parents/-/unist-util-visit-parents-5.1.3.tgz", + "integrity": "sha512-x6+y8g7wWMyQhL1iZfhIPhDAs7Xwbn9nRosDXl7qoPTSCy0yNxnKc+hWokFifWQIDGi154rdUqKvbCa4+1kLhg==", + "dependencies": { + "@types/unist": "^2.0.0", + "unist-util-is": "^5.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/remark-external-links/node_modules/vfile": { + "version": "5.3.7", + "resolved": "https://registry.npmjs.org/vfile/-/vfile-5.3.7.tgz", + "integrity": "sha512-r7qlzkgErKjobAmyNIkkSpizsFPYiUPuJb5pNW1RB4JcYVZhs4lIbVqk8XPk033CV/1z8ss5pkax8SuhGpcG8g==", + "dependencies": { + "@types/unist": "^2.0.0", + "is-buffer": "^2.0.0", + "unist-util-stringify-position": "^3.0.0", + "vfile-message": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/remark-external-links/node_modules/vfile-message": { + "version": "3.1.4", + "resolved": "https://registry.npmjs.org/vfile-message/-/vfile-message-3.1.4.tgz", + "integrity": "sha512-fa0Z6P8HUrQN4BZaX05SIVXic+7kE3b05PWAtPuYP9QLHsLKYR7/AlLW3NtOrpXRLeawpDLMsVkmk5DG0NXgWw==", + "dependencies": { + "@types/unist": "^2.0.0", + "unist-util-stringify-position": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/remark-gfm": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/remark-gfm/-/remark-gfm-4.0.0.tgz", + "integrity": "sha512-U92vJgBPkbw4Zfu/IiW2oTZLSL3Zpv+uI7My2eq8JxKgqraFdU8YUGicEJCEgSbeaG+QDFqIcwwfMTOEelPxuA==", + "dependencies": { + "@types/mdast": "^4.0.0", + "mdast-util-gfm": "^3.0.0", + "micromark-extension-gfm": "^3.0.0", + "remark-parse": "^11.0.0", + "remark-stringify": "^11.0.0", + "unified": "^11.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/remark-github": { + "version": "12.0.0", + "resolved": "https://registry.npmjs.org/remark-github/-/remark-github-12.0.0.tgz", + "integrity": "sha512-ByefQKFN184LeiGRCabfl7zUJsdlMYWEhiLX1gpmQ11yFg6xSuOTW7LVCv0oc1x+YvUMJW23NU36sJX2RWGgvg==", + "dependencies": { + "@types/mdast": "^4.0.0", + "mdast-util-find-and-replace": "^3.0.0", + "mdast-util-to-string": "^4.0.0", + "to-vfile": "^8.0.0", + "unist-util-visit": "^5.0.0", + "vfile": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/remark-parse": { + "version": "11.0.0", + "resolved": "https://registry.npmjs.org/remark-parse/-/remark-parse-11.0.0.tgz", + "integrity": "sha512-FCxlKLNGknS5ba/1lmpYijMUzX2esxW5xQqjWxw2eHFfS2MSdaHVINFmhjo+qN1WhZhNimq0dZATN9pH0IDrpA==", + "dependencies": { + "@types/mdast": "^4.0.0", + "mdast-util-from-markdown": "^2.0.0", + "micromark-util-types": "^2.0.0", + "unified": "^11.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/remark-reading-time": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/remark-reading-time/-/remark-reading-time-1.0.1.tgz", + "integrity": "sha512-Z3yW1JSNgQcjpPavsKmWgY7wmqRQMXIKoh8r5RtvJdpDIWWf7O7MkhuFDZh+Ge/1Olv0tvD1pN4T7LEhwBQnUA==", + "dependencies": { + "reading-time": "^1.3.0", + "unist-util-visit": "^3.1.0" + } + }, + "node_modules/remark-reading-time/node_modules/unist-util-is": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/unist-util-is/-/unist-util-is-5.2.1.tgz", + "integrity": "sha512-u9njyyfEh43npf1M+yGKDGVPbY/JWEemg5nH05ncKPfi+kBbKBJoTdsogMu33uhytuLlv9y0O7GH7fEdwLdLQw==", + "dependencies": { + "@types/unist": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/remark-reading-time/node_modules/unist-util-visit": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/unist-util-visit/-/unist-util-visit-3.1.0.tgz", + "integrity": "sha512-Szoh+R/Ll68QWAyQyZZpQzZQm2UPbxibDvaY8Xc9SUtYgPsDzx5AWSk++UUt2hJuow8mvwR+rG+LQLw+KsuAKA==", + "dependencies": { + "@types/unist": "^2.0.0", + "unist-util-is": "^5.0.0", + "unist-util-visit-parents": "^4.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/remark-reading-time/node_modules/unist-util-visit-parents": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/unist-util-visit-parents/-/unist-util-visit-parents-4.1.1.tgz", + "integrity": "sha512-1xAFJXAKpnnJl8G7K5KgU7FY55y3GcLIXqkzUj5QF/QVP7biUm0K0O2oqVkYsdjzJKifYeWn9+o6piAK2hGSHw==", + "dependencies": { + "@types/unist": "^2.0.0", + "unist-util-is": "^5.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/remark-stringify": { + "version": "11.0.0", + "resolved": "https://registry.npmjs.org/remark-stringify/-/remark-stringify-11.0.0.tgz", + "integrity": "sha512-1OSmLd3awB/t8qdoEOMazZkNsfVTeY4fTsgzcQFdXNq8ToTN4ZGwrMnlda4K6smTFKD+GRV6O48i6Z4iKgPPpw==", + "dependencies": { + "@types/mdast": "^4.0.0", + "mdast-util-to-markdown": "^2.0.0", + "unified": "^11.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/resolve": { + "version": "1.22.8", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.8.tgz", + "integrity": "sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==", + "dev": true, + "dependencies": { + "is-core-module": "^2.13.0", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + }, + "bin": { + "resolve": "bin/resolve" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/resolve-from": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", + "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/reusify": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", + "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", + "dev": true, + "engines": { + "iojs": ">=1.0.0", + "node": ">=0.10.0" + } + }, + "node_modules/rimraf": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", + "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", + "dev": true, + "dependencies": { + "glob": "^7.1.3" + }, + "bin": { + "rimraf": "bin.js" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/rollup": { + "version": "4.9.6", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.9.6.tgz", + "integrity": "sha512-05lzkCS2uASX0CiLFybYfVkwNbKZG5NFQ6Go0VWyogFTXXbR039UVsegViTntkk4OglHBdF54ccApXRRuXRbsg==", + "dev": true, + "dependencies": { + "@types/estree": "1.0.5" + }, + "bin": { + "rollup": "dist/bin/rollup" + }, + "engines": { + "node": ">=18.0.0", + "npm": ">=8.0.0" + }, + "optionalDependencies": { + "@rollup/rollup-android-arm-eabi": "4.9.6", + "@rollup/rollup-android-arm64": "4.9.6", + "@rollup/rollup-darwin-arm64": "4.9.6", + "@rollup/rollup-darwin-x64": "4.9.6", + "@rollup/rollup-linux-arm-gnueabihf": "4.9.6", + "@rollup/rollup-linux-arm64-gnu": "4.9.6", + "@rollup/rollup-linux-arm64-musl": "4.9.6", + "@rollup/rollup-linux-riscv64-gnu": "4.9.6", + "@rollup/rollup-linux-x64-gnu": "4.9.6", + "@rollup/rollup-linux-x64-musl": "4.9.6", + "@rollup/rollup-win32-arm64-msvc": "4.9.6", + "@rollup/rollup-win32-ia32-msvc": "4.9.6", + "@rollup/rollup-win32-x64-msvc": "4.9.6", + "fsevents": "~2.3.2" + } + }, + "node_modules/run-parallel": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", + "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "dependencies": { + "queue-microtask": "^1.2.2" + } + }, + "node_modules/sade": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/sade/-/sade-1.8.1.tgz", + "integrity": "sha512-xal3CZX1Xlo/k4ApwCFrHVACi9fBqJ7V+mwhBsuf/1IOKbBy098Fex+Wa/5QMubw09pSZ/u8EY8PWgevJsXp1A==", + "dev": true, + "dependencies": { + "mri": "^1.1.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/sander": { + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/sander/-/sander-0.5.1.tgz", + "integrity": "sha512-3lVqBir7WuKDHGrKRDn/1Ye3kwpXaDOMsiRP1wd6wpZW56gJhsbp5RqQpA6JG/P+pkXizygnr1dKR8vzWaVsfA==", + "dev": true, + "dependencies": { + "es6-promise": "^3.1.2", + "graceful-fs": "^4.1.3", + "mkdirp": "^0.5.1", + "rimraf": "^2.5.2" + } + }, + "node_modules/sander/node_modules/rimraf": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", + "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==", + "dev": true, + "dependencies": { + "glob": "^7.1.3" + }, + "bin": { + "rimraf": "bin.js" + } + }, + "node_modules/semver": { + "version": "7.6.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.0.tgz", + "integrity": "sha512-EnwXhrlwXMk9gKu5/flx5sv/an57AkRplG3hTK68W7FRDN+k+OWBj65M7719OkA82XLBxrcX0KSHj+X5COhOVg==", + "dev": true, + "dependencies": { + "lru-cache": "^6.0.0" + }, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/set-cookie-parser": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/set-cookie-parser/-/set-cookie-parser-2.6.0.tgz", + "integrity": "sha512-RVnVQxTXuerk653XfuliOxBP81Sf0+qfQE73LIYKcyMYHG94AuH0kgrQpRDuTZnSmjpysHmzxJXKNfa6PjFhyQ==", + "dev": true + }, + "node_modules/shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "dev": true, + "dependencies": { + "shebang-regex": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/signal-exit": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", + "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", + "dev": true, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/sirv": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/sirv/-/sirv-2.0.4.tgz", + "integrity": "sha512-94Bdh3cC2PKrbgSOUqTiGPWVZeSiXfKOVZNJniWoqrWrRkB1CJzBU3NEbiTsPcYy1lDsANA/THzS+9WBiy5nfQ==", + "dev": true, + "dependencies": { + "@polka/url": "^1.0.0-next.24", + "mrmime": "^2.0.0", + "totalist": "^3.0.0" + }, + "engines": { + "node": ">= 10" + } + }, + "node_modules/slash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", + "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/sorcery": { + "version": "0.11.0", + "resolved": "https://registry.npmjs.org/sorcery/-/sorcery-0.11.0.tgz", + "integrity": "sha512-J69LQ22xrQB1cIFJhPfgtLuI6BpWRiWu1Y3vSsIwK/eAScqJxd/+CJlUuHQRdX2C9NGFamq+KqNywGgaThwfHw==", + "dev": true, + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.4.14", + "buffer-crc32": "^0.2.5", + "minimist": "^1.2.0", + "sander": "^0.5.0" + }, + "bin": { + "sorcery": "bin/sorcery" + } + }, + "node_modules/source-map-js": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.2.tgz", + "integrity": "sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/space-separated-tokens": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/space-separated-tokens/-/space-separated-tokens-2.0.2.tgz", + "integrity": "sha512-PEGlAwrG8yXGXRjW32fGbg66JAlOAwbObuqVoJpv/mRgoWDQfgH1wDPvtzWyUSNAXBGSk8h755YDbbcEy3SH2Q==", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/string-width": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", + "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==", + "dev": true, + "dependencies": { + "eastasianwidth": "^0.2.0", + "emoji-regex": "^9.2.2", + "strip-ansi": "^7.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/string-width-cjs": { + "name": "string-width", + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/string-width-cjs/node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true + }, + "node_modules/string-width/node_modules/ansi-regex": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz", + "integrity": "sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" + } + }, + "node_modules/string-width/node_modules/strip-ansi": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", + "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", + "dev": true, + "dependencies": { + "ansi-regex": "^6.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" + } + }, + "node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-ansi-cjs": { + "name": "strip-ansi", + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-indent": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-indent/-/strip-indent-3.0.0.tgz", + "integrity": "sha512-laJTa3Jb+VQpaC6DseHhF7dXVqHTfJPCRDaEbid/drOhgitgYku/letMUqOXFoWV0zIIUbjpdH2t+tYj4bQMRQ==", + "dev": true, + "dependencies": { + "min-indent": "^1.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-json-comments": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", + "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", + "dev": true, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/sucrase": { + "version": "3.35.0", + "resolved": "https://registry.npmjs.org/sucrase/-/sucrase-3.35.0.tgz", + "integrity": "sha512-8EbVDiu9iN/nESwxeSxDKe0dunta1GOlHufmSSXxMD2z2/tMZpDMpvXQGsc+ajGo8y2uYUmixaSRUc/QPoQ0GA==", + "dev": true, + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.2", + "commander": "^4.0.0", + "glob": "^10.3.10", + "lines-and-columns": "^1.1.6", + "mz": "^2.7.0", + "pirates": "^4.0.1", + "ts-interface-checker": "^0.1.9" + }, + "bin": { + "sucrase": "bin/sucrase", + "sucrase-node": "bin/sucrase-node" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + } + }, + "node_modules/sucrase/node_modules/glob": { + "version": "10.3.10", + "resolved": "https://registry.npmjs.org/glob/-/glob-10.3.10.tgz", + "integrity": "sha512-fa46+tv1Ak0UPK1TOy/pZrIybNNt4HCv7SDzwyfiOZkvZLEbjsZkJBPtDHVshZjbecAoAGSC20MjLDG/qr679g==", + "dev": true, + "dependencies": { + "foreground-child": "^3.1.0", + "jackspeak": "^2.3.5", + "minimatch": "^9.0.1", + "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0", + "path-scurry": "^1.10.1" + }, + "bin": { + "glob": "dist/esm/bin.mjs" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/supports-preserve-symlinks-flag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", + "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", + "dev": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/svelte": { + "version": "4.2.10", + "resolved": "https://registry.npmjs.org/svelte/-/svelte-4.2.10.tgz", + "integrity": "sha512-Ep06yCaCdgG1Mafb/Rx8sJ1QS3RW2I2BxGp2Ui9LBHSZ2/tO/aGLc5WqPjgiAP6KAnLJGaIr/zzwQlOo1b8MxA==", + "dependencies": { + "@ampproject/remapping": "^2.2.1", + "@jridgewell/sourcemap-codec": "^1.4.15", + "@jridgewell/trace-mapping": "^0.3.18", + "@types/estree": "^1.0.1", + "acorn": "^8.9.0", + "aria-query": "^5.3.0", + "axobject-query": "^4.0.0", + "code-red": "^1.0.3", + "css-tree": "^2.3.1", + "estree-walker": "^3.0.3", + "is-reference": "^3.0.1", + "locate-character": "^3.0.0", + "magic-string": "^0.30.4", + "periscopic": "^3.1.0" + }, + "engines": { + "node": ">=16" + } + }, + "node_modules/svelte-check": { + "version": "3.6.3", + "resolved": "https://registry.npmjs.org/svelte-check/-/svelte-check-3.6.3.tgz", + "integrity": "sha512-Q2nGnoysxUnB9KjnjpQLZwdjK62DHyW6nuH/gm2qteFnDk0lCehe/6z8TsIvYeKjC6luKaWxiNGyOcWiLLPSwA==", + "dev": true, + "dependencies": { + "@jridgewell/trace-mapping": "^0.3.17", + "chokidar": "^3.4.1", + "fast-glob": "^3.2.7", + "import-fresh": "^3.2.1", + "picocolors": "^1.0.0", + "sade": "^1.7.4", + "svelte-preprocess": "^5.1.0", + "typescript": "^5.0.3" + }, + "bin": { + "svelte-check": "bin/svelte-check" + }, + "peerDependencies": { + "svelte": "^3.55.0 || ^4.0.0-next.0 || ^4.0.0 || ^5.0.0-next.0" + } + }, + "node_modules/svelte-eslint-parser": { + "version": "0.33.1", + "resolved": "https://registry.npmjs.org/svelte-eslint-parser/-/svelte-eslint-parser-0.33.1.tgz", + "integrity": "sha512-vo7xPGTlKBGdLH8T5L64FipvTrqv3OQRx9d2z5X05KKZDlF4rQk8KViZO4flKERY+5BiVdOh7zZ7JGJWo5P0uA==", + "dev": true, + "dependencies": { + "eslint-scope": "^7.0.0", + "eslint-visitor-keys": "^3.0.0", + "espree": "^9.0.0", + "postcss": "^8.4.29", + "postcss-scss": "^4.0.8" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/ota-meshi" + }, + "peerDependencies": { + "svelte": "^3.37.0 || ^4.0.0" + }, + "peerDependenciesMeta": { + "svelte": { + "optional": true + } + } + }, + "node_modules/svelte-fa": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/svelte-fa/-/svelte-fa-4.0.2.tgz", + "integrity": "sha512-lza8Jfii6jcpMQB73mBStONxaLfZsUS+rKJ/hH6WxsHUd+g68+oHIL9yQTk4a0uY9HQk78T/CPvQnED0msqJfg==", + "peerDependencies": { + "svelte": "^4.0.0" + } + }, + "node_modules/svelte-hmr": { + "version": "0.15.3", + "resolved": "https://registry.npmjs.org/svelte-hmr/-/svelte-hmr-0.15.3.tgz", + "integrity": "sha512-41snaPswvSf8TJUhlkoJBekRrABDXDMdpNpT2tfHIv4JuhgvHqLMhEPGtaQn0BmbNSTkuz2Ed20DF2eHw0SmBQ==", + "dev": true, + "engines": { + "node": "^12.20 || ^14.13.1 || >= 16" + }, + "peerDependencies": { + "svelte": "^3.19.0 || ^4.0.0" + } + }, + "node_modules/svelte-markdown": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/svelte-markdown/-/svelte-markdown-0.4.1.tgz", + "integrity": "sha512-pOlLY6EruKJaWI9my/2bKX8PdTeP5CM0s4VMmwmC2prlOkjAf+AOmTM4wW/l19Y6WZ87YmP8+ZCJCCwBChWjYw==", + "dependencies": { + "@types/marked": "^5.0.1", + "marked": "^5.1.2" + }, + "peerDependencies": { + "svelte": "^4.0.0" + } + }, + "node_modules/svelte-preprocess": { + "version": "5.1.3", + "resolved": "https://registry.npmjs.org/svelte-preprocess/-/svelte-preprocess-5.1.3.tgz", + "integrity": "sha512-xxAkmxGHT+J/GourS5mVJeOXZzne1FR5ljeOUAMXUkfEhkLEllRreXpbl3dIYJlcJRfL1LO1uIAPpBpBfiqGPw==", + "dev": true, + "hasInstallScript": true, + "dependencies": { + "@types/pug": "^2.0.6", + "detect-indent": "^6.1.0", + "magic-string": "^0.30.5", + "sorcery": "^0.11.0", + "strip-indent": "^3.0.0" + }, + "engines": { + "node": ">= 16.0.0", + "pnpm": "^8.0.0" + }, + "peerDependencies": { + "@babel/core": "^7.10.2", + "coffeescript": "^2.5.1", + "less": "^3.11.3 || ^4.0.0", + "postcss": "^7 || ^8", + "postcss-load-config": "^2.1.0 || ^3.0.0 || ^4.0.0 || ^5.0.0", + "pug": "^3.0.0", + "sass": "^1.26.8", + "stylus": "^0.55.0", + "sugarss": "^2.0.0 || ^3.0.0 || ^4.0.0", + "svelte": "^3.23.0 || ^4.0.0-next.0 || ^4.0.0 || ^5.0.0-next.0", + "typescript": ">=3.9.5 || ^4.0.0 || ^5.0.0" + }, + "peerDependenciesMeta": { + "@babel/core": { + "optional": true + }, + "coffeescript": { + "optional": true + }, + "less": { + "optional": true + }, + "postcss": { + "optional": true + }, + "postcss-load-config": { + "optional": true + }, + "pug": { + "optional": true + }, + "sass": { + "optional": true + }, + "stylus": { + "optional": true + }, + "sugarss": { + "optional": true + }, + "typescript": { + "optional": true + } + } + }, + "node_modules/tailwindcss": { + "version": "3.4.1", + "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-3.4.1.tgz", + "integrity": "sha512-qAYmXRfk3ENzuPBakNK0SRrUDipP8NQnEY6772uDhflcQz5EhRdD7JNZxyrFHVQNCwULPBn6FNPp9brpO7ctcA==", + "dev": true, + "dependencies": { + "@alloc/quick-lru": "^5.2.0", + "arg": "^5.0.2", + "chokidar": "^3.5.3", + "didyoumean": "^1.2.2", + "dlv": "^1.1.3", + "fast-glob": "^3.3.0", + "glob-parent": "^6.0.2", + "is-glob": "^4.0.3", + "jiti": "^1.19.1", + "lilconfig": "^2.1.0", + "micromatch": "^4.0.5", + "normalize-path": "^3.0.0", + "object-hash": "^3.0.0", + "picocolors": "^1.0.0", + "postcss": "^8.4.23", + "postcss-import": "^15.1.0", + "postcss-js": "^4.0.1", + "postcss-load-config": "^4.0.1", + "postcss-nested": "^6.0.1", + "postcss-selector-parser": "^6.0.11", + "resolve": "^1.22.2", + "sucrase": "^3.32.0" + }, + "bin": { + "tailwind": "lib/cli.js", + "tailwindcss": "lib/cli.js" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/tailwindcss/node_modules/postcss-load-config": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/postcss-load-config/-/postcss-load-config-4.0.2.tgz", + "integrity": "sha512-bSVhyJGL00wMVoPUzAVAnbEoWyqRxkjv64tUl427SKnPrENtq6hJwUojroMz2VB+Q1edmi4IfrAPpami5VVgMQ==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "dependencies": { + "lilconfig": "^3.0.0", + "yaml": "^2.3.4" + }, + "engines": { + "node": ">= 14" + }, + "peerDependencies": { + "postcss": ">=8.0.9", + "ts-node": ">=9.0.0" + }, + "peerDependenciesMeta": { + "postcss": { + "optional": true + }, + "ts-node": { + "optional": true + } + } + }, + "node_modules/tailwindcss/node_modules/postcss-load-config/node_modules/lilconfig": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-3.0.0.tgz", + "integrity": "sha512-K2U4W2Ff5ibV7j7ydLr+zLAkIg5JJ4lPn1Ltsdt+Tz/IjQ8buJ55pZAxoP34lqIiwtF9iAvtLv3JGv7CAyAg+g==", + "dev": true, + "engines": { + "node": ">=14" + } + }, + "node_modules/tailwindcss/node_modules/postcss-selector-parser": { + "version": "6.0.15", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.0.15.tgz", + "integrity": "sha512-rEYkQOMUCEMhsKbK66tbEU9QVIxbhN18YiniAwA7XQYTVBqrBy+P2p5JcdqsHgKM2zWylp8d7J6eszocfds5Sw==", + "dev": true, + "dependencies": { + "cssesc": "^3.0.0", + "util-deprecate": "^1.0.2" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/tailwindcss/node_modules/yaml": { + "version": "2.3.4", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.3.4.tgz", + "integrity": "sha512-8aAvwVUSHpfEqTQ4w/KMlf3HcRdt50E5ODIQJBw1fQ5RL34xabzxtUlzTXVqc4rkZsPbvrXKWnABCD7kWSmocA==", + "dev": true, + "engines": { + "node": ">= 14" + } + }, + "node_modules/text-table": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", + "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==", + "dev": true + }, + "node_modules/thenify": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/thenify/-/thenify-3.3.1.tgz", + "integrity": "sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw==", + "dev": true, + "dependencies": { + "any-promise": "^1.0.0" + } + }, + "node_modules/thenify-all": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/thenify-all/-/thenify-all-1.6.0.tgz", + "integrity": "sha512-RNxQH/qI8/t3thXJDwcstUO4zeqo64+Uy/+sNVRBx4Xn2OX+OZ9oP+iJnNFqplFra2ZUVeKCSa2oVWi3T4uVmA==", + "dev": true, + "dependencies": { + "thenify": ">= 3.1.0 < 4" + }, + "engines": { + "node": ">=0.8" + } + }, + "node_modules/tiny-glob": { + "version": "0.2.9", + "resolved": "https://registry.npmjs.org/tiny-glob/-/tiny-glob-0.2.9.tgz", + "integrity": "sha512-g/55ssRPUjShh+xkfx9UPDXqhckHEsHr4Vd9zX55oSdGZc/MD0m3sferOkwWtp98bv+kcVfEHtRJgBVJzelrzg==", + "dev": true, + "dependencies": { + "globalyzer": "0.1.0", + "globrex": "^0.1.2" + } + }, + "node_modules/to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dev": true, + "dependencies": { + "is-number": "^7.0.0" + }, + "engines": { + "node": ">=8.0" + } + }, + "node_modules/to-vfile": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/to-vfile/-/to-vfile-8.0.0.tgz", + "integrity": "sha512-IcmH1xB5576MJc9qcfEC/m/nQCFt3fzMHz45sSlgJyTWjRbKW1HAkJpuf3DgE57YzIlZcwcBZA5ENQbBo4aLkg==", + "dependencies": { + "vfile": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/totalist": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/totalist/-/totalist-3.0.1.tgz", + "integrity": "sha512-sf4i37nQ2LBx4m3wB74y+ubopq6W/dIzXg0FDGjsYnZHVa1Da8FH853wlL2gtUhg+xJXjfk3kUZS3BRoQeoQBQ==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/trough": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/trough/-/trough-2.2.0.tgz", + "integrity": "sha512-tmMpK00BjZiUyVyvrBK7knerNgmgvcV/KLVyuma/SC+TQN167GrMRciANTz09+k3zW8L8t60jWO1GpfkZdjTaw==", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/ts-api-utils": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-1.2.1.tgz", + "integrity": "sha512-RIYA36cJn2WiH9Hy77hdF9r7oEwxAtB/TS9/S4Qd90Ap4z5FSiin5zEiTL44OII1Y3IIlEvxwxFUVgrHSZ/UpA==", + "dev": true, + "engines": { + "node": ">=16" + }, + "peerDependencies": { + "typescript": ">=4.2.0" + } + }, + "node_modules/ts-interface-checker": { + "version": "0.1.13", + "resolved": "https://registry.npmjs.org/ts-interface-checker/-/ts-interface-checker-0.1.13.tgz", + "integrity": "sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA==", + "dev": true + }, + "node_modules/tslib": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.2.tgz", + "integrity": "sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==", + "dev": true + }, + "node_modules/type-check": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", + "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", + "dev": true, + "dependencies": { + "prelude-ls": "^1.2.1" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/type-fest": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", + "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/typescript": { + "version": "5.3.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.3.3.tgz", + "integrity": "sha512-pXWcraxM0uxAS+tN0AG/BF2TyqmHO014Z070UsJ+pFvYuRSq8KH8DmWpnbXe0pEPDHXZV3FcAbJkijJ5oNEnWw==", + "dev": true, + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, + "node_modules/undici-types": { + "version": "5.26.5", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz", + "integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==", + "dev": true + }, + "node_modules/unified": { + "version": "11.0.4", + "resolved": "https://registry.npmjs.org/unified/-/unified-11.0.4.tgz", + "integrity": "sha512-apMPnyLjAX+ty4OrNap7yumyVAMlKx5IWU2wlzzUdYJO9A8f1p9m/gywF/GM2ZDFcjQPrx59Mc90KwmxsoklxQ==", + "dependencies": { + "@types/unist": "^3.0.0", + "bail": "^2.0.0", + "devlop": "^1.0.0", + "extend": "^3.0.0", + "is-plain-obj": "^4.0.0", + "trough": "^2.0.0", + "vfile": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/unified/node_modules/@types/unist": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@types/unist/-/unist-3.0.2.tgz", + "integrity": "sha512-dqId9J8K/vGi5Zr7oo212BGii5m3q5Hxlkwy3WpYuKPklmBEvsbMYYyLxAQpSffdLl/gdW0XUpKWFvYmyoWCoQ==" + }, + "node_modules/unified/node_modules/is-plain-obj": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-4.1.0.tgz", + "integrity": "sha512-+Pgi+vMuUNkJyExiMBt5IlFoMyKnr5zhJ4Uspz58WOhBF5QoIZkFyNHIbBAtHwzVAgk5RtndVNsDRN61/mmDqg==", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/unist-util-is": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/unist-util-is/-/unist-util-is-6.0.0.tgz", + "integrity": "sha512-2qCTHimwdxLfz+YzdGfkqNlH0tLi9xjTnHddPmJwtIG9MGsdbutfTc4P+haPD7l7Cjxf/WZj+we5qfVPvvxfYw==", + "dependencies": { + "@types/unist": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/unist-util-is/node_modules/@types/unist": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@types/unist/-/unist-3.0.2.tgz", + "integrity": "sha512-dqId9J8K/vGi5Zr7oo212BGii5m3q5Hxlkwy3WpYuKPklmBEvsbMYYyLxAQpSffdLl/gdW0XUpKWFvYmyoWCoQ==" + }, + "node_modules/unist-util-stringify-position": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/unist-util-stringify-position/-/unist-util-stringify-position-2.0.3.tgz", + "integrity": "sha512-3faScn5I+hy9VleOq/qNbAd6pAx7iH5jYBMS9I1HgQVijz/4mv5Bvw5iw1sC/90CODiKo81G/ps8AJrISn687g==", + "dev": true, + "dependencies": { + "@types/unist": "^2.0.2" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/unist-util-visit": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/unist-util-visit/-/unist-util-visit-5.0.0.tgz", + "integrity": "sha512-MR04uvD+07cwl/yhVuVWAtw+3GOR/knlL55Nd/wAdblk27GCVt3lqpTivy/tkJcZoNPzTwS1Y+KMojlLDhoTzg==", + "dependencies": { + "@types/unist": "^3.0.0", + "unist-util-is": "^6.0.0", + "unist-util-visit-parents": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/unist-util-visit-parents": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/unist-util-visit-parents/-/unist-util-visit-parents-6.0.1.tgz", + "integrity": "sha512-L/PqWzfTP9lzzEa6CKs0k2nARxTdZduw3zyh8d2NVBnsyvHjSX4TWse388YrrQKbvI8w20fGjGlhgT96WwKykw==", + "dependencies": { + "@types/unist": "^3.0.0", + "unist-util-is": "^6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/unist-util-visit-parents/node_modules/@types/unist": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@types/unist/-/unist-3.0.2.tgz", + "integrity": "sha512-dqId9J8K/vGi5Zr7oo212BGii5m3q5Hxlkwy3WpYuKPklmBEvsbMYYyLxAQpSffdLl/gdW0XUpKWFvYmyoWCoQ==" + }, + "node_modules/unist-util-visit/node_modules/@types/unist": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@types/unist/-/unist-3.0.2.tgz", + "integrity": "sha512-dqId9J8K/vGi5Zr7oo212BGii5m3q5Hxlkwy3WpYuKPklmBEvsbMYYyLxAQpSffdLl/gdW0XUpKWFvYmyoWCoQ==" + }, + "node_modules/universal-user-agent": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/universal-user-agent/-/universal-user-agent-6.0.1.tgz", + "integrity": "sha512-yCzhz6FN2wU1NiiQRogkTQszlQSlpWaw8SvVegAc+bDxbzHgh1vX8uIe8OYyMH6DwH+sdTJsgMl36+mSMdRJIQ==" + }, + "node_modules/update-browserslist-db": { + "version": "1.0.13", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.13.tgz", + "integrity": "sha512-xebP81SNcPuNpPP3uzeW1NYXxI3rxyJzF3pD6sH4jE7o/IX+WtSpwnVU+qIsDPyk0d3hmFQ7mjqc6AtV604hbg==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "dependencies": { + "escalade": "^3.1.1", + "picocolors": "^1.0.0" + }, + "bin": { + "update-browserslist-db": "cli.js" + }, + "peerDependencies": { + "browserslist": ">= 4.21.0" + } + }, + "node_modules/uri-js": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", + "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", + "dev": true, + "dependencies": { + "punycode": "^2.1.0" + } + }, + "node_modules/util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", + "dev": true + }, + "node_modules/vfile": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/vfile/-/vfile-6.0.1.tgz", + "integrity": "sha512-1bYqc7pt6NIADBJ98UiG0Bn/CHIVOoZ/IyEkqIruLg0mE1BKzkOXY2D6CSqQIcKqgadppE5lrxgWXJmXd7zZJw==", + "dependencies": { + "@types/unist": "^3.0.0", + "unist-util-stringify-position": "^4.0.0", + "vfile-message": "^4.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/vfile-message": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/vfile-message/-/vfile-message-2.0.4.tgz", + "integrity": "sha512-DjssxRGkMvifUOJre00juHoP9DPWuzjxKuMDrhNbk2TdaYYBNMStsNhEOt3idrtI12VQYM/1+iM0KOzXi4pxwQ==", + "dev": true, + "dependencies": { + "@types/unist": "^2.0.0", + "unist-util-stringify-position": "^2.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/vfile/node_modules/@types/unist": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@types/unist/-/unist-3.0.2.tgz", + "integrity": "sha512-dqId9J8K/vGi5Zr7oo212BGii5m3q5Hxlkwy3WpYuKPklmBEvsbMYYyLxAQpSffdLl/gdW0XUpKWFvYmyoWCoQ==" + }, + "node_modules/vfile/node_modules/unist-util-stringify-position": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/unist-util-stringify-position/-/unist-util-stringify-position-4.0.0.tgz", + "integrity": "sha512-0ASV06AAoKCDkS2+xw5RXJywruurpbC4JZSm7nr7MOt1ojAzvyyaO+UxZf18j8FCF6kmzCZKcAgN/yu2gm2XgQ==", + "dependencies": { + "@types/unist": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/vfile/node_modules/vfile-message": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/vfile-message/-/vfile-message-4.0.2.tgz", + "integrity": "sha512-jRDZ1IMLttGj41KcZvlrYAaI3CfqpLpfpf+Mfig13viT6NKvRzWZ+lXz0Y5D60w6uJIBAOGq9mSHf0gktF0duw==", + "dependencies": { + "@types/unist": "^3.0.0", + "unist-util-stringify-position": "^4.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, + "node_modules/vite": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/vite/-/vite-5.1.0.tgz", + "integrity": "sha512-STmSFzhY4ljuhz14bg9LkMTk3d98IO6DIArnTY6MeBwiD1Za2StcQtz7fzOUnRCqrHSD5+OS2reg4HOz1eoLnw==", + "dev": true, + "dependencies": { + "esbuild": "^0.19.3", + "postcss": "^8.4.35", + "rollup": "^4.2.0" + }, + "bin": { + "vite": "bin/vite.js" + }, + "engines": { + "node": "^18.0.0 || >=20.0.0" + }, + "funding": { + "url": "https://github.com/vitejs/vite?sponsor=1" + }, + "optionalDependencies": { + "fsevents": "~2.3.3" + }, + "peerDependencies": { + "@types/node": "^18.0.0 || >=20.0.0", + "less": "*", + "lightningcss": "^1.21.0", + "sass": "*", + "stylus": "*", + "sugarss": "*", + "terser": "^5.4.0" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + }, + "less": { + "optional": true + }, + "lightningcss": { + "optional": true + }, + "sass": { + "optional": true + }, + "stylus": { + "optional": true + }, + "sugarss": { + "optional": true + }, + "terser": { + "optional": true + } + } + }, + "node_modules/vite-plugin-tailwind-purgecss": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/vite-plugin-tailwind-purgecss/-/vite-plugin-tailwind-purgecss-0.2.0.tgz", + "integrity": "sha512-6Q+SaalUd0t3BOIIiCQPlbZQuYARVgjoC78X+fLbQJqIEy/9fC58aQgHMgi+CmYfVfZmJToA8YiLueSGEo2mng==", + "dev": true, + "dependencies": { + "estree-walker": "^3.0.3", + "purgecss": "6.0.0-alpha.0" + }, + "peerDependencies": { + "vite": "^4.1.1 || ^5.0.0" + } + }, + "node_modules/vite/node_modules/fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "dev": true, + "hasInstallScript": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/vitefu": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/vitefu/-/vitefu-0.2.5.tgz", + "integrity": "sha512-SgHtMLoqaeeGnd2evZ849ZbACbnwQCIwRH57t18FxcXoZop0uQu0uzlIhJBlF/eWVzuce0sHeqPcDo+evVcg8Q==", + "dev": true, + "peerDependencies": { + "vite": "^3.0.0 || ^4.0.0 || ^5.0.0" + }, + "peerDependenciesMeta": { + "vite": { + "optional": true + } + } + }, + "node_modules/which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/worktop": { + "version": "0.8.0-next.18", + "resolved": "https://registry.npmjs.org/worktop/-/worktop-0.8.0-next.18.tgz", + "integrity": "sha512-+TvsA6VAVoMC3XDKR5MoC/qlLqDixEfOBysDEKnPIPou/NvoPWCAuXHXMsswwlvmEuvX56lQjvELLyLuzTKvRw==", + "dev": true, + "dependencies": { + "mrmime": "^2.0.0", + "regexparam": "^3.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/wrap-ansi": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz", + "integrity": "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==", + "dev": true, + "dependencies": { + "ansi-styles": "^6.1.0", + "string-width": "^5.0.1", + "strip-ansi": "^7.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/wrap-ansi-cjs": { + "name": "wrap-ansi", + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/wrap-ansi-cjs/node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true + }, + "node_modules/wrap-ansi-cjs/node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/wrap-ansi/node_modules/ansi-regex": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz", + "integrity": "sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" + } + }, + "node_modules/wrap-ansi/node_modules/ansi-styles": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz", + "integrity": "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/wrap-ansi/node_modules/strip-ansi": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", + "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", + "dev": true, + "dependencies": { + "ansi-regex": "^6.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" + } + }, + "node_modules/wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==" + }, + "node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true + }, + "node_modules/yaml": { + "version": "1.10.2", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-1.10.2.tgz", + "integrity": "sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==", + "dev": true, + "engines": { + "node": ">= 6" + } + }, + "node_modules/yocto-queue": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", + "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/zwitch": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/zwitch/-/zwitch-2.0.4.tgz", + "integrity": "sha512-bXE4cR/kVZhKZX/RjPEflHaKVhUVl85noU3v6b8apfQEc1x4A+zBxjZ4lN8LqGd6WZ3dl98pY4o717VFmoPp+A==", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + } + } +} diff --git a/website/package.json b/website/package.json index de3f7033..cab83dd1 100644 --- a/website/package.json +++ b/website/package.json @@ -1,43 +1,63 @@ { "name": "website", - "version": "0.1.0", + "version": "0.0.1", "private": true, + "type": "module", "scripts": { - "dev": "next dev", - "build": "next build", - "start": "next start", - "lint": "next lint" - }, - "dependencies": { - "@babel/core": "^7.18.6", - "@chakra-ui/react": "^2.2.4", - "@chakra-ui/system": "^2.2.2", - "@chakra-ui/theme-tools": "^2.0.5", - "@emotion/react": "^11", - "@emotion/styled": "^11", - "@octokit/rest": "^19.0.3", - "@types/progress": "^2.0.5", - "detect-browser": "^5.3.0", - "framer-motion": "^6", - "gray-matter": "^4.0.3", - "next": "12.2.2", - "nextjs-progressbar": "^0.0.14", - "react": "18.2.0", - "react-dom": "18.2.0", - "react-icons": "^4.4.0", - "react-markdown": "^8.0.3", - "remark-gemoji": "^7.0.1", - "remark-gfm": "^3.0.1", - "swr": "^1.3.0" + "dev": "vite dev", + "build": "vite build", + "preview": "vite preview", + "test": "playwright test", + "check": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json", + "check:watch": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json --watch", + "lint": "prettier --check . && eslint .", + "format": "prettier --write ." }, "devDependencies": { - "@types/node": "18.0.5", - "@types/react": "18.0.15", - "@types/react-dom": "18.0.6", - "@types/react-syntax-highlighter": "^15.5.3", - "eslint": "8.20.0", - "eslint-config-next": "12.2.2", - "eslint-config-prettier": "^8.5.0", - "typescript": "4.7.4" + "@playwright/test": "^1.28.1", + "@skeletonlabs/skeleton": "2.8.0", + "@skeletonlabs/tw-plugin": "0.3.1", + "@sveltejs/adapter-cloudflare": "^4.1.0", + "@sveltejs/kit": "^2.0.0", + "@sveltejs/vite-plugin-svelte": "^3.0.0", + "@tailwindcss/typography": "0.5.10", + "@types/eslint": "8.56.0", + "@types/node": "^20.11.16", + "@typescript-eslint/eslint-plugin": "^6.0.0", + "@typescript-eslint/parser": "^6.0.0", + "autoprefixer": "10.4.17", + "eslint": "^8.56.0", + "eslint-config-prettier": "^9.1.0", + "eslint-plugin-svelte": "^2.35.1", + "mdsvex": "^0.11.0", + "postcss": "8.4.35", + "prettier": "^3.1.1", + "prettier-plugin-svelte": "^3.1.2", + "svelte": "^4.2.7", + "svelte-check": "^3.6.0", + "tailwindcss": "3.4.1", + "tslib": "^2.4.1", + "typescript": "^5.0.0", + "vite": "^5.0.3", + "vite-plugin-tailwind-purgecss": "0.2.0" + }, + "dependencies": { + "@floating-ui/dom": "1.6.1", + "@fortawesome/free-brands-svg-icons": "^6.5.1", + "@octokit/openapi-types": "^19.1.0", + "@octokit/rest": "^20.0.2", + "date-fns": "^3.3.1", + "highlight.js": "11.9.0", + "lucide-svelte": "^0.323.0", + "mdsvex-relative-images": "^1.0.3", + "rehype-autolink-headings": "^7.1.0", + "rehype-slug": "^6.0.0", + "remark-container": "^0.1.2", + "remark-external-links": "^9.0.1", + "remark-gfm": "^4.0.0", + "remark-github": "^12.0.0", + "remark-reading-time": "^1.0.1", + "svelte-fa": "^4.0.2", + "svelte-markdown": "^0.4.1" } -} +} \ No newline at end of file diff --git a/website/pages/_app.tsx b/website/pages/_app.tsx deleted file mode 100755 index 99163093..00000000 --- a/website/pages/_app.tsx +++ /dev/null @@ -1,138 +0,0 @@ -import "../styles/globals.css"; -import type { AppProps } from "next/app"; -import { - ChakraProvider, - extendTheme, - withDefaultColorScheme, -} from "@chakra-ui/react"; -import Navbar from "components/Navbar"; -import { chakra } from "@chakra-ui/react"; -import { mode } from "@chakra-ui/theme-tools"; -import Head from "next/head"; -import { useRouter } from "next/router"; -// import Script from "next/script"; -// import * as gtag from "configurations/gtag"; -// import AdDetector from "components/AdDetector"; -import Footer from "components/Footer"; -import NextNProgress from "nextjs-progressbar"; - -const customTheme = extendTheme( - { - initialColorMode: 'system', - useSystemColorMode: true, - styles: { - global: (props: any) => ({ - body: { - bg: mode("white", "#171717")(props), - }, - }), - }, - colors: { - blue: { - 50: "#e6f2ff", - 100: "#e6f2ff", - 200: "#e6f2ff", - 300: "#1681bd", - 400: "#1681bd", - 500: "#3a4da5", - 600: "#2d3c7d", - 700: "#1f2b55", - 800: "#121c2e", - 900: "#080e18", - }, - components: { - Link: { - baseStyle: { - color: "blue", - }, - }, - }, - }, - }, - withDefaultColorScheme({ colorScheme: "blue" }) -); - -function MyApp({ Component, pageProps }: AppProps) { - const router = useRouter(); - // useEffect(() => { - // const handleRouteChange = (url: string) => { - // gtag.pageview(url); - // }; - // router.events.on("routeChangeComplete", handleRouteChange); - // router.events.on("hashChangeComplete", handleRouteChange); - // return () => { - // router.events.off("routeChangeComplete", handleRouteChange); - // router.events.off("hashChangeComplete", handleRouteChange); - // }; - // }, [router.events]); - - return ( - <> - {/* + +
    + {#each Object.entries(links) as link} + +
    + {#each link[1][1] as icon} + + {/each} +

    + {link[1][2]} +

    +
    +

    {link[0]}

    +
    + {/each} +
    diff --git a/website/src/lib/components/markdown/layout.svelte b/website/src/lib/components/markdown/layout.svelte new file mode 100644 index 00000000..54426420 --- /dev/null +++ b/website/src/lib/components/markdown/layout.svelte @@ -0,0 +1,3 @@ +
    + +
    diff --git a/website/src/lib/components/navbar/darkmode-toggle.svelte b/website/src/lib/components/navbar/darkmode-toggle.svelte new file mode 100644 index 00000000..ec4f757c --- /dev/null +++ b/website/src/lib/components/navbar/darkmode-toggle.svelte @@ -0,0 +1,32 @@ + + +
    + {#if label} + + {/if} + { + isDark.update((prev) => !prev); + }} + /> +
    diff --git a/website/src/lib/components/navbar/navbar.svelte b/website/src/lib/components/navbar/navbar.svelte new file mode 100644 index 00000000..093fc09c --- /dev/null +++ b/website/src/lib/components/navbar/navbar.svelte @@ -0,0 +1,57 @@ + + +
    +
    +
    + +

    + + Spotube Logo + Spotube + +

    +
    + + + +
    + +
    diff --git a/website/src/lib/components/navdrawer/navdrawer.svelte b/website/src/lib/components/navdrawer/navdrawer.svelte new file mode 100644 index 00000000..68f53e06 --- /dev/null +++ b/website/src/lib/components/navdrawer/navdrawer.svelte @@ -0,0 +1,37 @@ + + + diff --git a/website/src/lib/index.ts b/website/src/lib/index.ts new file mode 100644 index 00000000..f0fb2ab8 --- /dev/null +++ b/website/src/lib/index.ts @@ -0,0 +1,61 @@ +import { + faAndroid, + faApple, + faDebian, + faFedora, + faOpensuse, + faUbuntu, + faWindows, + faRedhat +} from '@fortawesome/free-brands-svg-icons'; +import { type IconDefinition } from '@fortawesome/free-brands-svg-icons/index'; +import { Home, Newspaper, Download } from 'lucide-svelte'; + +export const routes: Record = { + '/': ['Home', Home], + '/blog': ['Blog', Newspaper], + '/downloads': ['Downloads', Download], + '/about': ['About', null] +}; + +const releasesUrl = 'https://github.com/KRTirtho/Spotube/releases/latest/download'; + +export const downloadLinks: Record = { + 'Android Apk': [`${releasesUrl}/Spotube-android-all-arch.apk`, [faAndroid]], + 'Windows Executable': [`${releasesUrl}/Spotube-windows-x86_64-setup.exe`, [faWindows]], + 'macOS Dmg': [`${releasesUrl}/Spotube-macos-universal.dmg`, [faApple]], + 'Ubuntu, Debian': [`${releasesUrl}/Spotube-linux-x86_64.deb`, [faUbuntu, faDebian]], + 'Fedora, Redhat, Opensuse': [ + `${releasesUrl}/Spotube-linux-x86_64.rpm`, + [faFedora, faRedhat, faOpensuse] + ], + 'iPhone Ipa': [`${releasesUrl}/Spotube-iOS.ipa`, [faApple]] +}; + +export const extendedDownloadLinks: Record = { + Android: [`${releasesUrl}/Spotube-android-all-arch.apk`, [faAndroid], 'apk'], + Windows: [`${releasesUrl}/Spotube-windows-x86_64-setup.exe`, [faWindows], 'exe'], + macOS: [`${releasesUrl}/Spotube-macos-universal.dmg`, [faApple], 'dmg'], + 'Ubuntu, Debian': [`${releasesUrl}/Spotube-linux-x86_64.deb`, [faUbuntu, faDebian], 'deb'], + 'Fedora, Redhat, Opensuse': [ + `${releasesUrl}/Spotube-linux-x86_64.rpm`, + [faFedora, faRedhat, faOpensuse], + 'rpm' + ], + iPhone: [`${releasesUrl}/Spotube-iOS.ipa`, [faApple], 'ipa'] +}; + +const nightlyReleaseUrl = 'https://github.com/KRTirtho/Spotube/releases/download/nightly'; + +export const extendedNightlyDownloadLinks: Record = { + Android: [`${nightlyReleaseUrl}/Spotube-android-all-arch.apk`, [faAndroid], 'apk'], + Windows: [`${nightlyReleaseUrl}/Spotube-windows-x86_64-setup.exe`, [faWindows], 'exe'], + macOS: [`${nightlyReleaseUrl}/Spotube-macos-universal.dmg`, [faApple], 'dmg'], + 'Ubuntu, Debian': [`${nightlyReleaseUrl}/Spotube-linux-x86_64.deb`, [faUbuntu, faDebian], 'deb'], + 'Fedora, Redhat, Opensuse': [ + `${nightlyReleaseUrl}/Spotube-linux-x86_64.rpm`, + [faFedora, faRedhat, faOpensuse], + 'rpm' + ], + iPhone: [`${nightlyReleaseUrl}/Spotube-iOS.ipa`, [faApple], 'ipa'] +}; diff --git a/website/src/lib/persisted-store.ts b/website/src/lib/persisted-store.ts new file mode 100644 index 00000000..0581fc1d --- /dev/null +++ b/website/src/lib/persisted-store.ts @@ -0,0 +1,106 @@ +import { writable as internal, type Writable } from 'svelte/store'; + +declare type Updater = (value: T) => T; +declare type StoreDict = { [key: string]: Writable }; + +/* eslint-disable @typescript-eslint/no-explicit-any */ +interface Stores { + local: StoreDict; + session: StoreDict; +} + +const stores: Stores = { + local: {}, + session: {} +}; + +export interface Serializer { + parse(text: string): T; + stringify(object: T): string; +} + +export type StorageType = 'local' | 'session'; + +export interface Options { + serializer?: Serializer; + storage?: StorageType; + syncTabs?: boolean; + onError?: (e: unknown) => void; +} + +function getStorage(type: StorageType) { + return type === 'local' ? localStorage : sessionStorage; +} + +/** @deprecated `writable()` has been renamed to `persisted()` */ +export function writable(key: string, initialValue: T, options?: Options): Writable { + console.warn( + "writable() has been deprecated. Please use persisted() instead.\n\nchange:\n\nimport { writable } from 'svelte-persisted-store'\n\nto:\n\nimport { persisted } from 'svelte-persisted-store'" + ); + return persisted(key, initialValue, options); +} +export function persisted(key: string, initialValue: T, options?: Options): Writable { + const serializer = options?.serializer ?? JSON; + const storageType = options?.storage ?? 'local'; + const syncTabs = options?.syncTabs ?? true; + const onError = + options?.onError ?? + ((e) => + console.error(`Error when writing value from persisted store "${key}" to ${storageType}`, e)); + const browser = typeof window !== 'undefined' && typeof document !== 'undefined'; + const storage = browser ? getStorage(storageType) : null; + + function updateStorage(key: string, value: T) { + try { + storage?.setItem(key, serializer.stringify(value)); + } catch (e) { + onError(e); + } + } + + function maybeLoadInitial(): T { + const json = storage?.getItem(key); + + if (json) { + return serializer.parse(json); + } + + return initialValue; + } + + if (!stores[storageType][key]) { + const initial = maybeLoadInitial(); + const store = internal(initial, (set) => { + if (browser && storageType == 'local' && syncTabs) { + const handleStorage = (event: StorageEvent) => { + if (event.key === key) set(event.newValue ? serializer.parse(event.newValue) : null); + }; + + window.addEventListener('storage', handleStorage); + + return () => window.removeEventListener('storage', handleStorage); + } + }); + + const { subscribe, set } = store; + + stores[storageType][key] = { + set(value: T) { + set(value); + updateStorage(key, value); + }, + update(callback: Updater) { + return store.update((last) => { + const value = callback(last); + + updateStorage(key, value); + + return value; + }); + }, + subscribe + }; + } + + return stores[storageType][key]; +} diff --git a/website/src/lib/posts.ts b/website/src/lib/posts.ts new file mode 100644 index 00000000..02fa3d07 --- /dev/null +++ b/website/src/lib/posts.ts @@ -0,0 +1,41 @@ +export interface Post { + date: string; + title: string; + tags: string[]; + published: boolean; + author: string; + readingTime: { + text: string; + minutes: number; + time: number; + words: number; + }; + reading_time_text: string; + preview_html: string; + preview: string; + previewHtml: string; + slug: string | null; + path: string; +} + +export const getPosts = async () => { + // Fetch posts from local Markdown files + const posts: Post[] = await Promise.all( + Object.entries(import.meta.glob('../../posts/**/*.md')).map(async ([path, resolver]) => { + const resolved = (await resolver()) as { metadata: Post }; + const { metadata } = resolved; + const slug = path.split('/').pop()?.slice(0, -3) ?? ''; + return { ...metadata, slug }; + }) + ); + + let sortedPosts = posts.sort((a, b) => +new Date(b.date) - +new Date(a.date)); + + sortedPosts = sortedPosts.map((post) => ({ + ...post + })); + + return { + posts: sortedPosts + }; +}; diff --git a/website/src/routes/+layout.svelte b/website/src/routes/+layout.svelte new file mode 100644 index 00000000..6908b77a --- /dev/null +++ b/website/src/routes/+layout.svelte @@ -0,0 +1,71 @@ + + +
    + + {#if $drawerStore.id === 'navdrawer'} + + {/if} + + + +

    +
    + diff --git a/website/src/routes/+page.svelte b/website/src/routes/+page.svelte new file mode 100644 index 00000000..8b78dbc5 --- /dev/null +++ b/website/src/routes/+page.svelte @@ -0,0 +1,110 @@ + + + + Spotube + + + + + + + + +
    +
    +

    Spotube

    +
    +

    + An Open Source Spotify Client for every platform +
    + + + + +
    +

    +

    + And it's not + built with Electron (web technologies) +

    +
    + +
    +
    + + +

    + +

    + Supporters + +

    +

    + We are grateful for the support of individuals and organizations who have made Spotube possible. +

    + +
    + + Open Collective + +
    + + +
    diff --git a/website/src/routes/+page.ts b/website/src/routes/+page.ts new file mode 100644 index 00000000..5d50a467 --- /dev/null +++ b/website/src/routes/+page.ts @@ -0,0 +1,34 @@ +interface Member { + MemberId: number; + createdAt: string; + type: string; + role: string; + isActive: boolean; + totalAmountDonated: number; + currency?: string; + lastTransactionAt: string; + lastTransactionAmount: number; + profile: string; + name: string; + company?: string; + description?: string; + image?: string; + email?: string; + twitter?: string; + github?: string; + website?: string; + tier?: string; +} + +export const load = async () => { + const res = await fetch('https://opencollective.com/spotube/members/all.json'); + const members = (await res.json()) as Member[]; + + return { + props: { + members: members + .filter((m) => m.totalAmountDonated > 0) + .sort((a, b) => b.totalAmountDonated - a.totalAmountDonated) + } + }; +}; diff --git a/website/src/routes/about/+page.svelte b/website/src/routes/about/+page.svelte new file mode 100644 index 00000000..7f88ea46 --- /dev/null +++ b/website/src/routes/about/+page.svelte @@ -0,0 +1,22 @@ +
    +

    About

    + +

    + +

    Author & Developer

    +
    + + Author of Spotube +
    +
    Kingkor Roy Tirtho
    +

    Flutter developer

    +
    +
    diff --git a/website/src/routes/api/posts/+server.ts b/website/src/routes/api/posts/+server.ts new file mode 100644 index 00000000..af78499b --- /dev/null +++ b/website/src/routes/api/posts/+server.ts @@ -0,0 +1,9 @@ +import { getPosts } from '$lib/posts'; +import type { RequestHandler } from '@sveltejs/kit'; +import { json } from '@sveltejs/kit'; + +export const GET: RequestHandler = async () => { + const { posts } = await getPosts(); + + return json(posts); +}; diff --git a/website/src/routes/blog/+page.svelte b/website/src/routes/blog/+page.svelte new file mode 100644 index 00000000..5ee98938 --- /dev/null +++ b/website/src/routes/blog/+page.svelte @@ -0,0 +1,32 @@ + + +
    +

    Blog Posts

    +
    + +
    diff --git a/website/src/routes/blog/+page.ts b/website/src/routes/blog/+page.ts new file mode 100644 index 00000000..c48ac87f --- /dev/null +++ b/website/src/routes/blog/+page.ts @@ -0,0 +1,11 @@ +import type { Post } from '$lib/posts.js'; + +export const load = async ({ fetch }) => { + const res = await fetch(`api/posts`); + if (res.ok) { + const posts: Post[] = await res.json(); + return { posts }; + } else { + return { posts: [] }; + } +}; diff --git a/website/src/routes/blog/[slug]/+page.svelte b/website/src/routes/blog/[slug]/+page.svelte new file mode 100644 index 00000000..1931a991 --- /dev/null +++ b/website/src/routes/blog/[slug]/+page.svelte @@ -0,0 +1,26 @@ + + + + Blog | {title} + + +
    +

    {title}

    +
    +
    +

    {new Date(date).toDateString()}

    +

    {readingTime?.text ?? ''}

    + + + +
    +
    diff --git a/website/src/routes/blog/[slug]/+page.ts b/website/src/routes/blog/[slug]/+page.ts new file mode 100644 index 00000000..6621dbab --- /dev/null +++ b/website/src/routes/blog/[slug]/+page.ts @@ -0,0 +1,23 @@ +import type { Post } from '$lib/posts.js'; + +export const load = async ({ params }) => { + const { slug } = params; + + try { + const post = await import(`../../../../posts/${slug}.md`); + return { + Content: post.default as ConstructorOfATypedSvelteComponent, + meta: { + ...post.metadata, + slug, + path: `/blog/${slug}` + } as Post + }; + } catch (err) { + console.error('Error loading the post:', err); + return { + status: 500, + error: `Could not load the post: ${(err as Error).message || err}` + }; + } +}; diff --git a/website/src/routes/downloads/+page.svelte b/website/src/routes/downloads/+page.svelte new file mode 100644 index 00000000..50d101ee --- /dev/null +++ b/website/src/routes/downloads/+page.svelte @@ -0,0 +1,39 @@ + + +
    +

    + Download + +

    +

    +
    Spotube is available for every platform
    +
    + + + +


    + +

    Other Downloads

    +

    +
    + {#each otherDownloads as download} + +
    + +
    {download[1]}
    +
    +
    + {/each} +
    +
    diff --git a/website/src/routes/downloads/nightly/+page.svelte b/website/src/routes/downloads/nightly/+page.svelte new file mode 100644 index 00000000..279e6736 --- /dev/null +++ b/website/src/routes/downloads/nightly/+page.svelte @@ -0,0 +1,33 @@ + + +
    +

    + Nightly Downloads + +

    +

    + +
    + + +
    diff --git a/website/src/routes/downloads/older/+page.svelte b/website/src/routes/downloads/older/+page.svelte new file mode 100644 index 00000000..9f535230 --- /dev/null +++ b/website/src/routes/downloads/older/+page.svelte @@ -0,0 +1,138 @@ + + +
    +
    +

    Older versions

    + +
    +

    + +
    + {#each data.releases as release} +

    + {release.tag_name} + + ({formatDistanceToNow(release.published_at ?? new Date(), { addSuffix: true })}) + +

    +
    + {#each Object.entries(groupByOS(release.assets)) as [osName, assets]} +
    +
    + + {osName} +
    + +
    + {/each} +
    + + + + + Release Notes & Changelogs + + + + + + +
    + {/each} +
    +
    +
    diff --git a/website/src/routes/downloads/older/+page.ts b/website/src/routes/downloads/older/+page.ts new file mode 100644 index 00000000..e26a329c --- /dev/null +++ b/website/src/routes/downloads/older/+page.ts @@ -0,0 +1,14 @@ +import type { PageLoad } from './$types'; +import { Octokit } from '@octokit/rest'; + +const github = new Octokit(); +export const load: PageLoad = async () => { + const { data: releases } = await github.repos.listReleases({ + owner: 'KRTirtho', + repo: 'spotube' + }); + + return { + releases + }; +}; diff --git a/website/src/routes/downloads/packages/+page.svx b/website/src/routes/downloads/packages/+page.svx new file mode 100644 index 00000000..e7da4e74 --- /dev/null +++ b/website/src/routes/downloads/packages/+page.svx @@ -0,0 +1,70 @@ +--- +title: CLI Packages Managers +author: Kingkor Roy Tirtho +--- + + + +
    +

    Package Managers

    + + Spotube is available in various Package Managers supported by Platform + + ## Linux + +### Flatpak + +Make sure [Flatpak](https://flatpak.org) is installed in your Linux device & Run the following command in the terminal: + +```bash +$ flatpak install com.github.KRTirtho.Spotube +``` + +### Arch User Repository (AUR) + +If you're an Arch Linux user, you can also install Spotube from AUR. +Make sure you have `yay`/`pamac`/`paru` installed in your system. And Run the Following command in the Terminal: + +```bash +$ yay -Sy spotube-bin +``` + +```bash +$ pamac install spotube-bin +``` + +```bash +$ paru -Sy spotube-bin +``` + +## Windows + +### Chocolatey + +Spotube is available in [community.chocolatey.org](https://community.chocolatey.org) repo. If you have chocolatey install in your system just run following command in an Elevated Command Prompt or PowerShell: + +```powershell +$ choco install spotube +``` + +### WinGet + +Spotube is also available in the Official Windows PackageManager WinGet. Make sure you have WinGet installed in your Windows machine and run following in a Terminal: + +```powershell +$ winget install --id KRTirtho.Spotube +``` + +### Scoop + +Spotube is also available in [Scoop](https://scoop.sh) bucket. Make sure you have Scoop installed in your Windows machine and run following in a Terminal: + +```powershell +$ scoop bucket add extras +$ scoop install spotube +``` + +
    diff --git a/website/static/android-chrome-192x192.png b/website/static/android-chrome-192x192.png new file mode 100644 index 0000000000000000000000000000000000000000..2ef2f3e7ccee385755de9846c7df154518b1b0fb GIT binary patch literal 12127 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

    a&RA|{>vspp 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 MlTZ+^{Aw8ZKlJOuh5!Hn literal 0 HcmV?d00001 diff --git a/website/static/apple-touch-icon.png b/website/static/apple-touch-icon.png new file mode 100644 index 0000000000000000000000000000000000000000..c171ce48479aa1b1bee546db6c61ba540be094f8 GIT binary patch literal 10898 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 Yc!|W47K!}p|KUO9KPpRCNty=z59y$sMF0Q* literal 0 HcmV?d00001 diff --git a/website/static/favicon-16x16.png b/website/static/favicon-16x16.png new file mode 100644 index 0000000000000000000000000000000000000000..6c14fa3254b5f22e7c19355fd5d2552610d47c91 GIT binary patch literal 390 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`jKx9jP7LeL$-D$|Tv8)E(|mmy zw18|52FCVG1{RPKAeI7R1_tH@j10^`nh_+nfC(-uuz(rC1}QWNE&K$eK6tt~hFA!` zowU*Kuz`qczpRgDJi^scV{z zN)irE{yOjc#CKDVKE3LDl+XR$fom`BbAPMrR!D8nD~eq|{pXBLI#Tn^xV{|@=DWns zF3BG1^4B`-v--8uXC|9)g}u~WT6@s0Kg)slo#rLQqE9b4_Xy>_pYeUMz$Zy37CwQH z%4ccqGoCDooiLyO!u;TCi7cl&nOZxAza(|p?amNiV0M93wl0y$TT@%?o!*@__i{D& za0Gty(idCto}VdL!E9PzopM=IhTZK$u?POI?+IUYJ?QiUcDZw|pDP<)mxIE<)78&q Iol`;+08wCuU;qFB literal 0 HcmV?d00001 diff --git a/website/static/favicon-32x32.png b/website/static/favicon-32x32.png new file mode 100644 index 0000000000000000000000000000000000000000..8106368f759f00c71bf26a7b990482b9b213fe54 GIT binary patch literal 777 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnE1|*BCs=fdz#^NA%Cx&(BWL^R}E~ycoX}-P; zT0k}j17mw80}DtA5K93u0|WB{Mh0de%?J`(zyz07Sip>6gA}f5OZv>fz*Ow%;usRa z`8LEiJJ?ag*7&oX@9ZgFmn1d{noQ{3qEPzuy4RguV!zn$?D#PK2Ybw}kM0~?i}YN$ zShogDTD5ZJH`Qm0_1`BS`z=(d8}vKQ zLaxPpyJz=%I_zThdfN~eb#!0q!SC!Re(Oo)%L^WV?{{+MPw(#+PEWn4mbG{fTmE-n zE%Bgur_kNK*X~)*sFdB?@6UfySxR)#_OCo`vWxyEGp{N$7Ok8z#j9ZvpLH?Yh6=I6 z&x*CI@7+sm-Y4pPW4q*(3!3_tL7Xqv+;v=jyTy8aGi%AY)2}alaq2m@qw`Vg?+Xb* zeU0lj^FF_I_s4I~ZWqR&jDl66JKo19q_6~p@zu_sH+y1#;movTftuD$+!8bG?(~Mg z2sx*C<>b~Dk3B731)GXlGL~GO@?i^u?T!aZJ?Hfw2-){CS6C@03SCe)4b-)rDXbiL zU`Ld4K=XkTp#{|+T3b|^jB11?d4BN~4-ywtF( z&=&6F$aU-Ti=tyYLxiuYxjd46P}gAWC;jG{R)AguyPnN2@kVjy%@^ADPg%ZKac`5& zjb70k%u!`{n_-bu1>T1y38Kj75)u!z-$C$aXY*}NY2 x;=btRLIp7o*L)M|PY83VKYWrUg%1S(Fex+M{_nocdKD-cdb;|#taD0e0ssaeJXrt$ literal 0 HcmV?d00001 diff --git a/website/static/favicon.ico b/website/static/favicon.ico new file mode 100644 index 0000000000000000000000000000000000000000..e8e1c26b02efef5c96d1a88266a4de95943c5b8c GIT binary patch literal 15406 zcmeHN`%_!T6KB_Pgiq z-Ls4dSQLwkV^oXT$N|RWj4`n|@Lw9w*aPa5$$lKqW9+X9d|5TYAF;2xu_z1xKvWS>4`;? zB6CN6PX3Zvf;U>FsH8Sm=2{A{Y?1sdUXI^fUWoV2<+$H2!#WkNZK){y+5DW0n!-GI zm1X|IwRf8L%R0VoP}oH$7iYv&>Zow>DctX6^)El~$i-IPm%J}uWDErM3TZGm)83&- z0!49F$a_mc`vH!QqiNHp`P-55$;^dAxI8b!>Kz7~=_tlW52J3=J6~BU#@NVV^mHcT z?wbN!niXPx?jYHi9b)HhZQ|y2ds%=ktpJO!GdQe?a9R^!P^CYWttrohvqJ<=cRYOa z0ot2O0w_yE{j^*C%91SHxh#NH#jrRP*nbV0l3-MB?Af%m9~(3!!rLjr(rW?QTfY@T zB@;ijakqMd^ql_H1pzEo48GG0L#?S8YZ9YfzOiqrmr3v{^^KWQu{;@|y+eM8gnk9# zZGBD%QyIh65r$KwXR5xK_FdAabJLaNQC|rrjoG+1CV)xCaBoIPd(>aw+u=&6mRISDa^$Uy%K|UIk-I(1D_)X3vSU<`+~lF-dbLejYp@Gv1B^} zmrjgwvS~Y6_Bt_EdgAcu#4%JC{c`MY*74z>6w|sRc<2tl-@QLjNHlTyWT;?U`!>tl zZF^8tfRB5mSns4YHkHvgz=jXx)b_QN;k^?%_~1kyPSu6CakqLm(?77(V6CkHt8F=W z;?&`RNrQJywfKuehj-fZ@K$R+KCr6&-xizsBGs1Dch9P^7T@*OVOgJr#l}or(Pv^w zFUFsHwRopRTSE$ZYSK_Ih>#N#=$oe&~0yGSi4R6mrkj9|AajjPP2&Skcf5484a`sWL!Eg#M#kU%3*Du^WMY;&i*qe<0u~^gjG$rX<)d2 zoopdYc-oG_+kOl^jj176FeuV-uA6d6tx2#`PUqbl3{C^(bV$bKb3&Y>`#Sq&|D-1l zSEmK&P%!k?GCWvjaGQ@}r0Erm8DD|DKJ?y=u}X~Btr-|@%7ByR`Q8exS$#mp;#nc4 zyhrxWepeh;e#}SpC>b7JVepuaVM3RWv-*6vYq#FNp*v9(Ik?!Kk8xcdTrDYh=%Z&w zBY?S*;mWuW(}U#yXT;ucc;0P4_xw)uig52j6x};w=$12lc#+{G#iVoEQk<`sVW_4! z1V837DVCZmFiA9?=2U!iiJ`xSa$+Q7bvg=@c6xqE_HONY9{LVVIzE~`gqz+NxYbd3 zG#8B_V;W|(Rk&@aL0@I4{Y@qLxZhHXxwevq(N&+eFSc{@ z<^0s&n2yIYB22Z!;EUJdG18KTc3A;jic)a-n5}-{?v?dd6{Cahig^qf_#^RfypLx^ za5qt2e4l(Dw2RaC#bgF%S`Op0@f2L`3w>sTv_Gx0aq&bZK0lL+3&!8z@l<-mbBaIJ z7d{TJIwD!SKsi|$1}@m6C(eFWCos50=nPd=bx8n?%VFU_nv#sx#ymH zXJDK$7QwD!3bwkwrnXM`R8SgYd?M}^)K8o+WyS-wJ&eWeW-NbY{gi1{y+8iBjxpui zj475*n39t}?Z*W_;Qbfz{(|NeO{f?aBah-|lq@^p`H{Sfb{Z_`pkw-bFZB=tq zNAAb3q3k<>+!ak5SM$%=LA)P|_bn@%R|MQTZM&}P7hD@tQGDy_ zH7%=`DsS9|cYgs?FL3X+g8?@oJL6t2xBy=8JJ@ulV$)av6Yvh6;Ije{r1Jo)ryI1_ zdB=DU1}qn!;-T*kx#@kX4gCpBiR&MLA8`n*pI^&3zmDI?1b!3WiSu22k4TwHs#^TE z@$d5^N`7Q&#g~-*#O2q4ms08-{~5OPR=0zbiTWq~N@Md5nfx=~7bH_K-~ zQSpHa+!dJOe#RcHV3sjbHpZq-wOG(9%g+IFd#v1MVQd#Y=YJEZH!Y9|$_qvV27FS> z3@m^zMcRnmfy~6N;8*gU+$+QgE|mS2a9rqC>{jeoyr_63ep~#%ECx%oCEjASq*!t- zMV1;%yXDD5Q=&C7#VS~p)(ET4YP3dMH)??HBG6@CulG~$Yug$*rhPK`)P_^-r`k>}Kh=6_ z@u}uh(@zzjN;;MJ@k`3kZL4;>_9I=Ku0l6KH(U3V?uhOq-S>K{zE!_j|9gF} z-eX8JlpC51*BD+lDvhg+j~oAL3Ne+K)|(EP{$b8AUuAyT{7YnUp9za#$k z_&>ydlweL6kuW3SvV?~ddMq|ej%6w2@_Ebamd_It6SETMCoWHXB=Jz<8Edw6y0zJQ zm-S(5x2@3DZoA6%itU{wRgykwO49tKJCZ&~4on`Iyej#!6Aq$pE#DKk>;OmU~2 zv8UVbvVUs-E;TQ;H1)dFvuVz>RcQ~WeUu)Uo|`^4eR29N>CdJ2WSBEXW{k_&p3#-5 z%p8$SNWOn!1|pHFwt>srjVl+nQf$!)udk=hr?^`(f?B>oj#~byan{>Wev*8t!X&qv8FAe~wBYb?+$m=wwk3L)cy(!UWg_3%jbVseL62XX{yD<*Zr@ zTUb4Ls)bD+H({)WRZX5S&cgDiP99@nRtC#JHWUpUV&uRd z@=z+#3~p{}YiCQFo7T3lg^Su+m#{hbXkv{R(c0KV@pH8JStEXyiJv3n{6vLpFM&QK zx@46(#uxgOYLA-XT*X3!(Ku3ZjOM)`nGG+rzG4i$S%J#fzhY4&zv~STGJ&rL+($I?>7v&KVH6{JLLWt`F`Y( z`?a{{;0%p(049PVTE9JfS*R&<~+F58%7N-RX2D`UT_A zgDK!+oz8-+|Au{Ca#&;5Q)eC|unrrW24)yaokH7KncOIrPb^7%P@^`@q?5 z`AmTxpUGz7DYc3uA{;du#YgioT*_nNi9Cr*Iz?|l&UhU@IcUNegA9NV0l~-~AbcgC za~3W9Q9cJn;WhbO!6pl<{0jM8 z&C>Z)`8?F`Jd9f)>(cw-IAd%nYsayg6)_l4ww5(xByGiYJI=F#R@R1e749y<^9igD zEu4y6t$1d^)hf0U?^@UtoGr%L2G)dkTX08uqYY^@u2rZ*?ITSMStWnHOb)(WPEDtp#So~^sZn?hNG{M?6AzvFl7vhuZxdGQy z4-4*5xs_~^c-{`4SpHA^*#MdwP@i_TNo-FR&Q^hcEpmI;;8`>7tdLtmt!QP-#qz7b zAL@Z7+@rRR#(Qho%{ZHaJWZfNEu$PQXstwl>JaLcXdBUJL#{gHX-CgAiM=q$2jcx2 z+@+pafpiVZw}8%Kd|rrdHhANsd@kKAHW_r5pzg%kHN*B$F3UwPU5GaEdXW10^*)zA zy`3-8%NtVig=tiyb*sTK;>;4UUo9*ZTuJkzMI8UF?_H=RMD@2zK$_UggEC0%Bu!ZZ zNtN_vP{+oDw=2ZwG%63a)QVb@ypVSJ-yh0FD|;Ink3T*RA00?Hu~mFL%NG`~EWydj zFqp(E3PJe@%jfe6-d;h=N(3EC;Yw!X3ve%(W#L(na3_oB`&opL%4|X@ix+0IK+I}2 z!cu1C9+oCFvnZUK#rKgHH0(r2Olw$?Vil_so?}X37c&Zn@czG$t_CIoCvp7^GjgIq zcJS{=r!u3W0qO66UOc}PWmEbN(izMlJi(Fxqwo|{D*g?+Z+U+bwjf=^a``A$N_FN9 zXiqLH;WQ)vfn6&kGlMXeh44>7V=T@CSOmY4se}-3Kk6RBOJUbt-ep1?(h|_!2;X5T z3l$QWj`C3+{vF;s#1b(Q1qyRnfMCFcunIJ$U~*_+f)K=#z~@L_&Td4?(Ebu1?*#=b z6l$3n_Z&i#_ZNCcILhi!w}px@)bmXi!@ouU5dWvL9R3HEif3!ko>cMP1L%)OSRU>@ zC_KO>3hitR&lK}-LEkj;f3R%iuTvDTOdt`66>4O@6YqxrBbHL^3+e|yP(S!VDg4az z1N}gK;13;}BVJQq_=Ea_`fQ)~N0INu`yo&SfS=SC=m&p@{Xl(DigCEq`z89&K>Z{3 z1NDVJNXD$lPkrGJ>I>>KN~zsc_Rth^D3*Vrlw|Zy_|3NKPhmA+Il54x}leEFGacs}Hm^aQdh0{TKSOL{Yq zQXkOuVKG(mD(`>9ek5L!Uiqi@c;6N8EyOeGU*hqQG{DHx6cuPcbddDmycBv#xKE+9>uN$q)76ucV~!qRvtKsDFKW{{w6S>AzpfNxzf5V|;y2 zGEZ_RwvFV*S68`Cr2p(BY}yZOy^J+T+kl3{>u)*(q3iSTr{VVR1O(uIRf`5$bx51n3z&55* zybp8%u+#h!rs8KIhc55C;urv36yEXvtZ;ez74;PD!>o#CGWhcz#>hO(A0mGsfVULz z$pbNKQo(NyW+6D#q?~mVps83m#PtBmW|wIpEhiG52z@5o{!UIPi~^vNBfADloEDv1(SsYQevH z)*#O9#=!F&huOyjHW8lRWcXQA5#4OW++l_|3z*I3u(_DA&1VZ(6BpQn>>9R>y@Xlb zmux#cvm4mGY(IO5E7{67 z_*Q;3zlLw)+YzBY#GYl(vFBMQ#__}K4YrlN#;#>gVDA4iJH}o_{CWqh*^TTzb|-s` z-OcV|-|-vxjqG8zlkH`XvRl}0c02n$VhFFWSEWb;A__YZ>)y?8=X>}a{7!zCYTe4# z+}z4sIjvDuu4rmrvudTPNlKNK3)i%)Z&5ahiK=qdl2t2PmaCeiR9)TNx~6&Eip6a$ z8`aH&=ONXLR<$=ZH@B>84{07aRn{~&fwXdwl+>V{rgl}WTwse_V69YOiiw7z-OiWN;#WkZ+vU8oxd^QxB) zo(D86Y+4hr6d%e_?X7K#T9mC~q8cT)q*ZRoD5)i_66;3Eb#9eXVbo}$b(wnfAYJvc z!Sm2DeiaE_e$K^`H7zYG+nQD`YHe1IZE9ZE-lA+1lhCpL@3r||D91_+Y7>)yv1olj z8$OidrTiz@Kuap?PvWb>-)~s5+v_(<7a*3j45WzVnf&XT_`6@byy=MQ>0vL#Y8=2 zkag;{gXf}D=N0D5sY5wc%G@p{0aK|X+o>a`NgcUP>d0wwTh_^KnI^SmotOkpThqF7 zN#HvA44dZPlCX9DSE^}php&@T_4L7dsWqX{CH!Rjr)9WK9$7#|9~xE*7ucASS`n7qzymX<6I4 zHh6>YOgU3}ag&&YE?%{6&DwRVTh_F$S`$#aZq2ITrp2wTg?SFA*r)mVc}^-3=}2Mm zV#VUctw5WqsXd#5yvoH$+S-*%q-2?xsF!Yn+^!T~2x%Q)rJ{X)yJE@wR>gW?!~9nA zEjSPYAE1H>Vk|pcj%8D{k0Q(Di@?_qSmv=9)+Pl-+~$d?>~p9=l$7tU*vAT_j~Y!c#BWz3C_V?w5Qv95AKTc z;LGDn@%$k8a?p#_cA1Y|Nc+4e#X1h#Bfh+Ysjo!jr2gpx)ouWM_B{bd#qx2-jpxMw zVK^+la~xct+(ZfQ;EZ|%)WjMd7e7f}d|Xc$tcUnad=u^c0y^*=a-uguWuQl?PI%HS zK50d|Q_hc>?jR++a}wpcar9E1L4g20plj(poKyXJy+;P~oqL8dsHMb@N9Y_p6*#n<-qgj@pM@3g1Ssml(TO1 z`7xB-={+X5hWdROWb-hdEI>^jL7h5rkJ^krliw2Mgw8?b7|MIVdoSKUf>hK2(0c;h zeOS!D6YuQBn<9Vk?tsRku5?h}$nC^4Y8UF@`}5V-cl}#Zluo?vM2$MBzvxfw{Q+J| z_b&b^@f-3(?f#!M+n+AUFG`nXW$=lAyZp}w-xxge%RLb*JF`HKB#tyoN{3KKZLy1I z=%23*$P5x)>jZmW6sq zEt0LnKtKOLXW-X>l^>e(+-vWb=#l>bWK(=rgCy>A-+SKw`pzz#ihTjQ3o3rr3{+%_ z7tZPbMB)W$qCZ#uH!2cuiKttG@rusPHM;(%nH^dtHmxM87FYGY2 z3FQooNg*Ny>67x&2!pc3yTlFHX8MG^JThQ?2i}(6!so<+Gn@>T>a*gUrvC!^e^|3_^+hotYK#CI}~(vAebKawr*;s3F0v47#$`3Rp+@BBNycQ2HB zu`dyI`zLDW8!JiLy1XBVb^cK9gF$JcHVBA0VyhU=C{oE0rPLyVnS?`$`9~_EnCXZ& zh9KTpgs3G&8lw?ktV7JQ0g=Q6L=tBqLP-(CJVfnQAUe4UM**U9mm^BK6%nFBM2PN3 z1acpH29d{S5wlx_^|wDF()TAETi6HO$hIO5XJ(y<#6__;5R0o|Zz5_|%X$$r8;9u9 z9KIZTCs*N6iqS0I4 zF!9{vpM98fE$$@_bKiGsaQxLHvg|v|1Fi7AC#5t)ln!d2LO!VX8KTktM=+FCi0X%&qoaI zNsvDM>p|zfrN{x?cE?X!$@i z6LHW=L6rO{i-aDM5i;LlFQ@`6CeJNH8Nk7b?ggK?ymELcc_x2T7MDnxi?lB2}UkDc--(2hs9@Xxeck zA%>MKe@gjCc4@urxBnTzw`dWR$23q2vYthveUFS=82h{E-O;K1@u-85?Zyi2!SD~l z*N6R)=Z0OyR;m}O4Iw?jhM*(LUggHXWiX^1RD!`B9Vo|(bxgxJSS+s3(TdzuHk;j# zRjc>K6)8Ku1#lbI^=jZL)dBTD127qw3hV0f&GN z;4ttU@I3GWfQT4-9e4wH3pft^0eBa94|pFq3492A1pEc~7(jG|M*vzt4;TT|m7}iM zYtqk`0L$=RJZr?~40yRS;mgf}zcB~tQCzC2ii}U$F6VQx%OMqpd7XZ&<8v8e!20vjMEZa23g-q%@u8nyl zW^Z&)v^%;h+8ybR{8QxHkw+pAMm`?d7P;8`gSpG}f@z=WPSaNXHTpIBMf%D53Vpsl zQs>b}M*I-b6Y)yK;}IJp>cS#JzYpyVJrZhAd({6_f2HnJKdpX9y+?g3j;%=dsM~RW zp?a!%Ja)+!s*{2rQ5Oc^uf8?9D|nB&Yw$2_MR{B0<4!7T@IYDO5&C`bjNlZMG6MXKBNGN>Hz21i7Xdg?iNMLj;^m4Fu`D1BUAGb}c$ zlS02&7g7%d-|qvp4!wpFM0&`tzBK}G`an6*=UoBM1w0w;rq6(V0lU?=2Jb=7p-l?v zzgrbG>RVxLv!Siz6R2@;=xrG8MTi#40E?`GRUqq0wmb~loDN%;g_U>{yxnrxR`P^X zq1EGIp(er~&WHTXg~v;taJlFSSBRc)B|PDqur|LF{_uGC!_VM7@`P8w6aEucw?AN? zVLkN=9KXW~`9H9-`ZbRGu_FErY{hpt_F{m3A-Z>}jrm|NPAV z!GGQX|M>NjJ(j>$wzpP@FJiZ=W~F0zye?)-XF<~-p`l`F@G~kj6`YC-oLXL zSd%30b11!w72@3G{hEzHI@0?tYVs~>@;++P$x89=R=jsLa1F2x*bZC^+=KTK`(^h6 zzXR^W`>)}CC-5fF@9pBTuq^R_1+W51-miHIkP4*ZIupnSa)ErH04T&BkrAjpIKqp) zf5(2Uzw>gS+WQ+u6@cfHI&003F!Se%R1{*wB8IIR~=7 zmW6wdG7X>w;(&O-0@MI?Kt0d^j0PqGlYq&<6ksYa4QK>rfU7gTPom!UqFqN(_oJx$ zQMLkD1#AK?2lfFE0uKQX1CIcY0*?XvfyaR-fG2^cfJ4BuKnHLbcn)|TcmX&997VY= z0xtnC1IJK@SAo~@>8;5hIH;9cN7;C^q8nyBGa-FZ%6X^xKns5$?4BD}hUZ zHNY*vZq(Jp!k|l5$ehc22Kw?X^yORV${F-XA9UahWc&~(g8W?fShzdPC6hb z9gvd_$Vms}qyuu&0XgY_oOD1=Iv^(42PcKu$U!CmoQJ4#-Id~vIlaq2Xe9pa&kZ9 zqyuu&0XgY_oOD1=Iv^(H@VcQ0oGP=& zr3l2E!9WNQ25YT@?Xu$BhO`*hWV>d=Z(9tzzXWInmH{L^0^XpfJ+L~#xSo$sH>Al& zp$EC$kRf8&7>4U`dL1KC!F>Xl9uldT|kd|&p zOE;vY8`9DZY3YWfbVE|QAt~LElx|2$HzcJSlF|oB>4T*7K~nm_n?CTSZ-@`w4N2*S zq;x}4x*;h&kdz)sN;f2>8wW0;KJ-N|`l1iL-iKcAL$CMw`QP2>qh9n;FZ!q#ebk2@ccaJM=mGMO zsRzhQ?m_SOp!fUH`~B$se)z}1a{t*-mQpZn=OP@wO% zkrY_Lcj|evEA*UtkffqV&)e=%G$l)TA8V#S}4j59WnNlt&&0`86)QF%psOB7nSz z(HMWnVQ%;48tJ zcEXyvF(Y{y7WJU0N%N4BHZ4F(8U?QaJ=V!@!H(Bk@!oFG4Mj~##G1@OdI~rVdIsJRYn)K;9^(DvC_QGEm@+~nQIZ^QKscuUe>%;;dl z`|)NcOTnscI*^52`A7?ZLXk&Z@VJOiJ>XLh_~d4#=;=Brdr030P68hS9|3;> zJ_fphzvG=xfF9rsfHf%|?mY&L?d2MzTBJIpdZY%VMx?PoJYWI9eaJ=^PZs5)i`zvR z>EdZf(}4^i6UYLxfgB(g$OG~L2T%YwfkJ4l3w|^D0djQ+a^;4{*$0oa4<2V9uSfal z2Y8*mkhd;A7SHD(&s^l0hjc#D1xTBaF2u8D&{zzKSc3DV(B)Q~FT?qAoUa1NO56mR zw?QsKWtr-POg$oMqa;&@Nv7CA%;vv=rMG#HBgeD1R8TXE$&=um`vU zxD&V=xCht^+zb2;pt;q4jS_+;2D4-K+ggfiUJ))eO?4!0$v7uHtsd# z=>*;c-bQ)Hk)A+GQKEN{zKfLBtlvZWKH7Z}_z>qqqD9c3UU9Vh1SySpw0=sX-WjAA z`PkRMH^6s5AMh{WM*w?w;6L@lf9i+-)DQouAO2H6{HK2CUoZ5pANtn|{p*MR^+Nyp zp?|&5zkc{r{qU#yc?>|h7>AVfkz!1wlZi-4FKtLA-RyLpjH+!I) zz0l1b=w>f;vj@7_3*GF2ZuUYqd!U=W&`p}x9)WI3b6d&gAAxT6V5IJWe)eFr?tzZ> zV8rgh%&;H2+ABuPNLMj-$@)gthebB+2uHZG=9$F*doOlY60)d!dtip_6-|lY60)d)al~ zR_LW0dg+E4sjqp_hHo%RcBOzV`s!hjR9zUJn8f0S^O@0FMHX0sB#} z$AKq+CxNGcL%_4BV+Yd1z;nR!zze_;;CvnJ!MN6g=*3=mpvR%7dof=*4qe@gIm>bA zs~h^-1$}ixU%Q~MZs=-|UC_&3=w&bT zlEz3k^zsYnr5k$r1@zJlz5D`t>4si@0lg%hBz+`Z?2~noykgQt@{CCr$vY-pBoCQ% zk-TKmMH(l2Fiw7fak2;Fr$9b){6?3QK&`US; zvI}FV8+!Q#^pbRv#?T&l4DFG}&>oDTUqB~&Fm~?6n7J2Y=3b1MZfJ!Y`sapb^gsvQ z@Iih0AZgHd^hBHi9T)Y@_xx*I(fIYX_`Fse)spaL7PP4l_LX#DBhjx(<)&)K2 z6~`kQe`ezTEP#COIY{S19=GDXtAT5PZNPTmTHre1KIA`!_g)2F!!>reLWX*V&Q8$h zWJiBSU;T`J`Wb!n^Ev$kJq5qr;5W?_-Qaf@_}wecQcyo}rc#cSW-HZbVJ$EUG$h`- z!CNxR8^gST$jJ2!YsvrMveVqAZ~o{?`$UaK26XfHT)5EjG>%hgG?2E01~-gP26 zi&-mpCB-R;PcxCrU+<;1i+UuE0c8Kl_EUUPk{xOb$xfGOn=y9FGSG>7k_>dBo+JZQ zPny-3&;t>ojniOk_Srcz&LQ)d$rvy*J%Sn85zNSroFg+gc~7F&U7$g;5sC&%c2t2j z_AmqJMkA&BJ!mPF1#LqdIl{XQ%Avn8!@LrJtpGbBw#YG zry!k*XVZ{2;#%@mXmp_YPA_Dq>!SY1KID54cnEkHz@AUoI5%t@`R$#sahh*G|B$oq%2Igk9@|UF(Eh>x5nFl>Lw+uxsRp9FhHyBeEZI1UAhLo92d1bHk>& zVbk2OX>Qrq=#+hpPTAM!lzoj(*fck6nj1Ea>{%ylStsmRCu~@!XtT&(k*y*-MK+4; z6RlxECZQKy(1|YCA2)1|TlNV$VRvXQ*b5oi2D`Eic4Zsn{|Iae&6K0j8j2Fr8TFML zYZhimMKt7uM$#<2MZFIy=vk8b{tJ$77wbi7baBh0i(4LDXmscV2Rkt;bYeuHsQwYO zyaz4sLCbs4a zC2O%XGcQJ)B#*ocbK-nx^hvahB-RZsoP@+uJBPP+J3wnUa67OExC6KoxEml(`WW)R z3iw;WxAE)*@D9)g{2llN=mE|E|3=Njy{8}}f09P3olRVq>~*0n;h`dlG@!*i+l?aEE;a`AhFD`__s z=nAk^@Uw-t@Gf=}x|{_m1%-}$qd^(Rl{n2e8I*@AbF5?Q3X)Un(o+vLHh$BXGAZY) z#%V8RRAwYMVA)+jJ5KX7!Hb$;zlUBS5{Te7-^r(OsZrM8)csO|cS8)x=8Wg%1o^W- zq)@mDt035u<*>PIE{6z*3O{P4a;R(~=swOKjEdQ)Sr@%AVx2MC^dxXq_!W^?gl~?G zihcS|Pewnzf6mUiH{x&Z&N=({e~YdAfvn8?dm&6gYkq~;$5xGR$Ko5m`DUlX7|-)v z4zn%Ajx&Q&Wwbe!Ry#iJR+Y`}Fqxg%yr9tKbm$$<6uZr6Qs7pKRi!Vm8_PI1n4RIA z3udD(R$mbp9HNRSFPS`l{^VGt%^15uqYew!l+BtrZTk4w!XT5K$Hb(XqO6K1Cnsfl zz8Pap6Q1RYNz(%KhBr2)cEv0>a#?s~8CO(Po8!K`w%~MZ^ZxdTDQAN}4i5cH&EF0S z{6Njm{;AsjPH;Z|SGnb-5Q?E;4NLd}y{E!%h8Xm}0~>SXZWEM-cp<;gRalUXU)&4E z7gmK~pYShdF1T;z!cBq@Y)mo+D1~4{lF_q`Kb-2BGj^CqA#-;vY`kwSes^eIYK~SH zmAo+{TdVc_MR@US4PQ6pVaf)2Nb+0hRSN$=P4loPq86Q!UszyQT2h=~uUIXkL1i+V z%!Mu+y2Ykc#d8Ru&5CCvjw+kdp6^Prr`VMSlMXPKac6-|P~A5yFJ0>jZ5^=ABKI4LL~@l{VevWo6k@Zm~ylu)`V8dEmK( zglw5oaylsSgqI8RB}#}N&gLH~%&;YltIY8N_-Z#R!Q*nSB0(?bc9Gwv1a2qQkKis! z`1{XaqtWYYwqzw1#s+6>j!8>M*l;KyDpF(8&d$WWF#AkPUX-vP(H0P7jL3<(<;7@I zYRnb4hNR>gf)W!oS!r6$^aIhRG~3ddmgGF}Fon(Gz4(Scc2;p4^bMVkZg=qBlPT}M zn{tw8z5jk=2rm+=C-SW~h~jiF^J3AyIvoGArmdn261^#K_{ zX_eU(%NB~<$9KHZCP*IBgLM8c+!Rl%t>k0>4J+v?FjLlt85voVbF)Gmqw>?I=2G4u z?|po_B8Kvsp*KO?p6dB)lVbBP*O0X%ox4=jIqWkurDzH*CXG^IByB4Ta21yFf)uOr z@E!Yj)C2pzQRq?&V~pX!N-o4*7axLo{!>qSu6v5#JhN$HW0X>_PqijiRL9}&G&@*YgXM3x#FWiuDcB~#7<;d1EAq4LxV_OwE$!G`{ zRP;S}2UOmnNOZcuE7Zeac7RpZ6sN8I%gaM-iK!*ms7wD@TNJ7d@uasbX-t`wq>K;B zpPVIJ(%9G-o0SKa&JW5gsqlQ=K6l=(XDYMPHOAr$CpHUmvE>OU6IMnijS?!@O;Jxt ze9$S-Q=sJr~DkiK#KndOT%ufON|!nvbzCg%nvD5n-@q@^Y~6f<0j;}ex} zVntR@zprwdRtR1=e!=R<`h|rV#YT;`e%9mT3_*dW;Hv$ja(q?7&zyn_Rru9X9pd~9 zBIHbTajtJWN@LbJ?ZFKm&0u#pB+J`}o;7bLdVYBi<*v1^qP5s_i3 z6@LvJwRdT(^RDd;rHN@dQ*we6mDVb&E>Ouwjm-$+<)Oh*db4m>T!ePyYj#^g@zmv) z#cRu_6sA?0H5nL%EZLAS%p!#;;Bz#MjC!(wQ~~Iz%Teeouqvres1P>baY&unBwKlV ziuI{GmaNR1m>XnK-dx2C-dwZi3eTrpm80c>A;FqDTTm!|yiFCx3ts)xllD3rdM3ioGB^n`X2D3_O zJ6u-W{IHkRXN76h{FPOs)8bXJ){x@qt!t0jsyuD4U46;oj8GLc32{1MG}=VFqv15@ zvthrXIW*{s+_g9hTqcqhw1$Q*ZZefT(fwA``TMPpMA13X-Sf8nf2-@ zK^3G;v1-GFD84#ydhOJObMBd`Qs^FDu;AGKh*=XS{eJueVMhI?v`lqmq<+k0^$->K z&;3FJY7qy&iebdZ0E22sf@?s5g)aG)!-8L(!^mk*v02G#i+mOu_U~!kkT)qOC|;G3 zUJXrOHmm)<&D`YqFIXH95)_e|Wzs6R#N-{Xy+5%cwHQo}$VuLLcv5@I#`T_AJ}xK4 z)kjT}*i0S}Stb0^jEZc4PPR+F@mjJ^(?u)ADIyc!i|ivQ+g z(06wHPSV%B50OFq=!!Gh7{>Y6o)X^aS;KE`d@cHz?Xf3Natc>T7YC!?`tEKwrzcWG91 zI!9b4zacsPxrQ;x>lW^O^qnVXY)ctEMVFSFKK1&U2R?o3p3ARjsGCu-=}OPP{~TYI z+qkcSl?{@3; z!hy4s^m_h-=O^?NbWzv@oz%kPgZ0-Zl68=^2*ZWe#9Xbv&w4(baPtFyKBW#$z&z)bgkbewT9y-Es7)u(rZC!z%MCCrVoRK88;xjaj6EfT z3n$u_AN72O$~j+o#WOLbWqM=Um`J{?Ytk50U4QS{A8vW9=yW!|TERt%G%}#h`b4T( zhR7BSs($Axu@s{a6rxL?Gt*|xsR)bE>PnrFDRZ_&8iLM#TwE-?_-4x(&mZbbJnk_S zo?|N;|7sHG_fx6HcF>0pFg$%4y0tcuc5>5#*sR=&&(4HORMvTpKtlI`BEGM{M}s1~Iz81}rVz#RTrSUhF8olqm_vLw8dmB@ zyc;dQJB%%MYHbI3t?SZDC(X~DlBTu?$Cy&hW2o?n*IrgOA|o%oI6fjqU*5|9L%c)j z!bwoX?t8Ix7q|!YQi;0dP^kQ?6U3t@94LA6pM{=dIS&W>D(C4Gc#&TJiYFb-Di=Jj z%k84RE&^rPSE*ej?Xv9frOT40wGfFu--4%f-XD`B-(y+0DYWXK$p6=+B;&TZyOiZ3!-_x{nU7&|G2s zjh_9k9iU<0O4kly|JmsS`91hOKsb*Ajq1YdkTN6f^~X4jc|?j8{v#&+WG$g^0kT`m zf7BV0jU^ee+CZf~JfU(zj^{5AKf`Mtev~^$KcDLg3(}-!rWRe&aOo0L-nP3B^XYFK z^*r`6$^fr~1*j)kDR51+QA*N5NvaYDEK>wexnuXNsdofj?zxgold&W_W2Ern^wpbl zGCV&}!#z7D&&i!u1A?fzQLMQIGkNliEGDBS&={|PK_UyE0v8SAwH;ITY@R$^!_uho zo--p|u_jZB$|Q`xVXPrc7ap4(p6a;nM*hyw=JF{A-Z=WC=l9VnW&V`-i9%IfZFO2? znkF?^8GdNf`7EH8gS*e8<;mnx@&PR%TV@vhop}7%6uCK4mB~;m2Drf+oRyxV;6wJ- z6{g&&jguH`>c~yep#PrsY^BtB@ zquFN6t!leEKK|S36qiau$8DD-)@O(%ArO5@VRMK+v!)_+nrGLvu!_2LeTeYl&)b^L zt~45joh@5_1_iA33ip758UHl|_y)T`imf$J{6IEZJfi%e8I?O-D?R_%<>JMan-(r! z$~*OXPxako4X-q~@& zv(j7(xfFfK1$|D|+r`&oB;%s6sS)Rr2s}2WWF#*vzI|iM+f^^j+`V=BFFCxn?gY0S zL*aJ*7otcmlT6k76ZrBXs6s!|xYL2rpHx{dQ8P<%5QQG&v*+=u+wWWUUiE?Z3;Cp) zYwuY4Zq@!zi}XCm^B>r$6u!z}`2Kr?!SlUm6ZJXy7?*)A;sso8qpWpuMQ^&f<&CO4 zN90xAgJ;P=vC5=4s!?IQnQ$nm(X zvv$PmLOqOUq|KaDq>CWicgfmiKj?*B<2QAKLaBEFpR1sq^(@ess0EL$6#Otb_*~B? z+>(`S)Ti96Q#_^9S%3K?nZCzK^X?hayjzbSVawz8bkAQEF~3}+*eu3D7VuDsp2~>| zApioOz?rBuWT)tj$ywZTzfO~^uvm4vU#5Us36I6xN?k`twk4sDt zP99UOiq4Cp?}TFAMo8wL!{5$B1l0kr6AhK--8QSU0L~HAT{2LZLxzKeP(hkvVtBX4 z@t@+1@wzx=R8W3O>?Fqwv+2ad^D5ZLzF)>6=zthB6p~*OB?6E zIU~08r@Y0r1&+Upb$_pJ;^xc#3(?V?P0~r$n16+uYe{=)4(rHQB}y(VMhu&R`U`S- z>z3PAe;VxhJin|xNvCgau2`ZU856SYn=8)P7cSbYXqdIMM3L0%fRkYP{-;AKx*av4USzcs{iHmM5YK$wK;It=h7&9j-#xx?|UXvKJ zudq5dXH?$!JO_A#$d%BHUL+sPp)G^mFv`3UwZeB{3+dBTRo^qh^I4k4Xvxd)K>mbp zJv*~UJnA_Kw$zr`rj~emb&x&~6gAi(d<@RR8u_M;Dmgr+wJpucTU3z$&W|HJAGwN! z#KMUMInxVjJ%z+y@N}71$rZ>gdOLcI8lucfbAEX=L3~yWsr-D&Ra3?ljJGROH0DxM zYK)SRC8M%{*|l5}4Neo770d191Db-EVMQ^VHO#=@<}7Y&le=MTm~woH=X2^2oK7pIE&)$DR*RU>g3`r)#!`r1+2<4%dVW8n zfb+VU`U$&*`eAQB$IKWbBAhoOH0YAL3Z?ZZqrt|<8B>s#*Bot>p4>kF+yB5q$vK%f-27s)MvT{4wtj3pu|a9 zO8eq|$G@aFE*8P!(R-4sEJgptcp@q*cBCObz)Z0?(FEa+Dls&AM%CgddudI!Yr(|4 z0=*$TL>=l_o|7FOqzjEw)|AA!7ELcJ3RRhmAYkoY8}FqGiptF**zn^ z*E&+OzjTdC&3Ke&={);OQp#LBU*{*XPNX+4RSG<1mt7X(GstvUYTEQi+P@dA-rRb4M@<{or^$oWdY<;l6bEtmhnyP!N zuDr8|Pp;$k2X(p^yiBL-=+Noj{wD+qGzE+^v7ng<>)~HlnnTeDCa$=d;AFvuDFV5* za7BCdP5DO?C$F!`Oq!xZAlaB!5oen5#2^>Wel~AR;nd992%|ZE(v&i=1m(c@=O3dS z(Tl_^P4Xi3q}etX|M;7*sS9GlHJ&+r>Xr!!VPX7l7#3$VzZ=1iR<*r?{E_e>Hz`7~ zkDuu&o+r8iD##&*H~2L2@&he7U`P}-4U!x=FYf3_TcA;27&~t6%t^7uCR1Q?-if$* zyhd1?c9UU8m_}6@|E#rkWT2obu1`3YSQ@0!+@`rBb&Y^BZ}e_q&&sPm2#VZjzfy7c zFN>))47F*JYQyp0R8bY+(Ye4Uv1;P169X|8Casu*5*P6jZ<-f(A}=}66g47t(#*Nz zVhi=gK--vcjnQg!$xvaAX#F>cvAsocU991W;oEao zLPQe_J3*2_kZgpAcWGnU=mHXQ6gnT+C=4uOGX9)Yx^SG5h%i z-Fb=dBK;zUZ&pVwmjI8$Nmdh(=Xh7s9B=o!jT<-8Ja5gKHH-F&bG>VMGUj^k#*T{p zOt1e833t$ZPw}UM2XAIt}^KKEAixCAxVB`otY(_bk z#GV%J%~%iht*b0qb}SjZQHqs(irlK^5^MtlE-*H@xQsG8TUr7y?m!V>GEB6)NrAYz+Vuag*`?L zib;+gSv7H_SBXJ5yUr8FU9cd`Ln{;&_#^hdTFkS83L{G`p-4RL341j3F)J`CQS+7HEGOA z0S2W#u6o~`I#X!4B236~%!vq2wXdB~9cc`VG7BSI)frL2YMniyct+8<8s>{Xpc!DKZp5I{EII;Kpge_r*Ubr(AWt>cIo5 zt3VRgmPvdDNH`$5lw~-(B%;j%Bx;^nxJk7x>e#YP`evY(?AAtWYB#A$W zI5PEdKG_HCjDXA)6zZU7)JrZ=H6)dg)aiRYmicTS&m=d{PB2L&Ar z(#50)a={pB)>wJ8IXO-rHgke5Q;WK<5mNb9;aZ9-&=|XhYlPJK^NDk*{3o7>UX)h* zB;#Q9ZMPbmJvBFPvZ1_sLwS|3ce0~ka{hyR@AEbHYS__B~~|D6+Bid^)5 zkn+wuDId_f9nX5{rNn~=J%?!RE+0~}TH&I|0BNiNOLD%USl%Y!+a-`c?&ij+SESsZ zVGD{-dHz^Yo~?Jqs11P$&IG|TvT)_tYD03$GgBS;Qe62xY7(DbgINO%@6hwC0Qe zjWV$yZmhzw!0rg)fyJ%WGoq5Bt(wqiy|Xz(tq9Zw+83uLsnwdqn8c`5@@^l*EMk%z zwSifpZ7dI#=OiS?Z5Is3LR4{i(W~&*L~o*SE&oyEDDB7rL!4TdRu0r4k}QUkX_pK+ zzd887141>y5%IatNCBG5szNkX6Glb`6a{Dk15~Nz+5AV({`s1q@fF+^>{*aOF`B}x z%n^wNikm}H!qrAwY@lACdCnO4UX8Hi(d2yvYDE)L%*oq5cVg-?sK{&OoAf(&-gV2T zmH(MD);Z3uj5C@hX2qvm+ccT;9pCTNpB??pxVa9@O_Q^$>t|czUl5)my{g0SNc_m} zf{ZcW?Di6I1^Mg2eJ)$PYQ7rrIn3e^-IE*^*`k?MqFB<@QDy%jI@K83T2+@lGE#31 zjn*V<1qIwTMOckuW?Ff2eq@Rv+-w^ak%a$qgk#nDdVYz*Ib;{h{SCsc^);TaY8B=n z#6y=-WEDH|@a|D)f?AALilG=OZbjNa4wManoN|M{LU;S3rOmIsCB&6fm6g|ws4I0f z%zk3_lZQd04)XV+&kiNSBY_E`PM1&kfoFoIO%1v){v|m*3iI=HkZgy<6Z$nP?1@su z3NJxh!_hDBTd^w36@$BQxM)jgN{(rlZ*z(BJ6>t^yt3EVHhz22V+XD*)9cGJJe@bt zjyT~yxwW2;^%IOd%k$@g_30Dzmwt=lsQ(puxlGLChm@FfaaBDtr08WAQCA6R&@PGX|S{eE~wWHdR+SK>r4@{*Z}b_9-Y_(9Q&|va8N7;O=FyF*)YZ!8h+b zuZ-QA)XgC^h;;heaHUuV_OcCAh7O%2&U1u(SZ9~{{F3g-s#>N`(T1AiEcq?k%WK9m;_c_sEhkd^;7Q z48m)n=roPa=Qnh8gDoj(l+}>$TzV4PRSf*BgCIx8*_IKza`<7H-$$`Z#Iwfbjn*I z-lQ!Nywvjw7A1Fi-r&VF`lNYP;*Jrz7_ws|f?s%`!7Sl|yGe|zU2(&XLbeAEUSN|+ ztdM`+097m;;0uQAJgI`NCeZwL_?;Yb)B?~b!v^hL`)B5C)qWmgWU_(0h=pxqQ(`4u678zrmzMGL=lK=X$$->3f49;PbA6)4?K ztK`2{e$o)7yl5?Ws-J=mTanf0XsIAZ>_$TdL@&gD=gL5T4{Tw%#@Dy@>=!}&(4SV} z5S|WDeEJ;r$wXK9vrM4fC&Hg#W3ArtMpNs^>{*^Onbrr4+GGgl&o|Q4+-vhuP_pGGurdvh!un(6M2d ztuR;n4G#)wR}7?p)`@7IHQe?Q-@cf^@%w@sWL}UY<)Zs!6uSn*=YK4JV0^z|`M*dK zcG2>Mz5%iGl}|DFIB4a?+mEG5-}ryQ3V1pPWb;=l;S*S29j+AXfITZ0?E_(m09<&l zl6t5tT(mxlLO-#<7%uLXf({X1l4-r|;O*R45b%0Ae0<2*n$Je>FFN~o=e7rLA1PR}lF}S?mykw_yLg~qX0jO<+Q%dA zvk)EQAsc!oNa{4)z8;}tK#P8BDFf;=q!hKJG{csn8_*SBDL0@kn8RJDEq+e&kYbzz znlXGyK7~NPNnE=^j4-3$E>xCosMrlDag(304O?dAIWi{gRK5(oCH{uAFXAk(l1edV z=KvFjY$%cq&w1O5iU$}7X+Zo++#hI!4}cv;2;O7ONtuB&dHo#UF&Nwxr?>j=5!`aQ zv`KLPT5*@)c5yqLe*3^aLGJw#D}lSPM*~sPK&J!K2WLUHg1&<#h6jy^mN~TIP7V6r z4AwXiw6cn^4(*B`#2p&+R`wIJJSuq2PpA3HxTGz~lS#T`OIFLvl- z>Z4JzYAr>k6~6o8&Y_Y2m%T#@IllE9_7It*5ZJG7CF0M@F|vVr_xS3~Cm@tLSnm^J zy|M86zwdd{BU&xZ?GT7W@3?+L15TyXTBX@uer62K_I|Y~LgOw>|Hjm(rVq5`HD6oU zvLC1q@c-jNQj&#_#I_XSms8Cg|LnIJ>V`7w zrn@d#_Yv)h^6HcA!4}0io6<_l%FBKGq$W8Xa|{E+(A|X zZ9iuR*{{q8MJ=V+zPPgJEEwEfmXS3vX4nZ~V*6#oZ91EroUF_~Z$9YaoBem9K~iY1 z+gGBtHb~kUBWbIAU))Ist537_b2+S+4)&=fH5_JVSso7?)I6yy(mb&a zd_ov$9{xvev2L%)b->K+{95>Sv<)2*hSo;h;Wp84SQw^GTz~$kfZa*Gh$>@6-?t|c zp##}y?~-;$&Xcz*^~jqfJ^z$9W5MntI^jn_vR}dgfoT$ZX2}F>GDj)~^COUh{P<-M znu84Pkg^Xrq`tjUGvnj3^rh;{FUS5ZaVyy9mo>Tfsg}0Ff_c9Ll`?z}hgM)P+ZxKN z!M$bs{TSqvdYmbzu_>P1UyZ7to}S4*v3vSdrLExbrx!5eZM zFg6ggn8jeT1Tc=l4h9VAilW8-y((7y{wo1SSLsGdUsPWP(o;Ai@5c`>KBZ z{{8!_CFjhU8O}kLW%aLH%ddL%-hKClk;her5%7f>elW@k~IeBY(ue#>)4WoGpHD%cgeK{l9N>9$Lg)BX#b0DX4z53a+ zBZa|j$G7*~I-qtgUbSN7*u1ZtF^Vw-KM1V5BkPp;<2~QJFPWk z>x5x<<=id)&VY76CtR_3XSAPlKPY*>#6D%o>XL7bCA+IntP5+Bmr|oG6RMCYTBJ9J zBVqF?Z5n5-`1uiz1it=QNTNk)xnCyczKZ&!$e#;t#6)~7 z)XL@&Ix{az-6>`~nxCa)7-n0vO|#A0X7lmt(QJ#KzaXvViCQHn!AD~AOfeFifylYdML-8nujFR)oE-x{oA0BNovj{eIK~Ouf`e$_XRBHE z@4Ey=ThI{EW6|~txQ|p24}Ef0m)WNlljUXfdB>o9?KX@DFk!DpoMJ8aej_Q*!rN}A zfPa*SeFsZ7JGt4JXVUv4thK$EZ(&Jqa*Fpyw6veMg!_b5OCc?*8?=Z(bd$T&Q`;^K zC8xQrm|Ku%Zu~ZTd7iJ*{!n907{gJCfsJqsIN8SId2VMB<>p5spse^zgfLPS;wTU= z*qrNmes^kheoAU~<8W(rU*!)Y5Pl=-R>vhuSlM?1@XA`KMpmj~@p-a*JV1GgNf zo?6fW{{)O{%M=8<(i@P30va_07T`14TF$}676}P;g9dnS@T7!kOr#)0sz2KR zc!`#x0L0`;xe#|s?rS&41#mz{`2G>a)k0XYQc4eLepJiM(&_TTiIqc^(^39z4v2TN zP`sN0ljaAX920g_5%!7&>X?4Lx6XK-F7Nj`F51C3F3r-DV|9po$ZeD0vWsIPX723{ z&Skg8(=F)iI+}NNG@~BlDD49p*qoD~VIks0)qxTiiiv3UB%}13s8RYz$F(3uy!RAA zIbz?(^M(=6n=o@Y49Pl&_;npibT;wtB@XOpwEsM|=j8>xNi`^glc^l;}bpD4CnXR>>Tkd++V~XKQPNx?kkxh$Ng_y<1(oy(eFB zg}aEJh^W_EtR?J|lSO_)I3Qw1dvI1*#&}kod8W3WKT+ts5O=vv-18za><0$ef|FtB zVTPk4CYbHUQ^XS1r}|N%qob2V-10^u&}r}fWawJ7sBuhSzY}l2RWAEnEtf^dLvO#p zGwP+cjPftz70RVYPGAf)=0lErY$E^NDz|=CkKshARC}y4?IRC9N~)&p+IXJNRZJ=( zrrWRSbn9Ub>-?^)*>l2;cbAm-P1#<{E2}S%C)mP{%50}h{?b>kwiCt}4c_}QeJ6}L zJM0mC`>|X!AITj^pCj4{#T+e24e!w3vwuTm9ZyX=z~G;bts<~ehc}^~fbyQih}*Tu zVtW^N^jS7+UT*zvUiPmiv;{dKO>8{g^H=2MRk#C5V^^}yDW|rvqgrm8=Wu%MYG>!A znNv-1%Q-Gn+=j6N$YS`OeLqGTe8;Jdv|$ICM6zMjxQ9$Q-u9jPMgp5u8*$o6=8$#6 zMot=6#UT;5ni^J_UpEQNIKHDyh)?-Q+7xm%=-5V?hE0865n311r#g<}M0FB#iVoFD zAQmR|xC$GBv&tt#sUA(MFUd(LbT#-(8!8u*XNa#|djikET!PK-e`v+JDPuD$1kl`- z$qt|LvK^MaQT+eHx@Aw8dMeJqcd%niWvW3*m2iFXwdQsqBza+Od-o7fLtGG+Lm z(fuSd2b}s6uk7WlS-R#4|Mq2canByNdyh}elENqKW8WV2$c;E9?bJWmPw>3J2M1#* zh98caN<4n(kU0ysyBm41yS=YOWk@O^?^g7Om?5j|+t4rY@{DYbQd2NoXLGOybMRYA zi|jShAK*Xu6wmHbP!WuBS#fkmMrh)7A1&)L`v=uuYyR59(%1EY<`$LQnzcZTx88`D zEIS=#I$3cV)nqxY`U>n08~nV)o`>t3vhWN5($&wj20^GF4trn)Z)QK*f{Ku_tq2QF zZ#2=k)9TItIlQq_HW;D!De|Y_zi=B}2w@j7(;qXO?~^{_7sOMZY_7dc;)6mBY!}kU z3D2F`W`dcWQNjV972yzgNQ&n~nnWbKgRz3=0Vv;mIzGnLi$xiQZ_HO>W9hcTJpIu0Waab9M|nw2$v86Zbm2K_86nwKKe5S}7;# z8#HzR%9Kw-Y=y_~^G(K)bwtESYRW4e6!&Gc~LySmXn>QB+>TDC!K!FyeTF4<`~X+oSn!3}|18 z^x0sx*>{vLfRuQgI#S~^HJGeOK1_r8R^*e&XCg)wiLvHUwMh>^#6+{JwH;WOBvWtG zHeoT(@9{CDIIfONK1rhL5RcF>sbkvb#X2TD5)Fv5MAp$%(GY3E%^zqEq&%RDqje|G z>A+B_$CqZVR=-UmX)LigtDGSo%f`RJ7xFy`H2i6t2E?D__Df(&kB6G4sU{+&Q>e7XqogTn`oly_1aR77D@|Ka%F_|Pk6ep?k0|~ z_9#4_Wns8}CL&ta!PMn4s3mqtq3}i?O$+9$=`Aw%=y83?NB1duFHFSyx)xD{Jjxb` z89O#LYtciNDx0?MLz-Vx z))laBHZiT-415uqJ;73nNiHdeJ3`AT}vZd5MPln6B?K`4{JVyeRG!8xj}9fUT? zGUE{mYLwe$JRT+WXf*MkO;?S~BB`DH^fYgwSC;`2-Te68hh{7nf;$5n*se}Z4hT9i zk|Vs9^Krq$iOI%A`ipmB2CjOPrN?I8CUY;c;0}-%Sw!tOWs?U(BH7Q8z#ADGiShCf z1JdjIZDMX=ZftOO={FVl1qDX(0C9|LgkzNK<-0k?09Pc$f}2q9k&`eeZ!Ac0d7eNv zA;0_jWi@#@B{%IGuFlKNzab`6<4^?gN~p^4kOl&WZ>Pj^}3JSW}Nk=q}o*+*xb?Y6V#s{ zasjfdKD}ySKv3&$9~gK;C;j|Lh>?lbmBTpsNNuteqosRqrlvO;j&O{(P#-p!rvVkA8xm>(KX*hkPR%Z99qc_=nlZ$7j=m*qPRWvP6Oihic9Ec~@ zV~X6`t>l^1FLXE-LQN+NB2P=c(lFQi_*}Q0`e=oNppy^OgZlA0<@weRU46bOO2Oxw zEztbYT#pp1wHB-e@|{mnk<>1&x2a2$){50Sxk9P(TX}l{Zmx{Q*C~9zv`!;%e*?Jj zj-3i_oi8wDP1W=Ck)H~7>Fd<76O({rXY=3XPBdu1I=Key+)0sFq1pi@-HQVpyQ)zH z0J)jPP;HuuKx~S2qGoB$MV@5m`1XCTgA0yDiq)f)8jfht}7464&`fl$gn!W5{pESW(;%r9~CeMS$-wGL5cKng|{; zX#B(6mE*ATU=dsOxj0~C zqnOn6KGd8KQ61`IM~r@mu$D7CC5Abcfg*BVM@;AL-K6Tgd$&Q?S^c?Bea`D;y*}2; z)txb0pYhqk4bV<;5jkHxgu=}wE_v3);zN953^IVM(7TuG0Pgi3ltO?@i6tPirnbR9 zfirr-oGDYxgqd=tPM9MnmWfkK4cUU&g$48U2;PomJQBO4R@k%x(OMwF*iD3p(;-bL z%2>K(yETFlDcYmE32)D~snXcqezb?xH(`4bml9LMuJBEyAkPxQ^ZEsZta*WiZXlxP zBOHm$V7muMiek-%J4yz@gs0P(GGmG7d}Ef3j_7S2(V_@McXLFzxlS}XZg~d^UxrMO zu8z0@Sz^kty!nW+qMMHxtEG#@9!gA`J8*l)Jt7iSByW?LEx6fh;aa(F8@lG|w3gtE zipJXOOj78J*B4h_EQu|PS}T3ibZK<#-*IT0bSCk}_@m-S6RBy=j|e1P5}~ab8Aytz zPvbr1%Ib)4&gxfmPweK2xiZopd_hP$!#jBSVS% zM3pVT;(=C-uCb?WZ6f0_9QSlbM~$a=M2^_ z2&4v5eJ=cPVY|IO=jMy`pD9nb_1y1L-`H`Wb8$=Qbf2dvy{(76?%I8~{&%U*6IYCr zz=s`(xS)brBo%hG0!{8fmc2<{LKS&XeE~I|wtt{Z)1WBY^kr-Ms;4wBiBlX__Kb>_ zrpj5FC(m$;q=I`rFRA}jw#k=e9Y3)^-xrw;_6>R-DsF41o>v={iK@GIPBkTUr+CLF z%}ix~F`l`v%6@5kn*CkuFr-5ShS#Ym5$W;9DM}Jur0qzPC==RCY&bVPDwd|Z48eo<$qF!*PpZu zFRa%o<#@@|y2*0A>|z6+B;|{x$}Ji9Rrv2jeVMLFy$i5daLeWn1he06%FYqDbeK)< z8&Thibf4k;@T>1@y61hT=sh6hCeTxJ7YHHrT@v=x6w%c`MncE=gmD%%bSNfhaf37k z=Pa&~NfJZkE%HRMxvhANlF(wu*%Iq6sZ%pd*U1}YOVRg9^ft@KRXr~D#NEXD@p7Io=a@tC~ww@EQ$!}QN}R+ zF2nD>L#!pknR&&-LGUzu$qveH0*6cqlgFs#TND>N1N;Qo zt&)$VSu-v@o`0K?z*Z|ihZb)-MnE1=nHn+R3FFO4S#R92@%)Ry9$N^O6=Ls*l1Ju; zv4RxmEd5eZ-IvH5)4w8b5XeR&e9M&*c98Q1qgjLOpgBuc(K&)JKyB-w)%sn`09V50 z_bn~p{}9{Joz1lcB}(p9x_YbQg_MNchTP5gJpO|!_G`j|u3)ev?0#j_$z3dW zWb1Pnk=K5t5+Q){qV1$4UPru}ZkCP+m?-N>nV4B#za3Q&I#4edMh!}ed62IS^&3uT zu(S8tbDg=%8%jK`L{~t4Jvk#|-q^rJUwe}E9IDPLFKuia8Jm}pmb|`UIrCLt99NLh zTe>PIaOJ z6cnd-_;TZVGjmd0Manc(1b3`lym0+Ue_a1puWGoZIqBGprKL56rRNI^2(#M=a6Uh3?7glD|?|h`d!tZ>j0sk@hK2t^#wnwb5pD&67 z-5Q874kqrNVH}%n$AJU)KdLZ>`(F;v-;FUQ=B(X`h6c2EUFO^xmQm47AE6iY5jw|4 zj3{|4j->;ni{zOvr1_cxT9gpbds44SzY)`j@EftM-!D8N9)#w9$Eq+kJeS$SUSsLG zbP2KHU+hN>|6+em{!0z}!1lKCSAGfzzCGzs69wY&X)ALpJ^tFc4a#3rySfVFgU+({ zil&+|+8fwQ_|!XwvqRKI@Onn|PqCNqsiHXJr^e5tBo@uwY^@_BV_K;vm{u7)_DOSBL0MXf-LVYi z$G^_TfeZIC)c$bd&~Sts7jp(VUjsnG8<+$%YAs$A%+D*I5U8^zJD8Uri1F|28b`3c zHt3jHWR2b14zd5bhO!vHfZh$;_ObbqYT-M&XI?tkzi;k&vwNv_ww-EJD}S-w%g<`? z{-klys2LgZPf@M$Qy6vvHUZFow-_-Ao>7*Qv9oJG(qXhZJOJY2!F=P9I; zP@pt++bQWwG7}?zT59>bc2e#xJY(!zE7q+~Lmh+cj3kFWO?5^6WR3YJ*RvPP)$YX6 zT}$TfU&P8o9YeL*E{D_YDo?Fm)S|vK!9Q#Y|9p0h;R7dUlXf-jS*Vp@`v=!3hux5Cij8MR&6XFta0Wi z)hSP`yC-i!-d&d!mM3{b!Mc*RdAHr3=k*5icJ4l{y`(PK;4N#y4SgEcO)+o@?JF8y z;tkS1FG**l>fM|{Wsz9Mbc6q>d3v!!n$QZBbcg)|K{$%KD7W6AzS_R7zO=g_xgg0m zzqp&_GTYbc>WjPJa7t>e|F`99cCK8zB9$d%_+4?1lt)><(slC3%8+{6vfkcIE2P*uSf+iuvK_W} zCHg`4I;uoQaZy;HB_Th)*Zz(=rP_D+*DSWhk>ag$HT_|_tHG1vRQ5hrUVbFFws%AI z+T!A;`jzch)U`R(hchzRXhLi46&dOyX=!YsdKX)+K8^22GJa1p{Qt`;R&05&P3x39 zk(CWDs;Dg^m6O1zGOAkOOwYoa;A@$`%r8~jxIc?96kKacn!4LJ|NF64hvKslH`@fOjI61GX{bY?GOkgQFSi##*vhH;imS*D0Y=r zp6(ecP04a5dM-P^eOcAK^2G9l=DEt^z8_V0T|Rj3t!<|_w3f%^)U;l-c1Kmq#qDR` z(7wDbRBm^>IA^28b`kq8b}_7FQl2S>ybsmp5}Ngnpy}`I>w!l*O5Hwh!|X?jrx*Cj zW|{uJx!ISWT3Xs1N*#J2{4Kf%{&FW~`ggSI%KVrM>;t3=h2sRfgp+3e!}Gi=um1Mg z>X*#FID260x7IWJv)8!K_iyp9bC3A9V1?jrYbk*P!h1&(sboXUuL^FYx=>ar(rA58x9e<9|c_rAyHU zZaXXq`)Cq#v+o~y_0@asz3&0mqCU&|SfBa~o2LF#{Tsb^bSuh+T4xpUJ#8eWA@)5^ zkdSW`4zYBhYN*EpnoIfbHiu~M$AQzV+&`?QoO8XYWc+ zX-9car?CdBR*6+%=`)szTC5pqDQ!JB#*HMQE-N${coamr0thkT404I6UM^Hh<(~i- z4u@co1=z+-Y<8>qVa={y^$h?yuz%5+^~2SUij->QZ4b=N+^8+*N23|AE7YXaKn$z^k1N%x=SC?>X- zIReQZ^{znnu8ica00$ke;2Q?qwMZLUwLLM=m|a$AgiV!5eqparo`Vmn9jFPGetx06 z7}Z6~EFvFFF)wrnvxN*PRFI==cXx=k6$d%?*yHuVjB|^Uvx;lxKd8QWw5NGJ%N|Rw zzVX&?oZtK2WBZ?3|8k!1=HV-@D9-PzN^~{lS1V~{1y2vnExUN^mhZmy(6Z|Sb4Fbi z^_7cuEPwPrAHL(ttwRILdN13ie*Wu%?)oL)=><6c=5E0V;}{{mGEbrLjWjOyW>kJ- zsqT)F)CHGczEQmg>+kes{j+N4RU$B4&MDXEBB$LE%moVTj9tg?3n>Ky+&>KtzvTG%wabm2gCC+Zyc zH^z%P$BarMKPdzu*z;Mfb)(CizI;?VKC13B zF=cwddwmiaqbbsV4aXTae`03HX!MuaMcs#4sH<;G3l*z_Lu0|=jD)4Dkp`g0im6K1 z5Im4yC3_wgySMQK8!9NkNP!!`vwQ!w>c?PLDX)PG$Lrtd-h2}y4&|=M;a8R+O0E(C z?v`-5)!Ro?O1CXKgAL!3-CwWy^dpL|R)xm;ma-1@(fTTcfw+c(y#^JyXl_S=9`W;H z?omCJX?AIbdprr2X^KN-a^ove8Y<$_@-izt4V8X>jKbDK4eK6moYB6pN!_JQb{kU1 zkCk*ND{@@f&b-W)O_{B=qZ5|7&SkES)lC(@*Jr&$&uqu5VedjOxqbq#6YFk4IW-M7 z)+Rcwz-$VGrs}b^ZS`l)uIp@FINezums*fl-}TikKVTn;e0CwNckugrH?*v5FZUN@ zczt6(RQKb@daF1c;x?dFUTq#RRa95#juRnr-XwMjG-@n4YiOSrpA9v)bhIt%))3@o nWt5(F+Bc20Xn$Y;^XMO*Kfg6oqDgU=tDmV)F++t~iOlxj%bvYg literal 0 HcmV?d00001 diff --git a/website/static/images/spotube-logo.png b/website/static/images/spotube-logo.png new file mode 100644 index 0000000000000000000000000000000000000000..b24a8c238dbd80e359026b114a0c097de9422823 GIT binary patch literal 91271 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 H-`)QM?;rZo literal 0 HcmV?d00001 diff --git a/website/public/spotube-logo.svg b/website/static/images/spotube-logo.svg similarity index 100% rename from website/public/spotube-logo.svg rename to website/static/images/spotube-logo.svg diff --git a/website/static/manifest.json b/website/static/manifest.json new file mode 100644 index 00000000..a6f8ee29 --- /dev/null +++ b/website/static/manifest.json @@ -0,0 +1,19 @@ +{ + "name": "Spotube", + "short_name": "spotube", + "icons": [ + { + "src": "/android-chrome-192x192.png", + "sizes": "192x192", + "type": "image/png" + }, + { + "src": "/android-chrome-512x512.png", + "sizes": "512x512", + "type": "image/png" + } + ], + "theme_color": "#ffffff", + "background_color": "#ffffff", + "display": "standalone" +} \ No newline at end of file diff --git a/website/static/robots.txt b/website/static/robots.txt new file mode 100644 index 00000000..7d329b1d --- /dev/null +++ b/website/static/robots.txt @@ -0,0 +1 @@ +User-agent: * diff --git a/website/styles/globals.css b/website/styles/globals.css deleted file mode 100755 index e5e2dcc2..00000000 --- a/website/styles/globals.css +++ /dev/null @@ -1,16 +0,0 @@ -html, -body { - padding: 0; - margin: 0; - font-family: -apple-system, BlinkMacSystemFont, Segoe UI, Roboto, Oxygen, - Ubuntu, Cantarell, Fira Sans, Droid Sans, Helvetica Neue, sans-serif; -} - -a { - color: inherit; - text-decoration: none; -} - -* { - box-sizing: border-box; -} diff --git a/website/svelte.config.js b/website/svelte.config.js new file mode 100644 index 00000000..b5717e39 --- /dev/null +++ b/website/svelte.config.js @@ -0,0 +1,55 @@ +import adapter from '@sveltejs/adapter-cloudflare'; +import { vitePreprocess } from '@sveltejs/vite-plugin-svelte'; +import { mdsvex } from 'mdsvex'; +import readingTime from 'remark-reading-time'; +import remarkExternalLinks from 'remark-external-links'; +import slugPlugin from 'rehype-slug'; +import autolinkHeadings from 'rehype-autolink-headings'; +import relativeImages from 'mdsvex-relative-images'; +import remarkGfm from 'remark-gfm'; + +/** @type {import('@sveltejs/kit').Config} */ +const config = { + extensions: ['.svelte', '.svx', '.md'], + // Consult https://kit.svelte.dev/docs/integrations#preprocessors + // for more information about preprocessors + preprocess: [ + vitePreprocess(), + mdsvex({ + extensions: ['.svx', '.md'], + highlight: {}, + layout: './src/lib/components/markdown/layout.svelte', + smartypants: { + dashes: 'oldschool' + }, + + remarkPlugins: [ + remarkGfm, + // adds a `readingTime` frontmatter attribute + readingTime(), + relativeImages, + // external links open in a new tab + [remarkExternalLinks, { target: '_blank', rel: 'noopener' }] + ], + rehypePlugins: [ + slugPlugin, + [ + autolinkHeadings, + { + behavior: 'wrap' + } + ] + ] + }) + ], + vitePlugin: { + inspector: true + }, + kit: { + // adapter-auto only supports some environments, see https://kit.svelte.dev/docs/adapter-auto for a list. + // If your environment is not supported or you settled on a specific environment, switch out the adapter. + // See https://kit.svelte.dev/docs/adapters for more information about adapters. + adapter: adapter() + } +}; +export default config; diff --git a/website/tailwind.config.ts b/website/tailwind.config.ts new file mode 100644 index 00000000..77611a2e --- /dev/null +++ b/website/tailwind.config.ts @@ -0,0 +1,28 @@ +import { join } from 'path'; +import type { Config } from 'tailwindcss'; +import typography from '@tailwindcss/typography'; +import { skeleton } from '@skeletonlabs/tw-plugin'; + +export default { + darkMode: 'class', + content: [ + './src/**/*.{html,js,svelte,ts}', + join(require.resolve('@skeletonlabs/skeleton'), '../**/*.{html,js,svelte,ts}') + ], + theme: { + extend: {} + }, + plugins: [ + typography, + skeleton({ + themes: { + preset: [ + { + name: 'wintry', + enhancements: true + } + ] + } + }) + ] +} satisfies Config; diff --git a/website/tests/test.ts b/website/tests/test.ts new file mode 100644 index 00000000..5816be41 --- /dev/null +++ b/website/tests/test.ts @@ -0,0 +1,6 @@ +import { expect, test } from '@playwright/test'; + +test('index page has expected h1', async ({ page }) => { + await page.goto('/'); + await expect(page.getByRole('heading', { name: 'Welcome to SvelteKit' })).toBeVisible(); +}); diff --git a/website/tsconfig.json b/website/tsconfig.json old mode 100755 new mode 100644 index ace58477..8534dc99 --- a/website/tsconfig.json +++ b/website/tsconfig.json @@ -1,23 +1,18 @@ { + "extends": "./.svelte-kit/tsconfig.json", "compilerOptions": { - "target": "es5", - "lib": ["dom", "dom.iterable", "esnext"], "allowJs": true, - "skipLibCheck": true, - "strict": true, - "forceConsistentCasingInFileNames": true, - "noEmit": true, - "declaration": true, - "sourceMap": true, + "checkJs": true, "esModuleInterop": true, - "module": "esnext", - "moduleResolution": "node", + "forceConsistentCasingInFileNames": true, "resolveJsonModule": true, - "isolatedModules": true, - "jsx": "preserve", - "incremental": true, - "baseUrl": "." - }, - "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx"], - "exclude": ["node_modules"] -} + "skipLibCheck": true, + "sourceMap": true, + "strict": true, + "moduleResolution": "bundler" + } + // Path aliases are handled by https://kit.svelte.dev/docs/configuration#alias + // + // If you want to overwrite includes/excludes, make sure to copy over the relevant includes/excludes + // from the referenced tsconfig.json - TypeScript does not merge them in +} \ No newline at end of file diff --git a/website/vite.config.ts b/website/vite.config.ts new file mode 100644 index 00000000..839d4507 --- /dev/null +++ b/website/vite.config.ts @@ -0,0 +1,22 @@ +import { purgeCss } from 'vite-plugin-tailwind-purgecss'; +import { sveltekit } from '@sveltejs/kit/vite'; +import { defineConfig } from 'vite'; + +export default defineConfig({ + plugins: [ + sveltekit(), + purgeCss({ + safelist: { + // any selectors that begin with "hljs-" will not be purged + greedy: [/^hljs-/] + } + }) + ], + server: { + fs: { + // Allow serving files from one level up to the project root + // posts, copy + allow: ['..'] + } + } +}); From 90f7c531cdc8640afdbabf5a0592159715ea1e6f Mon Sep 17 00:00:00 2001 From: Kingkor Roy Tirtho Date: Sat, 17 Feb 2024 21:33:09 +0600 Subject: [PATCH 140/195] fix: non-banger songs breaking the queue if sources not found Now fallbacks to another audio source if not found in one --- .../proxy_playlist_provider.dart | 3 +- lib/services/sourced_track/exceptions.dart | 11 ++++-- lib/services/sourced_track/sourced_track.dart | 38 +++++++++++++++++-- .../sourced_track/sources/jiosaavn.dart | 27 +++++++++++-- lib/services/sourced_track/sources/piped.dart | 9 +++-- .../sourced_track/sources/youtube.dart | 2 +- pubspec.lock | 4 +- pubspec.yaml | 2 +- untranslated_messages.json | 1 + 9 files changed, 79 insertions(+), 18 deletions(-) diff --git a/lib/provider/proxy_playlist/proxy_playlist_provider.dart b/lib/provider/proxy_playlist/proxy_playlist_provider.dart index ca0fb308..0811fe35 100644 --- a/lib/provider/proxy_playlist/proxy_playlist_provider.dart +++ b/lib/provider/proxy_playlist/proxy_playlist_provider.dart @@ -144,8 +144,7 @@ class ProxyPlaylistNotifier extends PersistedStateNotifier } } catch (e, stackTrace) { // Removing tracks that were not found to avoid queue interruption - // TODO: Add a flag to enable/disable skip not found tracks - if (e is TrackNotFoundException) { + if (e is TrackNotFoundError) { final oldTrack = mapSourcesToTracks([audioPlayer.nextSource!]).firstOrNull; await removeTrack(oldTrack!.id!); diff --git a/lib/services/sourced_track/exceptions.dart b/lib/services/sourced_track/exceptions.dart index 517d6ba4..85bc5b27 100644 --- a/lib/services/sourced_track/exceptions.dart +++ b/lib/services/sourced_track/exceptions.dart @@ -1,7 +1,12 @@ import 'package:spotify/spotify.dart'; -class TrackNotFoundException implements Exception { - factory TrackNotFoundException(Track track) { - throw Exception("Failed to find any results for ${track.name}"); +class TrackNotFoundError extends Error { + final Track track; + + TrackNotFoundError(this.track); + + @override + String toString() { + return '[TrackNotFoundError] ${track.name} - ${track.artists?.map((e) => e.name).join(", ")}'; } } diff --git a/lib/services/sourced_track/sourced_track.dart b/lib/services/sourced_track/sourced_track.dart index 3ceafbf7..c73f3078 100644 --- a/lib/services/sourced_track/sourced_track.dart +++ b/lib/services/sourced_track/sourced_track.dart @@ -1,15 +1,21 @@ +import 'dart:io'; + +import 'package:http/http.dart'; import 'package:collection/collection.dart'; +import 'package:dio/dio.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:spotify/spotify.dart'; import 'package:spotube/provider/user_preferences/user_preferences_provider.dart'; import 'package:spotube/provider/user_preferences/user_preferences_state.dart'; import 'package:spotube/services/sourced_track/enums.dart'; +import 'package:spotube/services/sourced_track/exceptions.dart'; import 'package:spotube/services/sourced_track/models/source_info.dart'; import 'package:spotube/services/sourced_track/models/source_map.dart'; import 'package:spotube/services/sourced_track/sources/jiosaavn.dart'; import 'package:spotube/services/sourced_track/sources/piped.dart'; import 'package:spotube/services/sourced_track/sources/youtube.dart'; import 'package:spotube/utils/service_utils.dart'; +import 'package:youtube_explode_dart/youtube_explode_dart.dart'; abstract class SourcedTrack extends Track { final SourceMap source; @@ -101,9 +107,8 @@ abstract class SourcedTrack extends Track { required Track track, required Ref ref, }) async { + final preferences = ref.read(userPreferencesProvider); try { - final preferences = ref.read(userPreferencesProvider); - return switch (preferences.audioSource) { AudioSource.piped => await PipedSourcedTrack.fetchFromTrack(track: track, ref: ref), @@ -112,8 +117,35 @@ abstract class SourcedTrack extends Track { AudioSource.jiosaavn => await JioSaavnSourcedTrack.fetchFromTrack(track: track, ref: ref), }; + } on TrackNotFoundError catch (_) { + return switch (preferences.audioSource) { + AudioSource.piped || + AudioSource.youtube => + await JioSaavnSourcedTrack.fetchFromTrack( + track: track, + ref: ref, + weakMatch: true, + ), + AudioSource.jiosaavn => + await PipedSourcedTrack.fetchFromTrack(track: track, ref: ref), + }; + } on HttpClientClosedException catch (_) { + return await PipedSourcedTrack.fetchFromTrack(track: track, ref: ref); } catch (e) { - return YoutubeSourcedTrack.fetchFromTrack(track: track, ref: ref); + if (e is DioException || e is ClientException || e is SocketException) { + if (preferences.audioSource == AudioSource.jiosaavn) { + return await JioSaavnSourcedTrack.fetchFromTrack( + track: track, + ref: ref, + weakMatch: true, + ); + } + return await JioSaavnSourcedTrack.fetchFromTrack( + track: track, + ref: ref, + ); + } + rethrow; } } diff --git a/lib/services/sourced_track/sources/jiosaavn.dart b/lib/services/sourced_track/sources/jiosaavn.dart index 7455f4d7..f731de6c 100644 --- a/lib/services/sourced_track/sources/jiosaavn.dart +++ b/lib/services/sourced_track/sources/jiosaavn.dart @@ -37,15 +37,17 @@ class JioSaavnSourcedTrack extends SourcedTrack { static Future fetchFromTrack({ required Track track, required Ref ref, + bool weakMatch = false, }) async { final cachedSource = await SourceMatch.box.get(track.id); if (cachedSource == null || cachedSource.sourceType != SourceType.jiosaavn) { - final siblings = await fetchSiblings(ref: ref, track: track); + final siblings = + await fetchSiblings(ref: ref, track: track, weakMatch: weakMatch); if (siblings.isEmpty) { - throw TrackNotFoundException(track); + throw TrackNotFoundError(track); } await SourceMatch.box.put( @@ -119,6 +121,7 @@ class JioSaavnSourcedTrack extends SourcedTrack { static Future> fetchSiblings({ required Track track, required Ref ref, + bool weakMatch = false, }) async { final query = SourcedTrack.getSearchTerm(track); @@ -126,9 +129,12 @@ class JioSaavnSourcedTrack extends SourcedTrack { await jiosaavnClient.search.songs(query, limit: 20); final trackArtistNames = track.artists?.map((ar) => ar.name).toList(); - return results + + final matchedResults = results .where( (s) { + s.name?.unescapeHtml().contains(track.name!) ?? false; + final sameName = s.name?.unescapeHtml() == track.name; final artistNames = [ s.primaryArtists, @@ -139,12 +145,27 @@ class JioSaavnSourcedTrack extends SourcedTrack { (artist) => trackArtistNames?.any((ar) => artist == ar) ?? false, ); + if (weakMatch) { + final containsName = + s.name?.unescapeHtml().contains(track.name!) ?? false; + final containsPrimaryArtist = s.primaryArtists + .unescapeHtml() + .contains(trackArtistNames?.first ?? ""); + + return containsName && containsPrimaryArtist; + } return sameName && sameArtists; }, ) .map(toSiblingType) .toList(); + + if (weakMatch && matchedResults.isEmpty) { + return results.map(toSiblingType).toList(); + } + + return matchedResults; } @override diff --git a/lib/services/sourced_track/sources/piped.dart b/lib/services/sourced_track/sources/piped.dart index 8a1ec1bc..1eec8549 100644 --- a/lib/services/sourced_track/sources/piped.dart +++ b/lib/services/sourced_track/sources/piped.dart @@ -55,7 +55,7 @@ class PipedSourcedTrack extends SourcedTrack { if (cachedSource == null) { final siblings = await fetchSiblings(ref: ref, track: track); if (siblings.isEmpty) { - throw TrackNotFoundException(track); + throw TrackNotFoundError(track); } await SourceMatch.box.put( @@ -160,13 +160,16 @@ class PipedSourcedTrack extends SourcedTrack { final query = SourcedTrack.getSearchTerm(track); final PipedSearchResult(items: searchResults) = await pipedClient.search( - "$query - Topic", + query, preference.searchMode == SearchMode.youtube ? PipedFilter.video : PipedFilter.musicSongs, ); - final isYouTubeMusic = preference.searchMode == SearchMode.youtubeMusic; + // when falling back to piped API make sure to use the YouTube mode + final isYouTubeMusic = preference.audioSource != AudioSource.piped + ? false + : preference.searchMode == SearchMode.youtubeMusic; if (isYouTubeMusic) { final artists = (track.artists ?? []) diff --git a/lib/services/sourced_track/sources/youtube.dart b/lib/services/sourced_track/sources/youtube.dart index f363937c..d27510e4 100644 --- a/lib/services/sourced_track/sources/youtube.dart +++ b/lib/services/sourced_track/sources/youtube.dart @@ -48,7 +48,7 @@ class YoutubeSourcedTrack extends SourcedTrack { if (cachedSource == null || cachedSource.sourceType != SourceType.youtube) { final siblings = await fetchSiblings(ref: ref, track: track); if (siblings.isEmpty) { - throw TrackNotFoundException(track); + throw TrackNotFoundError(track); } await SourceMatch.box.put( diff --git a/pubspec.lock b/pubspec.lock index 0d1b2993..0050a745 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -1619,10 +1619,10 @@ packages: dependency: "direct main" description: name: piped_client - sha256: "8b96e1f9d8533c1da7eff7fbbd4bf188256fc76a20900d378b52be09418ea771" + sha256: "87b04b2ebf4e008cfbb0ac85e9920ab3741f5aa697be2dd44919658a3297a4bc" url: "https://pub.dev" source: hosted - version: "0.1.0" + version: "0.1.1" platform: dependency: transitive description: diff --git a/pubspec.yaml b/pubspec.yaml index d3fb5630..21175930 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -76,7 +76,7 @@ dependencies: path: ^1.8.0 path_provider: ^2.0.8 permission_handler: ^11.0.1 - piped_client: ^0.1.0 + piped_client: ^0.1.1 popover: ^0.2.6+3 scrobblenaut: git: diff --git a/untranslated_messages.json b/untranslated_messages.json index 4240c8c0..e4e45624 100644 --- a/untranslated_messages.json +++ b/untranslated_messages.json @@ -77,6 +77,7 @@ ], "nl": [ + "audio_source", "start_a_radio", "how_to_start_radio", "replace_queue_question", From badd52223af8dfd0d34714a76a5f6bd28dca2dca Mon Sep 17 00:00:00 2001 From: Kingkor Roy Tirtho Date: Sat, 17 Feb 2024 22:07:32 +0600 Subject: [PATCH 141/195] chore: use piped_client git version to fix search issue --- lib/services/sourced_track/sources/piped.dart | 3 ++- pubspec.lock | 9 +++++---- pubspec.yaml | 4 +++- 3 files changed, 10 insertions(+), 6 deletions(-) diff --git a/lib/services/sourced_track/sources/piped.dart b/lib/services/sourced_track/sources/piped.dart index 1eec8549..75f83125 100644 --- a/lib/services/sourced_track/sources/piped.dart +++ b/lib/services/sourced_track/sources/piped.dart @@ -157,12 +157,13 @@ class PipedSourcedTrack extends SourcedTrack { }) async { final pipedClient = ref.read(pipedProvider); final preference = ref.read(userPreferencesProvider); + final query = SourcedTrack.getSearchTerm(track); final PipedSearchResult(items: searchResults) = await pipedClient.search( query, preference.searchMode == SearchMode.youtube - ? PipedFilter.video + ? PipedFilter.videos : PipedFilter.musicSongs, ); diff --git a/pubspec.lock b/pubspec.lock index 0050a745..03ea66a1 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -1618,10 +1618,11 @@ packages: piped_client: dependency: "direct main" description: - name: piped_client - sha256: "87b04b2ebf4e008cfbb0ac85e9920ab3741f5aa697be2dd44919658a3297a4bc" - url: "https://pub.dev" - source: hosted + path: "." + ref: HEAD + resolved-ref: "64631732eefe3d93889756dc2e4ff5c8523ed763" + url: "https://github.com/KRTirtho/piped_client.git" + source: git version: "0.1.1" platform: dependency: transitive diff --git a/pubspec.yaml b/pubspec.yaml index 21175930..a9144845 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -76,7 +76,9 @@ dependencies: path: ^1.8.0 path_provider: ^2.0.8 permission_handler: ^11.0.1 - piped_client: ^0.1.1 + piped_client: + git: + url: https://github.com/KRTirtho/piped_client.git popover: ^0.2.6+3 scrobblenaut: git: From e964f61d38cb303e3d3fd60c866414f57207181c Mon Sep 17 00:00:00 2001 From: Kingkor Roy Tirtho Date: Sat, 17 Feb 2024 22:22:00 +0600 Subject: [PATCH 142/195] fix: track loading when not found in Youtube --- .../sourced_track/sources/youtube.dart | 25 ++++++++++++++----- 1 file changed, 19 insertions(+), 6 deletions(-) diff --git a/lib/services/sourced_track/sources/youtube.dart b/lib/services/sourced_track/sources/youtube.dart index d27510e4..5f75c4db 100644 --- a/lib/services/sourced_track/sources/youtube.dart +++ b/lib/services/sourced_track/sources/youtube.dart @@ -1,5 +1,6 @@ import 'package:collection/collection.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; +import 'package:http/http.dart'; import 'package:spotify/spotify.dart'; import 'package:spotube/models/source_match.dart'; import 'package:spotube/services/sourced_track/enums.dart'; @@ -70,9 +71,14 @@ class YoutubeSourcedTrack extends SourcedTrack { ); } final item = await youtubeClient.videos.get(cachedSource.sourceId); - final manifest = await youtubeClient.videos.streamsClient.getManifest( - cachedSource.sourceId, - ); + final manifest = await youtubeClient.videos.streamsClient + .getManifest( + cachedSource.sourceId, + ) + .timeout( + const Duration(seconds: 5), + onTimeout: () => throw ClientException("Timeout"), + ); return YoutubeSourcedTrack( ref: ref, siblings: [], @@ -125,7 +131,10 @@ class YoutubeSourcedTrack extends SourcedTrack { SourceMap? sourceMap; if (index == 0) { final manifest = - await youtubeClient.videos.streamsClient.getManifest(item.id); + await youtubeClient.videos.streamsClient.getManifest(item.id).timeout( + const Duration(seconds: 5), + onTimeout: () => throw ClientException("Timeout"), + ); sourceMap = toSourceMap(manifest); } @@ -243,8 +252,12 @@ class YoutubeSourcedTrack extends SourcedTrack { final newSiblings = siblings.where((s) => s.id != sibling.id).toList() ..insert(0, sourceInfo); - final manifest = - await youtubeClient.videos.streamsClient.getManifest(newSourceInfo.id); + final manifest = await youtubeClient.videos.streamsClient + .getManifest(newSourceInfo.id) + .timeout( + const Duration(seconds: 5), + onTimeout: () => throw ClientException("Timeout"), + ); await SourceMatch.box.put( id!, From 9f9244062a39759aa0ce28d2d5f7c8fa53d73003 Mon Sep 17 00:00:00 2001 From: Kingkor Roy Tirtho Date: Sat, 17 Feb 2024 23:01:14 +0600 Subject: [PATCH 143/195] feat(playlist): show confirmation before deleting user playlist #1222 --- .../sections/header/header_actions.dart | 6 +- .../shared/tracks_view/track_view_props.dart | 4 +- lib/l10n/app_en.arb | 4 +- lib/pages/playlist/playlist.dart | 20 +++++- untranslated_messages.json | 72 ++++++++++++++----- 5 files changed, 81 insertions(+), 25 deletions(-) diff --git a/lib/components/shared/tracks_view/sections/header/header_actions.dart b/lib/components/shared/tracks_view/sections/header/header_actions.dart index b050c199..75aa3f61 100644 --- a/lib/components/shared/tracks_view/sections/header/header_actions.dart +++ b/lib/components/shared/tracks_view/sections/header/header_actions.dart @@ -70,9 +70,9 @@ class TrackViewHeaderActions extends HookConsumerWidget { tooltip: props.isLiked ? context.l10n.remove_from_favorites : context.l10n.save_as_favorite, - onPressed: () { - props.onHeart?.call(); - if (isUserPlaylist) { + onPressed: () async { + final shouldPop = await props.onHeart?.call(); + if (isUserPlaylist && shouldPop == true && context.mounted) { context.pop(); } }, diff --git a/lib/components/shared/tracks_view/track_view_props.dart b/lib/components/shared/tracks_view/track_view_props.dart index 1c6c7647..21bbaec7 100644 --- a/lib/components/shared/tracks_view/track_view_props.dart +++ b/lib/components/shared/tracks_view/track_view_props.dart @@ -1,3 +1,5 @@ +import 'dart:async'; + import 'package:fl_query/fl_query.dart'; import 'package:flutter/material.dart' hide Page; import 'package:spotify/spotify.dart'; @@ -62,7 +64,7 @@ class InheritedTrackView extends InheritedWidget { final String shareUrl; // events - final VoidCallback? onHeart; // if null heart button will hidden + final FutureOr Function()? onHeart; // if null heart button will hidden const InheritedTrackView({ super.key, diff --git a/lib/l10n/app_en.arb b/lib/l10n/app_en.arb index 0628cc43..b1e8331f 100644 --- a/lib/l10n/app_en.arb +++ b/lib/l10n/app_en.arb @@ -290,5 +290,7 @@ "start_a_radio": "Start a Radio", "how_to_start_radio": "How do you want to start the radio?", "replace_queue_question": "Do you want to replace the current queue or append to it?", - "endless_playback": "Endless Playback" + "endless_playback": "Endless Playback", + "delete_playlist": "Delete Playlist", + "delete_playlist_confirmation": "Are you sure you want to delete this playlist?" } \ No newline at end of file diff --git a/lib/pages/playlist/playlist.dart b/lib/pages/playlist/playlist.dart index 29601a09..89a279ab 100644 --- a/lib/pages/playlist/playlist.dart +++ b/lib/pages/playlist/playlist.dart @@ -2,8 +2,11 @@ import 'package:flutter/material.dart' hide Page; import 'package:flutter_hooks/flutter_hooks.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:spotify/spotify.dart'; +import 'package:spotube/components/shared/dialogs/prompt_dialog.dart'; +import 'package:spotube/components/shared/tracks_view/sections/body/use_is_user_playlist.dart'; import 'package:spotube/components/shared/tracks_view/track_view.dart'; import 'package:spotube/components/shared/tracks_view/track_view_props.dart'; +import 'package:spotube/extensions/context.dart'; import 'package:spotube/extensions/infinite_query.dart'; import 'package:spotube/provider/spotify_provider.dart'; import 'package:spotube/services/mutations/mutations.dart'; @@ -45,6 +48,8 @@ class PlaylistPage extends HookConsumerWidget { ], ); + final isUserPlaylist = useIsUserPlaylist(ref, playlist.id!); + return InheritedTrackView( collectionId: playlist.id!, image: TypeConversionUtils.image_X_UrlString( @@ -72,9 +77,20 @@ class PlaylistPage extends HookConsumerWidget { shareUrl: playlist.externalUrls?.spotify ?? "", onHeart: () async { if (!isLikedQuery.hasData || togglePlaylistLike.isMutating) { - return; + return false; } - await togglePlaylistLike.mutate(isLikedQuery.data!); + final confirmed = isUserPlaylist + ? await showPromptDialog( + context: context, + title: context.l10n.delete_playlist, + message: context.l10n.delete_playlist_confirmation, + ) + : true; + if (confirmed) { + await togglePlaylistLike.mutate(isLikedQuery.data!); + return isUserPlaylist; + } + return null; }, child: const TrackView(), ); diff --git a/untranslated_messages.json b/untranslated_messages.json index e4e45624..4525caeb 100644 --- a/untranslated_messages.json +++ b/untranslated_messages.json @@ -3,77 +3,99 @@ "start_a_radio", "how_to_start_radio", "replace_queue_question", - "endless_playback" + "endless_playback", + "delete_playlist", + "delete_playlist_confirmation" ], "bn": [ "start_a_radio", "how_to_start_radio", "replace_queue_question", - "endless_playback" + "endless_playback", + "delete_playlist", + "delete_playlist_confirmation" ], "ca": [ "start_a_radio", "how_to_start_radio", "replace_queue_question", - "endless_playback" + "endless_playback", + "delete_playlist", + "delete_playlist_confirmation" ], "de": [ "start_a_radio", "how_to_start_radio", "replace_queue_question", - "endless_playback" + "endless_playback", + "delete_playlist", + "delete_playlist_confirmation" ], "es": [ "start_a_radio", "how_to_start_radio", "replace_queue_question", - "endless_playback" + "endless_playback", + "delete_playlist", + "delete_playlist_confirmation" ], "fa": [ "start_a_radio", "how_to_start_radio", "replace_queue_question", - "endless_playback" + "endless_playback", + "delete_playlist", + "delete_playlist_confirmation" ], "fr": [ "start_a_radio", "how_to_start_radio", "replace_queue_question", - "endless_playback" + "endless_playback", + "delete_playlist", + "delete_playlist_confirmation" ], "hi": [ "start_a_radio", "how_to_start_radio", "replace_queue_question", - "endless_playback" + "endless_playback", + "delete_playlist", + "delete_playlist_confirmation" ], "it": [ "start_a_radio", "how_to_start_radio", "replace_queue_question", - "endless_playback" + "endless_playback", + "delete_playlist", + "delete_playlist_confirmation" ], "ja": [ "start_a_radio", "how_to_start_radio", "replace_queue_question", - "endless_playback" + "endless_playback", + "delete_playlist", + "delete_playlist_confirmation" ], "ne": [ "start_a_radio", "how_to_start_radio", "replace_queue_question", - "endless_playback" + "endless_playback", + "delete_playlist", + "delete_playlist_confirmation" ], "nl": [ @@ -81,48 +103,62 @@ "start_a_radio", "how_to_start_radio", "replace_queue_question", - "endless_playback" + "endless_playback", + "delete_playlist", + "delete_playlist_confirmation" ], "pl": [ "start_a_radio", "how_to_start_radio", "replace_queue_question", - "endless_playback" + "endless_playback", + "delete_playlist", + "delete_playlist_confirmation" ], "pt": [ "start_a_radio", "how_to_start_radio", "replace_queue_question", - "endless_playback" + "endless_playback", + "delete_playlist", + "delete_playlist_confirmation" ], "ru": [ "start_a_radio", "how_to_start_radio", "replace_queue_question", - "endless_playback" + "endless_playback", + "delete_playlist", + "delete_playlist_confirmation" ], "tr": [ "start_a_radio", "how_to_start_radio", "replace_queue_question", - "endless_playback" + "endless_playback", + "delete_playlist", + "delete_playlist_confirmation" ], "uk": [ "start_a_radio", "how_to_start_radio", "replace_queue_question", - "endless_playback" + "endless_playback", + "delete_playlist", + "delete_playlist_confirmation" ], "zh": [ "start_a_radio", "how_to_start_radio", "replace_queue_question", - "endless_playback" + "endless_playback", + "delete_playlist", + "delete_playlist_confirmation" ] } From 86123456f2ff577921cf62cffca180427dfe1dd5 Mon Sep 17 00:00:00 2001 From: Kingkor Roy Tirtho Date: Sun, 18 Feb 2024 21:11:28 +0600 Subject: [PATCH 144/195] fix: cleanTitle removing feat and ft from words instead of whole words --- lib/utils/service_utils.dart | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/utils/service_utils.dart b/lib/utils/service_utils.dart index 9e3b5893..4d9d1e67 100644 --- a/lib/utils/service_utils.dart +++ b/lib/utils/service_utils.dart @@ -53,9 +53,9 @@ abstract class ServiceUtils { return "$title ${artists.map((e) => e.replaceAll(",", " ")).join(", ")}" .toLowerCase() - .replaceAll(RegExp(" *\\[[^\\]]*]"), '') - .replaceAll(RegExp("feat.|ft."), '') - .replaceAll(RegExp("\\s+"), ' ') + .replaceAll(RegExp(r"\s*\[[^\]]*]"), ' ') + .replaceAll(RegExp(r"\sfeat\.|\sft\."), ' ') + .replaceAll(RegExp(r"\s+"), ' ') .trim(); } From c3289a0ba4e7de094a15246677ffcb940504ebde Mon Sep 17 00:00:00 2001 From: Kingkor Roy Tirtho Date: Sun, 18 Feb 2024 23:02:14 +0600 Subject: [PATCH 145/195] fix(android): pressing back button in any other tab other than home exits the app --- lib/pages/home/home.dart | 2 - lib/pages/root/root_app.dart | 73 ++++++++++++++++++++---------------- pubspec.lock | 4 +- pubspec.yaml | 2 +- 4 files changed, 44 insertions(+), 37 deletions(-) diff --git a/lib/pages/home/home.dart b/lib/pages/home/home.dart index dbec0564..312ca7f9 100644 --- a/lib/pages/home/home.dart +++ b/lib/pages/home/home.dart @@ -1,6 +1,4 @@ -import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; -import 'package:flutter/widgets.dart'; import 'package:flutter_desktop_tools/flutter_desktop_tools.dart'; import 'package:flutter_hooks/flutter_hooks.dart'; import 'package:gap/gap.dart'; diff --git a/lib/pages/root/root_app.dart b/lib/pages/root/root_app.dart index 2ff49737..aaf3e30a 100644 --- a/lib/pages/root/root_app.dart +++ b/lib/pages/root/root_app.dart @@ -162,38 +162,47 @@ class RootApp extends HookConsumerWidget { } } - return Scaffold( - body: Sidebar( - selectedIndex: rootPaths[location], - onSelectedIndexChanged: onSelectIndexChanged, - child: child, - ), - extendBody: true, - drawerScrimColor: Colors.transparent, - endDrawer: DesktopTools.platform.isDesktop - ? Container( - constraints: const BoxConstraints(maxWidth: 800), - decoration: BoxDecoration( - boxShadow: theme.brightness == Brightness.light - ? null - : kElevationToShadow[8], - ), - margin: const EdgeInsets.only( - top: 40, - bottom: 100, - ), - child: const PlayerQueue(floating: true), - ) - : null, - bottomNavigationBar: Column( - mainAxisSize: MainAxisSize.min, - children: [ - BottomPlayer(), - SpotubeNavigationBar( - selectedIndex: rootPaths[location], - onSelectedIndexChanged: onSelectIndexChanged, - ), - ], + return WillPopScope( + onWillPop: () async { + if (rootPaths[location] != 0) { + onSelectIndexChanged(0); + return false; + } + return true; + }, + child: Scaffold( + body: Sidebar( + selectedIndex: rootPaths[location], + onSelectedIndexChanged: onSelectIndexChanged, + child: child, + ), + extendBody: true, + drawerScrimColor: Colors.transparent, + endDrawer: DesktopTools.platform.isDesktop + ? Container( + constraints: const BoxConstraints(maxWidth: 800), + decoration: BoxDecoration( + boxShadow: theme.brightness == Brightness.light + ? null + : kElevationToShadow[8], + ), + margin: const EdgeInsets.only( + top: 40, + bottom: 100, + ), + child: const PlayerQueue(floating: true), + ) + : null, + bottomNavigationBar: Column( + mainAxisSize: MainAxisSize.min, + children: [ + BottomPlayer(), + SpotubeNavigationBar( + selectedIndex: rootPaths[location], + onSelectedIndexChanged: onSelectIndexChanged, + ), + ], + ), ), ); } diff --git a/pubspec.lock b/pubspec.lock index 03ea66a1..b9268b56 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -1014,10 +1014,10 @@ packages: dependency: "direct main" description: name: go_router - sha256: "3b40e751eaaa855179b416974d59d29669e750d2e50fcdb2b37f1cb0ca8c803a" + sha256: c5fa45fa502ee880839e3b2152d987c44abae26d064a2376d4aad434cf0f7b15 url: "https://pub.dev" source: hosted - version: "13.0.1" + version: "12.1.3" google_fonts: dependency: "direct main" description: diff --git a/pubspec.yaml b/pubspec.yaml index a9144845..82377d08 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -55,7 +55,7 @@ dependencies: flutter_svg: ^1.1.6 form_validator: ^2.1.1 fuzzywuzzy: ^1.1.6 - go_router: ^13.0.1 + go_router: 12.1.3 # Stuck on this https://github.com/flutter/flutter/issues/140869 google_fonts: ^6.1.0 hive: ^2.2.3 hive_flutter: ^1.1.0 From 3294f657fe8a03b18d9be8974968b6508465963d Mon Sep 17 00:00:00 2001 From: Kingkor Roy Tirtho Date: Sun, 18 Feb 2024 23:05:43 +0600 Subject: [PATCH 146/195] fix(android): system back button in player page exits the app --- lib/components/player/player.dart | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/lib/components/player/player.dart b/lib/components/player/player.dart index 33283c3e..298458b5 100644 --- a/lib/components/player/player.dart +++ b/lib/components/player/player.dart @@ -94,10 +94,10 @@ class PlayerView extends HookConsumerWidget { final topPadding = MediaQueryData.fromView(View.of(context)).padding.top; - return PopScope( - canPop: false, - onPopInvoked: (didPop) async { - panelController.close(); + return WillPopScope( + onWillPop: () async { + await panelController.close(); + return false; }, child: IconTheme( data: theme.iconTheme.copyWith(color: bodyTextColor), From 6f8271f5e9394cb4053e41dd222aa2844c34d609 Mon Sep 17 00:00:00 2001 From: Kuyumee <69566792+Kuyumee@users.noreply.github.com> Date: Mon, 19 Feb 2024 01:35:42 +0800 Subject: [PATCH 147/195] feat: Sort by Duration (#1238) --- lib/components/library/user_local_tracks.dart | 5 ++-- .../shared/sort_tracks_dropdown.dart | 5 ++++ lib/l10n/app_en.arb | 1 + lib/utils/service_utils.dart | 24 +++++++++---------- 4 files changed, 21 insertions(+), 14 deletions(-) diff --git a/lib/components/library/user_local_tracks.dart b/lib/components/library/user_local_tracks.dart index f4e782d9..095e6e97 100644 --- a/lib/components/library/user_local_tracks.dart +++ b/lib/components/library/user_local_tracks.dart @@ -50,10 +50,11 @@ enum SortBy { none, ascending, descending, - artist, - album, newest, oldest, + duration, + artist, + album, } final localTracksProvider = FutureProvider>((ref) async { diff --git a/lib/components/shared/sort_tracks_dropdown.dart b/lib/components/shared/sort_tracks_dropdown.dart index 0547beb0..ab35b2e3 100644 --- a/lib/components/shared/sort_tracks_dropdown.dart +++ b/lib/components/shared/sort_tracks_dropdown.dart @@ -48,6 +48,11 @@ class SortTracksDropdown extends StatelessWidget { enabled: value != SortBy.oldest, title: Text(context.l10n.sort_oldest), ), + PopSheetEntry( + value: SortBy.duration, + enabled: value != SortBy.duration, + title: Text(context.l10n.sort_duration), + ), PopSheetEntry( value: SortBy.artist, enabled: value != SortBy.artist, diff --git a/lib/l10n/app_en.arb b/lib/l10n/app_en.arb index b1e8331f..244d75e2 100644 --- a/lib/l10n/app_en.arb +++ b/lib/l10n/app_en.arb @@ -41,6 +41,7 @@ "sort_z_a": "Sort by Z-A", "sort_artist": "Sort by Artist", "sort_album": "Sort by Album", + "sort_duration": "Sort by Duration", "sort_tracks": "Sort Tracks", "currently_downloading": "Currently Downloading ({tracks_length})", "cancel_all": "Cancel All", diff --git a/lib/utils/service_utils.dart b/lib/utils/service_utils.dart index 4d9d1e67..60c77e59 100644 --- a/lib/utils/service_utils.dart +++ b/lib/utils/service_utils.dart @@ -292,24 +292,24 @@ abstract class ServiceUtils { return List.from(tracks) ..sort((a, b) { switch (sortBy) { - case SortBy.album: - return a.album?.name?.compareTo(b.album?.name ?? "") ?? 0; - case SortBy.artist: - return a.artists?.first.name - ?.compareTo(b.artists?.first.name ?? "") ?? - 0; case SortBy.ascending: return a.name?.compareTo(b.name ?? "") ?? 0; - case SortBy.oldest: - final aDate = parseSpotifyAlbumDate(a.album); - final bDate = parseSpotifyAlbumDate(b.album); - return aDate.compareTo(bDate); + case SortBy.descending: + return b.name?.compareTo(a.name ?? "") ?? 0; case SortBy.newest: final aDate = parseSpotifyAlbumDate(a.album); final bDate = parseSpotifyAlbumDate(b.album); return bDate.compareTo(aDate); - case SortBy.descending: - return b.name?.compareTo(a.name ?? "") ?? 0; + case SortBy.oldest: + final aDate = parseSpotifyAlbumDate(a.album); + final bDate = parseSpotifyAlbumDate(b.album); + return aDate.compareTo(bDate); + case SortBy.duration: + return a.durationMs?.compareTo(b.durationMs ?? 0) ?? 0; + case SortBy.artist: + return a.artists?.first.name?.compareTo(b.artists?.first.name ?? "") ?? 0; + case SortBy.album: + return a.album?.name?.compareTo(b.album?.name ?? "") ?? 0; default: return 0; } From ba69496dcc9a1b7f6ea4e104e71764a854d27f1f Mon Sep 17 00:00:00 2001 From: olivier2 Date: Sun, 18 Feb 2024 13:47:10 -0500 Subject: [PATCH 148/195] feat(windows): Install Visual C++ 2015-2022 Redistributable if missing when installing --- Makefile | 1 + windows/packaging/exe/inno_setup.iss | 76 ++++++++++++++++++++++++++ windows/packaging/exe/make_config.yaml | 1 + 3 files changed, 78 insertions(+) create mode 100644 windows/packaging/exe/inno_setup.iss diff --git a/Makefile b/Makefile index c2678d2e..1add46b0 100644 --- a/Makefile +++ b/Makefile @@ -28,6 +28,7 @@ publishaur: innoinstall: powershell curl -o build\installer.exe http://files.jrsoftware.org/is/6/innosetup-${INNO_VERSION}.exe + powershell git clone https://github.com/DomGries/InnoDependencyInstaller.git build\inno-depend powershell build\installer.exe /verysilent /allusers /dir=build\iscc inno: diff --git a/windows/packaging/exe/inno_setup.iss b/windows/packaging/exe/inno_setup.iss new file mode 100644 index 00000000..64acc2b3 --- /dev/null +++ b/windows/packaging/exe/inno_setup.iss @@ -0,0 +1,76 @@ +; https://github.com/DomGries/InnoDependencyInstaller +; requires netcorecheck.exe and netcorecheck_x64.exe (see CodeDependencies.iss) +; path is relative to dist\{VERSION} directory +#define public Dependency_Path_NetCoreCheck "..\..\build\inno-depend\dependencies\" +#include "..\..\build\inno-depend\CodeDependencies.iss" + +[Setup] +AppId={{APP_ID}} +AppVersion={{APP_VERSION}} +AppName={{DISPLAY_NAME}} +AppPublisher={{PUBLISHER_NAME}} +AppPublisherURL={{PUBLISHER_URL}} +AppSupportURL={{PUBLISHER_URL}} +AppUpdatesURL={{PUBLISHER_URL}} +DefaultDirName={{INSTALL_DIR_NAME}} +DisableProgramGroupPage=yes +OutputDir=. +OutputBaseFilename={{OUTPUT_BASE_FILENAME}} +Compression=lzma +SolidCompression=yes +SetupIconFile={{SETUP_ICON_FILE}} +WizardStyle=modern +PrivilegesRequired={{PRIVILEGES_REQUIRED}} +ArchitecturesAllowed=x64 +ArchitecturesInstallIn64BitMode=x64 + +[Languages] +{% for locale in LOCALES %} +{% if locale == 'en' %}Name: "english"; MessagesFile: "compiler:Default.isl"{% endif %} +{% if locale == 'hy' %}Name: "armenian"; MessagesFile: "compiler:Languages\\Armenian.isl"{% endif %} +{% if locale == 'bg' %}Name: "bulgarian"; MessagesFile: "compiler:Languages\\Bulgarian.isl"{% endif %} +{% if locale == 'ca' %}Name: "catalan"; MessagesFile: "compiler:Languages\\Catalan.isl"{% endif %} +{% if locale == 'zh' %}Name: "chinesesimplified"; MessagesFile: "compiler:Languages\\ChineseSimplified.isl"{% endif %} +{% if locale == 'co' %}Name: "corsican"; MessagesFile: "compiler:Languages\\Corsican.isl"{% endif %} +{% if locale == 'cs' %}Name: "czech"; MessagesFile: "compiler:Languages\\Czech.isl"{% endif %} +{% if locale == 'da' %}Name: "danish"; MessagesFile: "compiler:Languages\\Danish.isl"{% endif %} +{% if locale == 'nl' %}Name: "dutch"; MessagesFile: "compiler:Languages\\Dutch.isl"{% endif %} +{% if locale == 'fi' %}Name: "finnish"; MessagesFile: "compiler:Languages\\Finnish.isl"{% endif %} +{% if locale == 'fr' %}Name: "french"; MessagesFile: "compiler:Languages\\French.isl"{% endif %} +{% if locale == 'de' %}Name: "german"; MessagesFile: "compiler:Languages\\German.isl"{% endif %} +{% if locale == 'he' %}Name: "hebrew"; MessagesFile: "compiler:Languages\\Hebrew.isl"{% endif %} +{% if locale == 'is' %}Name: "icelandic"; MessagesFile: "compiler:Languages\\Icelandic.isl"{% endif %} +{% if locale == 'it' %}Name: "italian"; MessagesFile: "compiler:Languages\\Italian.isl"{% endif %} +{% if locale == 'ja' %}Name: "japanese"; MessagesFile: "compiler:Languages\\Japanese.isl"{% endif %} +{% if locale == 'no' %}Name: "norwegian"; MessagesFile: "compiler:Languages\\Norwegian.isl"{% endif %} +{% if locale == 'pl' %}Name: "polish"; MessagesFile: "compiler:Languages\\Polish.isl"{% endif %} +{% if locale == 'pt' %}Name: "portuguese"; MessagesFile: "compiler:Languages\\Portuguese.isl"{% endif %} +{% if locale == 'ru' %}Name: "russian"; MessagesFile: "compiler:Languages\\Russian.isl"{% endif %} +{% if locale == 'sk' %}Name: "slovak"; MessagesFile: "compiler:Languages\\Slovak.isl"{% endif %} +{% if locale == 'sl' %}Name: "slovenian"; MessagesFile: "compiler:Languages\\Slovenian.isl"{% endif %} +{% if locale == 'es' %}Name: "spanish"; MessagesFile: "compiler:Languages\\Spanish.isl"{% endif %} +{% if locale == 'tr' %}Name: "turkish"; MessagesFile: "compiler:Languages\\Turkish.isl"{% endif %} +{% if locale == 'uk' %}Name: "ukrainian"; MessagesFile: "compiler:Languages\\Ukrainian.isl"{% endif %} +{% endfor %} + +[Tasks] +Name: "desktopicon"; Description: "{cm:CreateDesktopIcon}"; GroupDescription: "{cm:AdditionalIcons}"; Flags: {% if CREATE_DESKTOP_ICON != true %}unchecked{% else %}checkedonce{% endif %} +Name: "launchAtStartup"; Description: "{cm:AutoStartProgram,{{DISPLAY_NAME}}}"; GroupDescription: "{cm:AdditionalIcons}"; Flags: {% if LAUNCH_AT_STARTUP != true %}unchecked{% else %}checkedonce{% endif %} +[Files] +Source: "{{SOURCE_DIR}}\\*"; DestDir: "{app}"; Flags: ignoreversion recursesubdirs createallsubdirs +; NOTE: Don't use "Flags: ignoreversion" on any shared system files + +[Icons] +Name: "{autoprograms}\\{{DISPLAY_NAME}}"; Filename: "{app}\\{{EXECUTABLE_NAME}}" +Name: "{autodesktop}\\{{DISPLAY_NAME}}"; Filename: "{app}\\{{EXECUTABLE_NAME}}"; Tasks: desktopicon +Name: "{userstartup}\\{{DISPLAY_NAME}}"; Filename: "{app}\\{{EXECUTABLE_NAME}}"; WorkingDir: "{app}"; Tasks: launchAtStartup + +[Run] +Filename: "{app}\\{{EXECUTABLE_NAME}}"; Description: "{cm:LaunchProgram,{{DISPLAY_NAME}}}"; Flags: {% if PRIVILEGES_REQUIRED == 'admin' %}runascurrentuser{% endif %} nowait postinstall skipifsilent + +[Code] +function InitializeSetup: Boolean; +begin + Dependency_AddVC2015To2022; + Result := True; +end; \ No newline at end of file diff --git a/windows/packaging/exe/make_config.yaml b/windows/packaging/exe/make_config.yaml index 2f6b352a..97dcd87d 100644 --- a/windows/packaging/exe/make_config.yaml +++ b/windows/packaging/exe/make_config.yaml @@ -4,5 +4,6 @@ publisher_url: https://github.com/KRTirtho/spotube display_name: Spotube create_desktop_icon: true install_dir_name: Spotube +script_template: inno_setup.iss locales: - en From b6d42659b7540438067417f53fae81c6d12572ad Mon Sep 17 00:00:00 2001 From: Kingkor Roy Tirtho Date: Fri, 23 Feb 2024 20:57:35 +0600 Subject: [PATCH 149/195] chore: debug linux tar not getting updated --- .github/workflows/spotube-release-binary.yml | 2 +- macos/Podfile.lock | 2 +- untranslated_messages.json | 18 ++++++++++++++++++ 3 files changed, 20 insertions(+), 2 deletions(-) diff --git a/.github/workflows/spotube-release-binary.yml b/.github/workflows/spotube-release-binary.yml index 3ef0ff61..bfe97328 100644 --- a/.github/workflows/spotube-release-binary.yml +++ b/.github/workflows/spotube-release-binary.yml @@ -190,7 +190,7 @@ jobs: dist/spotube-linux-${{ env.BUILD_VERSION }}-x86_64.tar.xz - name: Debug With SSH When fails - if: ${{ failure() && inputs.debug && inputs.channel == 'nightly' }} + if: ${{ inputs.debug && inputs.channel == 'nightly' }} uses: mxschmitt/action-tmate@v3 with: limit-access-to-actor: true diff --git a/macos/Podfile.lock b/macos/Podfile.lock index 65fe3535..566e8196 100644 --- a/macos/Podfile.lock +++ b/macos/Podfile.lock @@ -143,4 +143,4 @@ SPEC CHECKSUMS: PODFILE CHECKSUM: 353c8bcc5d5b0994e508d035b5431cfe18c1dea7 -COCOAPODS: 1.14.3 +COCOAPODS: 1.15.2 diff --git a/untranslated_messages.json b/untranslated_messages.json index 4525caeb..70a2d0e6 100644 --- a/untranslated_messages.json +++ b/untranslated_messages.json @@ -1,5 +1,6 @@ { "ar": [ + "sort_duration", "start_a_radio", "how_to_start_radio", "replace_queue_question", @@ -9,6 +10,7 @@ ], "bn": [ + "sort_duration", "start_a_radio", "how_to_start_radio", "replace_queue_question", @@ -18,6 +20,7 @@ ], "ca": [ + "sort_duration", "start_a_radio", "how_to_start_radio", "replace_queue_question", @@ -27,6 +30,7 @@ ], "de": [ + "sort_duration", "start_a_radio", "how_to_start_radio", "replace_queue_question", @@ -36,6 +40,7 @@ ], "es": [ + "sort_duration", "start_a_radio", "how_to_start_radio", "replace_queue_question", @@ -45,6 +50,7 @@ ], "fa": [ + "sort_duration", "start_a_radio", "how_to_start_radio", "replace_queue_question", @@ -54,6 +60,7 @@ ], "fr": [ + "sort_duration", "start_a_radio", "how_to_start_radio", "replace_queue_question", @@ -63,6 +70,7 @@ ], "hi": [ + "sort_duration", "start_a_radio", "how_to_start_radio", "replace_queue_question", @@ -72,6 +80,7 @@ ], "it": [ + "sort_duration", "start_a_radio", "how_to_start_radio", "replace_queue_question", @@ -81,6 +90,7 @@ ], "ja": [ + "sort_duration", "start_a_radio", "how_to_start_radio", "replace_queue_question", @@ -90,6 +100,7 @@ ], "ne": [ + "sort_duration", "start_a_radio", "how_to_start_radio", "replace_queue_question", @@ -99,6 +110,7 @@ ], "nl": [ + "sort_duration", "audio_source", "start_a_radio", "how_to_start_radio", @@ -109,6 +121,7 @@ ], "pl": [ + "sort_duration", "start_a_radio", "how_to_start_radio", "replace_queue_question", @@ -118,6 +131,7 @@ ], "pt": [ + "sort_duration", "start_a_radio", "how_to_start_radio", "replace_queue_question", @@ -127,6 +141,7 @@ ], "ru": [ + "sort_duration", "start_a_radio", "how_to_start_radio", "replace_queue_question", @@ -136,6 +151,7 @@ ], "tr": [ + "sort_duration", "start_a_radio", "how_to_start_radio", "replace_queue_question", @@ -145,6 +161,7 @@ ], "uk": [ + "sort_duration", "start_a_radio", "how_to_start_radio", "replace_queue_question", @@ -154,6 +171,7 @@ ], "zh": [ + "sort_duration", "start_a_radio", "how_to_start_radio", "replace_queue_question", From ab08c82c8dd501263049f3adcbd48907ba13e3a9 Mon Sep 17 00:00:00 2001 From: Kingkor Roy Tirtho Date: Sat, 24 Feb 2024 18:38:18 +0600 Subject: [PATCH 150/195] fix: friends list not scrollable with mouse drag --- .github/workflows/spotube-release-binary.yml | 2 +- ios/Flutter/AppFrameworkInfo.plist | 2 +- ios/Podfile | 2 +- ios/Podfile.lock | 6 +-- ios/Runner.xcodeproj/project.pbxproj | 2 +- .../xcshareddata/xcschemes/Runner.xcscheme | 2 +- lib/components/home/sections/friends.dart | 40 ++++++++------ lib/l10n/app_en.arb | 3 +- lib/pages/library/library.dart | 2 +- untranslated_messages.json | 54 ++++++++++++------- 10 files changed, 71 insertions(+), 44 deletions(-) diff --git a/.github/workflows/spotube-release-binary.yml b/.github/workflows/spotube-release-binary.yml index bfe97328..3ef0ff61 100644 --- a/.github/workflows/spotube-release-binary.yml +++ b/.github/workflows/spotube-release-binary.yml @@ -190,7 +190,7 @@ jobs: dist/spotube-linux-${{ env.BUILD_VERSION }}-x86_64.tar.xz - name: Debug With SSH When fails - if: ${{ inputs.debug && inputs.channel == 'nightly' }} + if: ${{ failure() && inputs.debug && inputs.channel == 'nightly' }} uses: mxschmitt/action-tmate@v3 with: limit-access-to-actor: true diff --git a/ios/Flutter/AppFrameworkInfo.plist b/ios/Flutter/AppFrameworkInfo.plist index 9625e105..7c569640 100644 --- a/ios/Flutter/AppFrameworkInfo.plist +++ b/ios/Flutter/AppFrameworkInfo.plist @@ -21,6 +21,6 @@ CFBundleVersion 1.0 MinimumOSVersion - 11.0 + 12.0 diff --git a/ios/Podfile b/ios/Podfile index 5b0d5a2c..bc3dcaa6 100644 --- a/ios/Podfile +++ b/ios/Podfile @@ -1,5 +1,5 @@ # Uncomment this line to define a global platform for your project -# platform :ios, '11.0' +# platform :ios, '12.0' # CocoaPods analytics sends network stats synchronously affecting flutter build latency. ENV['COCOAPODS_DISABLE_STATS'] = 'true' diff --git a/ios/Podfile.lock b/ios/Podfile.lock index 35f3dc18..0b75217f 100644 --- a/ios/Podfile.lock +++ b/ios/Podfile.lock @@ -196,7 +196,7 @@ SPEC CHECKSUMS: DKPhotoGallery: fdfad5125a9fdda9cc57df834d49df790dbb4179 file_picker: 15fd9539e4eb735dc54bae8c0534a7a9511a03de file_selector_ios: 8c25d700d625e1dcdd6599f2d927072f2254647b - Flutter: f04841e97a9d0b0a8025694d0796dd46242b2854 + Flutter: e0871f40cf51350855a761d2e70bf5af5b9b5de7 flutter_inappwebview: acd4fc0f012cefd09015000c241137d82f01ba62 flutter_keyboard_visibility: 0339d06371254c3eb25eeb90ba8d17dca8f9c069 flutter_mailer: 2ef5a67087bc8c6c4cefd04a178bf1ae2c94cd83 @@ -221,6 +221,6 @@ SPEC CHECKSUMS: Toast: 91b396c56ee72a5790816f40d3a94dd357abc196 url_launcher_ios: 08a3dfac5fb39e8759aeb0abbd5d9480f30fc8b4 -PODFILE CHECKSUM: e36c7ad9836dfd8d22934c7680185432a658e28f +PODFILE CHECKSUM: 5129d2e80ab0dfc533f262cedf032011b1dfe4fd -COCOAPODS: 1.14.3 +COCOAPODS: 1.15.2 diff --git a/ios/Runner.xcodeproj/project.pbxproj b/ios/Runner.xcodeproj/project.pbxproj index dbcdd7a6..13f624a4 100644 --- a/ios/Runner.xcodeproj/project.pbxproj +++ b/ios/Runner.xcodeproj/project.pbxproj @@ -406,7 +406,7 @@ 97C146E61CF9000F007C117D /* Project object */ = { isa = PBXProject; attributes = { - LastUpgradeCheck = 1430; + LastUpgradeCheck = 1510; ORGANIZATIONNAME = ""; TargetAttributes = { 97C146ED1CF9000F007C117D = { diff --git a/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme b/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme index a6b826db..5e31d3d3 100644 --- a/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme +++ b/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme @@ -1,6 +1,6 @@ 0, diff --git a/untranslated_messages.json b/untranslated_messages.json index 70a2d0e6..41251435 100644 --- a/untranslated_messages.json +++ b/untranslated_messages.json @@ -6,7 +6,8 @@ "replace_queue_question", "endless_playback", "delete_playlist", - "delete_playlist_confirmation" + "delete_playlist_confirmation", + "local_tracks" ], "bn": [ @@ -16,7 +17,8 @@ "replace_queue_question", "endless_playback", "delete_playlist", - "delete_playlist_confirmation" + "delete_playlist_confirmation", + "local_tracks" ], "ca": [ @@ -26,7 +28,8 @@ "replace_queue_question", "endless_playback", "delete_playlist", - "delete_playlist_confirmation" + "delete_playlist_confirmation", + "local_tracks" ], "de": [ @@ -36,7 +39,8 @@ "replace_queue_question", "endless_playback", "delete_playlist", - "delete_playlist_confirmation" + "delete_playlist_confirmation", + "local_tracks" ], "es": [ @@ -46,7 +50,8 @@ "replace_queue_question", "endless_playback", "delete_playlist", - "delete_playlist_confirmation" + "delete_playlist_confirmation", + "local_tracks" ], "fa": [ @@ -56,7 +61,8 @@ "replace_queue_question", "endless_playback", "delete_playlist", - "delete_playlist_confirmation" + "delete_playlist_confirmation", + "local_tracks" ], "fr": [ @@ -66,7 +72,8 @@ "replace_queue_question", "endless_playback", "delete_playlist", - "delete_playlist_confirmation" + "delete_playlist_confirmation", + "local_tracks" ], "hi": [ @@ -76,7 +83,8 @@ "replace_queue_question", "endless_playback", "delete_playlist", - "delete_playlist_confirmation" + "delete_playlist_confirmation", + "local_tracks" ], "it": [ @@ -86,7 +94,8 @@ "replace_queue_question", "endless_playback", "delete_playlist", - "delete_playlist_confirmation" + "delete_playlist_confirmation", + "local_tracks" ], "ja": [ @@ -96,7 +105,8 @@ "replace_queue_question", "endless_playback", "delete_playlist", - "delete_playlist_confirmation" + "delete_playlist_confirmation", + "local_tracks" ], "ne": [ @@ -106,7 +116,8 @@ "replace_queue_question", "endless_playback", "delete_playlist", - "delete_playlist_confirmation" + "delete_playlist_confirmation", + "local_tracks" ], "nl": [ @@ -117,7 +128,8 @@ "replace_queue_question", "endless_playback", "delete_playlist", - "delete_playlist_confirmation" + "delete_playlist_confirmation", + "local_tracks" ], "pl": [ @@ -127,7 +139,8 @@ "replace_queue_question", "endless_playback", "delete_playlist", - "delete_playlist_confirmation" + "delete_playlist_confirmation", + "local_tracks" ], "pt": [ @@ -137,7 +150,8 @@ "replace_queue_question", "endless_playback", "delete_playlist", - "delete_playlist_confirmation" + "delete_playlist_confirmation", + "local_tracks" ], "ru": [ @@ -147,7 +161,8 @@ "replace_queue_question", "endless_playback", "delete_playlist", - "delete_playlist_confirmation" + "delete_playlist_confirmation", + "local_tracks" ], "tr": [ @@ -157,7 +172,8 @@ "replace_queue_question", "endless_playback", "delete_playlist", - "delete_playlist_confirmation" + "delete_playlist_confirmation", + "local_tracks" ], "uk": [ @@ -167,7 +183,8 @@ "replace_queue_question", "endless_playback", "delete_playlist", - "delete_playlist_confirmation" + "delete_playlist_confirmation", + "local_tracks" ], "zh": [ @@ -177,6 +194,7 @@ "replace_queue_question", "endless_playback", "delete_playlist", - "delete_playlist_confirmation" + "delete_playlist_confirmation", + "local_tracks" ] } From 846ae82084d2241982a52488253e3375bb505de0 Mon Sep 17 00:00:00 2001 From: Kingkor Roy Tirtho Date: Sat, 24 Feb 2024 20:21:09 +0600 Subject: [PATCH 151/195] chore: upgrade flutter version --- .fvm/fvm_config.json | 2 +- .github/workflows/spotube-release-binary.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.fvm/fvm_config.json b/.fvm/fvm_config.json index f1f9ceed..7ca74200 100644 --- a/.fvm/fvm_config.json +++ b/.fvm/fvm_config.json @@ -1,4 +1,4 @@ { - "flutterSdkVersion": "3.16.0", + "flutterSdkVersion": "3.19.1", "flavors": {} } \ No newline at end of file diff --git a/.github/workflows/spotube-release-binary.yml b/.github/workflows/spotube-release-binary.yml index 3ef0ff61..772c9fe2 100644 --- a/.github/workflows/spotube-release-binary.yml +++ b/.github/workflows/spotube-release-binary.yml @@ -26,7 +26,7 @@ on: default: true env: - FLUTTER_VERSION: '3.16.3' + FLUTTER_VERSION: '3.19.1' jobs: windows: From 095587ee84f7d867c69fcf4b09ed608d63478e1e Mon Sep 17 00:00:00 2001 From: powen Date: Sat, 24 Feb 2024 23:22:23 +0800 Subject: [PATCH 152/195] feat: Add iOS background play support (#1166) * Create build-iPA.yml * Update build-iPA.yml * update-iOS - Set AppIcon(same as Android) - Set to correct app name(Sptube -> Spotube) - * update iOS flavors * Update build-iPA.yml * Update spotube-release-binary.yml * rename release-bin iPA filename * update appicon * Update dev-Info.plist * Add iOS background play support https://github.com/KRTirtho/spotube/issues/1061 * background modes edit --- ios/Runner/Info.plist | 118 +++++++++++++++++++++-------------------- ios/dev-Info.plist | 4 ++ ios/nightly-Info.plist | 118 +++++++++++++++++++++-------------------- ios/stable-Info.plist | 118 +++++++++++++++++++++-------------------- pubspec.lock | 68 +++++++++--------------- 5 files changed, 213 insertions(+), 213 deletions(-) diff --git a/ios/Runner/Info.plist b/ios/Runner/Info.plist index 5ba9991f..e1db8f01 100644 --- a/ios/Runner/Info.plist +++ b/ios/Runner/Info.plist @@ -1,66 +1,70 @@ + + CADisableMinimumFrameDurationOnPhone + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleDisplayName + Spotube + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + spotube + CFBundlePackageType + APPL + CFBundleShortVersionString + $(FLUTTER_BUILD_NAME) + CFBundleSignature + ???? + CFBundleVersion + $(FLUTTER_BUILD_NUMBER) + LSRequiresIPhoneOS + + NSAppTransportSecurity - CFBundleDevelopmentRegion - $(DEVELOPMENT_LANGUAGE) - CFBundleDisplayName - Spotube - CFBundleExecutable - $(EXECUTABLE_NAME) - CFBundleIdentifier - $(PRODUCT_BUNDLE_IDENTIFIER) - CFBundleInfoDictionaryVersion - 6.0 - CFBundleName - spotube - CFBundlePackageType - APPL - CFBundleShortVersionString - $(FLUTTER_BUILD_NAME) - CFBundleSignature - ???? - CFBundleVersion - $(FLUTTER_BUILD_NUMBER) - LSRequiresIPhoneOS + NSAllowsArbitraryLoads - UILaunchStoryboardName - LaunchScreen - UIMainStoryboardFile - Main - UISupportedInterfaceOrientations - - UIInterfaceOrientationPortrait - UIInterfaceOrientationLandscapeLeft - UIInterfaceOrientationLandscapeRight - - UISupportedInterfaceOrientations~ipad - - UIInterfaceOrientationPortrait - UIInterfaceOrientationPortraitUpsideDown - UIInterfaceOrientationLandscapeLeft - UIInterfaceOrientationLandscapeRight - - UIViewControllerBasedStatusBarAppearance + NSAllowsArbitraryLoadsForMedia - NSAppTransportSecurity - - NSAllowsArbitraryLoads - - NSAllowsArbitraryLoadsForMedia - - - CADisableMinimumFrameDurationOnPhone - - UIStatusBarHidden - - NSPhotoLibraryUsageDescription - This app require access to the photo library - NSCameraUsageDescription - This app require access to the device camera - NSMicrophoneUsageDescription - This app does not require access to the device microphone - UIApplicationSupportsIndirectInputEvents + + NSCameraUsageDescription + This app require access to the device camera + NSMicrophoneUsageDescription + This app does not require access to the device microphone + NSPhotoLibraryUsageDescription + This app require access to the photo library + UIApplicationSupportsIndirectInputEvents + + UIBackgroundModes + + audio + + UILaunchStoryboardName + LaunchScreen + UIMainStoryboardFile + Main + UIStatusBarHidden + + UISupportedInterfaceOrientations + + UIInterfaceOrientationPortrait + UIInterfaceOrientationLandscapeLeft + UIInterfaceOrientationLandscapeRight + + UISupportedInterfaceOrientations~ipad + + UIInterfaceOrientationPortrait + UIInterfaceOrientationPortraitUpsideDown + UIInterfaceOrientationLandscapeLeft + UIInterfaceOrientationLandscapeRight + + UIViewControllerBasedStatusBarAppearance diff --git a/ios/dev-Info.plist b/ios/dev-Info.plist index 022d5419..3581787b 100644 --- a/ios/dev-Info.plist +++ b/ios/dev-Info.plist @@ -41,6 +41,10 @@ This app require access to the photo library UIApplicationSupportsIndirectInputEvents + UIBackgroundModes + + audio + UILaunchStoryboardName LaunchScreen UIMainStoryboardFile diff --git a/ios/nightly-Info.plist b/ios/nightly-Info.plist index 5ba9991f..e1db8f01 100644 --- a/ios/nightly-Info.plist +++ b/ios/nightly-Info.plist @@ -1,66 +1,70 @@ + + CADisableMinimumFrameDurationOnPhone + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleDisplayName + Spotube + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + spotube + CFBundlePackageType + APPL + CFBundleShortVersionString + $(FLUTTER_BUILD_NAME) + CFBundleSignature + ???? + CFBundleVersion + $(FLUTTER_BUILD_NUMBER) + LSRequiresIPhoneOS + + NSAppTransportSecurity - CFBundleDevelopmentRegion - $(DEVELOPMENT_LANGUAGE) - CFBundleDisplayName - Spotube - CFBundleExecutable - $(EXECUTABLE_NAME) - CFBundleIdentifier - $(PRODUCT_BUNDLE_IDENTIFIER) - CFBundleInfoDictionaryVersion - 6.0 - CFBundleName - spotube - CFBundlePackageType - APPL - CFBundleShortVersionString - $(FLUTTER_BUILD_NAME) - CFBundleSignature - ???? - CFBundleVersion - $(FLUTTER_BUILD_NUMBER) - LSRequiresIPhoneOS + NSAllowsArbitraryLoads - UILaunchStoryboardName - LaunchScreen - UIMainStoryboardFile - Main - UISupportedInterfaceOrientations - - UIInterfaceOrientationPortrait - UIInterfaceOrientationLandscapeLeft - UIInterfaceOrientationLandscapeRight - - UISupportedInterfaceOrientations~ipad - - UIInterfaceOrientationPortrait - UIInterfaceOrientationPortraitUpsideDown - UIInterfaceOrientationLandscapeLeft - UIInterfaceOrientationLandscapeRight - - UIViewControllerBasedStatusBarAppearance + NSAllowsArbitraryLoadsForMedia - NSAppTransportSecurity - - NSAllowsArbitraryLoads - - NSAllowsArbitraryLoadsForMedia - - - CADisableMinimumFrameDurationOnPhone - - UIStatusBarHidden - - NSPhotoLibraryUsageDescription - This app require access to the photo library - NSCameraUsageDescription - This app require access to the device camera - NSMicrophoneUsageDescription - This app does not require access to the device microphone - UIApplicationSupportsIndirectInputEvents + + NSCameraUsageDescription + This app require access to the device camera + NSMicrophoneUsageDescription + This app does not require access to the device microphone + NSPhotoLibraryUsageDescription + This app require access to the photo library + UIApplicationSupportsIndirectInputEvents + + UIBackgroundModes + + audio + + UILaunchStoryboardName + LaunchScreen + UIMainStoryboardFile + Main + UIStatusBarHidden + + UISupportedInterfaceOrientations + + UIInterfaceOrientationPortrait + UIInterfaceOrientationLandscapeLeft + UIInterfaceOrientationLandscapeRight + + UISupportedInterfaceOrientations~ipad + + UIInterfaceOrientationPortrait + UIInterfaceOrientationPortraitUpsideDown + UIInterfaceOrientationLandscapeLeft + UIInterfaceOrientationLandscapeRight + + UIViewControllerBasedStatusBarAppearance diff --git a/ios/stable-Info.plist b/ios/stable-Info.plist index 5ba9991f..e1db8f01 100644 --- a/ios/stable-Info.plist +++ b/ios/stable-Info.plist @@ -1,66 +1,70 @@ + + CADisableMinimumFrameDurationOnPhone + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleDisplayName + Spotube + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + spotube + CFBundlePackageType + APPL + CFBundleShortVersionString + $(FLUTTER_BUILD_NAME) + CFBundleSignature + ???? + CFBundleVersion + $(FLUTTER_BUILD_NUMBER) + LSRequiresIPhoneOS + + NSAppTransportSecurity - CFBundleDevelopmentRegion - $(DEVELOPMENT_LANGUAGE) - CFBundleDisplayName - Spotube - CFBundleExecutable - $(EXECUTABLE_NAME) - CFBundleIdentifier - $(PRODUCT_BUNDLE_IDENTIFIER) - CFBundleInfoDictionaryVersion - 6.0 - CFBundleName - spotube - CFBundlePackageType - APPL - CFBundleShortVersionString - $(FLUTTER_BUILD_NAME) - CFBundleSignature - ???? - CFBundleVersion - $(FLUTTER_BUILD_NUMBER) - LSRequiresIPhoneOS + NSAllowsArbitraryLoads - UILaunchStoryboardName - LaunchScreen - UIMainStoryboardFile - Main - UISupportedInterfaceOrientations - - UIInterfaceOrientationPortrait - UIInterfaceOrientationLandscapeLeft - UIInterfaceOrientationLandscapeRight - - UISupportedInterfaceOrientations~ipad - - UIInterfaceOrientationPortrait - UIInterfaceOrientationPortraitUpsideDown - UIInterfaceOrientationLandscapeLeft - UIInterfaceOrientationLandscapeRight - - UIViewControllerBasedStatusBarAppearance + NSAllowsArbitraryLoadsForMedia - NSAppTransportSecurity - - NSAllowsArbitraryLoads - - NSAllowsArbitraryLoadsForMedia - - - CADisableMinimumFrameDurationOnPhone - - UIStatusBarHidden - - NSPhotoLibraryUsageDescription - This app require access to the photo library - NSCameraUsageDescription - This app require access to the device camera - NSMicrophoneUsageDescription - This app does not require access to the device microphone - UIApplicationSupportsIndirectInputEvents + + NSCameraUsageDescription + This app require access to the device camera + NSMicrophoneUsageDescription + This app does not require access to the device microphone + NSPhotoLibraryUsageDescription + This app require access to the photo library + UIApplicationSupportsIndirectInputEvents + + UIBackgroundModes + + audio + + UILaunchStoryboardName + LaunchScreen + UIMainStoryboardFile + Main + UIStatusBarHidden + + UISupportedInterfaceOrientations + + UIInterfaceOrientationPortrait + UIInterfaceOrientationLandscapeLeft + UIInterfaceOrientationLandscapeRight + + UISupportedInterfaceOrientations~ipad + + UIInterfaceOrientationPortrait + UIInterfaceOrientationPortraitUpsideDown + UIInterfaceOrientationLandscapeLeft + UIInterfaceOrientationLandscapeRight + + UIViewControllerBasedStatusBarAppearance diff --git a/pubspec.lock b/pubspec.lock index b9268b56..c7ac5085 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -543,10 +543,10 @@ packages: dependency: transitive description: name: file - sha256: "5fc22d7c25582e38ad9a8515372cd9a93834027aacf1801cf01164dac0ffa08c" + sha256: "1b92bec4fc2a72f59a8e15af5f52cd441e4a7860b49499d69dfa817af20e925d" url: "https://pub.dev" source: hosted - version: "7.0.0" + version: "6.1.4" file_picker: dependency: "direct main" description: @@ -1263,30 +1263,6 @@ packages: url: "https://pub.dev" source: hosted version: "0.4.2" - leak_tracker: - dependency: transitive - description: - name: leak_tracker - sha256: "78eb209deea09858f5269f5a5b02be4049535f568c07b275096836f01ea323fa" - url: "https://pub.dev" - source: hosted - version: "10.0.0" - leak_tracker_flutter_testing: - dependency: transitive - description: - name: leak_tracker_flutter_testing - sha256: b46c5e37c19120a8a01918cfaf293547f47269f7cb4b0058f21531c2465d6ef0 - url: "https://pub.dev" - source: hosted - version: "2.0.1" - leak_tracker_testing: - dependency: transitive - description: - name: leak_tracker_testing - sha256: a597f72a664dbd293f3bfc51f9ba69816f84dcd403cdac7066cb3f6003f3ab47 - url: "https://pub.dev" - source: hosted - version: "2.0.1" lints: dependency: transitive description: @@ -1331,18 +1307,18 @@ packages: dependency: transitive description: name: matcher - sha256: d2323aa2060500f906aa31a895b4030b6da3ebdcc5619d14ce1aada65cd161cb + sha256: "1803e76e6653768d64ed8ff2e1e67bea3ad4b923eb5c56a295c3e634bad5960e" url: "https://pub.dev" source: hosted - version: "0.12.16+1" + version: "0.12.16" material_color_utilities: dependency: transitive description: name: material_color_utilities - sha256: "0e0a020085b65b6083975e499759762399b4475f766c21668c4ecca34ea74e5a" + sha256: "9528f2f296073ff54cb9fee677df673ace1218163c3bc7628093e7eed5203d41" url: "https://pub.dev" source: hosted - version: "0.8.0" + version: "0.5.0" media_kit: dependency: "direct main" description: @@ -1411,10 +1387,10 @@ packages: dependency: transitive description: name: meta - sha256: d584fa6707a52763a52446f02cc621b077888fb63b93bbcb1143a7be5a0c0c04 + sha256: a6e590c838b18133bb482a2745ad77c5bb7715fb0451209e1a7567d416678b8e url: "https://pub.dev" source: hosted - version: "1.11.0" + version: "1.10.0" metadata_god: dependency: "direct main" description: @@ -1499,10 +1475,10 @@ packages: dependency: "direct main" description: name: path - sha256: "087ce49c3f0dc39180befefc60fdb4acd8f8620e5682fe2476afd0b3688bb4af" + sha256: "8829d8a55c13fc0e37127c29fedf290c102f4e40ae94ada574091fe0ff96c917" url: "https://pub.dev" source: hosted - version: "1.9.0" + version: "1.8.3" path_drawing: dependency: transitive description: @@ -1628,10 +1604,10 @@ packages: dependency: transitive description: name: platform - sha256: "12220bb4b65720483f8fa9450b4332347737cf8213dd2840d8b2c823e47243ec" + sha256: ae68c7bfcd7383af3629daafb32fb4e8681c7154428da4febcff06200585f102 url: "https://pub.dev" source: hosted - version: "3.1.4" + version: "3.1.2" plugin_platform_interface: dependency: transitive description: @@ -1668,10 +1644,10 @@ packages: dependency: transitive description: name: process - sha256: "21e54fd2faf1b5bdd5102afd25012184a6793927648ea81eea80552ac9405b32" + sha256: "53fd8db9cec1d37b0574e12f07520d582019cb6c44abf5479a01505099a34a09" url: "https://pub.dev" source: hosted - version: "5.0.2" + version: "4.2.4" provider: dependency: transitive description: @@ -2250,10 +2226,10 @@ packages: dependency: transitive description: name: vm_service - sha256: b3d56ff4341b8f182b96aceb2fa20e3dcb336b9f867bc0eafc0de10f1048e957 + sha256: c538be99af830f478718b51630ec1b6bee5e74e52c8a802d328d9e71d35d2583 url: "https://pub.dev" source: hosted - version: "13.0.0" + version: "11.10.0" watcher: dependency: transitive description: @@ -2262,6 +2238,14 @@ packages: url: "https://pub.dev" source: hosted version: "1.1.0" + web: + dependency: transitive + description: + name: web + sha256: afe077240a270dcfd2aafe77602b4113645af95d0ad31128cc02bce5ac5d5152 + url: "https://pub.dev" + source: hosted + version: "0.3.0" web_socket_channel: dependency: transitive description: @@ -2274,10 +2258,10 @@ packages: dependency: transitive description: name: webdriver - sha256: "003d7da9519e1e5f329422b36c4dcdf18d7d2978d1ba099ea4e45ba490ed845e" + sha256: "3c923e918918feeb90c4c9fdf1fe39220fa4c0e8e2c0fffaded174498ef86c49" url: "https://pub.dev" source: hosted - version: "3.0.3" + version: "3.0.2" wikipedia_api: dependency: "direct main" description: From 87e203b8b4135985814f06c588eb50b242fa03ac Mon Sep 17 00:00:00 2001 From: Kingkor Roy Tirtho Date: Sat, 24 Feb 2024 21:50:10 +0600 Subject: [PATCH 153/195] chore: Minor typographical splash screen correction (English translation) #1256 --- .../drawable-hdpi-v31/android12branding.png | Bin 11057 -> 10655 bytes .../src/main/res/drawable-hdpi/branding.png | Bin 11057 -> 10655 bytes .../drawable-mdpi-v31/android12branding.png | Bin 4042 -> 3954 bytes .../src/main/res/drawable-mdpi/branding.png | Bin 4042 -> 3954 bytes .../android12branding.png | Bin 11057 -> 10655 bytes .../android12branding.png | Bin 4042 -> 3954 bytes .../android12branding.png | Bin 12793 -> 12389 bytes .../android12branding.png | Bin 33287 -> 31989 bytes .../android12branding.png | Bin 20728 -> 20612 bytes .../drawable-xhdpi-v31/android12branding.png | Bin 12793 -> 12389 bytes .../src/main/res/drawable-xhdpi/branding.png | Bin 12793 -> 12389 bytes .../drawable-xxhdpi-v31/android12branding.png | Bin 33287 -> 31989 bytes .../src/main/res/drawable-xxhdpi/branding.png | Bin 33287 -> 31989 bytes .../android12branding.png | Bin 20728 -> 20612 bytes .../main/res/drawable-xxxhdpi/branding.png | Bin 20728 -> 20612 bytes .../app/src/main/res/values-night/styles.xml | 4 + assets/branding.png | Bin 27368 -> 26973 bytes .../BrandingImage.imageset/BrandingImage.png | Bin 4042 -> 3954 bytes .../BrandingImage@2x.png | Bin 12793 -> 12389 bytes .../BrandingImage@3x.png | Bin 33287 -> 31989 bytes ios/Runner/Info.plist | 134 +++++++++--------- web/index.html | 78 +++++++++- web/splash/img/branding-1x.png | Bin 4042 -> 3954 bytes web/splash/img/branding-2x.png | Bin 12793 -> 12389 bytes web/splash/img/branding-3x.png | Bin 33287 -> 31989 bytes web/splash/img/branding-4x.png | Bin 20728 -> 20612 bytes web/splash/img/branding-dark-1x.png | Bin 4042 -> 3954 bytes web/splash/img/branding-dark-2x.png | Bin 12793 -> 12389 bytes web/splash/img/branding-dark-3x.png | Bin 33287 -> 31989 bytes web/splash/img/branding-dark-4x.png | Bin 20728 -> 20612 bytes 30 files changed, 144 insertions(+), 72 deletions(-) diff --git a/android/app/src/main/res/drawable-hdpi-v31/android12branding.png b/android/app/src/main/res/drawable-hdpi-v31/android12branding.png index 9e62c813076506454218bc984cc90033539443d4..fff3f1487b79953c1791418afde72094233927b5 100644 GIT binary patch literal 10655 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 literal 11057 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 diff --git a/android/app/src/main/res/drawable-hdpi/branding.png b/android/app/src/main/res/drawable-hdpi/branding.png index 9e62c813076506454218bc984cc90033539443d4..fff3f1487b79953c1791418afde72094233927b5 100644 GIT binary patch literal 10655 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 literal 11057 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 diff --git a/android/app/src/main/res/drawable-mdpi-v31/android12branding.png b/android/app/src/main/res/drawable-mdpi-v31/android12branding.png index 80579983440f33182388472285e5e7106ca027e3..5a197da3c16283569e3797546269db62ec6a645e 100644 GIT binary patch literal 3954 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 delta 3819 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 diff --git a/android/app/src/main/res/drawable-mdpi/branding.png b/android/app/src/main/res/drawable-mdpi/branding.png index 80579983440f33182388472285e5e7106ca027e3..5a197da3c16283569e3797546269db62ec6a645e 100644 GIT binary patch literal 3954 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 delta 3819 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 diff --git a/android/app/src/main/res/drawable-night-hdpi-v31/android12branding.png b/android/app/src/main/res/drawable-night-hdpi-v31/android12branding.png index 9e62c813076506454218bc984cc90033539443d4..fff3f1487b79953c1791418afde72094233927b5 100644 GIT binary patch literal 10655 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 literal 11057 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 diff --git a/android/app/src/main/res/drawable-night-mdpi-v31/android12branding.png b/android/app/src/main/res/drawable-night-mdpi-v31/android12branding.png index 80579983440f33182388472285e5e7106ca027e3..5a197da3c16283569e3797546269db62ec6a645e 100644 GIT binary patch literal 3954 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 delta 3819 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 diff --git a/android/app/src/main/res/drawable-night-xhdpi-v31/android12branding.png b/android/app/src/main/res/drawable-night-xhdpi-v31/android12branding.png index 0bcf138d3e17cace5a37b4adb6a97afa76ae805e..efc7e6c8c995fb3d26927d09c6b0448b0ff1c42a 100644 GIT binary patch delta 11605 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 N002ovPDHLkV1jRz_$UAX diff --git a/android/app/src/main/res/drawable-night-xxhdpi-v31/android12branding.png b/android/app/src/main/res/drawable-night-xxhdpi-v31/android12branding.png index c7d0177681e63abe4a1d58e1b5cbf7325dbadfa0..593877e01266445699239227caa666a8ef43118d 100644 GIT binary patch delta 20410 zcmce;Wl)vjyDu!Ff*>g&(jZ;Z4bt5W(%s$hC@s?6NJ@97bc2F)x3qM#&h3BC`LySp znKx$pag7U}xZ+ngA%RaXZs4NHpZc^`QS>rEJ8;BezdBA(Ec4)A2L6m8Ym>B?crBd7 z7`#sR?bF|eZ`5M+t%Vhm*qu-PC6C*ZewIkS-X-yul=4US!o-Y)owXeFj&2`072$WE zJ@{<9xx2Y-H`LVBj336cL-DP0X&gf};{tTPcfrpPjcz0H3B!^P!F(t>HUgJ+!xT! zNgLNxD2sWgTC^Y67ex#i{ax+6V-FeNM1V|1voGcPSlhg>5YJ*!U9dvmxVbu*iz7t% zSSq4-KFywlAe$wio7&S&GH`(RF&5{NbSbjg1({^YRJu!pUlcuM&->#Qr^8asyJMD? zj~KCW-$;f<6^lmVhVV*+%$QtvZy)cDp(^jIBOG+Cg2++#qs5djLFfEu%o@vtsZ{Ukr+I>Kmux?*zC*3D*!i;87Dx7`NB4~IZ(rQq-X7^TIc-THerDM=-u&*e zI}uSO>5Opm{ZqS>p7UKS?MN@ zWu0ivx8Mop<>kd4i=&G2F%ejJS#36&`q1dQukM*Z?pkt5(EHe>jwTC1&AHKbG88x8 z+taah`J?t9;c!G)hH>~)w8{|&r4*y{!}Ar6W;5)CgoI#o^|oo@&Ggv|*gx}SlA=fk z#E1ImDq1o9&bCK0uO+xeez_Ll^6~Kv{b?E{l5GQA%15dK<;Wd@~LF7Gm2}a)wzepdpW z2I^9~uQ$P%3e7Gp&OPy5as1p zn~rlY=svRkD^*D48;K0wE+2gc!HB&~-b7W4{;#8@7Lh0-{@X7d9k8@!T~u_#QSZwG z?umoX2tRLWR0>q}D-DFswCk*-Bo6qj<`)(k>|wc=1_}xayHpon8OIRK&39U8lHZNy zU9sq5!%bTb9zmx|j&p43Ekb4nf*6f(*LZbR?W7U2y^<@S3S z`@~ouEG~via%fB_T1wzDXi`2U8X2t_mvkU;w@W5jKq8VrEA$>lupUV-*}=sQzZW$ zt%oE=T`ve}rWU{4mHgv=)!$;PwS8pD=%^hNQRY+Mncd0nDzxs(iJ66_mW=C6QP*-^ zuNYBJ^glG`R<*jHtoK^S#Kg>x%s?XS4Y4m**hB?}abKP8w=$7s5zpiI2O;AUZ4kh| zI;X>((8P&01UrlC1)&mf{pAhyebC{*x!0iB$~uMUFTUm{4XI#DU$Bz#f#KSg0RnNwDrhXGSUlbRO zL-*{eku#JEnXSnC#B)eYIsN|bm@$c{cOCufcd7)KA@@l|*!65yzXvS4gHde%Rwhwy zwn}$(Gns7kMf7`J?3p$U=+#+GiOm{X;@rr>c~S_I>cW##%BMH#rSls)W)OGTcGYo= z7DTe#_l>4;=A)&CT6uOmy|we}^nY&u9hydsr@%mj$Q}hTplTYXQiI*E7Dr#qZIb1m6!%coFWdw6;GrSt|rGac_*fwG+0W&FMiXTmpsRqw+G=tnUJ;_;l-Sn7DL1a(5Rs7+*J2>WPj4h+T>D5q3Y;!aVFF%{f7`8VpUt*wn>>P=t@OOE;bhtF<;uiNEHL}gxe zA`lP!bg^u9smEkHQK8xkIDZxCeGKXaRuJ_ePS$L`)=~@}f`>PC(M6!RG3iWvk6ln% zSs5UcNbl*n`r|X?j73EHj!IZa+{S5pBn6>61T9Ozdb)H=NlA$a;2K+<7B|})y?j}- zqKt#7^G*vs`l$AY%LU?~z(9hat zn^Y?b*-k)MQxvcNMpCO4|6Usy81SZ42xAroWd!czc~64uv`3442G0Z(;_D%qDx`%e zh8!GHSz`fs27&wc>?pD*oyQU$6$;ruFCa?REW(G=D zAxCKdippUX01I;&shswYEbGlg1O$9e`_p9&7~_&XDugXrv#&$K=oY`*F4Xha8+7_Z zo|+XZ-#&a^^?SIrl@lY7QatNHD}i&MSe5R=4jG2WMZH2;L~Uf?TB)TpetM&bcY|)E zp!u<;4M4H3Zx44@`jfYupeZLX(Xp|&Y8*HEvTo0J&m5&4N0XU11j}?9h`!!O2|Xf^ z!_W#Y2tpqeqcK2#JxBY!1{U;XCuD`qRpKxEp|MKZ|Ido-(WY~ zg;PR8qQ8ivwPaoqdyG-&h2ac*e{1LzZ+Uq+Yh`PMNAQpFrOXZ2`=j;sQ}kgk2hZEf zLtgjMRCbh^a$Rp`6vvcLgw|Dsw&Vi{4zai!2mk?`q}jJOWhA;pqXk7n>V_DfPwPi< z5YHyseeZY->t1#pao+X!^xS7sDP-cK&nM`6AJ(;ZJl^gL&pHoj^BvCDoryOJX)@ez z4#o|0J*sQlP!)yzYj7vVC|4OBQM#A@vc%K1C{@^5bQ+9l#ZT^>jjPsfFZPMmN;Mr- zJv=Wc7=Uv#Rp)s&2@kJ3p#}mnJ^ghw^Y zc?u4G0D9OF{SROxcWIpVe&}ukI^zv%dI1KRAM+$*HWJr`m%}wy1~R%FSMqu_V>$lQ z#k0=?+tB<;&~a+uKzB^RMa?B%+9H`>MuHgOBf_n=_ON zBPuCgEEBLOCPrh(CF0qwr+pTSRKD94YcPnQNJk#ZYwmtnIj4GB=yP*wp2(!HSL3`h zhP*~$kDA})dIThiFf@D)dUp8N2kS!#bn8aL@ifL$?P6bX+9p8*Vrw#7&*($GN&pE( zG3v=$H0jn^smai5hrZEig*;BaBf2N$iq_yDv49nY=U-FfoNP9kN!d&AMXRUvdi^U} zey;Ds?S+C-&C`2iG(w(p2E=M9ybQCsYE!xo;rtbL+61DN4r^Vm=-RwhZ=(gFM*#|% z#B>B9H%e;ifd+6Hxl;y7xb&LuRlJGbS^rmYk$QM~y8g7ugx-%t+lU6dK*>z!_rB~s z-5SnPPLq*11SmrJ!-o&W>onT67AH<0j)^faFz|_pmeET#NWPs8KlwzbQBGft)enl_ zh*B<s8h4{d;LY2kan&qpDbD|Tz`X$d5t4Gvb6QTA zwAz$pKwTHk8gslX$^}-H7gm(heeE_Op_NG3wCUoRHl1e3TvvBj$DG|0M@>H+N;d$U zGjN{Abk;WL`8Pv4wVgLwj@w&a`rGgT5$T++yKaHYWFY!@>Q^>Z$K6rOE67{oAmHC@ z2-RI|blj+3Rv^0lH}`%NQ%yUU5DuV0t(WuG_^v{2fNJWY-zi%Sg`ZwtGFlizYCX;q z;#BUF14G~)PJ3@9XuPs_o(#?D)wItJE2x&HeWpdb%Wd2jZt8n`&TY={AzL_T83hI9 zklucfq)**om(sU?b>%%h{m8uGySVIsEp3E$;$e_fOTKul4?SFzu$qsBL%(nCgd0tJ zCYSL}ROM+D+kI|K!Xo$aqVdv#gwy4^B^@s)Nt%fSeXboog@lBJKXrW_bG_ObaPqe!>1~T- zAAoa+r0>Mm*VhREpih8ojFc(XBI5b3nFi9TIs*_CGT$5ei;+fu{-{){pi6qmcY1yv zK45~c{8iS5E|-pQtyS5x6uu{}*H~2c-#l#wvcibUclpsz7K!5@*`bXHPSI$s0~tyz zCOw}s@B<;g%Q%-A(dh6% zXBkqOlni~duh8_+qY5J;9-bO8!{XUG>!gv~=-;h#`?Iu@OBUV{t>VqEW&v-+f@nPpko zF+S7hS;sIIk52ITcbxQf6Vq7DBPXC5bA_*;_55y3Z>SqvdNbZFy&~fCkoECtO}Z7g zas}ed)W7elL6Mks3h@7)T&y$q3k{61CX>Nf_9{Ljn&_mYB-vL(W+k$#e}3iaR=u&Z zBjR)39{D*UJ=`r~My%9aboS$LxYR{*8!$rf0FnYcxUSHde}aCH;)UD}EO6eud6SRw zq{CfiN`aAN*f*3Wnp;=XsEj;zJ4F;lGD%K{)Nl`KYPFbKIs6>cvdt0V_o@R^G^49 z39$dkW=l1Y|M|Pf1vm|9XOcU09qHrc^Gw9y|mp2_8CL@O)*V{-DWibDXuhkOJt?}B_H)x=(V`&y_L zAfpc3w=o3&1(FRm8Ime0j*F+ubdEDw&E+L1*5GGczVPqB6O-x%m}mDmu5M3O~$AxPZ z%ra| zrU}3oh%2sbYimmYXfSm`ES*JAqgg!GYT4%ti;SvyrJPxNlG)Gzty=NBmsy!(cUMPC zaS99%8QX};kuXvmG*&vlSf2mjqGX86?LgB8sP(eBXCv$IPmQ^8hFQrT&qL#Ya)TFJ z&VLg6M+LKeCq*>SRJD0?_tU>+CdoogIq~8wA`kmNm?027;6Lj{7?JtS|I-hk{}|P#aG=Qo1Db5xSh9;fZ`F(7Nz-3wMbbS>`5KFvs?X+X4yd8Azf(fKVBv3==M&BOele`ayG-X-)$ zY3cGaC`QkH)9>)>eRz1#r&TGC{Z|SaK}q-@XVD&b#-+I8HZj|PO4GQaqnosp#zu)7o0$(c%213-mDKpNlf@=bc00S zMzDI;>jnlSJA?vWO!YU@r4y&aFA_KQk8cpcP_C|J7dJ41-^w@XOLcj9`J-8v_$O?~?^`3!(2jU!*|yzgeNjdkydNKPMFG$kZ?GxzDfHQq>6F8+_0y?RVRswsn$~ zl^qC1!S`Bk{*W~y7~0WEbZJB4 zrmA!jV@8K$44L0v!6oTNILnSzpj;2|<=9qNzW76(pMh@&>EnTifonwXm?a;+`#^v( z{kp$35Q%ROtRDXRhX;*;ee+m$k`=)p>oR8rbq;&%al};a?(Uwfr%s@)cy`fKlN)DL5cNEL_(72LC?ny$3_G6{!|`X_zAoN`2Z z7pxNHn81aeWDL~&M5jF2ZC2O4-<%0hPcq32dH#M<V;pbaB zS&$!giD1`O*MlV^)#c*xNn=07Na#+c_t7u}G+`aDP|R3bR6-ssKky3Sd&96xN*7$a zdV9CR%ZvfH*8&#l;c%6<=-S!6J{r?EBd?a6#WwE-l1E$mNj5nvy4^d6v$gi__7z8X zHl$at4k8aP5wrBqnC68d#`kY_vS2SAj|RcYu$a#JHQ5bj)?1gudDmF4B}`(d{7D+B zMpZk;QBLen0yX?{y!0fmMw)xTR{Mg3gR5sQRh|%exjHELRlJK25ydD-#BCZ+I-ITA zNCPF18K|#d(}6gnjB@-9r*wz9Pg4AIvjmM^tA`*~nfI&@A>)f9`XR#wAhIskyV7Th zk*!M?rd_s+lFVTtu_%7~00$w2GOIWzY-iie^Eqt}uwdQliG-l~<{fD$YRM4CMgu^{ zL%{216ARd3YqnJB>J%3r#?IRw-JRnO7{_XDRPCxmgltjM8u+?5}cC}6f+o>cm zk{2N03P9Lg=|I!Iwh6Aa_+=!5lOp@7XJtiDLsD`8lkeJTAA-5`_V$*Q0%qC(jIZS2 z+CjfYJk1PdtKWt5{}j)N3najNDmKTnU~DTsap9s2_Q%E-52{4-diZiLQbk{V@_#jw z!FvU1VyVYI8Ykj!_5)|=VlsG2y{oWwV}GVX5SYyYxQf{d>S?T4TUlZ4m%vX92=Mn$ zG|6j&<{k{A)h>Z1Rr~?4Fe{x|?6(92_d#_V4szxq)Z>1;`AMlgeSJjZ)ZWz_uFMPZ zG4-aZAGI>{ubtU3cN2cMOZEEhf4XyHJ=!R5%rYJ^taJ0dUJD5UO#Zjc!E9AorssA_ z(Cvekkl9BGo!$F|gF)21{%MzVD1lSS>#fSD@?h^22_7 zBy1~5KhJoJ6ZDxk9H*L$@7Wd*oOlflRibT|Tj%iIGzsK80P+06VLKoC#{>1~&0>A4 z=NXaQNsrAZE?x8;I!#-|ou|0R+uQYU9HlE&#{Ih9>pxCV0j4hp7IxUgu?m#-$+wEu za=?W&I}}1&U-@)BY3zkbQV?dS^t-E^_vq*-ram&EArZX8xr9U)czF1;_0+nE@bLKi zv*5UWN8}k(aqabC+27V{_GKdmkahf0q~^sB_U2_!=2c*a)ZR#IM5u@ttA8$myXpsH zjAO%ZF6G5SUiyHJyrmZu(=gKDD0tZITg%1nnE&kY&EUgzxt&8~XjQ*t1^?0H8@iCx zWC7pXi<`3@SbXZufTH|ICHeX6^xvwO1^O`s&VwaQ10||*jQQIM#O21x3AK5$?VoDr z4bD)zhaMYl*oPUb$e6mxfABpZ!K=Srpx>D$KjmuQKZG1GGM)nhI5Q zTN>~T!KF5DcV{t9mv+!Ray+hks)m5unVYr%5D|%v+zw(G4B^nC{f`o+#UtSG*XuRd zWfaw4ot!{}?m(R!uj2V2tycf?22BW$d{p8US7sVBNm_!pyK&+1)kF(JeQ{=O4o(%r+x47 zdCza@@#1_FzfVciEBpj)yzuMkyY~EnMDe#n-|uGYczV4WchQ*zN#hoka@YJd5s?7K zRfX>Q01}2%x=A1nJ6`3coXWh(1+o$~0?yY9I+!eWPPwpafNV@^2~dg zb%voZiBFM9YUcBxgDKmf)DoHL>C3%l4JG#x5nb~WcFeAkPT_3=wyXU(Z%g*D6RN~6 zpfG5F^d-WmCMl4mr z;!}I*V>qYyX4pN<>G0wpw!u*xl@$^4Gea>h|`nr2h zpY)E;@1Co}6CQgyE;Tf4!o?Sqs@njwZ9Yos9Ubryt1!1cZwL~~%Q{hvepRTB|b zok}>U0V{&}0T-|Uzsh_(Q_XBVlmB%|9sS5$K?H0IcwcHo0B8SE<}&Eirw@iwMp;f4sQsC#$OtAEVI!&t1Hy5+iSUY?|6Z|r{7qg zwfZ(HzH)x(W1HFFW8gPg9wL4(7iywDa<+$x*o@{_MUH~i+xGB%{BY-vY!t<66DiZ{ zziUfCMuV}h(^ybsil(6#^cO1SY9|7M0n(qo{e zl1DF>iEhXk@tYp{68rbN#UUV1m;cB(=g|i8dX>I65N6wd%ueo(1{Ke&1IE-H%#LkIDX6mK4e@C~g4I|dz6<|S!|q_FUAuQGaPF?I8O9rxCaXfY z&EQpTfcZ0l%rf)m&!3(&A22hkH3Qi8)9lryh}{M{hHf+}^b(L17MN(YOv{@F)3RBv zIq2z2`vF;qn|pTxtn7+!KnN1DNwt-9d>5(e4^ZO`LH{EZ3N;oe<%Di<+414kX{y%= z;rJo464a0T6P93Kyl6N@mtGW4pK{F1BK-*Ixa9=`98~mD@>g4Z(wW`QZ=D*Iw%8L$ z3JP!0Ik8*ZkNuuGHt!CH=KtMx4)NFxcXsJ@)1gz+Deh4&o?V}Me=B7lH=-73P33GV zMUkoD%rFE<$WB&%3{{W=gT$WrYbw#q)dtxt>M`SIIOMfE=EIVko+1R~_Vde=xBBfq zTB+h&a0jIYwyca&GUCi4uf|3F$`9t%U{5;*@^plO4Z-k$*R*zYWT)|3SDIe0Rr4h( zYT~J;a9l(E*mx}(w7IvD-Hzu^KiKUE{DohI3eea$0jb!XiMFRXX1{@mMzzXwIXR^} zUpwM!$WPKG`i?(fYrNW)v{gM`Cexc_JV_{;Viy%17ne#dGIw;%M5)nX%?i|I`6s6f zgafV5#u+xfOqV%6mqOP?fcwBNEiUrxcmFw5nn56oLd$tYUmcxPg>$dmoJ4;ZrRL%c zy)iRvGgt66u#{&h*|pSa^QwEKW5Lsc%}z;+C~p_xntbzb*MIqu`Z0U{Ai(6y?Ch)w zY$)$3(#w~Yp=`1h7gN93j8~apPHiK8MiQV#Hs$8`w~dJfeBO8gDIw^3rUpL25ak~K zFpWuHpzJytUcVT$vn*n@NlgfdLO{9CXt6A56SM|K*A=w$$_aQ}EMC_)P`@0-u?6Gh zLD?wJs@LC`BK%xe1qg%aXltCm$H$olODqF-9q+Fl-FtMjq=|@# z65=<}sCGHy8HMUW=ByDw`Nzd_-4;seQ|U$c`k=1*&mOa*Hy1PdWgOX%RxW@8&q;vQ zRFHNAclQTi(>puBd7kb3Q3rXu+sw>NcCi5~G5kxZjxNLcR5%voP1yIw0#@wNfWHGV z=vwA>SpDJ1rz-aMmb9$-FD_g$AJFiU z_NGdrrh6wv#aZ^C^_c2wx^=B6k4=ScR&>23V4!Hgh~s44wu2l}L-Xr6-*E^nPRvv$ zFAK7;u+Wo{k+s=dZbf|-0U&7eF>x1Ron5Y-nVJegNj~oe_HsyyJ^r;P>rpu!RsL#2 z_sk5ZA}`rp&zIL(LZ75mN_3127R{+AomS4LlK&!J?O;IhC+|a_(S+oW%xENr>Zi^! z8SfhU<@z^oA?+oS&tCqhvo5R}Oy3a$>NWOnu;^^JMHQ(8K5${^@{e4~)NHPGhvctl z;5Ldf2VX0YKTd{rkgVIA;6!deG;(f@<{=6=bNgHa<%ziGqOmM7AG2BTRTIhm)2iBc z11u2-s?c#ZflS(sS{d;KQ-QBv(T$Iq`yY{brL;-&=z~rbx&byhEk+!-@2*FcCJ*qx z(|Q+0zu5}JX?5MD5}%(sbd9#Eo<&{B13r%rI~``)E(os!Q+5GSa5uEP>{|wSC0Cb# zO2;8qgK(**YN4WGa}I`aF~9jqMY#yjX`#B;*<(U{Dr>jEuQMPZdV-JF8{&Li+pxdgXgj}sB&%r70?-8h2d?`|jeix~jC-y*M*O{pax!2n&UmH%a6v0~C>2Q2?lXNLTs#bTMKk3An3 zI-rhr8mg&-g@y{#rDj*1;dO@s5WqbkYH1VX98j5p1YxBpj!ZB@8-#T6KXx zx(eCxVLTNNbqXXGM#ubs`q^P{)CnOl`NPxC#}5k4A_@v}EUYQ-KP<1DowKs?Pfbm! zO{v-I!X`8lw6gTeHI*SeD|^AB}^iq z&)Q_AQ6?4&5mQg2u|q6CpUvW`R5S{Cwi>wT(<6((CPjf6S{} zXRA>&)yYEf6=rU^y07a(6xV85@4gCit7ymJ;o&i-N|g?<<^bbDRVWxqEqFUm!yv?z zrP-7ENNBNyJM*pry+XN@e}72P3}69R`5Vksue-wrs???I%0!RkkggNCMp%fc#bgJ- zk0MHlycq@`!|!u+(}0Z|@f}LK9#2?PC6J+m)JrWwH9L@T8BOqULDEf^k~wMS;Q52+ zW%lb3emTEqsfI$P?0KznG* z7+SS8vre~k!+W+Ea`n3iu{fdK?V;W5eOc%Y{i`sUzblKm#MX-EZ>&iF&WuByU#*|omJc%0edzGHl9|_JnlL4 z`Hpv001|!bX{rBDe%btd|LZ9Px1}W(&m=UX6TL*erDtT6lQ*Y##+?@wz?=6=FC=cW z;9Cz83mnr(-0jTMou0vlxV<@02Oy;jj2P?QQIPt)Edk?o7A}cw_ls!ridBQ3yW4x$nYDje&vW^`z+dL z=!g2Sbk4C4AWYEFL0jJq)hddu`^SO9~uj8kNM0n-0df=Kv*z|RuL_yx7jJB49h zbB*@yiu2IWP$e^F$`8?m!TOdS6=nYPBZK6U6(jK5mB@2*bG*bpe>;yyjAT11=#Qe! zon|@D!IB+M>rL(iX^|_Mo$cnhI|6j~Bu2O+_OU|Cb5aj;64 z6OM}^Quf-ujf=DCY-Z+cLp!BQcK0{CA}>+tre6KJy4|l3ES*D^Xu4hpA&c12BPALh zS^sIV%_Kyfg0uc9)iUiVlaCGW*9(C=SdyEQGw%ydfmBoHBni|Ow2BVn4-wP?FN(uL zE>iTXTAhh^AyI{yLgX4=M(X}2l6WFqODSlf?AmKHMq-cL#_()sTyS-)1{-@bH{qWM z`OC`>2(Nl)t!ENpoInz)aZstC0XKuMriG2UP4MR`TtF5_bAvCsm(98tA zc*Ju!ecmQ9KdzD0#9{ZRQ_sQkeqHz69A8HUZ3KQg?kg^nd>4Nt&0^9tR)n%cEwCf# zG8RR)9;M+7Y1Qp&|MP%dgtleI_Co5WJl-%&KLmZG6K4G3R9>*<&M@h|P%r?@SC`pD z5u}9h@No2db0Rlp+N1>QX^4yM2VwB-W-3r&#*tpuG95%ofnkfLbU5hnH zvrX1no6(N6eca9-xrIkSy{CNtz7kkk0+!f_R~C_27HpgX0*{Ea`T9U`v(fd}f6m~y zYst5I3hxQGnY%(VKrnW^(jnONUZfEH1xxGh`;Kba6qfy^m+<#c3{f6Zfl7UC<-7_D zm(TTI<7>o*W{G4K`Sia-h`9}xxqm*>I|xPdA!P2LKTEk_`a-qu%@8{9lJz0cn^25^ zR;-NGVSH3CtQ*_I{Z0hCFm%lWs|>MlfL0zL#czeX449fh2+W+uFM zDrG()1X7Q2TPLSDUfLC%exXHKn)j0W{wZVEU_pQJF6| zkO}psf>89JhP5H#L3Yx#p-8UI9fAh`Puo!}?2_kZr0Bx*xj;o#){<-w8Sxz$**%DrdHW3^0fnDy^C_7y1JTR;unft zFe#Eo*BkA|*GY;uD#u_};=#ee#iBtGt(rq@AMM~fVBpSH>?}mFT;V;8k76&`D?*%9=no9y`tP;f{-qt!AU4u_T!o z!EfW~*p+Y{zIki$M2bmE=~+rx4n0}p-09$GSdDu+*G_T4z=FkZt~V4^nLNE8 zl9W?p;SmvXy1@99uF3zagHgNPgV`n>y_I%_h=kD=DE;4U&D9ii=NFSv-~aj98(6dAPu73}^{{fkIaMUVAVi}BMFWG?j#_K)xGfV?PvgAvf**5>8TXmV;AIj`1XZ|FOS5Cyh?y!0 zsGN1(XMkRga5$Yglpn)=jz?)@#6S1%pqi0*X_?Ha&$Oc}{UW;8W7 zr%U&i_wl(O1Ol<`;Y9vdSFK#)^;*HB<7PrM2`KNmF}6whh+K<`BcqO>Bs1AvK#q@n z@wLqMv8UDkQ6j?ekaO`F$WrDT8yU^k>_3-oB|%0*QxFxu6C8DPRp|#dptx{!({IAG z%$yU#*1@kD&z|Nw!=qdmCRK zKy%JAWk|(9J+lDWB3f`NV_SnyC;O=4W0Uf@m%P4*Av-Ba{kPJyEY$=H0njqqz#=82 zG!;1@l2%Y?U_4Mn+2S6h0wol0c#$dp$T(ClEFB4Qw$18g+Ql6`hy}y`BPoKW!-$pUV&tOg1ASJJ5SjP;bvIQjtKuQQM7jZKp%S5~u)iQ_=`ufrVLTQ# zX^t*`#QjIWu1$t|CSPem`6LMj&ffXdU2l7BNZm|oU1W81bR1yS49Kj}{)+by!XY4_ z7xA44xcGL%N4xt8zz^R~NFD!%EE0iRihytPxj0H)7&E~xa4Q}f8lbK)htOXG{q$?` zNVYjAx)xx0r1yH19(I5Op9;YXn)X3E;s*EEC%GUAIDZDbt28PT#6E_N1lGG0VCe=|t^eI36pXWhwpV#<2It8ijW>cLeSE%^$LsSJ9*X zDG^8*4Z{KN<6TfKBE83!&0I~`G?mI>C|N>bQyuvdQ4kSf_*Gr9zo*EW)6HZD1Ql)M z-4|`<-Jf^`ROTtKKi2}K>#6#thR5X(iT_Bs#7n$N43>>YaO{%`fU_2D*9S1p^#4qL zANMG!vwLu-N76K3plJ%Sk>#_UXTvkA)tSmaW_a_xQFL2q3oUyuNMWY2u~C_snYp3o z9i1pTVs)ehSB2N`)9*{Ajq0zagV$5-!=0(|mxo72d~|A#s}dFFNQGzytY*r6 zD@?rt82CWOUeot9PiH?=lE^!nLzn*PK4~i_yAtK5M4`Zzh?|gS*S((g%;hbX3O6)? z%yz{S+(r@~_oppTW-ID9uLoz(cKGBe0-Jg|Ig#S}^OTBP~OVMz}yaIncol_^_OHGOs1C$)3pTPqsNonC-mR z$OlMjt3;!M=q(1u$&Us54qe@AJz4jJanDj-dj7Y4-kl z4TO^y4LNvXnK zq;=u5fISm8E$z_!T|t>{i<>gImPc?^-mziPD_{7g+oZ8|B;+X?@gv7OgL6UXX3ToA z@#OXPUvONy=6Rq+00<@cg;1RolJWENqdavc?=hhoZJ%g{_pBoB65ybq=rv5nI8odO z|2qZrGf%}GRD<_;{|cJ7zU&Ut#b>u-TLs4l(%>KhJ@o6>E`ZiYj|<$<*Gt7wB49*G z4?mXYeBbp(?64`B8nQZizO%=uQ!o3Lxdgh|N;Fava`CzV9NqvObSLiZ}0O@t52GIa6ZjDc0-od%*Ds zxm?ZQ338V=R& z1nISFC27&RHEn5@U;;%&MN@xEA>U02-rsJeesmwN>pjvayj@6nGWMt?ro4@` zz!ZjGQ&y`@E)n_atbimyvN?Q%zc!jTWqkknnV{k~&WH0!1>D@9i69nwv4D8ufV-Z( z)D?tm4vcBr+9L(V$dkkTBHO2a*KMHZR8B6Gu4`}}CCB60Fo`fpUqD3If_1H=eQ_Yv z0`plHb-wH34`<7OcwDWrK;-O;BJM`VcBa{eH$LJIjx-M2p^mXoh(Bv7;%XhW6*uHn z$J!3p^_)_RnRMp>RY0_YorplpjkWpt4yKStM_m%?&AS)tlN&p9gWpDCm$g%h4LJK> zpAei(>)7X8dGgnG2AAtcz+Xg^h6jb*k2YQXpOtpjdv`C zRYH5cFHs0OdgH?uOtVs=@_lSr3^6R3y|9${rsQ_S_{xd6m5&(2oY$Bv5~!(+81-7O z-)nOoyZrfSSbf3m;ERAIKEdxR1{+s^t+bj)sA3Z58oX5vG^bJj`4lHN`|NLByI*nT zd3Bmf2-iK@`d=|~2Hu{vSBTYm*Yj#MOwo-O$;I7iPt=Ff#g#)Zj+XAKz=Kp*s3IzS==m+{GqGE7bMJ=JgA+*Y^No<>#^DjF zN^|J54_@egx`4vnS;UOfmwtVdFowk^qg5N6hcNKI$5OS>Pa96B^~V;E1*1%<+C`eX(kI}1+*G1Crcse1g?bm`4l0||l$Uu$y8WYnAoH^pR z0SJoqq^51{dr@?CUl!@mcmb4`*Xjl6$WwC!VnIJ2n#DFm=8M$81p>3lt23}7w39M3 zm*ICkmAot+9)0fxpY~^9;t(MG`wJSu>W&s5G8U+m920BX(xrE8l50oy+J1WUI_ znWD&NxcD@DH~p2|V?FqD9fXp|AwlH->Qo7MfwUeow{Q8G3w(^^;K{R0a>(uqfiWKR zQchvw=aRK5jNAEm(0kv`W0BVUuigJ@(u=l)&~{8a z#gs{kU}#ERT1wjlm3@k$?uy1;^+eq&4o=<1r435a(V>S%8KjZ8w3O&1q~a{jnQ!OI znRE8DzwPH)d+oLM-s@fO`~Ur0?}R?o;CKbe6Mkrx;sa4ny{?hb94u>pgHT^r*QYzp zT0(Ui7DCL^c^c9A*_npt11xXMItf~bd`yHPlUHJ)_Q$6AJD)>kAJz`SnXe85OO7NE z=Kq}~UOw>ZJI#^i*cbeI(STNiWyI?2BcRDhVLjbUD$Xt-MXJpV4)zL6bW)u^hYjUl zRUywD$&*_~>?I?>9^Fc6-xmhZ>^I==7zr*yWRxR;(Obs7IA@4!015aM@c;cD4MOY^ zkmw3BKRS+igvzW{QiI>088v^Rn<&*dCdMv4RTR33LFL@9Nni}vEO)_JV9mzh1Z5H< z(2GVWqWzmj=}n`9O`~V4cDZ<7NOwJeE5;C+B=1`dw*tbef4r0tbDQGtL-mHH)H-Y< zqVBE+B&@cSfh`)vYV(Ug(XHqn9Dh*kwM;^PBDpVqIgflJCNHFEG$#uFP_)`9_S)ik7MH86w?$aj{82y`Q7-$~%4;q0V6 z#?0_0c=u%)b;1=iHK1L`lBRt1#x+dGQQGIpy*_kb#Z-H{$an|S6*I(!Do9FLt7pHp z_!3kKmgM1)Z_Nh{)P%n+bZJqQg%9K;1wH&0N8B2D1n`xOTE{~fuSGXh4;M*58Cv2E z0L7SyA~T+TA2MD4)8LRP9(4g3rp7ojR()1b zEQDD(Wzjd^<3zA#&dk`c>u-ob(c+|zg+-IGbnXNR%Po{co{d3Dnj_S7G>n?>{RbpO^3oPyNikQ_OPPF$xDJ$3S-+Al!O6ywtLHBSb z%Fghv4W1`Wel`xAHQq_zd!wD_Zx5XrjwgnOh1GDmT4#C>5NthOxL^H=mw zeD(ghDv+gz<-zd_#%IEUFcFtwmD<_*L+5y=j3^K+Ucl3yu!;6cP&~cRiio!%dE6~_ zp5lMMj76i*#Z~D`$h0^v%q*r>Bl|;WRA`m^E&kM|p{PSv0#$n`8xiGJ{6KVb&MRWB z^s-En^D(4?I&x_b+|(dyLUt0suuSbi{mvSh*tq~7AD>fXGC2%mvWNVSB_+jlkgky2 znr7X-u*TE1hAbG>i-TwHTBprB+`kEN&Pzx~PhGkGmoslxY$M^~RnPDa5U`_&REUWwiYxw4@Ts~$jjl=ap;xwDP8FH3W@YTVAX zP5JU?hw*cdwNY)oLF_G=)WH$lTQA+m(a|sQ&;{R zd@ozv9v3|TW30Sh@zkx6mGOI++)_C?TqTS_)~*34sdb|qiDL=VTow_LQqyUz<=3jd zhC~bVDkn~#Ip`SNQ@mK_a)o|&h8-1_<9*2LWD)c5&<4dd{Mp8jE+UvpGzU&=sj(@1 zXx-uBP`8n#v9vy<70ju&{Hs_md?U1?bpp$~I5E4{H6v~kFH-L>QfoZg#{gXFsLWo1{NKoBC)ui8&x}Ph=#t2A=G$c1k-Wz z^qHFb4)*pJqdP0YwKylXDM5Q#nC*he<7}bu=(TatFi`I%pp*rsK0nwHoDwtU6CX@` z!|mxdyY!-UE-7R(@!z+l;}KZJ zp)tqeI^@#~zPyiVxb^ZJn@S$bATIQrHSLS2zoewZYj38`s*)@$cPTyDl5gsjSfa zf`=%9=3X*xXD-ROdyrMDj7c`>qniXn?#4q90BE8bIGU_SZvkS0 zPLX_%nfm89xHrxXQ8$6HS_Lan3Sq95k)9s1M~(CV`R)ZT<9VC!vrJ%caa}bkKIOJv zb9p|wF)w?avNlP?qZOUfCwBa;pN_QcO_5)y;B2Gvzzd^id$1s#SkWKQke1yR9~g_| zT-wHPkhZtwx2N1TA+2N!U$vE4Hrt*R86DgowiW+s< fIrtyOmbWQ|p!hu*l`%NF103I-b~wef{VDpNbzV{@ delta 21718 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 diff --git a/android/app/src/main/res/drawable-xhdpi-v31/android12branding.png b/android/app/src/main/res/drawable-xhdpi-v31/android12branding.png index 0bcf138d3e17cace5a37b4adb6a97afa76ae805e..efc7e6c8c995fb3d26927d09c6b0448b0ff1c42a 100644 GIT binary patch delta 11605 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 N002ovPDHLkV1jRz_$UAX diff --git a/android/app/src/main/res/drawable-xhdpi/branding.png b/android/app/src/main/res/drawable-xhdpi/branding.png index 0bcf138d3e17cace5a37b4adb6a97afa76ae805e..efc7e6c8c995fb3d26927d09c6b0448b0ff1c42a 100644 GIT binary patch delta 11605 zcmX9^bwE_z)0PH-1*Bz{PD$yIE~zC{I;E9P$qOtJ(hbrfAl*odpmcX5u&}f&-QT|7 z@BV-1%sFS~%*^vV*OqYecqV|4OGQEU?I*OuY@94I#fv^aS*?)Q{PFIiA+L!sF=Z8) zOEEuB$)jPEtol4o39R^(61m?iUJ457qHLNBWl)}I4% zi(=_W_)waH3wA2HKJ>j<)5p20`xlkq5Q1~ZUSlSE1? zmm8Q!;P{OfuT`9E1KBLTLCHns^saId0CDY@$Le61yiE@!4awG8kpTf$rEaQ%gDg+2xUZOXwXOv#SHMo*e1vJh^G z+E$!_9dS79A=|Xo@m|W>8HNDpeSfmtdrmv^O~$nq?Kct1|8pQqaAYt4!up66@?qQz zbH7Uru@sgkh$Q>>B9k~#s^~LpV0hRea$U_}tux?O4s+~XmGSkt<5H7J$T{Ft+`daj z?``x=H64l{-i}72Z)|4tcS_HG1wQf#y%wv;R0`}x^So)Z*>@`sUuMv1 zK0cXMqrV%FS1eA7QC(9&`~Yo36_E5SdXOcyd~c>%PO9?{v3Udz&ky^&YPh0VEG+geNA~b37l>)F9eA9v)G@ltY&x>1ge!ft56-UFnv#yDmN}daHDiRtj9ju zz~``2Fl#15f4|AD?j#F>>{>aIf;? zF??4Ul%Vo(K+bbcdGORuR++TH5TVwMgsDFu1mZeNvC6f}ad20zKmej{{`R|$H8Pdk z=z{SM7i#`&@uPXj3r(tZXR}Xr=(m_#EBtA4KUdf*0HlF3u;o^ zhx&DSiqX2>agqA?@^yk3WMpNH}k+21y%+D4H9f z+2WFpf4bYrOUoP70IQDq!Or>$YM5hayddK@2!S27W^v3P zKO{|pupuiEsN+7DSDr(MtQ36mpzrcXCfXeIC-lh5&QqZr97BaTrI85HzN_S@+-h7(RX8Nk)?)X0+^Q9ttudKnicku^g9rEr zF#xNo`*40AO2`yi#LaPRzBgMbp&D>CNB!5rLFDJnB|@F3=cJ$9kD~&pwq95-P%X}| z=kcKj1VL}Ces&W<@et!}-zThi&F`B;J@83lCkUtWG51_vSEiZP+i1K|3vl^z4suO( z-mfBnAaVaO@45Lgw&F7EYM{~s4T9SLyK-I0H`S&cMsIg)i){rzOe44&#a0yit~b!) zA0r;#uYo5Iif9-O)_f{VJ8r7A72rL+Mhv%%brok7Z<#w@IqZTu47|xod*VR5e&%K| zH|P702hBg(;gHW&bv*W=#EFWAqNt^IvT=`$TioFCxJH%<)PdH?2D3wt@F5`W5tr>u z5r$3pFs6Ys315n#oN4tRIX)*0m;7?59`Q)jY7)-K)IsK8e7J4=)+bf~w^WeVi(|o- zc>0%)$?vG10B}>lk$kwxs-cL{&z*6hWu`9CR?EO4)Pb_uZ<;%dUrQ3RRAwu$jxlTP zBT0570|!H=O80truG8z^C)1r_pA?DpKTK3RkU{7S%OD%WW6HLuAa>^qC6+^CC*{8s z0lo|m4|9_AKMr?gB_y2WE;sdU{le!>w*UBr*Z4<`$ghx^lg{O)NM_1|&C^<-&-~ov zU=7E;RQ);=FTA?#TxDvyeIKvoc&t`Bd@+OE^tei0z1di zSAXz~ih_EiFuLv8d+b>cNe5np6DN7N@CEv)uGuX$9m@IzthW2Ssa=s@3KU}_9NIxZ zjOWd`HyLHB5b}V0e4m(wnD?x2cC6(9-{j69QEbbJDE7HTWazPutG1_PNMCKgS@0vt z;gx!UI9}xEyDjrFyZzg<&?uf(z;4+#H-I&6!RqVd!r@Z0_uUv(qW}2r=UCYTSn%Ou zqaSVgH=%^fihiirSpMpgVtbpw!OQ{7*+*vl3-|>*FH9f zd%s}r8=wSX?_4F_2t&6bI1XLqcKX%cZGbMinK6^vAGWwZb3Egor~;k=Lz}t35{y~Q zM5+FxMDga>Jzd|bvaRkxtMq#9e6?GWtJ_PCz%ev_*V|ZES1tb8b^IO+c^qLw zfJ{-KzrkimzQeB_R$LvyB@#W;+8OxA2*Ihp1qzYJf z#JU!8b(m1fRWHMN|7nM(U*M=XPp)?7xqo$55c7H~$|3i-Zg*!5xY1zdnsZpOm0wNZ zI`L0?e5Nh8?28?dy5351HapPa(guUqt~;7%?~NgXbxStO}Wzt+2MIHhR#?W-t@^6-j{pg>&9U%^UsNvxJJ5v zZW9(i+0!9BApzpJfu;f;q_V4YA_n@5{$ah}h8`SL(qp}X|tQM1VM9_GroJnu}C)Pk4DLA!d(e%*N%GvixW zk%;}F`8bJ`gLRi)?KKHo|4J<)=*}O3*HQYrl^{Q*%d&GA;3k4Le1o#_AqS-uP0JJ^ zzZtzHYz-EUA#y$iqLle1o_p|pQvxWS(IO&J^gW0gfN zM0#rS z8KJG?h5SWp4)&v1K4uE5H4JSp+x_B`9`q3GSP(#&d805+s`V^Ujptfx>YQl$GSE7z ze}B}PW%7BMe+ko?)c!R2N9(P_kh6ul;D59Z;aU894LVaydW9RzaaRpXq(WKkSrp{? zsIFm3I4&PD+OULnEv+=Jopk@y(=LbW)-8duX8st&`*KqFJx8P$m7V>lfi&$;f!ED+ zx%a@j_N+=jNIo;R`$U`Cw@JSQtf*kLJ#{bZAMXXi#%b^<+s1KTiY`Z{r%U=>beOby zT+2BwLQeLZ+)0XhW+9l+I);ebw&Lxs#T%Zfmfoixlrzow&Z&QMpW8QuN>bEkM-8$; zx--Ju{rcP7*kAm}yqiS2XO`UCRKPxFj@5xI5a#lOdkkyjeAagO7s#VG+6zoYqj}K?6-RG1w5)sK#e;Ck11=sMuS^K|O_JeM3~(erR|rop?S6HP)`Vk@P5 zd-MW(u^3alQ$8{yBJ% zXuZnfN6I}`Jv}em+ArAv&%`e-`$a1*`#(t0A^(266eCv@d?aaIO^oYs0VnxV>!Q@m z>|hU@ko$c2?Qxg%(_6>VRKa)KmvT45q8?D0)f2SR0ZptPS|}L7{*#@^9B^7Qrl{*2uP%Mxi&!w3K?!t|S^DBj0 z0w)W3HeEF60eNEIgOEeYnlUFet@B@)$RqU{hi5APGkpk{`<@{fAhQttMl+r}HEaJll`sZQ$OqH`~d`IsnCuBZ`4GHxOC8;$3f_@H&RYvT*2;RgNV3!IVo zI8u4<=j>eo>)=|RARYMFKHXp0yfk83-vn`jRsGyP35HA!_cz7@SNPR zH*A{1v7_5J%bcD2MHCj#*pVZ#b6_Kj(dUQtx=YE*rcUxT-?-e1F~rjm%&pR|pC?^_ zl+vXFe1|xz+xgGB7!k=`y%+YlkS_K=cv@h4=wmiOLWuywp-fxmdADzR-)UJ}|CI8x zD-o5uB}p}I@e`+-w&e5}3U|7Y$fC(Vh4uta(A~TdE)r3`dGEM%K>t3_I8A*EH1#8j z1jkV#y~|*M4q}5=yAUseBh)Z6JECliT+y)e!kO-Pxwv7}NM{AD){R`uWrk|jb&h|= z+IxZO=<3cMMpPYuctKV((R9-eU+&+*ymUktb(`ZE4)qc~q(uW%0oQs%lh9pPMzeR` z@AlyqW8S#Zb-x}D)TQj|rB@Hu^=kbU%Dnq)0JaUeH$U6&FO~@XE|2b`Qaf>%^z;`1 zuXoRPZz$K;5-yzshd{*lgI9tFJ%-2ar=x&x28G$`keyq0?LBx;0BzqkkH>jewZ>#= zz7tfJZ?R#ApD}erNciqV1N{B2}_Y*0h->nS!;Nbng6Nc+a2|J#AMC{;$5 za~ECr_ctY}y=YZy1#!KJaC4WsnH+xW!J*e_1L*LVGZaj1rhm|eGD`W8=rq>Lk^H@p zZ-3X(2oFSFr2fPx~)gv<$P+!;X&fCfJ2Mx#C4CMh%J&;qhjyPg0zGx z0IOTd*w+1I2QMEz9r*{FhXPMWMBqK@KE{lCM{3nA+h0rB0{Od^FW(SJ*Of-SS{!WM zR0!B|&0VHGO3;|@bB{+yN(Ze6voqcd6G^wI`VgxHV9m3{Z65(Hs!{LKCNFVAl$R&- z-N7NQ6CPIyDjq=m88aNBE*{KzVOQ9dhz-3m!ByH(Fc3rA+dTWht6lbCKWZiPH8a{F zQDVq=_ZFWEqZ(>FWUJ@m{h6{#D?!WlZTRAq4(Uqf<{voI`0D4?Pn$6~HN30cfw=DU zH*2K0@ofUOl}rG$WFBn5=WBjXB8lUq>p(950w7?lOzC@nK6jldtw!04UYYcOhUdSqIU(zJo@CtDin&Lh9#0awb{BT$0KUq30CFaWB4)wFTZs#Xh zk+Q1WNqqXZ?$csN!C;RCAz*kaPAQj&pX5Rjn`B1e4GgfgUu{J7kZ`qKZ)Z}97I`XZ zk=irOcnM)Tf~W7kz)AZdF8Nd}WShr+On!{ce-9N+cf5#JW#LpF6LIV5Qf(%ZIZRg)DD}moGLnEs zxB`}2H-#roC5NQ!E9j+s33ozo9arP+cuUd^!1S>THkYG8=Ta#i%gPI_!=Tbm&MybA z5@dZcaI632FKvfDbq;%w#2pKbJ;JT-=0_JcgB_lRfgpRzbB5E^RkW^~F(Rol4{-es z8nsjywWRM^plEuAeg}9To_8xDKgO+pL4Pe*zf+v406-_v8D3y|NnpKbuhot;wb;> zr_=t{K$54a4?Kmg=2|#4gw|k`nlnSt>BnE}7Si1>@KO$f5`Mf<#Z~u#+j2J7Ic69w zKgna;)-?Tj9t!jR5i&T^8tF0d$m)AD+v@B+uP!#70M2cd-v5hHT*Ue6=bod0JLgk()Cx^=a#l4dJ^ zvVg%;2TcyUbA;l_ic|e&<(diTS8U&+6SUL1$0KF!kIL`fP>6qs&yfneyE1X%%e82f zOg)^BrFxc=`=2@BM+m5~l7yvjXcm=g<>Aqvs2PM;-1@-CcEVO1iGE1rMDHiju@d86 zlhNKtQauZM{GB?YOr*w;d@(`R=x^jNy7D+y8=F0O9QoG|i~^~jL=&&2&Yk4?d{aK= zFF>kBWf7y57Hx`2dGf3Ecc{O#o(-zlqfU9i>_-4W27rk2lRg%7gIu*Rd^j)1d`Esl z!QjCcy2Y!i{#9_`xu}adyId3ZG08g)qP+zw*;&6rGz@GHsMbm@X*2shidSHMq-XjS zR^Yy3m?smweSdqoCgOwKdU}6zZnQz48Qu4K;`O38Ln+K(u!ZjYdWNNgeviE;{16Sl zOMY4N1elNTm(1I@=WGiwro&5g_|GvmD=RC4q2b|VXVJ2}q~$0UIqY3$`6?0JHY^9| zo8(3&)f=Xo&91K|+h?5O2E2!V&H0I~*nM1uk&LEbS$hp#sT%*ek{D0ODrDh~*0=`%zbkQSn7%GxP7S-#Bj(Mv=VdXZ8j5>adLf|T)78Wi znyKsP)xS_W05yK=djr0T4q8sA^yr^eQslhq2iBzpICySsIVVCg&7 z^OYP7apoO$8G=Uj7$9aE4MPF(#D>;R*i@hW;ttljC2m^EeO zAiCwP9~;A&ge0+XROb%*LEG2v%#@p=ELd-Y&hzLj7U3(dpK#v->hj_cVKIfHEG-4m>XfAb5j{?2nnS-N*s6yA3!{G%7I!~sZ4IAvbIKqX2{&0;Ml75J$PnU2DSk22w z;bZmE^oMCnLN~?uhjJ21aov?gLkYTq9Q*$E*sy)`5+!)Ul!|7IjTlU^yM{$D+@ zOZo@ftrUqcyt3s}k~@g?(0V9(YU_~P9eIQwR=IV<-5As3WzFHMW;YXdCx;=X+8xVj z2H_5@%p#bmNnE%_pH_*cb_tISZ4tL3v9A>25);@@kUII=IhiBwV9@-YE7=wIFD}q4 z`T2+3*RM6@D*fuA!!xaw?8nEJelz{a`q+;LeO-cX!+-6)&RSD$H8ctG%D1mXQPF+DBAO zm7YMNhFFgP{yJ;v(A{;5ny96j<+#S8C$*=T*6@LW5d$*Tx+SfrMEjTC!w)bx?lr4C z;55%v(~k9c5x&Boo;N&#Th_`<8B#UsmME45{$24J$9CfdM#nwZ42O9D#(`6Klh0_+ z?2PV3b_{9bH&|FU_18NG%oVTZC(Bt4W0ZXi7nnFR4Skcm}8kiwkQw zJaCR(xFVVCf-c-z)e-}QH9dgumOp}E>hF?k(X9m=n38)qOC5|uk>YZX3~Wpcexwec zp6$Ao=q$=AjDCjcUVWC+ZErFiR%y;ue>TQu0+6JA61naOb9AM9+*K+QqsksJMORDZ zx}J%6D#i{r_x>w`-(mM#_C?%U9jM}TOxg?_*IqA1B(A%_FKP!b6FdMgwb(LOd>~4z z#kiMZTPe^Q#*J8p<%n-#U(!bN+Mh{;+;NlSgl0V;cv<_tv~o)bRY<>m;4R%8!gcl- zpg{MrHTXMfO?8m?gRw?UoanZ!OVmnQ)(7&wmiIY(3Ep5$^}|?L$C_wFfc<=#M4D!v zJnb!6XpXh2t&c`vGWii;>?C(Xz{1N!T3-I?eoyK}&52hb2sq8u`x%(PFw*MogPJj8 zYKR@a+E^2LQ#|c{Sh*noA)YF{Alw6LvE(eV(v$6b7vJ)9pCOznyZl>LR6`@VPlXWQ zaFToPQAK9CyNu{}BxTK#0bT^p65gQesThi(qHB}a_>h}~v6BP@x}M^seF|LKk{c9F z|E89f`m#V*?CGCBBx(=`QR0&CKcMU%KN~)F4@!M9EOWg7-I7(|&UL6-gW_3!r*Rvl zeuuAo`SxXTR)T9+OX<7kt(9m{EYn+M#Ebh8k+o24!G8UKqCS3MGx3SIGu&xc+%sdM z4!6eTLW6o6CvU+Ups?DW-MgV9_&hP=@9L0iuSR>`;Rr*)Mas5T!vGoQZMx*&_vNn^ z_w1Zy9>58GQrFNV>axl%jO&+Q{ka=7UW+*Fh6sN>>^V?Xf&`u=uwh;dnJjL9m?v}7 z*LS9mORacADZKN10X~r*U_9S9$+*=f1AoLp?t2Rw^hxab0<4R_1I-xXrXKdJXpoOI z*XM0$VmMI7NBhNEp17Wa&AggPGyGkeX20fX#%&LL*8UtCM=!8B@my&r%+gSrJ5^U%%C()O1 zRX`Ik4gAalYbS{XdqRS*;$gu#M#Rih-Tfx&2vx|%xoZM`8zM-9&1B2LDJnIh3Ac?? zsU=vm1lH8{W=#olkL*uzWxM8*`CpG zY?^QN2yVWpO3ZZN`fwgY&Z(OYL(i(Io^9Pr5dEH7NGiQFNQ*{3TNNSg4IfOIsH#dj z`N8|5bcxrlhlmC>n>^WHGh86$TkJPhXELt4$**aCt-jTZ;|O*-)e@fK1Ip6ur9*iFjyPW;wy=LT*qF;5E=dtY zYLB45^+2`%#|9m~=M&7ynPlq-t9~b@O~rr$$c^_ZqeZXp4hbeQu%e0N5^|v@aZnxe za_^>h^61WmJ)-Ag-+ZInwTdf|e~ShueGv2qrG0p(;(?2^GC4!63qZygT0z$7aeN27 zsqoB@9K-hZvFmmeKFR+=MakCD3?%^wZ24+TS?E7QA02@~jdewMkfz(2~i%&qFI5 zD)dpOO&?!@dXoSG2(VNbH6N)V;%VzQ^(ypVHfa|sk-#wB@I5|_{kn*typ@W7oQm{C zm+_VkpmEIaD)qVv(i~f20A-@1-SRK?rFM3^nnR^^h|j@aF6a)^8NkiW4%RB7?BaEaNG@J{+_a7=Fkq7UvnxX8kBkF(aS4b zclXAqi)KjTYlZp{iEtgk&9AWA0)l`CwuwVu#n^VbmT$j<{pqP&qmq5)A1$@Fq`N0& zlce#HF9YgIb9ncBz56z+0K9z!cEr3sa8&nJ)rSnBhB)Iz5+xCe2s zT(htg=2vnXQofDcRsIur!c6kaClu~`rv`-FXAf^mk0t4VY*t!5kp=D26amn>ZDcMl z?j_T`42s~k?yvOGJLQHBigcW9Dx^_6!6m4!#cu#z#AG<%P^2TME1BWjPU$&+zce0> z*8D5g2tO*{FvjBrQ#c#`{J#i8?vQhu2`S{&pNCXsn`Dq52hq~e+-wOAjKen%)RV_n z{wC>0|Bta_E8pIY-$D3zvj7q<+5~q-|3I(NnG$~~iPUMYU=^T&D-D0##yT^>Sjlh0 z`3{I2WX8J0KuVTC*G^$~v_)x(S4phA!cy1<*YBkqyteFQbRYDTr8@C7(9k=O0RxBZ z?rAT~V$tk@3}2R^ZhDPvcw+U$;iXQBMUQ*`Esk}Ze`NKVy&}y~PFX(}#`DMY%($}53SU^1qlg7HL-ms>g;R2Y=V+!AV#BH+11vrWp z+y_2O{iE0_ptfca^mtXBr~^{^8S5`!JXBLxtt3C8KlmO;T#|H9cSM*fn3+%;vk+Klcdg5VnGr*O;j6p&hHJ7~l{^oq^e_qnteGurhNZD1{VCdrTM zDR7PNhjIQK@Ak1$_&iSeQnjzlR>ALeIL9%+L%6Rva{rjEXxN>e?GbR2Xi_WC>!Y5z zaQkbXJC3C_`(ge?Pbs`W{zwLY19L6tN(_YjOaiq!xKN#+kS6-4=y9PW7HBDK<`sNe9>{{Z zXY|}{<8A%Xa6He{2?{qQcQFqzEL4i&M^U%&eGL56xl`_A%^zkf#NKcIiHVH<0VF^_ z@SUlLqHnoUWyIxzZ@b&8Cnm!M31;_WtL) zQy26hZ;9NG6E@j43|&bAO~e4tU|`SS1N*xjo+3$Z>w;(;tuRqGYT^k9+k(BQN*rg4 z{@$Xd#_)HbhwP$DS~MT7ZTPYaKz>PA4$dFdsjjoTEz_sOITXyzSXPnx;+0;CQWG5x z;+`MZ4d<^7(OU-QABVnK!V1VyzO^-A`*onbGvR{^KS^A*ksw*a?u%OCL1M~wx*7z1 zDxqctpWh|~cRnq&8M4u)%^1Y1}5+ z?m_1XV+>m>nfHk5S|YzUiODG9(Q6XT)7I_H`Q8ltLw63_!9Ns%5*V8}L+(LPP?$Ff zSBtAFq<1I{^7I+A1nBC?Zngk}z_6SEkoE3Z0;H?!go*Tb73_m*=A3z^G1k(WFF05- z=NJ-yiNBTPB}&=4RS4+#7_)oZY+B55m5AG0t10^tB8Rfy==L2=r;fk*#bUbp{r85| zk&*#F-8+?J$+rtHPAfZbOePr)Vr5O0JP(6S`tDMl(X;sv0~BYD6yKWkCeXT0MZH?m zZW2vF>US-O3-$Dp^=isV&FwyR#F9!M+9UpD7f-^0&x|(B5x)VY7UH*#HfGnkGTA*_ z@twH4wyj_RylhSO#~Nd>OxLUTV~b`sVjEO~H1Oqk`~ou#iJ6nNKcdGMa?q~yskPIs z&lb1A@pT|2WeBdT7`c30KwfVJzK{1tp6~N=&D-R-^k>Yp)VbCw9q-+=45fCtj$`YM z#qy1pCP#vqRwHrs&zQJFphQ)Ah6@7CLu=2^6#eHB3K^VydeOsZ{~@o;13x3@ zfod(P{So3p{$*Lg1hFTluTYQ{aiZ0WcV*Low-<-VPZdzI+FAZP@e+qYLS!2(p%&4M zDuvowoiY6aq&m;!bTT0lUI!tkrAGO3Sk$hpOdOi>SVEJQ^BY!c#NkldV*ZIy(P-4f*kVis#6m{|L=C7QDo9ljklvAw6cH6e|NqW=v)8$Eckk{k``)|v z{l1^i-r1cwbLPzK?wl>Na|>C75JE@*6v}M_2qA=|Cv-4`5R)Y^DwD7;pMOX@2UE6e z*%AoO!BPOrX)Gsp@7{e-rIkUD;gC(_4nXdtq32wW;?5w?9v3^xA~=fl!%@<`IEDQC ze9G>J>ddMYx0_xWn=_g&%b=w9Zcrl8|c9c~~lb?s+Qs^&&_5V5O z+m4_V@)YnYn-G#dq=kbybLLDl1dC;T$BrF~5WG~eV#NvDw{O21>wle0dDAIC?w$%2 zD!c%vaKKD+av)wn&m^^ak(-RE7j-y;U<#tUxnzl!76#g&m(*X@Ro(uK)t<1cC)SH2 z{J}%T87CW+zA@0z8|IEdavvpE1>2{gcQe+@8TD$4-~!k*!jJ8Qkn|zt9gK9CRLT`FDGYsspl`U(e1+po3&VCU zYW-ydQokM&kBK> zTby(_y#TLLrHVbQ`Dra$oY~*8BL(JGE?s&Q zI^n7+T7TY2To#X=2EIp;MFV|*{Y3Jkt$Lu%mLq%`x^93??>UIA!%_<}cPCO7Atbd) zX$OOjZbvs-bX=IANmt0vfddC3?le%wUC^J%6}|6K zWF90uTo`TkH`GV&(qwURFa;AWgAkJXq_l&nQGcVxe);|as|&CsGKx$($s5seo(-qv z`-^uSl| ziO)jE-oZzf(`E$nb&>Z58#Zj1kM+17XCdz=O4pMP$uqHZj7M*>fHOW9ZIv~Z3v6^8 zxPK6XuF`7tgMvol^oj^iFCt*~?hJCl1|0gky9AbtsNH98v3~)~#FD$WkAiV!chA z<=eU|LWev8JdL{Cn}{w#NP3g<4n{yn*MDlwnl&%fu3h^s)%ls}8TISeKVNOW>!PEH zcmU)-roY%Xhcr9shDg?T9&6XG{c{vi`7rTr$i9Lst34|fNf!@Wu7%#LI||g{dx!LI zVPDlcb?W@+x4GJKyD{5W7=J)!B!yd(U9>o6(-L6BCkzNuuu61)RsyxRT1XP+A zyOrz<2&!YLqT;B)92?2%s_-3hH=Z;H+28qq^5>0djZ9EXc^I8-g3`rU(?_hxZ1#opQ zA)K&svNpE27c5xNPD}1>h>OF?Qw}DLxXUBGF*@2TnHDWtG{yQ?9`bnwnOwB7r&J_+ zDta1o3Ne2hxm*@12mMvQzw%6y+pFaiLowe=P za?-GTj^4qA{nauq0_2K5^fv@~oKu!_XRX)iB$f;#{ZskDF*gdwpnfNj@Leh{s%}T{ z3>Nt-@ZX^wUr1CZA+eC3984u`{eYfu<&}R|zBza9TzSkU)BMkB-MY2of5wpHgHA7W z3}PSjYSpUMzpz?L6PaN}cFK7U_1-Sx-JS8DI(I?tRj2$o1`nbBw_){mEX#2Wy8f+1 z4EzI&{l7iDQz1D{zHl%&$Dh@=aUw@dX^#^+M_#HDcd!q}BN*@XCvPcCk!Xo_{gZ!K z9{&`Mu0XI>Z&oO08Z}O_BtHUT8H#{bLPw`k1Nm*wYbWN%e1nuI)yi( zdmi%djAjh-l|Uf+`XH42i?Do(yju|-aVp==4*f4^58^U=5zuh zul!Twue7M+SmbW!d@K9CLnu!a=OWx-{qpkopq2gC&HBG(PPL5p7ARZpa;E4}SdOT& zZJNXOtteZ6UnT$Y*+Q+~i%#MtE8MvR!4>*OyLRoS>f5lP!Y7}6Vs>WVTiJJUcD;*9 zM~S?J5T@e$hmg$;8#aI3gZ&rk*ij!jj%0rqHuB8Ga;*>Du8$z0`;cLSK1iW3>{x>1 z<1#%@KG`264${)W;2Z`B* zNYnKM>idYYMdWqovKndiRKBy3?|}8o6>CN0?SS-IvVrhHY=@jO>a<$ZBUhv1B#-&D z+Y>dMyo?qVp&K@A*EUa}9nQ1c0r@{c&{mWE0(EGbEcPd%5qh>+zc`ABw#=vdgZLor91IR<=~T@R-nJW8 zxZ|g1nTvB)XN;4@+0EUGva32E5`A#O^y*iWuZ-rqD|%Tn;ak8 zp=XknePI2h+4^(}s!YgueOa%>_=JULM)>m(*A339zws zqMMEyG9370s{XwFTb`Ay|($Nn; z{O}2cp%gY=}|*X?+8>ZBDTKun~ViIH@x~`skyuyA+i1UzfaVqQuv8 zNt5y_+Z$-hJN%jH3-dX@&C?FfMX2gSr;HK|b!ajG0XF|5PW$pICxTFlM z;r<}5q@9BiI(6za6n71St?VzD1$jC7HV*1rl2n9SC+&t?$DI)9fUklxmG36X>hXx{ z;F5nua2rA`BemS@45Tv?><=wJ_~3)#*lz>1q$x7L7t*K4p>s6yj?$v!4l><3G^Y_; z34?v$I8;3m^2z=n4y2`n5pYmnWV~1CcFi@{)I~?O+BK7ZqFvEB;rS>7wpEPP2sjd% zW<(z?wqeGM8SSsT?z(t}g2q~>q=Nbnnm&Jh`oe3kz4i?)TJFMl0C87Kv z$kqLoAc^b`l0u}dgAveS-GR&k?fxNpCESp4<$o?QHL|T74 zn9iL$ONVtIR_&Mk8Q7K~x^<)F3jpc#qdFLHQ>;o+zc$OdJ#!~mAj{dK|Q{KZu!v7euvW^I`22^7yY3>WkY&X zq%YOB%?={w$92g>?l6tJ7;(_HgL%x#{^&3Zh|Pk$IjEtfwr)P+lJ9Opvpb;f4bT=} ztNkEzdSxbRf08&m$@)SU7N~!#9D~Wy`|)2EGudu; z@+L@=G5YeamZhB1<3zry?x@zw!k#?{KeodE>`Xprvp?Q!<5#hKM5=eluzwfgLQ}xJ z^Ugc+9QZP4*EuRmI{6;joL@3L z)Ba~n8M#!_)RAEMolt+CJQlNGV9SXfaxPP+PVI8@%{RXbncEx{cq3Ee+^E)zt0BHw z-@5NeKOG@NFU;$ zFI*mxy_e_cG50c)bgM*RD`40LKoHAuf2^`@1E&4DlSq=s#TaC$+C%=YtnJiEq zQ*AS{>t!6WoQWzUFR)R@{U}46NM$U0VUwJgf9%$+o7bZQFWp_xDe8ZuCf~;t*V6Ao z*&9)|OjPOgUg3Xp*wP+$9Ct|b-Nrufr3ZG(qd#5tY%OgC>e2|IJVLA%ncLcqy7Wa| z<~XEDTeL*}$B|zq0F_Ss1mtDb=znQ>WMGDUwSAeB9-ruSi2C(9?79Yay$HMHorSz7 z+WYCJpVn{Nw(Uv>U2eyquCG7zZBg~CY-K-!J&3x>+OFOu-)WU)Lt1e7o#PlP1ZBnewP>d9;;v$BFvL<371F{8lzmAJ0Jw$UhXp&?qAM%nv`fN_h}V zeFfMhkLG{wb4rUz=?d-y?b|=WqBd4^uD#@aZ<``&%-p) z{W)%2J_7As_^r3z8j5`}4f`R?f#`ovAVBW^oV9aZ6gS?wVLz4+fTj*eN z7&wm^2xcJcpWC+NXVCsKvPqnIXe8O_(W6`T?b~;LE}BJ1T0sXxh=R_AkmN#>AQs(| z5HKiza*0;}f<<@UdFLpHw1Eg3BkfMLT@1lLTvTm@*z;Q6hY*yv^SYG%R|Lf%a-U0j zKLqu$oQ-7*QdN^nVDd+MO1*#o-K&qU*7YjEv%HT{`6I(KaR z|MqF4Yg?=2zroH2WnQm2p$kx&$pszS|t;Fh|uw*%y5hF$%goBxm)$6cc25qy)&~q1- zZ;>{~XSrzu9Sk8U4m#3l==A1c^~!j4pi_Ur%62ZVqEj7c=ocrj2{Plbeh8g^_rD7{;X}~ z9Be*v@ZiBqr%s(3R%htz483R2CR^cP&avYWWjoNaan>cJp@ShLJvcYP{PL)5kLg@= zUVH5|=|f8+Jc$l-H9FH036|-9RK^T+;{C0xzI2|0u>U)(%KIlj4#p8U zmp{8C-G*fx%6I@}Jq!C=V!JAq(WqBkPB_(}gCQivdHwa*hazZ#Ws{ez6LLi_;T?C} zQO8GFr_foxjn!M?Da#M&oW+xk#NEu;WI7lDb-etIH{RF?{k>3**Ngvui%{R!jr?*a zBJYomo5G?GdgW!l490jC_J4}-4B~&CEc;UpIv7Gy2)TuDNs{*#)%6H;q;L3C+ed!h zeDlr2euPoZtzrk%w?~KTII=7We2t}n9^qCW*l>qmrKsa3rRH~7yd2E=QFKpqioE^y z+iRnYU1*-o*es0gh?o9<`3X80LQ;snz#)3ym@#8!nvv+-ZuhA+;$4FupuSFk4rYsG zI2gD3#NuEyA_fsS5b=_~PoF+@Mvor-Dpvc76G8gpditnQqjtl=%*ASJEIY8hFb><& z209o*QV2MbF@9yEjk+@KgyMQXfX?=#c=GwAni&zpC^A3n^C1&|;ds&fYp}FL^BusZ zeADu{DFZXFQtkV6;%25cbTEYEE)gFV<^s=R8HtXw0-VMUFJbhZvn3omcI^59ZK`Kw zebf^2fK{dh4ry?%lh~aAO$_b^=S`i4!Ll z>d~Wze8pcfU|Yt*7P*@mg77eGkq<9NpzJ-cp%vEqz_tM*i?H>iNt3>hMZeN!xTH@yA!+Z)WR@)KnUbqM8PvOWrh?zx73;ZE2wEFS&ZAb={+ z`?aBaA8hXg+vj=Ns8K6QnZH4CQ#|tX9ZYT;KuCUn2OX6>5*lj8qqCQ*@8fE{hLt_D zu_us~xv!#rWe=Hao%Ept{z#l&w{G38u(D@5mOkPLmaUT~Pu}RFOYR8#ypvg{hpc7lAtvhz^F8MsaO@Yh@9_fo?C{LV=?=S8lFU}wq{a+&Z(x>by zZz*4T5}H9E(fsL?VHR(HfVp$${sqDG)~#EAk=wSU3u)nC=FOWYfBkwjmP{-AZ&?>y zdF7Sca@D9j2HHseA~#cQE<*dv$W43l3##4gVJU{?zi4-MUU`r+K&=kNKD!6|>EF3( zP@0g^4rc!R`O{mpXweR<=a^|YUjDaW!Gcd(wrqJ_E|`{QKs(HTL(l?Ch7m6()Mm8N zM6}T(xnf+Jg5&a99GA~vwT>0u?vJSB@^!TN-MM5QF~B|v+ZWh3_aUHzNdhV9U~qzF zHgDcsI?jSo#LmGG-OlT^@#9m5hvx+j7vf zv;}P`cZSzQ5s~A6@-E1=MVr^jDZ5Bi78=|8oP^NtbVhI+`ku?N@2UlFR_c>-4hGJm zXl7=nc|dH(av$P%FIu!nuEzDdmJA#a$hNRJ!XI+Z(%c0d*iTltb2)-#tXh{7rJ|ic z=aL-I=I>aM&Sg4|%O`ML%A+#5GA^#-f1jhq5m#{he}#R2Hvy|Xv8==Xy2?oo{l|Nj z@g#smC*>RrcK#uKyIHel4Zi&H%a!&v4wlZBUw(PC+g zA~;uzT8DP2t!>|pHo63D)D`PL<*aq-3EEuVv2@YnaBP;wv3XF|(f*4OJc^ENsM`J@ z=dC1eV1M*~LeR@gEGKM9CsNA6phJ`s_$)2zJ>9w3Anph{(4q)WYtiS$SXN&I<*`ge zN3kV_eAgprt~TFCUh{5Cmo0|$AB{M<>*%jGM=)Gwq5u6@ZHg6?S;cI3wNGkAvq9M^`(QVJWM1}BjC#4(=PTGn3Hcr+X-DGic%S-H!uynNJaP|1Eod+H49hY5p+5K3pk7YRG2P>JK z2+C=Hs-8sLLFl^yEFvdbt&TmGdCte?(rnV;HT&;_EMxzv0U2MKHbps>q`jWf^{9Q;Mvh^m zpNsSjR`_u)$J#cOaj8+p2*}Evt{j&cDy|6PHtPAMt)c%_=pU%I=OAdUsj|<7OCS?} zcGrw}{n7RN>TbgFBa^K2$tqU3yfD z3OO4be08mC=OPTkG8j8vWQ$mlTmbp`I5~Gn7roVN>W1-r-mhM^G2-<#d-M`)t1GQpa$A0SB4N zC}S1MsAoqghgVS9xCG_3h5jQ>MnZM~Y;tNPOv=UP9WTjrK*aT&Y-LkJBIwt z5T1sd{^&0z$BMeG_+?mssQjN$$JY?{cgYq4d1qST&SennlDHzUOF9qxs=pXyKSOzK zVzDn8D5oLHu&@3vguTlh#1dxge=#a-g1)*n!(pgrMA8v&^mjOtBe^1HF$iylt zUcb7J3T(XBsKaA^^9tB6GNf5|E-yjHKM@v&O;fGx;m$%~*uU4l0$0b<7TadnA$M$L zl0B-4T%@h7$YZUpVV;~Lc4ysGodd#YmA`=9&PqUZ*-lW7o6nIh z-~QMgYEt{095|o!i<{qny2SI_CKpo1!7N+0>;fZdjiX>}9JAEHh68b`iff0mR;l&x ztn7oQncCK0oXg2N+tRKC8#QWFY{iNdXSBTEV5y|G^$trql;LXKJ{b<7;|SFex=Jly zzC1LbLB{GMJ(jWg(usboN1%@Vpyzhzm8<2>jT<+1yQ9$`eN9Dwxg+citd}?w?!6pG z+{6po-W(!oUuh0Rn@qN{kJ(c$w#uWew)O_(FA{m|lRcWuKy7^*N_})jJ5ZEsdXq#(cQ^;Xqy{!s1I zp?4o~9Lrt=c0TF*0(pMx6i?hq83%&{q_+`u%26;jDj%6=$ z;(Q|UkunYjn4Nbrkh>H8MdWZ(04LHRBT8N*k2B>OG-wdkQR9G?M*{lGMArcV;9KK_ zbt2~avb9Ajd0|s>k!0;91Qf_g&>&@ zM($!lSL(2@tBYLNMF(s;?ILG$Pqaj|Mc7?2$_;!v9kkv3`ZntDttkULrW%ht+nF*N z`yJxK-VZ|Ggjj4efsN(>hOqZJI6hi~kAFM~NT)8sjh;VQ}2VG$uI=0DRDm?OiYA%i+X4hDxp2RJN0?{0)j-Xaly zM02dXGS7kYiTERB9E=08ej6ezOG3H!v*obI0&pVr9AuxbQ>V^@YuBzlo`iCf0vw$T z*{yH9s86&*-{UP3Myz)pK_KtPY8Y{Qu)kVie{GIY*JqY?=Z8Z<9JXHv6AzAaWs#I2 z-#EZjb}-hOHET+sLpbb~u705t}UaIWOUY! zb?esUm#fJQG0ImC!iYGKQGm;_&*a_PVeBub_ZOZZ|2=R@{j{jguELRohSZ|8%0B0MOlC-$q;LFRGnB;M4QAiNmHq zz`l(3v88Wt9GKIO6hu7-qWwoWW(Y^VAqhDc>mrpd~*9AP8Npf7B= zFUrv8e-hoUSLDe1v0GXk$On?4yGW@w^#47I{AXC&X!7SnKBjM0q9FT!{~>z=dWS=Q zMT8HVf{6bE;{PG**iU`YeqFVEasdxP=BVR|~4PE+w5N0{C&Ec0ar1T=SegX22#{m>Jj}qdZgr0%Od!bkP$pSV! zrB;hzy+7JV9^csC^2m(RVK3!j+aucgyT)LO&Zxs6=*jBTq&}80SDP-3y8Z_HA@uEx zd^wJ7`I~^MNRw|RQ zq?bncgC;LF{vERN#eCT8$kBkT{I8CDd>5Jm1bXHBl6z6+ZdJY<1JeF7^-7k5L7L3V zC10c4@1-ijhL@1{x5^&*5?{a5iZ=Ar2Tfu6y%WSllI2(IzH2KCU(8)42 z9zwgfG|y!nnI;K;Hp*OQ)nR8n?EkDmM-IpTF>K2a{*p+u=aLJ3;4R2SGs;S6=y+Zw zr5uca9r>0_mtkdJjfSGJl*SHpdR#UVc?LMdM<5*#f=&)eC#zSl9x)6RaTPXh+!*?Z z4EcM)Hn|#=4okkg4$WzV_-AE$8b5X<0r>z?f8UhVK2CyvsDsnoPcoc&p1py34TJsv zRGa$8qx+>})ia_!q{EbV8MZ?`8~OG36H?|ykdyyEw;kKn(W~Q(YJ0hGuutd$C~GZj zm0{F!(II!B1#yCJLi}t8`LhszM9IrQ4Bh$0{QeB}DvmOw?)t0~#ZX4XBOUoT5^Z<4 z%2yHjLIWj#AU*`?GC!VNNr%mihdeD~wJWcK`Zv zrsJW5$t&Q%np3rE)eAOl+9Z!dWHLUd=bmp@t5$7)$mY$P6B%(Mom5}w84o=X9S+Jr zjx@1jzh=YPR^%7_a?nk)-0`y?eD5o9sA!)*z%KdYHE|5)G&@o2h5Ykz0?T(hpKH-( zon|7xlQXsue=*8_%gX*JRp$YuJuhXVjG-t)oRbWQxE3c_A)KTqm0T=!?XD)~)W2a0 z``;gboY3+pt*BplMa-kXP-m%EX|#Q1tc!zon$Jw`B%ek*jM4J##dbx6`gd98(C-zH zF~87v!l~_oKF_25v#b+g_Nepd5`^-2NpG`Vh;M=8#cmgQf*{|xEJVE13=@v}{m4LH zIo1B5b7lYj{h1eDc;O;V=3K~x%_6Nhh+|BD?oOsFx#EzMK|sw7Iq8#rjrz#v5c2NL ze)QMChrKCDN;((;JL!#&;AW*lsjt6=+Ek7KaM^SuM|&O<(b zX@`rUOFk-<$AxldHVSslbgGk9wsf?&BEQ@@Wp(UMZ3#WaUE<}PS}acHPbf>~qbh;2 z2P#`-zO@<9B^|=v802MC*SE0igx~T_pi`#3FR$9Yh^mV?(qnFVk!J_W7N=4c>vvke z%rG$-@#B%tb^3p=b^!Ge@Vc32kq^yI{ zQ3pa?PQ}n;A1E>FLf&0CsGi5_^FHMxrUZ#c#%Eblub3Q^mQOm%KgC(DoKUVBZRzH~ z5pPb<gv6muqQX5gCT^F zB(rVXwuY4|RgxLakAL&cH><7encL-W4Q@t!*yu!=D==4#%mL_N2q7fNz=_y@uW%OD z8zYouu!CqKa{%Uf=wJvTB*|2$P@(mX9XsUlSj{M6&1Lv?PT7fHxCZr^Uq&7Qu?%WOMQL9|Jax&sfMp70+oZP|8Kz}1I^$+gawd-VbEvZkwb}%>q zClaU7_lMn$~k^xW_{6DVrQq~yOS3>{* N002ovPDHLkV1jRz_$UAX diff --git a/android/app/src/main/res/drawable-xxhdpi-v31/android12branding.png b/android/app/src/main/res/drawable-xxhdpi-v31/android12branding.png index c7d0177681e63abe4a1d58e1b5cbf7325dbadfa0..593877e01266445699239227caa666a8ef43118d 100644 GIT binary patch delta 20410 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 delta 21718 zcmce;WmHvP_%-@dB%~4P25IST0qIscrKG!ai*!hLOLuolNQZ!QcX#(){_nW&{cu0L zpYD4;=okma+57DEtoh7m&bhd}eG%yQGLqt@&qyWZZwAQZrQXC?`zgV!WOuYAx&e-s zRb?GbA%}Tz(Tr{-lU1Rn%>CJPeJNuBj!kK9-Hev`YyA69D)-njim}q){nW`rH=ZBL z94;Fguc^4^U#A~$vt3&{eD!8C8A;k6NlG%jp>f-vDs|c%Oh{<+GMvnk!qex|)m=>a zLK%Kv0FMWKX+}Tt7k#|DycglmeBU3q5crGOg;LvXk@8qYrT|7-Qj$5ng^QZ(y3($_ z|4MQl3t?o&rtS8t1@`azKObANF^*wPOib_+*ECz*ou-#sJ-Eb|oJY!Dh|emPA-I`k zk`9uqmT9};VtFy~%f_$hpOq-YRS8<1ZS?1hhZEjHDSK~kw=%qwgq^qL&acA_a|dODx_i=MR3j;AouW{qd!j}Q9a{kT;&kbTbd*DAP|i0l`v zH=D?tB;<88ZMrk`4-AwD^!N8d5v~)t_7uulD^@Efh96^5)akHXXgKYuH0+(4F43sY zI=X#;Y7Q3~&rJ$mJvb?xYqfD`p4U$67DpH|ia+;}#J|_5dVajWo-niz?^s@jmRmip z8Fyqo-|YP@{0vj1T3Yn1eqN#9WuRmy|3T2xc!3pGn9y;pJ2(cxBqI!;QLE09gPJ;j zdb0d&?j+3Sip$34v+S(T@$kNg4OX-E05i;-{Ko$Oxe?$a$CbG)aBh2qEF2Zu_sG6W zKDYEbK_t@xT4#*KgIHutm~V|V5QynyHdn(Y^8$1R#_hU;F!YXQtMg$$#I?(UCi5fKqL zr4hqiC|9(%W}$)2VP~HrE~Gg(8d>RBpx0)!uUW1-6-4ML7^C8?{SmQv%{`HCnF&K1 z0}caF2u2p_ZS=HC@D)N=cQ!Xw)KcB^?|8pF!i^j|Z4KeYoVV(?JN7*NcjRH5aLRAz z&XT81KMR?UWr=m225ywJER7fP2F%aT;|wP-Wq2A1_P(zAI-LAiVKvWbHV|b}4DtRj zfRw7Kzw$2y2i4~?ZsxZgIEs(DXACht@@Xz5%z5(1#GP=2M5|yrU^XFpY~n84mek5 zV0E_7Si9n)x;Qxzy-z7Jd%L0X9eVJH3*6cSOQB#rp40!{>y@)J2Gw^~YrKlNr^3(q z&SFogpYN3{UyJ)IBVv83ihBOKw6x@~?0tWzyVc45DjV_m-8k!iW{rlcwc$TT20VvI zx9&)D=Xw>#|BLcO-fb{q|07&bVKH4+AEo;EuIm2!IN~(|0&a!*WKntLtT-fK98g%H z(hGID9j`x}$6E?(B>PtRWo^(IkY)(eAO*bkuOw;&-+2>UWY_%JdrV#8Q(d>Nat(cL@Wuv=G zeHo~fICgb)b^VD&N;hUnEmuOb88zjckeK+X!ToX%^L%r#9w94#0je>Z$Psm73r30? zCQ&I;)(F_txh1XGWB<$`GwSu0Ti}WU8WD|@61?*LtdJCmgry^aP{kqs^jl$>LL&UV z#1j;L*@R6;hY@8MibY?Cjg`_8&N1IBUa53enHkJ(%!{CQr-ZkyVm*VAHrE)yPRbPE zeZA|3w2a$JgSxJdcjTCAeA{$Xz$xp78eDVGwlcqrYB(h?z>+6`SWLC z93QQWLTpvdt5vlRH}3jy34SMC=*QFQJ=#r@G#$=I-1&b<9{%;}T5)7xkzZxNvx$zIT zcXuH->W2Lhw2@Hy(p0*`V^iDc0}4N(jckUX7uS?f?S|gRh~UN1;2Pu^AzrrQ98D^wie1)XNWxQM`oKiRc_~7h5{Z}vekXM_124&Gy3M(x9?xLQHqd> z!cgSNr!`4wYd);;3i-`{wY-PeEB;__BblslQ;@*mGlRBSx#8ce^2AldN)yHy}S56mgKq`5B@EWNN&wC zCToJNZs&P+4`)(b#e(|*XAsV|Q}t9^$$L=P$cm9svbnCOYpkPjg?Nu$atDK|S4WE} zJ8Ns?pXs2I>A85E*L-|@F)z9K#P>LC7*Pax6|xs29I3=9V{nid0Fv`yAhJf&P4SZs z#?h-S&CfU2nJ2XQGWz}5ea{kZD(z+ayoLHMO#-1JB8JF;7icGySRhJtmR_UWrEdwotcpU znV%8LTcdX>M+=SFN5AMX+nfV#_DVeFFs7M>BEzO?K2zPlMULTJDpfB06f#N>rIxHj zH>O+pG5Af!NFs}73(lMEV9{Veu;aZqK*RJs&TpWqQN#C`2bVCv#iz%0~sAvXpa7?3PYaxNO=aNqitG zjiH4`hfuI326mdRnqp&MQ$+L<$;ru4%QS0??!iWNP02n%AY-CHWe1H+M)rHRtoQxe8k4IRkX}|~zX>Xim!y+0s=Y4<;w z!soTpE?>`Bb9^>rY5EYzx}^;a4Y|Z5B-(u@Dbv%_Ns`a0v96b)X91F8A|&kh4WtU` z{9P*dNQNA585!ettQ(q|$_CT;t`qjshLbspn-TfFA7;qjy~}YMO&1u=`C1>u((Qqu z9|x$pp&ccEXEi!sJSHA~y zT<{9#e?Xm255eR^)?dWtvu(vDjo{M6^G3vG&{WO^eT&QtIt{Hk7M%+uJLLL%AGI_f z?XF|jioN3g$X8ooyZG$C|HLpJ`OW^#H%Ag#8+^$*fa!kd^ul5)MW$m}uoarD9PKC5 zxS|3@DG3Cl>j zr8e$7O^yg+`jivIXtUHp+11%OwU>^_()vv~CFrnf#(FGYA)|a%JeEn%`}TJz&T%s0 zF`&4)X{o92mdf~CjvmIRr@7>u@nJkH$XYY>CujZS#8&AH_3pvMG}>|ZK|4DGv=0M0 zKf}KI?^AQ%9Ai;XQOmy9AhWHDm33K2Nl6iXk%9h_Ko2a4?q5$Qi`6hof5=4chctxX zZ@1H~%dYwcrCn?#G$fVbnBI$soUF_W(L82#U*n?a>oe9-1 zTFv$;?P5m0B=CC}x=2<0JLB7K)AqJ#Y?dn)W|uRrWzPw0U3`OD!kgb+UD;+vMnFMnhvNs%g8y7x4(FWyEA}Vmcl`rDh_TDAaK@y2tsLp!nYZ3ohl!3X z)fIqJyafgroO`+tiQI;b7Xxwh^YILj)|3aB%BF{5U9S#ihtIc$=dEpQY*M5bvI5qk zxB>xRXJW`E|CUagPNCk)>3XuVY`pyZblrZZenUDs@MTvMaGu+WY>u+kOcukQ1$l|& z%W16BcMRGMw!{ammIte=U4c?T^)DYBedXlUpAa#2ssZ&!viH0`T0BMXgr2RZN;EJD znfSf#E>_WvyoOudiP%jQ(WHD!)?1EkpME>e$c?}FhYhAf^}iNa5CRGbI4y5-gni*K zrDJK7D9Fh>(c;V$RcCxEdcT~)rlNfGN9gep3&qw6ydhp}^SWp0jzC@e{q=8w5~fnp zb{i;r@%Q_`^h#?jrma1p^&ebIytXU9c$^Z!PvTVR%#5R^-Q8HbMj|64Ge^?+6vD#8 zr)-{Y)+4SO9kxf-x3|@-JHEpXRuqdwk&7jxkO)3-ze<`_i@{;iUEl#6lXj~6amnL& zH>D_tPZ!J&J^dETCnvTTAx#r{Uo_WP78?L}U$3f&*p$1N=_Idyh+ zuCdJva@g6~1;epWEdZ%SSk{-BZ*P75b0v7*gI^@na(Ypm{dstJ;sO<=F~W1zew+P* znA0u<;Y=$*?U5*ZXeskuop%MwW*DU8q#gyebFGW#EIOfVEq<@osVq8#eFfZs6 zf<$o*+2(s{SdD_%U+y-Qs#mU2jZ=DE4S-47S_BMu)JF9TpaZ-B%m;-I6g9Oar^j*Y z^_*~I=|D&WAf!}`m6o$rwBdNVa^wmD&b#BACME66EX>myAfm&ng(Mc z-7{d%3Hi2r5Gp0N{%gQ}p*~PVmF!pqO}69VoXTAVPu9!u3aUYrTt{2 z>FRouQqYq7`8EhVWI1u}WM??NI?GvH1lIm)DhAD(oiQ*&ip|&CJhSmxMNY|W$o+S= znOq}#dwbizzw#c#XmcR07=cAqZ`-l6h!{zA9?(XhZ z09LbBR=5}#82xQ+ZF)e?nm|iw)X~uiG~f|rJFJPn+@GfY#Q?gP4yI-NDcmeWA9AV? zyRBNO{JVbUw?=;GSuF9qml60J(%sQR zt+_}@NPODu-j81lgqGZks@fEX~f!G6;LDv0ijP2V4I0p`^{%cyGMhL@m{W z!$Y*(SzC&yyZ!Rs?QaNGE=z9t(i3@dxv*5^t*gdxK=_OL?Y5B?_R0#0OWup{_KNcC z5K~6qa=y+=A3)OhBDH+n<~ZFI6{PKT-p1zt3rq{;yYuzOZVtpDZ)wkzK+*AyO9y0K zv&FmR9OGVbg$4b&h;AMKSGGX`eUd^Ltk^AmIq3w78uA?59b;o-DpZccL3jhKI+%%q zNZma>f7Xl=K$lMa)ZRCAN#1wx1C4Z9JJNt0xGl%+ab*eN;3Qc84#A3%3TnN-*kvDztEyVDX_(D~&^4s-H(}G2| zB6+Z*qa%x9Hb^)q7fO7W9V4|$V}SVEB)zzJ zKf+`rH3`iJFKBTX&_FK?BdYu8*Sfm8T4==lH_bJs2Iu17*_z~bF-8af&(=ozS5m6- zKu<8yd`Lz&k_y38BKK-9Ir?iu%EF?QHyRnN#Z;;THD8rq1jO_!tH$^KdqU0>%TFnC z&bZ?Jx_v_*P|81oDtHr$%`k^K|6^6U&U|vu>wuHKFDpCSa5Rn2h2Xm^=dtKX?v48Jc$u=h|9ju%Fo*P>5 z`qvKec&Xw!oB3ep1js)?Xnf8GiG>WGr)jZSI)R^C6czGpX9-qEcI9Xk=~g*HiGteuy*$A=CMG6+ zR?_??FZ|cv=x4uK=ip#5YpSQUwC+!9f4&m`e
    CK#VCD;@I1#{hXJxKOv?1C9y~- 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 delta 21718 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 diff --git a/android/app/src/main/res/drawable-xxxhdpi/branding.png b/android/app/src/main/res/drawable-xxxhdpi/branding.png index 5477b799402ee040a54891c591185621526ad5d0..9d233302d7f782b2651e8842317004812aa5044d 100644 GIT binary patch literal 20612 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 diff --git a/android/app/src/main/res/values-night/styles.xml b/android/app/src/main/res/values-night/styles.xml index 3db14bb5..5eb2eda1 100644 --- a/android/app/src/main/res/values-night/styles.xml +++ b/android/app/src/main/res/values-night/styles.xml @@ -5,6 +5,10 @@ @drawable/launch_background + false + false + false + shortEdges diff --git a/web/splash/img/branding-1x.png b/web/splash/img/branding-1x.png index 80579983440f33182388472285e5e7106ca027e3..5a197da3c16283569e3797546269db62ec6a645e 100644 GIT binary patch literal 3954 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 delta 3819 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 diff --git a/web/splash/img/branding-2x.png b/web/splash/img/branding-2x.png index 0bcf138d3e17cace5a37b4adb6a97afa76ae805e..efc7e6c8c995fb3d26927d09c6b0448b0ff1c42a 100644 GIT binary patch delta 11605 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 N002ovPDHLkV1jRz_$UAX diff --git a/web/splash/img/branding-3x.png b/web/splash/img/branding-3x.png index c7d0177681e63abe4a1d58e1b5cbf7325dbadfa0..593877e01266445699239227caa666a8ef43118d 100644 GIT binary patch delta 20410 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 delta 21718 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
    CK#VCD;@I1#{hXJxKOv?1C9y~- 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 diff --git a/web/splash/img/branding-dark-1x.png b/web/splash/img/branding-dark-1x.png index 80579983440f33182388472285e5e7106ca027e3..5a197da3c16283569e3797546269db62ec6a645e 100644 GIT binary patch literal 3954 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 delta 3819 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 diff --git a/web/splash/img/branding-dark-2x.png b/web/splash/img/branding-dark-2x.png index 0bcf138d3e17cace5a37b4adb6a97afa76ae805e..efc7e6c8c995fb3d26927d09c6b0448b0ff1c42a 100644 GIT binary patch delta 11605 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 N002ovPDHLkV1jRz_$UAX diff --git a/web/splash/img/branding-dark-3x.png b/web/splash/img/branding-dark-3x.png index c7d0177681e63abe4a1d58e1b5cbf7325dbadfa0..593877e01266445699239227caa666a8ef43118d 100644 GIT binary patch delta 20410 zcmce;Wl)vjyDu!Ff*>g&(jZ;Z4bt5W(%s$hC@s?6NJ@97bc2F)x3qM#&h3BC`LySp znKx$pag7U}xZ+ngA%RaXZs4NHpZc^`QS>rEJ8;BezdBA(Ec4)A2L6m8Ym>B?crBd7 z7`#sR?bF|eZ`5M+t%Vhm*qu-PC6C*ZewIkS-X-yul=4US!o-Y)owXeFj&2`072$WE zJ@{<9xx2Y-H`LVBj336cL-DP0X&gf};{tTPcfrpPjcz0H3B!^P!F(t>HUgJ+!xT! zNgLNxD2sWgTC^Y67ex#i{ax+6V-FeNM1V|1voGcPSlhg>5YJ*!U9dvmxVbu*iz7t% zSSq4-KFywlAe$wio7&S&GH`(RF&5{NbSbjg1({^YRJu!pUlcuM&->#Qr^8asyJMD? zj~KCW-$;f<6^lmVhVV*+%$QtvZy)cDp(^jIBOG+Cg2++#qs5djLFfEu%o@vtsZ{Ukr+I>Kmux?*zC*3D*!i;87Dx7`NB4~IZ(rQq-X7^TIc-THerDM=-u&*e zI}uSO>5Opm{ZqS>p7UKS?MN@ zWu0ivx8Mop<>kd4i=&G2F%ejJS#36&`q1dQukM*Z?pkt5(EHe>jwTC1&AHKbG88x8 z+taah`J?t9;c!G)hH>~)w8{|&r4*y{!}Ar6W;5)CgoI#o^|oo@&Ggv|*gx}SlA=fk z#E1ImDq1o9&bCK0uO+xeez_Ll^6~Kv{b?E{l5GQA%15dK<;Wd@~LF7Gm2}a)wzepdpW z2I^9~uQ$P%3e7Gp&OPy5as1p zn~rlY=svRkD^*D48;K0wE+2gc!HB&~-b7W4{;#8@7Lh0-{@X7d9k8@!T~u_#QSZwG z?umoX2tRLWR0>q}D-DFswCk*-Bo6qj<`)(k>|wc=1_}xayHpon8OIRK&39U8lHZNy zU9sq5!%bTb9zmx|j&p43Ekb4nf*6f(*LZbR?W7U2y^<@S3S z`@~ouEG~via%fB_T1wzDXi`2U8X2t_mvkU;w@W5jKq8VrEA$>lupUV-*}=sQzZW$ zt%oE=T`ve}rWU{4mHgv=)!$;PwS8pD=%^hNQRY+Mncd0nDzxs(iJ66_mW=C6QP*-^ zuNYBJ^glG`R<*jHtoK^S#Kg>x%s?XS4Y4m**hB?}abKP8w=$7s5zpiI2O;AUZ4kh| zI;X>((8P&01UrlC1)&mf{pAhyebC{*x!0iB$~uMUFTUm{4XI#DU$Bz#f#KSg0RnNwDrhXGSUlbRO zL-*{eku#JEnXSnC#B)eYIsN|bm@$c{cOCufcd7)KA@@l|*!65yzXvS4gHde%Rwhwy zwn}$(Gns7kMf7`J?3p$U=+#+GiOm{X;@rr>c~S_I>cW##%BMH#rSls)W)OGTcGYo= z7DTe#_l>4;=A)&CT6uOmy|we}^nY&u9hydsr@%mj$Q}hTplTYXQiI*E7Dr#qZIb1m6!%coFWdw6;GrSt|rGac_*fwG+0W&FMiXTmpsRqw+G=tnUJ;_;l-Sn7DL1a(5Rs7+*J2>WPj4h+T>D5q3Y;!aVFF%{f7`8VpUt*wn>>P=t@OOE;bhtF<;uiNEHL}gxe zA`lP!bg^u9smEkHQK8xkIDZxCeGKXaRuJ_ePS$L`)=~@}f`>PC(M6!RG3iWvk6ln% zSs5UcNbl*n`r|X?j73EHj!IZa+{S5pBn6>61T9Ozdb)H=NlA$a;2K+<7B|})y?j}- zqKt#7^G*vs`l$AY%LU?~z(9hat zn^Y?b*-k)MQxvcNMpCO4|6Usy81SZ42xAroWd!czc~64uv`3442G0Z(;_D%qDx`%e zh8!GHSz`fs27&wc>?pD*oyQU$6$;ruFCa?REW(G=D zAxCKdippUX01I;&shswYEbGlg1O$9e`_p9&7~_&XDugXrv#&$K=oY`*F4Xha8+7_Z zo|+XZ-#&a^^?SIrl@lY7QatNHD}i&MSe5R=4jG2WMZH2;L~Uf?TB)TpetM&bcY|)E zp!u<;4M4H3Zx44@`jfYupeZLX(Xp|&Y8*HEvTo0J&m5&4N0XU11j}?9h`!!O2|Xf^ z!_W#Y2tpqeqcK2#JxBY!1{U;XCuD`qRpKxEp|MKZ|Ido-(WY~ zg;PR8qQ8ivwPaoqdyG-&h2ac*e{1LzZ+Uq+Yh`PMNAQpFrOXZ2`=j;sQ}kgk2hZEf zLtgjMRCbh^a$Rp`6vvcLgw|Dsw&Vi{4zai!2mk?`q}jJOWhA;pqXk7n>V_DfPwPi< z5YHyseeZY->t1#pao+X!^xS7sDP-cK&nM`6AJ(;ZJl^gL&pHoj^BvCDoryOJX)@ez z4#o|0J*sQlP!)yzYj7vVC|4OBQM#A@vc%K1C{@^5bQ+9l#ZT^>jjPsfFZPMmN;Mr- zJv=Wc7=Uv#Rp)s&2@kJ3p#}mnJ^ghw^Y zc?u4G0D9OF{SROxcWIpVe&}ukI^zv%dI1KRAM+$*HWJr`m%}wy1~R%FSMqu_V>$lQ z#k0=?+tB<;&~a+uKzB^RMa?B%+9H`>MuHgOBf_n=_ON zBPuCgEEBLOCPrh(CF0qwr+pTSRKD94YcPnQNJk#ZYwmtnIj4GB=yP*wp2(!HSL3`h zhP*~$kDA})dIThiFf@D)dUp8N2kS!#bn8aL@ifL$?P6bX+9p8*Vrw#7&*($GN&pE( zG3v=$H0jn^smai5hrZEig*;BaBf2N$iq_yDv49nY=U-FfoNP9kN!d&AMXRUvdi^U} zey;Ds?S+C-&C`2iG(w(p2E=M9ybQCsYE!xo;rtbL+61DN4r^Vm=-RwhZ=(gFM*#|% z#B>B9H%e;ifd+6Hxl;y7xb&LuRlJGbS^rmYk$QM~y8g7ugx-%t+lU6dK*>z!_rB~s z-5SnPPLq*11SmrJ!-o&W>onT67AH<0j)^faFz|_pmeET#NWPs8KlwzbQBGft)enl_ zh*B<s8h4{d;LY2kan&qpDbD|Tz`X$d5t4Gvb6QTA zwAz$pKwTHk8gslX$^}-H7gm(heeE_Op_NG3wCUoRHl1e3TvvBj$DG|0M@>H+N;d$U zGjN{Abk;WL`8Pv4wVgLwj@w&a`rGgT5$T++yKaHYWFY!@>Q^>Z$K6rOE67{oAmHC@ z2-RI|blj+3Rv^0lH}`%NQ%yUU5DuV0t(WuG_^v{2fNJWY-zi%Sg`ZwtGFlizYCX;q z;#BUF14G~)PJ3@9XuPs_o(#?D)wItJE2x&HeWpdb%Wd2jZt8n`&TY={AzL_T83hI9 zklucfq)**om(sU?b>%%h{m8uGySVIsEp3E$;$e_fOTKul4?SFzu$qsBL%(nCgd0tJ zCYSL}ROM+D+kI|K!Xo$aqVdv#gwy4^B^@s)Nt%fSeXboog@lBJKXrW_bG_ObaPqe!>1~T- zAAoa+r0>Mm*VhREpih8ojFc(XBI5b3nFi9TIs*_CGT$5ei;+fu{-{){pi6qmcY1yv zK45~c{8iS5E|-pQtyS5x6uu{}*H~2c-#l#wvcibUclpsz7K!5@*`bXHPSI$s0~tyz zCOw}s@B<;g%Q%-A(dh6% zXBkqOlni~duh8_+qY5J;9-bO8!{XUG>!gv~=-;h#`?Iu@OBUV{t>VqEW&v-+f@nPpko zF+S7hS;sIIk52ITcbxQf6Vq7DBPXC5bA_*;_55y3Z>SqvdNbZFy&~fCkoECtO}Z7g zas}ed)W7elL6Mks3h@7)T&y$q3k{61CX>Nf_9{Ljn&_mYB-vL(W+k$#e}3iaR=u&Z zBjR)39{D*UJ=`r~My%9aboS$LxYR{*8!$rf0FnYcxUSHde}aCH;)UD}EO6eud6SRw zq{CfiN`aAN*f*3Wnp;=XsEj;zJ4F;lGD%K{)Nl`KYPFbKIs6>cvdt0V_o@R^G^49 z39$dkW=l1Y|M|Pf1vm|9XOcU09qHrc^Gw9y|mp2_8CL@O)*V{-DWibDXuhkOJt?}B_H)x=(V`&y_L zAfpc3w=o3&1(FRm8Ime0j*F+ubdEDw&E+L1*5GGczVPqB6O-x%m}mDmu5M3O~$AxPZ z%ra| zrU}3oh%2sbYimmYXfSm`ES*JAqgg!GYT4%ti;SvyrJPxNlG)Gzty=NBmsy!(cUMPC zaS99%8QX};kuXvmG*&vlSf2mjqGX86?LgB8sP(eBXCv$IPmQ^8hFQrT&qL#Ya)TFJ z&VLg6M+LKeCq*>SRJD0?_tU>+CdoogIq~8wA`kmNm?027;6Lj{7?JtS|I-hk{}|P#aG=Qo1Db5xSh9;fZ`F(7Nz-3wMbbS>`5KFvs?X+X4yd8Azf(fKVBv3==M&BOele`ayG-X-)$ zY3cGaC`QkH)9>)>eRz1#r&TGC{Z|SaK}q-@XVD&b#-+I8HZj|PO4GQaqnosp#zu)7o0$(c%213-mDKpNlf@=bc00S zMzDI;>jnlSJA?vWO!YU@r4y&aFA_KQk8cpcP_C|J7dJ41-^w@XOLcj9`J-8v_$O?~?^`3!(2jU!*|yzgeNjdkydNKPMFG$kZ?GxzDfHQq>6F8+_0y?RVRswsn$~ zl^qC1!S`Bk{*W~y7~0WEbZJB4 zrmA!jV@8K$44L0v!6oTNILnSzpj;2|<=9qNzW76(pMh@&>EnTifonwXm?a;+`#^v( z{kp$35Q%ROtRDXRhX;*;ee+m$k`=)p>oR8rbq;&%al};a?(Uwfr%s@)cy`fKlN)DL5cNEL_(72LC?ny$3_G6{!|`X_zAoN`2Z z7pxNHn81aeWDL~&M5jF2ZC2O4-<%0hPcq32dH#M<V;pbaB zS&$!giD1`O*MlV^)#c*xNn=07Na#+c_t7u}G+`aDP|R3bR6-ssKky3Sd&96xN*7$a zdV9CR%ZvfH*8&#l;c%6<=-S!6J{r?EBd?a6#WwE-l1E$mNj5nvy4^d6v$gi__7z8X zHl$at4k8aP5wrBqnC68d#`kY_vS2SAj|RcYu$a#JHQ5bj)?1gudDmF4B}`(d{7D+B zMpZk;QBLen0yX?{y!0fmMw)xTR{Mg3gR5sQRh|%exjHELRlJK25ydD-#BCZ+I-ITA zNCPF18K|#d(}6gnjB@-9r*wz9Pg4AIvjmM^tA`*~nfI&@A>)f9`XR#wAhIskyV7Th zk*!M?rd_s+lFVTtu_%7~00$w2GOIWzY-iie^Eqt}uwdQliG-l~<{fD$YRM4CMgu^{ zL%{216ARd3YqnJB>J%3r#?IRw-JRnO7{_XDRPCxmgltjM8u+?5}cC}6f+o>cm zk{2N03P9Lg=|I!Iwh6Aa_+=!5lOp@7XJtiDLsD`8lkeJTAA-5`_V$*Q0%qC(jIZS2 z+CjfYJk1PdtKWt5{}j)N3najNDmKTnU~DTsap9s2_Q%E-52{4-diZiLQbk{V@_#jw z!FvU1VyVYI8Ykj!_5)|=VlsG2y{oWwV}GVX5SYyYxQf{d>S?T4TUlZ4m%vX92=Mn$ zG|6j&<{k{A)h>Z1Rr~?4Fe{x|?6(92_d#_V4szxq)Z>1;`AMlgeSJjZ)ZWz_uFMPZ zG4-aZAGI>{ubtU3cN2cMOZEEhf4XyHJ=!R5%rYJ^taJ0dUJD5UO#Zjc!E9AorssA_ z(Cvekkl9BGo!$F|gF)21{%MzVD1lSS>#fSD@?h^22_7 zBy1~5KhJoJ6ZDxk9H*L$@7Wd*oOlflRibT|Tj%iIGzsK80P+06VLKoC#{>1~&0>A4 z=NXaQNsrAZE?x8;I!#-|ou|0R+uQYU9HlE&#{Ih9>pxCV0j4hp7IxUgu?m#-$+wEu za=?W&I}}1&U-@)BY3zkbQV?dS^t-E^_vq*-ram&EArZX8xr9U)czF1;_0+nE@bLKi zv*5UWN8}k(aqabC+27V{_GKdmkahf0q~^sB_U2_!=2c*a)ZR#IM5u@ttA8$myXpsH zjAO%ZF6G5SUiyHJyrmZu(=gKDD0tZITg%1nnE&kY&EUgzxt&8~XjQ*t1^?0H8@iCx zWC7pXi<`3@SbXZufTH|ICHeX6^xvwO1^O`s&VwaQ10||*jQQIM#O21x3AK5$?VoDr z4bD)zhaMYl*oPUb$e6mxfABpZ!K=Srpx>D$KjmuQKZG1GGM)nhI5Q zTN>~T!KF5DcV{t9mv+!Ray+hks)m5unVYr%5D|%v+zw(G4B^nC{f`o+#UtSG*XuRd zWfaw4ot!{}?m(R!uj2V2tycf?22BW$d{p8US7sVBNm_!pyK&+1)kF(JeQ{=O4o(%r+x47 zdCza@@#1_FzfVciEBpj)yzuMkyY~EnMDe#n-|uGYczV4WchQ*zN#hoka@YJd5s?7K zRfX>Q01}2%x=A1nJ6`3coXWh(1+o$~0?yY9I+!eWPPwpafNV@^2~dg zb%voZiBFM9YUcBxgDKmf)DoHL>C3%l4JG#x5nb~WcFeAkPT_3=wyXU(Z%g*D6RN~6 zpfG5F^d-WmCMl4mr z;!}I*V>qYyX4pN<>G0wpw!u*xl@$^4Gea>h|`nr2h zpY)E;@1Co}6CQgyE;Tf4!o?Sqs@njwZ9Yos9Ubryt1!1cZwL~~%Q{hvepRTB|b zok}>U0V{&}0T-|Uzsh_(Q_XBVlmB%|9sS5$K?H0IcwcHo0B8SE<}&Eirw@iwMp;f4sQsC#$OtAEVI!&t1Hy5+iSUY?|6Z|r{7qg zwfZ(HzH)x(W1HFFW8gPg9wL4(7iywDa<+$x*o@{_MUH~i+xGB%{BY-vY!t<66DiZ{ zziUfCMuV}h(^ybsil(6#^cO1SY9|7M0n(qo{e zl1DF>iEhXk@tYp{68rbN#UUV1m;cB(=g|i8dX>I65N6wd%ueo(1{Ke&1IE-H%#LkIDX6mK4e@C~g4I|dz6<|S!|q_FUAuQGaPF?I8O9rxCaXfY z&EQpTfcZ0l%rf)m&!3(&A22hkH3Qi8)9lryh}{M{hHf+}^b(L17MN(YOv{@F)3RBv zIq2z2`vF;qn|pTxtn7+!KnN1DNwt-9d>5(e4^ZO`LH{EZ3N;oe<%Di<+414kX{y%= z;rJo464a0T6P93Kyl6N@mtGW4pK{F1BK-*Ixa9=`98~mD@>g4Z(wW`QZ=D*Iw%8L$ z3JP!0Ik8*ZkNuuGHt!CH=KtMx4)NFxcXsJ@)1gz+Deh4&o?V}Me=B7lH=-73P33GV zMUkoD%rFE<$WB&%3{{W=gT$WrYbw#q)dtxt>M`SIIOMfE=EIVko+1R~_Vde=xBBfq zTB+h&a0jIYwyca&GUCi4uf|3F$`9t%U{5;*@^plO4Z-k$*R*zYWT)|3SDIe0Rr4h( zYT~J;a9l(E*mx}(w7IvD-Hzu^KiKUE{DohI3eea$0jb!XiMFRXX1{@mMzzXwIXR^} zUpwM!$WPKG`i?(fYrNW)v{gM`Cexc_JV_{;Viy%17ne#dGIw;%M5)nX%?i|I`6s6f zgafV5#u+xfOqV%6mqOP?fcwBNEiUrxcmFw5nn56oLd$tYUmcxPg>$dmoJ4;ZrRL%c zy)iRvGgt66u#{&h*|pSa^QwEKW5Lsc%}z;+C~p_xntbzb*MIqu`Z0U{Ai(6y?Ch)w zY$)$3(#w~Yp=`1h7gN93j8~apPHiK8MiQV#Hs$8`w~dJfeBO8gDIw^3rUpL25ak~K zFpWuHpzJytUcVT$vn*n@NlgfdLO{9CXt6A56SM|K*A=w$$_aQ}EMC_)P`@0-u?6Gh zLD?wJs@LC`BK%xe1qg%aXltCm$H$olODqF-9q+Fl-FtMjq=|@# z65=<}sCGHy8HMUW=ByDw`Nzd_-4;seQ|U$c`k=1*&mOa*Hy1PdWgOX%RxW@8&q;vQ zRFHNAclQTi(>puBd7kb3Q3rXu+sw>NcCi5~G5kxZjxNLcR5%voP1yIw0#@wNfWHGV z=vwA>SpDJ1rz-aMmb9$-FD_g$AJFiU z_NGdrrh6wv#aZ^C^_c2wx^=B6k4=ScR&>23V4!Hgh~s44wu2l}L-Xr6-*E^nPRvv$ zFAK7;u+Wo{k+s=dZbf|-0U&7eF>x1Ron5Y-nVJegNj~oe_HsyyJ^r;P>rpu!RsL#2 z_sk5ZA}`rp&zIL(LZ75mN_3127R{+AomS4LlK&!J?O;IhC+|a_(S+oW%xENr>Zi^! z8SfhU<@z^oA?+oS&tCqhvo5R}Oy3a$>NWOnu;^^JMHQ(8K5${^@{e4~)NHPGhvctl z;5Ldf2VX0YKTd{rkgVIA;6!deG;(f@<{=6=bNgHa<%ziGqOmM7AG2BTRTIhm)2iBc z11u2-s?c#ZflS(sS{d;KQ-QBv(T$Iq`yY{brL;-&=z~rbx&byhEk+!-@2*FcCJ*qx z(|Q+0zu5}JX?5MD5}%(sbd9#Eo<&{B13r%rI~``)E(os!Q+5GSa5uEP>{|wSC0Cb# zO2;8qgK(**YN4WGa}I`aF~9jqMY#yjX`#B;*<(U{Dr>jEuQMPZdV-JF8{&Li+pxdgXgj}sB&%r70?-8h2d?`|jeix~jC-y*M*O{pax!2n&UmH%a6v0~C>2Q2?lXNLTs#bTMKk3An3 zI-rhr8mg&-g@y{#rDj*1;dO@s5WqbkYH1VX98j5p1YxBpj!ZB@8-#T6KXx zx(eCxVLTNNbqXXGM#ubs`q^P{)CnOl`NPxC#}5k4A_@v}EUYQ-KP<1DowKs?Pfbm! zO{v-I!X`8lw6gTeHI*SeD|^AB}^iq z&)Q_AQ6?4&5mQg2u|q6CpUvW`R5S{Cwi>wT(<6((CPjf6S{} zXRA>&)yYEf6=rU^y07a(6xV85@4gCit7ymJ;o&i-N|g?<<^bbDRVWxqEqFUm!yv?z zrP-7ENNBNyJM*pry+XN@e}72P3}69R`5Vksue-wrs???I%0!RkkggNCMp%fc#bgJ- zk0MHlycq@`!|!u+(}0Z|@f}LK9#2?PC6J+m)JrWwH9L@T8BOqULDEf^k~wMS;Q52+ zW%lb3emTEqsfI$P?0KznG* z7+SS8vre~k!+W+Ea`n3iu{fdK?V;W5eOc%Y{i`sUzblKm#MX-EZ>&iF&WuByU#*|omJc%0edzGHl9|_JnlL4 z`Hpv001|!bX{rBDe%btd|LZ9Px1}W(&m=UX6TL*erDtT6lQ*Y##+?@wz?=6=FC=cW z;9Cz83mnr(-0jTMou0vlxV<@02Oy;jj2P?QQIPt)Edk?o7A}cw_ls!ridBQ3yW4x$nYDje&vW^`z+dL z=!g2Sbk4C4AWYEFL0jJq)hddu`^SO9~uj8kNM0n-0df=Kv*z|RuL_yx7jJB49h zbB*@yiu2IWP$e^F$`8?m!TOdS6=nYPBZK6U6(jK5mB@2*bG*bpe>;yyjAT11=#Qe! zon|@D!IB+M>rL(iX^|_Mo$cnhI|6j~Bu2O+_OU|Cb5aj;64 z6OM}^Quf-ujf=DCY-Z+cLp!BQcK0{CA}>+tre6KJy4|l3ES*D^Xu4hpA&c12BPALh zS^sIV%_Kyfg0uc9)iUiVlaCGW*9(C=SdyEQGw%ydfmBoHBni|Ow2BVn4-wP?FN(uL zE>iTXTAhh^AyI{yLgX4=M(X}2l6WFqODSlf?AmKHMq-cL#_()sTyS-)1{-@bH{qWM z`OC`>2(Nl)t!ENpoInz)aZstC0XKuMriG2UP4MR`TtF5_bAvCsm(98tA zc*Ju!ecmQ9KdzD0#9{ZRQ_sQkeqHz69A8HUZ3KQg?kg^nd>4Nt&0^9tR)n%cEwCf# zG8RR)9;M+7Y1Qp&|MP%dgtleI_Co5WJl-%&KLmZG6K4G3R9>*<&M@h|P%r?@SC`pD z5u}9h@No2db0Rlp+N1>QX^4yM2VwB-W-3r&#*tpuG95%ofnkfLbU5hnH zvrX1no6(N6eca9-xrIkSy{CNtz7kkk0+!f_R~C_27HpgX0*{Ea`T9U`v(fd}f6m~y zYst5I3hxQGnY%(VKrnW^(jnONUZfEH1xxGh`;Kba6qfy^m+<#c3{f6Zfl7UC<-7_D zm(TTI<7>o*W{G4K`Sia-h`9}xxqm*>I|xPdA!P2LKTEk_`a-qu%@8{9lJz0cn^25^ zR;-NGVSH3CtQ*_I{Z0hCFm%lWs|>MlfL0zL#czeX449fh2+W+uFM zDrG()1X7Q2TPLSDUfLC%exXHKn)j0W{wZVEU_pQJF6| zkO}psf>89JhP5H#L3Yx#p-8UI9fAh`Puo!}?2_kZr0Bx*xj;o#){<-w8Sxz$**%DrdHW3^0fnDy^C_7y1JTR;unft zFe#Eo*BkA|*GY;uD#u_};=#ee#iBtGt(rq@AMM~fVBpSH>?}mFT;V;8k76&`D?*%9=no9y`tP;f{-qt!AU4u_T!o z!EfW~*p+Y{zIki$M2bmE=~+rx4n0}p-09$GSdDu+*G_T4z=FkZt~V4^nLNE8 zl9W?p;SmvXy1@99uF3zagHgNPgV`n>y_I%_h=kD=DE;4U&D9ii=NFSv-~aj98(6dAPu73}^{{fkIaMUVAVi}BMFWG?j#_K)xGfV?PvgAvf**5>8TXmV;AIj`1XZ|FOS5Cyh?y!0 zsGN1(XMkRga5$Yglpn)=jz?)@#6S1%pqi0*X_?Ha&$Oc}{UW;8W7 zr%U&i_wl(O1Ol<`;Y9vdSFK#)^;*HB<7PrM2`KNmF}6whh+K<`BcqO>Bs1AvK#q@n z@wLqMv8UDkQ6j?ekaO`F$WrDT8yU^k>_3-oB|%0*QxFxu6C8DPRp|#dptx{!({IAG z%$yU#*1@kD&z|Nw!=qdmCRK zKy%JAWk|(9J+lDWB3f`NV_SnyC;O=4W0Uf@m%P4*Av-Ba{kPJyEY$=H0njqqz#=82 zG!;1@l2%Y?U_4Mn+2S6h0wol0c#$dp$T(ClEFB4Qw$18g+Ql6`hy}y`BPoKW!-$pUV&tOg1ASJJ5SjP;bvIQjtKuQQM7jZKp%S5~u)iQ_=`ufrVLTQ# zX^t*`#QjIWu1$t|CSPem`6LMj&ffXdU2l7BNZm|oU1W81bR1yS49Kj}{)+by!XY4_ z7xA44xcGL%N4xt8zz^R~NFD!%EE0iRihytPxj0H)7&E~xa4Q}f8lbK)htOXG{q$?` zNVYjAx)xx0r1yH19(I5Op9;YXn)X3E;s*EEC%GUAIDZDbt28PT#6E_N1lGG0VCe=|t^eI36pXWhwpV#<2It8ijW>cLeSE%^$LsSJ9*X zDG^8*4Z{KN<6TfKBE83!&0I~`G?mI>C|N>bQyuvdQ4kSf_*Gr9zo*EW)6HZD1Ql)M z-4|`<-Jf^`ROTtKKi2}K>#6#thR5X(iT_Bs#7n$N43>>YaO{%`fU_2D*9S1p^#4qL zANMG!vwLu-N76K3plJ%Sk>#_UXTvkA)tSmaW_a_xQFL2q3oUyuNMWY2u~C_snYp3o z9i1pTVs)ehSB2N`)9*{Ajq0zagV$5-!=0(|mxo72d~|A#s}dFFNQGzytY*r6 zD@?rt82CWOUeot9PiH?=lE^!nLzn*PK4~i_yAtK5M4`Zzh?|gS*S((g%;hbX3O6)? z%yz{S+(r@~_oppTW-ID9uLoz(cKGBe0-Jg|Ig#S}^OTBP~OVMz}yaIncol_^_OHGOs1C$)3pTPqsNonC-mR z$OlMjt3;!M=q(1u$&Us54qe@AJz4jJanDj-dj7Y4-kl z4TO^y4LNvXnK zq;=u5fISm8E$z_!T|t>{i<>gImPc?^-mziPD_{7g+oZ8|B;+X?@gv7OgL6UXX3ToA z@#OXPUvONy=6Rq+00<@cg;1RolJWENqdavc?=hhoZJ%g{_pBoB65ybq=rv5nI8odO z|2qZrGf%}GRD<_;{|cJ7zU&Ut#b>u-TLs4l(%>KhJ@o6>E`ZiYj|<$<*Gt7wB49*G z4?mXYeBbp(?64`B8nQZizO%=uQ!o3Lxdgh|N;Fava`CzV9NqvObSLiZ}0O@t52GIa6ZjDc0-od%*Ds zxm?ZQ338V=R& z1nISFC27&RHEn5@U;;%&MN@xEA>U02-rsJeesmwN>pjvayj@6nGWMt?ro4@` zz!ZjGQ&y`@E)n_atbimyvN?Q%zc!jTWqkknnV{k~&WH0!1>D@9i69nwv4D8ufV-Z( z)D?tm4vcBr+9L(V$dkkTBHO2a*KMHZR8B6Gu4`}}CCB60Fo`fpUqD3If_1H=eQ_Yv z0`plHb-wH34`<7OcwDWrK;-O;BJM`VcBa{eH$LJIjx-M2p^mXoh(Bv7;%XhW6*uHn z$J!3p^_)_RnRMp>RY0_YorplpjkWpt4yKStM_m%?&AS)tlN&p9gWpDCm$g%h4LJK> zpAei(>)7X8dGgnG2AAtcz+Xg^h6jb*k2YQXpOtpjdv`C zRYH5cFHs0OdgH?uOtVs=@_lSr3^6R3y|9${rsQ_S_{xd6m5&(2oY$Bv5~!(+81-7O z-)nOoyZrfSSbf3m;ERAIKEdxR1{+s^t+bj)sA3Z58oX5vG^bJj`4lHN`|NLByI*nT zd3Bmf2-iK@`d=|~2Hu{vSBTYm*Yj#MOwo-O$;I7iPt=Ff#g#)Zj+XAKz=Kp*s3IzS==m+{GqGE7bMJ=JgA+*Y^No<>#^DjF zN^|J54_@egx`4vnS;UOfmwtVdFowk^qg5N6hcNKI$5OS>Pa96B^~V;E1*1%<+C`eX(kI}1+*G1Crcse1g?bm`4l0||l$Uu$y8WYnAoH^pR z0SJoqq^51{dr@?CUl!@mcmb4`*Xjl6$WwC!VnIJ2n#DFm=8M$81p>3lt23}7w39M3 zm*ICkmAot+9)0fxpY~^9;t(MG`wJSu>W&s5G8U+m920BX(xrE8l50oy+J1WUI_ znWD&NxcD@DH~p2|V?FqD9fXp|AwlH->Qo7MfwUeow{Q8G3w(^^;K{R0a>(uqfiWKR zQchvw=aRK5jNAEm(0kv`W0BVUuigJ@(u=l)&~{8a z#gs{kU}#ERT1wjlm3@k$?uy1;^+eq&4o=<1r435a(V>S%8KjZ8w3O&1q~a{jnQ!OI znRE8DzwPH)d+oLM-s@fO`~Ur0?}R?o;CKbe6Mkrx;sa4ny{?hb94u>pgHT^r*QYzp zT0(Ui7DCL^c^c9A*_npt11xXMItf~bd`yHPlUHJ)_Q$6AJD)>kAJz`SnXe85OO7NE z=Kq}~UOw>ZJI#^i*cbeI(STNiWyI?2BcRDhVLjbUD$Xt-MXJpV4)zL6bW)u^hYjUl zRUywD$&*_~>?I?>9^Fc6-xmhZ>^I==7zr*yWRxR;(Obs7IA@4!015aM@c;cD4MOY^ zkmw3BKRS+igvzW{QiI>088v^Rn<&*dCdMv4RTR33LFL@9Nni}vEO)_JV9mzh1Z5H< z(2GVWqWzmj=}n`9O`~V4cDZ<7NOwJeE5;C+B=1`dw*tbef4r0tbDQGtL-mHH)H-Y< zqVBE+B&@cSfh`)vYV(Ug(XHqn9Dh*kwM;^PBDpVqIgflJCNHFEG$#uFP_)`9_S)ik7MH86w?$aj{82y`Q7-$~%4;q0V6 z#?0_0c=u%)b;1=iHK1L`lBRt1#x+dGQQGIpy*_kb#Z-H{$an|S6*I(!Do9FLt7pHp z_!3kKmgM1)Z_Nh{)P%n+bZJqQg%9K;1wH&0N8B2D1n`xOTE{~fuSGXh4;M*58Cv2E z0L7SyA~T+TA2MD4)8LRP9(4g3rp7ojR()1b zEQDD(Wzjd^<3zA#&dk`c>u-ob(c+|zg+-IGbnXNR%Po{co{d3Dnj_S7G>n?>{RbpO^3oPyNikQ_OPPF$xDJ$3S-+Al!O6ywtLHBSb z%Fghv4W1`Wel`xAHQq_zd!wD_Zx5XrjwgnOh1GDmT4#C>5NthOxL^H=mw zeD(ghDv+gz<-zd_#%IEUFcFtwmD<_*L+5y=j3^K+Ucl3yu!;6cP&~cRiio!%dE6~_ zp5lMMj76i*#Z~D`$h0^v%q*r>Bl|;WRA`m^E&kM|p{PSv0#$n`8xiGJ{6KVb&MRWB z^s-En^D(4?I&x_b+|(dyLUt0suuSbi{mvSh*tq~7AD>fXGC2%mvWNVSB_+jlkgky2 znr7X-u*TE1hAbG>i-TwHTBprB+`kEN&Pzx~PhGkGmoslxY$M^~RnPDa5U`_&REUWwiYxw4@Ts~$jjl=ap;xwDP8FH3W@YTVAX zP5JU?hw*cdwNY)oLF_G=)WH$lTQA+m(a|sQ&;{R zd@ozv9v3|TW30Sh@zkx6mGOI++)_C?TqTS_)~*34sdb|qiDL=VTow_LQqyUz<=3jd zhC~bVDkn~#Ip`SNQ@mK_a)o|&h8-1_<9*2LWD)c5&<4dd{Mp8jE+UvpGzU&=sj(@1 zXx-uBP`8n#v9vy<70ju&{Hs_md?U1?bpp$~I5E4{H6v~kFH-L>QfoZg#{gXFsLWo1{NKoBC)ui8&x}Ph=#t2A=G$c1k-Wz z^qHFb4)*pJqdP0YwKylXDM5Q#nC*he<7}bu=(TatFi`I%pp*rsK0nwHoDwtU6CX@` z!|mxdyY!-UE-7R(@!z+l;}KZJ zp)tqeI^@#~zPyiVxb^ZJn@S$bATIQrHSLS2zoewZYj38`s*)@$cPTyDl5gsjSfa zf`=%9=3X*xXD-ROdyrMDj7c`>qniXn?#4q90BE8bIGU_SZvkS0 zPLX_%nfm89xHrxXQ8$6HS_Lan3Sq95k)9s1M~(CV`R)ZT<9VC!vrJ%caa}bkKIOJv zb9p|wF)w?avNlP?qZOUfCwBa;pN_QcO_5)y;B2Gvzzd^id$1s#SkWKQke1yR9~g_| zT-wHPkhZtwx2N1TA+2N!U$vE4Hrt*R86DgowiW+s< fIrtyOmbWQ|p!hu*l`%NF103I-b~wef{VDpNbzV{@ delta 21718 zcmce;WmHvP_%-@dB%~4P25IST0qIscrKG!ai*!hLOLuolNQZ!QcX#(){_nW&{cu0L zpYD4;=okma+57DEtoh7m&bhd}eG%yQGLqt@&qyWZZwAQZrQXC?`zgV!WOuYAx&e-s zRb?GbA%}Tz(Tr{-lU1Rn%>CJPeJNuBj!kK9-Hev`YyA69D)-njim}q){nW`rH=ZBL z94;Fguc^4^U#A~$vt3&{eD!8C8A;k6NlG%jp>f-vDs|c%Oh{<+GMvnk!qex|)m=>a zLK%Kv0FMWKX+}Tt7k#|DycglmeBU3q5crGOg;LvXk@8qYrT|7-Qj$5ng^QZ(y3($_ z|4MQl3t?o&rtS8t1@`azKObANF^*wPOib_+*ECz*ou-#sJ-Eb|oJY!Dh|emPA-I`k zk`9uqmT9};VtFy~%f_$hpOq-YRS8<1ZS?1hhZEjHDSK~kw=%qwgq^qL&acA_a|dODx_i=MR3j;AouW{qd!j}Q9a{kT;&kbTbd*DAP|i0l`v zH=D?tB;<88ZMrk`4-AwD^!N8d5v~)t_7uulD^@Efh96^5)akHXXgKYuH0+(4F43sY zI=X#;Y7Q3~&rJ$mJvb?xYqfD`p4U$67DpH|ia+;}#J|_5dVajWo-niz?^s@jmRmip z8Fyqo-|YP@{0vj1T3Yn1eqN#9WuRmy|3T2xc!3pGn9y;pJ2(cxBqI!;QLE09gPJ;j zdb0d&?j+3Sip$34v+S(T@$kNg4OX-E05i;-{Ko$Oxe?$a$CbG)aBh2qEF2Zu_sG6W zKDYEbK_t@xT4#*KgIHutm~V|V5QynyHdn(Y^8$1R#_hU;F!YXQtMg$$#I?(UCi5fKqL zr4hqiC|9(%W}$)2VP~HrE~Gg(8d>RBpx0)!uUW1-6-4ML7^C8?{SmQv%{`HCnF&K1 z0}caF2u2p_ZS=HC@D)N=cQ!Xw)KcB^?|8pF!i^j|Z4KeYoVV(?JN7*NcjRH5aLRAz z&XT81KMR?UWr=m225ywJER7fP2F%aT;|wP-Wq2A1_P(zAI-LAiVKvWbHV|b}4DtRj zfRw7Kzw$2y2i4~?ZsxZgIEs(DXACht@@Xz5%z5(1#GP=2M5|yrU^XFpY~n84mek5 zV0E_7Si9n)x;Qxzy-z7Jd%L0X9eVJH3*6cSOQB#rp40!{>y@)J2Gw^~YrKlNr^3(q z&SFogpYN3{UyJ)IBVv83ihBOKw6x@~?0tWzyVc45DjV_m-8k!iW{rlcwc$TT20VvI zx9&)D=Xw>#|BLcO-fb{q|07&bVKH4+AEo;EuIm2!IN~(|0&a!*WKntLtT-fK98g%H z(hGID9j`x}$6E?(B>PtRWo^(IkY)(eAO*bkuOw;&-+2>UWY_%JdrV#8Q(d>Nat(cL@Wuv=G zeHo~fICgb)b^VD&N;hUnEmuOb88zjckeK+X!ToX%^L%r#9w94#0je>Z$Psm73r30? zCQ&I;)(F_txh1XGWB<$`GwSu0Ti}WU8WD|@61?*LtdJCmgry^aP{kqs^jl$>LL&UV z#1j;L*@R6;hY@8MibY?Cjg`_8&N1IBUa53enHkJ(%!{CQr-ZkyVm*VAHrE)yPRbPE zeZA|3w2a$JgSxJdcjTCAeA{$Xz$xp78eDVGwlcqrYB(h?z>+6`SWLC z93QQWLTpvdt5vlRH}3jy34SMC=*QFQJ=#r@G#$=I-1&b<9{%;}T5)7xkzZxNvx$zIT zcXuH->W2Lhw2@Hy(p0*`V^iDc0}4N(jckUX7uS?f?S|gRh~UN1;2Pu^AzrrQ98D^wie1)XNWxQM`oKiRc_~7h5{Z}vekXM_124&Gy3M(x9?xLQHqd> z!cgSNr!`4wYd);;3i-`{wY-PeEB;__BblslQ;@*mGlRBSx#8ce^2AldN)yHy}S56mgKq`5B@EWNN&wC zCToJNZs&P+4`)(b#e(|*XAsV|Q}t9^$$L=P$cm9svbnCOYpkPjg?Nu$atDK|S4WE} zJ8Ns?pXs2I>A85E*L-|@F)z9K#P>LC7*Pax6|xs29I3=9V{nid0Fv`yAhJf&P4SZs z#?h-S&CfU2nJ2XQGWz}5ea{kZD(z+ayoLHMO#-1JB8JF;7icGySRhJtmR_UWrEdwotcpU znV%8LTcdX>M+=SFN5AMX+nfV#_DVeFFs7M>BEzO?K2zPlMULTJDpfB06f#N>rIxHj zH>O+pG5Af!NFs}73(lMEV9{Veu;aZqK*RJs&TpWqQN#C`2bVCv#iz%0~sAvXpa7?3PYaxNO=aNqitG zjiH4`hfuI326mdRnqp&MQ$+L<$;ru4%QS0??!iWNP02n%AY-CHWe1H+M)rHRtoQxe8k4IRkX}|~zX>Xim!y+0s=Y4<;w z!soTpE?>`Bb9^>rY5EYzx}^;a4Y|Z5B-(u@Dbv%_Ns`a0v96b)X91F8A|&kh4WtU` z{9P*dNQNA585!ettQ(q|$_CT;t`qjshLbspn-TfFA7;qjy~}YMO&1u=`C1>u((Qqu z9|x$pp&ccEXEi!sJSHA~y zT<{9#e?Xm255eR^)?dWtvu(vDjo{M6^G3vG&{WO^eT&QtIt{Hk7M%+uJLLL%AGI_f z?XF|jioN3g$X8ooyZG$C|HLpJ`OW^#H%Ag#8+^$*fa!kd^ul5)MW$m}uoarD9PKC5 zxS|3@DG3Cl>j zr8e$7O^yg+`jivIXtUHp+11%OwU>^_()vv~CFrnf#(FGYA)|a%JeEn%`}TJz&T%s0 zF`&4)X{o92mdf~CjvmIRr@7>u@nJkH$XYY>CujZS#8&AH_3pvMG}>|ZK|4DGv=0M0 zKf}KI?^AQ%9Ai;XQOmy9AhWHDm33K2Nl6iXk%9h_Ko2a4?q5$Qi`6hof5=4chctxX zZ@1H~%dYwcrCn?#G$fVbnBI$soUF_W(L82#U*n?a>oe9-1 zTFv$;?P5m0B=CC}x=2<0JLB7K)AqJ#Y?dn)W|uRrWzPw0U3`OD!kgb+UD;+vMnFMnhvNs%g8y7x4(FWyEA}Vmcl`rDh_TDAaK@y2tsLp!nYZ3ohl!3X z)fIqJyafgroO`+tiQI;b7Xxwh^YILj)|3aB%BF{5U9S#ihtIc$=dEpQY*M5bvI5qk zxB>xRXJW`E|CUagPNCk)>3XuVY`pyZblrZZenUDs@MTvMaGu+WY>u+kOcukQ1$l|& z%W16BcMRGMw!{ammIte=U4c?T^)DYBedXlUpAa#2ssZ&!viH0`T0BMXgr2RZN;EJD znfSf#E>_WvyoOudiP%jQ(WHD!)?1EkpME>e$c?}FhYhAf^}iNa5CRGbI4y5-gni*K zrDJK7D9Fh>(c;V$RcCxEdcT~)rlNfGN9gep3&qw6ydhp}^SWp0jzC@e{q=8w5~fnp zb{i;r@%Q_`^h#?jrma1p^&ebIytXU9c$^Z!PvTVR%#5R^-Q8HbMj|64Ge^?+6vD#8 zr)-{Y)+4SO9kxf-x3|@-JHEpXRuqdwk&7jxkO)3-ze<`_i@{;iUEl#6lXj~6amnL& zH>D_tPZ!J&J^dETCnvTTAx#r{Uo_WP78?L}U$3f&*p$1N=_Idyh+ zuCdJva@g6~1;epWEdZ%SSk{-BZ*P75b0v7*gI^@na(Ypm{dstJ;sO<=F~W1zew+P* znA0u<;Y=$*?U5*ZXeskuop%MwW*DU8q#gyebFGW#EIOfVEq<@osVq8#eFfZs6 zf<$o*+2(s{SdD_%U+y-Qs#mU2jZ=DE4S-47S_BMu)JF9TpaZ-B%m;-I6g9Oar^j*Y z^_*~I=|D&WAf!}`m6o$rwBdNVa^wmD&b#BACME66EX>myAfm&ng(Mc z-7{d%3Hi2r5Gp0N{%gQ}p*~PVmF!pqO}69VoXTAVPu9!u3aUYrTt{2 z>FRouQqYq7`8EhVWI1u}WM??NI?GvH1lIm)DhAD(oiQ*&ip|&CJhSmxMNY|W$o+S= znOq}#dwbizzw#c#XmcR07=cAqZ`-l6h!{zA9?(XhZ z09LbBR=5}#82xQ+ZF)e?nm|iw)X~uiG~f|rJFJPn+@GfY#Q?gP4yI-NDcmeWA9AV? zyRBNO{JVbUw?=;GSuF9qml60J(%sQR zt+_}@NPODu-j81lgqGZks@fEX~f!G6;LDv0ijP2V4I0p`^{%cyGMhL@m{W z!$Y*(SzC&yyZ!Rs?QaNGE=z9t(i3@dxv*5^t*gdxK=_OL?Y5B?_R0#0OWup{_KNcC z5K~6qa=y+=A3)OhBDH+n<~ZFI6{PKT-p1zt3rq{;yYuzOZVtpDZ)wkzK+*AyO9y0K zv&FmR9OGVbg$4b&h;AMKSGGX`eUd^Ltk^AmIq3w78uA?59b;o-DpZccL3jhKI+%%q zNZma>f7Xl=K$lMa)ZRCAN#1wx1C4Z9JJNt0xGl%+ab*eN;3Qc84#A3%3TnN-*kvDztEyVDX_(D~&^4s-H(}G2| zB6+Z*qa%x9Hb^)q7fO7W9V4|$V}SVEB)zzJ zKf+`rH3`iJFKBTX&_FK?BdYu8*Sfm8T4==lH_bJs2Iu17*_z~bF-8af&(=ozS5m6- zKu<8yd`Lz&k_y38BKK-9Ir?iu%EF?QHyRnN#Z;;THD8rq1jO_!tH$^KdqU0>%TFnC z&bZ?Jx_v_*P|81oDtHr$%`k^K|6^6U&U|vu>wuHKFDpCSa5Rn2h2Xm^=dtKX?v48Jc$u=h|9ju%Fo*P>5 z`qvKec&Xw!oB3ep1js)?Xnf8GiG>WGr)jZSI)R^C6czGpX9-qEcI9Xk=~g*HiGteuy*$A=CMG6+ zR?_??FZ|cv=x4uK=ip#5YpSQUwC+!9f4&m`e
    CK#VCD;@I1#{hXJxKOv?1C9y~- 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 From 6f71e52ea8a5712d2c3527f2a524af9fbb718bef Mon Sep 17 00:00:00 2001 From: Kingkor Roy Tirtho Date: Sat, 24 Feb 2024 22:53:30 +0600 Subject: [PATCH 154/195] fix: no draggable scrollbar in playlist/album page #1158 --- .../inter_scrollbar/inter_scrollbar.dart | 2 - .../shared/tracks_view/track_view.dart | 23 ++++--- pubspec.lock | 68 ++++++++++++------- 3 files changed, 57 insertions(+), 36 deletions(-) diff --git a/lib/components/shared/inter_scrollbar/inter_scrollbar.dart b/lib/components/shared/inter_scrollbar/inter_scrollbar.dart index 11f75829..2b3ce319 100644 --- a/lib/components/shared/inter_scrollbar/inter_scrollbar.dart +++ b/lib/components/shared/inter_scrollbar/inter_scrollbar.dart @@ -15,8 +15,6 @@ class InterScrollbar extends HookWidget { @override Widget build(BuildContext context) { - final theme = Theme.of(context); - if (DesktopTools.platform.isDesktop) return child; return DraggableScrollbar.semicircle( diff --git a/lib/components/shared/tracks_view/track_view.dart b/lib/components/shared/tracks_view/track_view.dart index a1a2d48b..4103573c 100644 --- a/lib/components/shared/tracks_view/track_view.dart +++ b/lib/components/shared/tracks_view/track_view.dart @@ -1,7 +1,9 @@ import 'package:flutter/material.dart'; import 'package:flutter_desktop_tools/flutter_desktop_tools.dart'; +import 'package:flutter_hooks/flutter_hooks.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:sliver_tools/sliver_tools.dart'; +import 'package:spotube/components/shared/inter_scrollbar/inter_scrollbar.dart'; import 'package:spotube/components/shared/page_window_title_bar.dart'; import 'package:spotube/components/shared/tracks_view/sections/header/flexible_header.dart'; import 'package:spotube/components/shared/tracks_view/sections/body/track_view_body.dart'; @@ -13,6 +15,7 @@ class TrackView extends HookConsumerWidget { @override Widget build(BuildContext context, ref) { final props = InheritedTrackView.of(context); + final controller = useScrollController(); return Scaffold( appBar: DesktopTools.platform.isDesktop @@ -29,14 +32,18 @@ class TrackView extends HookConsumerWidget { extendBodyBehindAppBar: true, body: RefreshIndicator( onRefresh: props.pagination.onRefresh, - child: const CustomScrollView( - slivers: [ - TrackViewFlexHeader(), - SliverAnimatedSwitcher( - duration: Duration(milliseconds: 500), - child: TrackViewBodySection(), - ), - ], + child: InterScrollbar( + controller: controller, + child: CustomScrollView( + controller: controller, + slivers: const [ + TrackViewFlexHeader(), + SliverAnimatedSwitcher( + duration: Duration(milliseconds: 500), + child: TrackViewBodySection(), + ), + ], + ), ), ), ); diff --git a/pubspec.lock b/pubspec.lock index c7ac5085..b9268b56 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -543,10 +543,10 @@ packages: dependency: transitive description: name: file - sha256: "1b92bec4fc2a72f59a8e15af5f52cd441e4a7860b49499d69dfa817af20e925d" + sha256: "5fc22d7c25582e38ad9a8515372cd9a93834027aacf1801cf01164dac0ffa08c" url: "https://pub.dev" source: hosted - version: "6.1.4" + version: "7.0.0" file_picker: dependency: "direct main" description: @@ -1263,6 +1263,30 @@ packages: url: "https://pub.dev" source: hosted version: "0.4.2" + leak_tracker: + dependency: transitive + description: + name: leak_tracker + sha256: "78eb209deea09858f5269f5a5b02be4049535f568c07b275096836f01ea323fa" + url: "https://pub.dev" + source: hosted + version: "10.0.0" + leak_tracker_flutter_testing: + dependency: transitive + description: + name: leak_tracker_flutter_testing + sha256: b46c5e37c19120a8a01918cfaf293547f47269f7cb4b0058f21531c2465d6ef0 + url: "https://pub.dev" + source: hosted + version: "2.0.1" + leak_tracker_testing: + dependency: transitive + description: + name: leak_tracker_testing + sha256: a597f72a664dbd293f3bfc51f9ba69816f84dcd403cdac7066cb3f6003f3ab47 + url: "https://pub.dev" + source: hosted + version: "2.0.1" lints: dependency: transitive description: @@ -1307,18 +1331,18 @@ packages: dependency: transitive description: name: matcher - sha256: "1803e76e6653768d64ed8ff2e1e67bea3ad4b923eb5c56a295c3e634bad5960e" + sha256: d2323aa2060500f906aa31a895b4030b6da3ebdcc5619d14ce1aada65cd161cb url: "https://pub.dev" source: hosted - version: "0.12.16" + version: "0.12.16+1" material_color_utilities: dependency: transitive description: name: material_color_utilities - sha256: "9528f2f296073ff54cb9fee677df673ace1218163c3bc7628093e7eed5203d41" + sha256: "0e0a020085b65b6083975e499759762399b4475f766c21668c4ecca34ea74e5a" url: "https://pub.dev" source: hosted - version: "0.5.0" + version: "0.8.0" media_kit: dependency: "direct main" description: @@ -1387,10 +1411,10 @@ packages: dependency: transitive description: name: meta - sha256: a6e590c838b18133bb482a2745ad77c5bb7715fb0451209e1a7567d416678b8e + sha256: d584fa6707a52763a52446f02cc621b077888fb63b93bbcb1143a7be5a0c0c04 url: "https://pub.dev" source: hosted - version: "1.10.0" + version: "1.11.0" metadata_god: dependency: "direct main" description: @@ -1475,10 +1499,10 @@ packages: dependency: "direct main" description: name: path - sha256: "8829d8a55c13fc0e37127c29fedf290c102f4e40ae94ada574091fe0ff96c917" + sha256: "087ce49c3f0dc39180befefc60fdb4acd8f8620e5682fe2476afd0b3688bb4af" url: "https://pub.dev" source: hosted - version: "1.8.3" + version: "1.9.0" path_drawing: dependency: transitive description: @@ -1604,10 +1628,10 @@ packages: dependency: transitive description: name: platform - sha256: ae68c7bfcd7383af3629daafb32fb4e8681c7154428da4febcff06200585f102 + sha256: "12220bb4b65720483f8fa9450b4332347737cf8213dd2840d8b2c823e47243ec" url: "https://pub.dev" source: hosted - version: "3.1.2" + version: "3.1.4" plugin_platform_interface: dependency: transitive description: @@ -1644,10 +1668,10 @@ packages: dependency: transitive description: name: process - sha256: "53fd8db9cec1d37b0574e12f07520d582019cb6c44abf5479a01505099a34a09" + sha256: "21e54fd2faf1b5bdd5102afd25012184a6793927648ea81eea80552ac9405b32" url: "https://pub.dev" source: hosted - version: "4.2.4" + version: "5.0.2" provider: dependency: transitive description: @@ -2226,10 +2250,10 @@ packages: dependency: transitive description: name: vm_service - sha256: c538be99af830f478718b51630ec1b6bee5e74e52c8a802d328d9e71d35d2583 + sha256: b3d56ff4341b8f182b96aceb2fa20e3dcb336b9f867bc0eafc0de10f1048e957 url: "https://pub.dev" source: hosted - version: "11.10.0" + version: "13.0.0" watcher: dependency: transitive description: @@ -2238,14 +2262,6 @@ packages: url: "https://pub.dev" source: hosted version: "1.1.0" - web: - dependency: transitive - description: - name: web - sha256: afe077240a270dcfd2aafe77602b4113645af95d0ad31128cc02bce5ac5d5152 - url: "https://pub.dev" - source: hosted - version: "0.3.0" web_socket_channel: dependency: transitive description: @@ -2258,10 +2274,10 @@ packages: dependency: transitive description: name: webdriver - sha256: "3c923e918918feeb90c4c9fdf1fe39220fa4c0e8e2c0fffaded174498ef86c49" + sha256: "003d7da9519e1e5f329422b36c4dcdf18d7d2978d1ba099ea4e45ba490ed845e" url: "https://pub.dev" source: hosted - version: "3.0.2" + version: "3.0.3" wikipedia_api: dependency: "direct main" description: From 9095a8c8f849e42daabb7efcc20085cfb863c974 Mon Sep 17 00:00:00 2001 From: Kingkor Roy Tirtho Date: Sun, 25 Feb 2024 11:13:23 +0600 Subject: [PATCH 155/195] feat: add songlink based track matching for youtube and open song link button songlink.com will provide accurate match verified by community for most spotify tracks improving overall match accuracy for Youtube audio source --- assets/logos/songlink-transparent.png | Bin 0 -> 73176 bytes assets/logos/songlink.png | Bin 0 -> 88538 bytes lib/collections/assets.gen.dart | 16 + lib/components/player/player.dart | 16 + .../shared/track_tile/track_options.dart | 17 + lib/l10n/app_en.arb | 3 +- lib/services/song_link/model.dart | 19 ++ lib/services/song_link/song_link.dart | 47 +++ lib/services/song_link/song_link.freezed.dart | 320 ++++++++++++++++++ lib/services/song_link/song_link.g.dart | 33 ++ .../sourced_track/sources/youtube.dart | 15 + lib/songlink.dart | 43 +++ pubspec.yaml | 1 + untranslated_messages.json | 54 ++- 14 files changed, 565 insertions(+), 19 deletions(-) create mode 100644 assets/logos/songlink-transparent.png create mode 100644 assets/logos/songlink.png create mode 100644 lib/services/song_link/model.dart create mode 100644 lib/services/song_link/song_link.dart create mode 100644 lib/services/song_link/song_link.freezed.dart create mode 100644 lib/services/song_link/song_link.g.dart create mode 100644 lib/songlink.dart diff --git a/assets/logos/songlink-transparent.png b/assets/logos/songlink-transparent.png new file mode 100644 index 0000000000000000000000000000000000000000..6b7064c92fcb567ca37c040d637b53cb038211d6 GIT binary patch literal 73176 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 literal 0 HcmV?d00001 diff --git a/assets/logos/songlink.png b/assets/logos/songlink.png new file mode 100644 index 0000000000000000000000000000000000000000..43d823a587e26534ae0f57d7a2c527ed8a1b3bfa GIT binary patch literal 88538 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�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 z zbjDl3Kl8Ng+IRMTxRX7TgMMcdO&6}u%~aW%K)+Qix7KrSIKH6>o(&9H}`)JycC!U6uPe~|&sVkrS|$Lxmfnbt5@ycPU2Wj3-|IC>13SaW@!Q1iKR24oa>f2=1-Ffxm zsU!THKY|rYRxb1FU%|xCfm@Rj04IBwuZ~w_d0F6Ps-GKmEd^s5+oKG)|*&M1cgNp(=XSK{c zTHF&E5p^}y3vdIPcS1o;;#!vqyGQGoux+yzlAd_N1FmasMV1}0umb*9vKSkQMS;(Q zlboI>HgiFv30~*&nX+s>7q@s<;+TVeXR8%X7ra;(H@m{UQBqsm*OHz~9CX!wfVgS5r zeCN%RX>S@j;Q970Pmfl&du^aTklWZhw=As>pq)`W5qNxWN%_mo5i?a@QGh|ptJ?wQ z(Dgx@WOMlr4hJ~V2-53;KxXlndvAOra9XjPm{Z!`9^OlL%0v&!&_(kJ_3tOALZCj7 zU3I53@gUnNNBscTrDnRtrXSp#aaHlHB*OR29+Sr+!v(iA4JZam0Gt3BYSAF`;>SG8 zFFj7hX~hC~)|Btn1OI3T^gA2X!OEpNgL>H|Ys1~!ul!##`C5O6D+o#)L7*^V{OyBa$r!ph zItx7B`$us@aNfyYJ>o=Zb%HQZ{Q%dtE^=^_`?*%s`Ms~AtTCo7mj;PyOev$5G zjh+SuzDBca%WYL=IIS3@$1Sd!MOsGD0SD;{xj4wsrZ&Z)8!^e==zxQUNnL7eaNKZ&EgSoU53kvCJ1-wjJE~z69R!3mwR2o@*C(pN zLQGZJ^&z!xp);mh;s9SGN|w(Y`rn`1aPo^E$?}Q}B^1<+O&9KLjFbi8t>BmdH|9F0 zPQ^WRVh|O{S6U;cCRJh1*iB8GnUtnnkHwY|J0^s0Mv^mn1$~MGl#UL$1OSacY;yuYA71fvx$lSC1P+S*k zYlivpwrSm1j$2H3Z&Fjh!34a+&i2++GZhBh&?c;6bTchO1P{1*Q=kEsrtt5}YkTu4 z@PG@_8_pqSpLi=cCcyPfEL>Z_!(boJutqN$CVBfyJA1oQvAY(zR!*I}`NBW8R!srt zx%DEm+%Y+BL{A4FScG*8*U`}r6R#HBaO4+JPywenrXNfWjiiKN ze!P)((eb3}YfLo-oGJ`oyyZJl5u(C?%WScxlFHqb0JskaJK(z3R&dTy8oERy)_m|z zDb6Xx)1akOJooxp!n`2f9361CjKW*}!>zWM&F@TY%X%i(k2)NH5xRyN0&Zo$A1pol zxF<-J2MHsi*L&9=&U47HQ{9X>EL{wM|Ha?QYkMIbleLYkdGXioo$bakg#z4fV}0>y zv?G&+dS@dGI)WceMvkOn4r!V=N3@PUT1*%t5_Hv(aBGpv-NnnxQ&FlM)I|s{eRS^z zjbTNGyN464<)#mR_ZOd+C6k}7DUdS{2-bl#QNsPr3LH}?!h?n%y(#bTbl{*q3`S!v zmZR+L1q!8;~{}Wk)QK_ z@%eyj5-DW3OM-z9O(c9;v)qMK3MJ>MO=)n3lgI}Za07?f^jzuWP#NaO+tAE8HO2R( zhZ~DzM9@?}z{xbX==6I@;uK@meraoUZ8zL?7i2Qv>{WHi6uI{;7QhW)eRIkAe8+%f zX=fSED3n4*w^wg_xCrQ|?^`0xdq4SL{c#26$6L?T)wx(KMQoEPL^TB5ARqWP)k}T5 zRDFm}%DL5GiKi$BE)xxAvKe3n95_ZmuCO_Ho0i;;8*juJg%Z28AE^&_3`7N-kYgVm zp1a!Fjrs9Le9@ifVxBnFLf;R+6A^it_OT#W*kY;TzD-$k>x&*YgiLElzzt;P=$HW4 zhMoJ&;?M6Dyga)Qg)<5zZp+-trDr9cMW}%5299}3lHXtK!Cd*TV+bm17UG^?Q@hC~ zA6{{sTD~`!(pGAr;1idzn^rz&ktu5 zN@kVAzE{&coN7@6GP+czU_LzU>|*K?&0KGoiolTlq|D)$0r+-qiLwX z0b8;`f#lix7IyD{WW4C?IJsQC`apl};weU+|`cCK4{yPBIJq(egX z0n-2eISr$~`l(XBYmIz&kAuAaJ5{(_6P!#_yN5x0;SDA#aGDfqQ>Ifv(gGLCx2b#i zy?=nCL!glw0&ZYVt(`A;eaB11=WN(iZS^M}c(^Ocx9O*!(J=ZKGQQzISEI?hPpaojEv;U%db;2OFHWU6DfR9qRvHdW;_xRa+j@* zCH89Ul%>R)f<1Q!b2S89QGHyP-F%Y2(?*LPP+!@RiIi#4+*HdhNhqQ_Wg z)R1ruO(T9r+N;sBVpmmmUNi}b=xX1&Cy9p#oFXq+Q1p!cE7?oI#|r+droAhC)LWKn zgS$1sNzamPTPALJDzGMKqgN(qG+jH|=>uOo_FAr}KE!!ZBCtB6mLfQSJlR5bqq8bI zFB-bqW;IVPUZ=qWZY585{L_yWyMoI)$p}Jz2 ztba{ne|w6B3Ih(jxJ*JGzs$&l2b>xoC<}>y2H?8%99Y0Xu)`r-x@4*1qg>TNh{cah z?@C&@yB*C3)p=2a;gl>rztEh;#h#;$sJr7UEuUwoDd0Ko>9T1$TvdMbK+CA*k~G{w zQv()ps~mZs;pYJElWz^3j%@(#Pbwf$PF15Pa>S)`f zO&7Ri7shP&+Ne6aWqY_7T+XwSp#k1I(_$-~ny0+GHB{T!rj^Xd7T$Re7Pk8cva>`l70XOd3d3Hm@ z477$T8zu2rp9{FQIR~!LMVCsm^Uk<`vlj-tmjO;< z!8IBX0{Px9{x2_<;(#khh7oON8-g?D9Z0CaS@UB{svB0?BCtPrT<7BMxAznH))WJE z1f0|~CVW?&H0P({30mVGB(UPm4}_}=r&y6>fGd;-|H1z!`-;dUI7@VcTDR!%XEFUP zc#(^8q#w0)QC2>R4mgP^lw@C79}mU;HnDVduH3FkcPsKyU|y2yRjZO2OhG{Mp*YM~ zwQXGtyE|8NO9Jd`;b1c&k!2Sth0M`^{5#nWZbXKAsTgH?CKSBbS*y~=*;EeTexv>C zFF^UIH7aoA9D&n*^=f|=<`2^|w&aGLdr6G0_>fTjGdr(nqk$aj@UJKiLcs zwb#*eomjs;EfmFDsh_o~hPIJ8XYl&&WOs;#i7M|fdSNsDJ2mwZJGhjU#z$He1{_}I zZhJ>b+e3A>IN-{W4m)LZ?d$~)Zw@Npx+I^b!5c?;y-+hBE&I+Mq{q4q`lz9`swTmJ zQX8F{H{xewsmehhz2cswSF6vb?UmGcuL$5jP|inLJC^LOgDH4HIN(YGoEuR$yxidL zPDMR3Ya6lXwXwl*Tc#$4dYB2f9NB!IeBE6XsD^+8$8Uoo@D1DvwPmYvN12{&_rm$O z+Zk?30{jQxBH+UC`-ze5RnB;$iIM=f@T(d*cUbS_g9Syp?5N3Y~$nYFYWKGDmGK$ zCr~G(taoYUAYG^=>zuz;0PtTc32@Ksm&?P=jcgonB>`^iY8%m)mm5vjM(zIqjeNSI z@S4snKL}$sldiSIhUyIWOoKD(NVtZT(4%H~xGqbTpFkaUWApIx%WO|20sd=rzW=9^ zER(I=%fb7zB8rOxt|Y(>Eo}UHR(9XTQ-}&o{nX%R0O!SsAne9$#$^i^FE3^X@YND< za7lCvPkS^zQ>n_AL>+EaMQ^{f++7Lg3&>x7`ae+t{~OsQP6;LxPW7vEEupp+cr&7Aal@ghHl{e>N_rObOf1+{o$s?9X@M+s z<}?O7?(J;Vg?eFb*ELKn9axUZofeSQ6L538>%o^M$7fSj8E{jZ)X?F$hq3U0f3P|K zZ;IT&wMp=`4b*_=J0r!;X2v++$^zWb)S^**SRX5*(a}4~G?>75aA35{53}>4eo$9? zWZsn$H;Q@!P8qwF{9?VoFG7VAwOYnz&c!1;&jYB?|93w?i*^hDFUYe&;Xnhf;S+sy zw#CNGR38UiS@$)4W7Dvuq~{Vxev`EVfV(_gJvUqzg?Z?NUPxo<@T(UdLXw7h0`3s& zQMmeQB2<+D*Ecn@X?gT4S_y!2WN-cdf&#egw^A99fP*9j<67Zlm6@qAUgx5`EnMHY zxNW^KV_ra0V5T%JAi3ehg)3MEIv$jrvg_OH6+|1$IT`E-sS!ll`cjH$Fh{oLL~sMn=dzBR3OHt z%Y)p(!E`92oR0g;5r!&0gI(PS*9n=~Y^dLN7b!4Py2&%VFzMA$1sgNq7G4ou1D6Y8 z=>|k?HS}#FGR8dLB{wXWsxsi~PY$w&p1B&2`rsb2x7-ZAOkP^!leK0*=(F zYEo+<0XGlK6a*B+%sJykDp{758=I@Q)18>;fU}s6(It!P1K6!qfp3#p)%Hsdp+gQ; z4U1j0$(o^bM$>hQX?l(XT^|Xiw?Ls&l>8Zw3$xn_YNlqDlBj! zl`K83UrKXlgNGY>URpz2mq>C7Uhj1U&cT=gw;A1DefHEv5U8$s@OwM$s-7mZs92gj zya!SvP`N9xFIy`JIEiWw7qA};@K3w7JyB+f6RBkBSUN{lMjn<64YX0m#)HY;1n>IS zcYP zCieG*n&Lz%8*o#$UlynjcjADd@#x1aU19m^QkEav6!RsV+cJ0aL2ij>y!v&U5CcW? z`vubNQdI}sG_<`xu_oEY0S<5yhom6jWNXNjJ74nf(&qR`gb7ZhvH>^YdPPm#s&;9j znk!H~s_U37?FYVDW|({W%qoY^ucu|lGSv@oqj=$U|NFPZ6)F#S#3+*cleKN|qIw3FSF5j&!2wP-H_}iHa07}F)N<d^*Ao~I$!+&Cy69PeFa+_O%pAP zEl%*@5&|T+1-IZ%Ah-wj4el%u+(U2;?(Vv{yZhqqZsG3xJ@-EM2h2=$bx(EoIj5?S zFvGT{7}OhS;rcM~GAgr9SHxVwDi|t&x2O|0+(_u~x(kw5tAGusI_$(H2h`i>ja>7t z?(fl+*e3pTQ_}u%-MX&>x8LBC5PDeajL8ua@0JYYT`;S`X}YEQouI4uP!jmhV@o-HoJ+^3gX; zU&F=wAhDw5a0_+OL`~=9eaw%CrT!Ml9X3DBCLWW*|Ip`r{dWpyPw895r=CO*fZ+QX z?Wpwu?tSgjNGoT-Q37sRQ645uq#;-v^6_FKlkxnC^E7s z+EA(-YtB-$;r(E{^G_*e^Ob<7?a8x$!M3-6)l;jnI~h%UUCNM4t{uVY6z6=st$tCU zpy4|eRi7sP@a9To;LdJa@OD71(*aXW0~&lqu_6^NU|GsEoG)Tq9J`Dhzu7}>I&el~ z1M53zuIpNDf{CG2o@vbWJ1N9}Le$T#h?(eKLWE$6OJv-OGM!4IQDbfga2$2Q6Q7$5 zD<1@*m0y_Z?e@XpoJ`FQ2>Ho|MqZ^zJ#;W$nQsj#j@U_HRR~!BUO!%4fDW-gM|ZK^MRavN&;I&r zi;Becw=TYJszQ0X6y4ggq8msKSwWx-^z`>;)-#R0R}MGLpaS!FtY;!5%kyl~u!t7o z2V#PDe#eDo_Zc(L49?+GdV)T0CEB^{k*`Kco>R_eUu->ABgvwxoVoL>cTAhcx?_JI z^!T>DU9ZKm_D0n$jUzG$4U7~H$Dn;ie}@$6954!4d{pGCzvSAZ@*5pjJfL8dW!3s~ z22KeiG&%{^X}UU2Zb1&hEKg)azc8dge=ra4LlB#D0m+bd26+e=iN51E?vZK@Ot3kwTU#IWE6 z;v^e>|2{j5SX34jQ#h3@nvxQTh4sRoB0(cS1&9@jP0P)_P`gSTnVDJp^kunkce$SQ zoc|7wV_N9txb&QdR_G|*5|zXMs^sYlK$-+2n3dkE$I#zYxz~^q{o&kni3_Gdq_q#m zG~omv(`pmCZQvMIB%0;~?_FNM`erjXZ54p60uf@_0Z}jR0 znUO^uR83DFER)|h&weZiB~8oA3OEQXG_-tJ4Cc4y(2yQ^7x~^UrW6L2)SxA9kfT3f zPk0MSlc9koLXL$7SH;LK)Z%1SmQK2#PO*@lLR`X32}NGoc?tHKO5*G5oM8FXLYCz! zn7l!F??o62wSP^%#F;(LABRE6-n}D_s$y!!Qb~+^;aYi1>lGGg(bQ^k|9G0c*M6hs z2|Bz05irnw`gArwS9*MWEZ`Alp=n^}b{FGd8|9poznpwjJhI5Nv~wR$I9v+_=bNEZ6g#S_hwr9G?Yv}$9;A8FBAT?2ij{ZD(^l+X^gQsQh?V0s-Agq}=ryPj>VN4y&QoF@I5BSxH-oEH*d0=)K-TcZJ4#*{6vp_nCC!*tnb_zf@Z1-(kht7n?wKm`wb=Fen*Sty&t zx8gouG3wB_^cKDL&g!7R=4$4!xibk&%)xg&-|nIxZrQ;|}tG4X7hJteI(}5T?7k+}o3caOM1SiW%5Pj?M6}u`Y0HsL0{i z#rxV6jS>O>o#=T9d1z;stQ%RNu{tvv*2Fu1CiP)8tgIZBFLX`Dyx|Ue0Pf$1o$3C+ z5CB#{(Oz{k&rgW5GL?gM+Q*I^)*E*E+=<({aW{{K+62|nFa1xeHXd_hcKw1QAc?G> z@`(FR-ykzyN%OnEr=Aa{meP1MHRy2c><#qRk@@{7E><`Eu=s3aD#tKwsYDU#@2RCv zRUZlU)d^Dx)KBhF0Y&X?=@}W~wziA5nkh|sFxfAjxXrTF@H1Fe zQ$~Km+EP1)CdZP_@G;F~VBc@wb#!#3q@+wuO|7rTEoEkAPEV_X#w(7`?5*s|AKVwE zXjhWeU;s@&8{A@o&7G_^oHl$)YHI4BnXRpDX!^t)`(1ASoXa%>7)eN63+o{T??f*f z0Q^R1ebYYlIlX5lV(2~0u&9MDz^EwW%@asb%J$XxO+m5*X}$)Ld7*zP>NNQ3(R+56 zo|6MfX%}<9^c|c?j^*RI=@Vv3@(V!8q^C0fP0TaYc{1uO6@go8yFQi_Kkjt>9RXfbd-4n*6YE?D5+PlG-e6g85qF2mpeS02@%4A|OhcM^p z6!eDNRv+vgm{KV29I~D|d>@Iwaw{Gl)0gca7=o+72%=%7|My4_cvIU!8~YSMiq9BP zbF$&59?ZJ*3Etk;dcM^$_RLCpn>ZWc?Dd99dDUR3AEPPXZs|l+6(ovxbVUmOX=H!M z+E6M=jA$_M!1vk9#V@NLssdFt%cH?^411eVhW|%U1DLVdgrnD)v3WEqFhlDwEp#)U zLHNbP%0t_V^7vRJi>+8vmB(h)THZ%&a~_je?4)r#Kex}qcX00Jltl-lD;w9?teQpS z@|h@2FKiCyLE6@;%;bFV-Y(ve%pw$6pbNAK{Je#9?7pNE{0|)2966;TbZ)E~?_xZ2 zr+1nZHRT zlAz7@H$}04Rs?H=&;o9eFRx4aW19@4;A7pIK-C6T)6mhO-gvxvDtWm*J_6c$?rsc; zXOr(5|3O-@#4`SZIh>Pl6VzhsSC7#Eq>wEX?;#~kKCME zl7r2I1-UPa^FpL#yeTn z?3JOKb6cI3c%c~}_ct3;!{4q>mb87uJaezGS&8u&B{b&&m!cIl^)l%6ie1!*WL-K8&){hJ@<_9i5xvfe z#-xD^yG!3C|6rLz7O|YJWnx~;Y8;VPoFxgZ08-jlL`iHqu?ma#*@Xe!D!s0XL15VA z?@w+%b@}w~6~^0)D?Mz=yS8ivyKEeK$DaHWeieOC4iR|($Sy4{^2KocQX6NCDM6lm!UF?b`z zmSHfI;1UW~NQwR6kO0rS#zNJm)52#K0UP-+7j2o1jnG2AtQt-l<%iajxy^TYD7hT3 zCC$A_UBqV!vy5c^d(A{I96#IU@C`rqnF-W?Dn~}xKLCNRcffBCO|CHP0H}#E@~+99 ztemA0_}|z$jGu$<=++Z^@#+Yw9@%m8IxkA1d1UD`{9d-2fQU3F1G4{DlR<#pQiG{yt%x2P-~a^WK$cVwW7 z3_?QK^*^bw`R$5V(;4jq%Yaq^#eNVkDHtm6It(V&O%2LG5YLZ8e&-C~gk=_GrCBrg zlP%3x4_O#RAdjV?A_I>^I8o4>CnEB;)X zEngEHWxgEsM@n~2Ki=9HaRX5>K{usK$0#5S`-yU}*gy$&zL_bBo_<-~X6hCuJzDr0|IO!OHgXCOOm3Q`L~xO(DPGPC-9Uz}y~+kr@Q`hP zgO#O0?3%a_i*u<+2Jkdgeacj9qc_fh$w2Th21ldU((;Q9^x7!&jUhZN9qT^)l}F%# z2@!qo_O@^S2>+M|^VGe$nLRerf?Ld&1;uXERE&AUUyt$}hHtHx6h_{0JtpIEO?szo zeVmvt999*-a8#EBR9fmr>)s^CXu3c$1S@)(8#lpzjQ^e3?z4pj@yJ1pK!>n5u`RYc zc-q(`CuV_-*wZtWW0O4py_H$SD^qcozYXr(X#tL>I*T1HeLb?bfC(kt4TA$mSYW>~ z(`&fAySSUt0^VHGg=!iMTrbEkrhy@X1S2Sy)?M6QA>O~~QXTL(-YE*I;RF%2GGILP z-g)XY3?nE-w0l*}cod=mUvy)Qw=+(g5d4UQ`Jtx#YCGS3Wh2)@#nImxwBft`f!Y%} zM5Ve*Bj+%)-f(Tv^T7s1a<fr!>gZxw%TGu0OR$yoS=xADM;deO;e ze@7Lzi2&r~wPu37*hIngW)T5Z(DmcP5B!{T>1kK=}~S< zEO=%Lt`L_B;OBnOI)&%oh~`TQ76=({P^8Ec$njeG5NBrqnOad{4*iEsz7TiK9z?-% zcaZPI z(`S3omiV{M7eo?Ke1ugUt&W!O!~{RW>igtJYHWW9oOOiYVct>$5T@WcGAms*pkPM2 zh|tWx*Gd09iw82{+}|p03b_tfEaP;$u{=mG?-nLd8R4?|?tSOu$c5+ACYv3|Mv~W^ z2Fp)E_U^gApvK~@aDcP09Ij6p8^O%}Y+5c?gDtX{&R}P1Vs|;s5oW!E`Lo^6nIDeB|HIPmi8i_LlkGLW7j0~QFz!IfSM$DaV$M;4iA%b1IeI>IDrawgP>B_fx)+nOG-LH`+NHq%P(B=DRn^fXHP zBRZGXi(N_2f5}{OU~+oS!CL5^q;n|b*D}aa%6wFV*eq}Yrynp7q<%8}uM~I-tBoLT z2QR*}ekswi7P+RQzR}y=O!RAN4LPlBk`jNfHTSl-Ws+(&`BWbMg&LlBUGc7bsNU?f z41YEx*X#8_HRVoe(~7Y@*~_E;219Xi%m_TyMy>|1c(+`Cl$W0p{^P~?!4Ym?MY7W_ z#ibq=h7UG>8EhBX>F*f5Vc};PxouBQ@o<&$vX*z!?d<2$uW#pO4X)oc@j;Rh-MjLy z#bMEZD;{TgJxfcCBI=(hm3R+w21Wl`mwhr2_dGEHCTOJRMYW#Nr?bu&wpkB<9tH(= zu%cZ6R}gBOaz`5JMnaeJcjd7ic(c=l-;EXfNB=9evmK>Gj$BgsI^e+Uspn*x!}FJ? zS){$DV@<<%ADNGqI+Ny|H=`o#ypYI^`6nKe z%9^F1-af=Q_|n|Jf5le3h!67%1KS1lIv>UhZamzXHb`!_-`kTb8|a;$V|FLukzY8J z>fko>Hc^J_)b#9_`<(NipVT*O0wtSfJWvpr6w?kWTd4<-m8!fdA|Px zWrUe08J}l35x?M5ZTpM8>eG;!Tr=PTD+T#k?aLp=oq!on;ZlnibN zCYb9cTs4EuB_#;3%M#I1TT;=S-I1h#otcb^s2qJ5O*X>{J4-}MXU?+|92bA1_zD)7 z+^jY`6pO%thdI{l-tS-;zKjjkpF*>O+>w@^2nvJE@}2AF$D$iHtVp%IFp_<_A1(Kf zj+5u)RS%z2(XAp{gMxw@ar`^aSqz%95?xhhE{wPjt=GrKPX7%c;5o1g5~QkOI8O<* zy{}f*cwW&}W3G}~avtqI3U16FQaU)bK_m?9S8jT1AVq!Hj_}Pfz3!Sb@@B(o3edEb zZ%DGUmXK4|l(ca>JeciX-TrqvmL|~1LMdm1MHo{Oh<+45@>&ba4DONVxWnz3H;|H& zl9hFL_iXTUeC^qn4zfDebP(eA?%0>vPbSTFbD!ED$tMzHt|o>BbhVY?xWT*-fd4_? zIXm z^@R;gZE~W{-m2bIOQqE(hwW#w}jV zSPw~5KAihSHHn!io777}UYzH*o6mJ#UAu><3+caH6_CS3sSe<+-VDF~D`$C7hmVut z%F%Li=XzdjcZ_+3lNOHZ`f4ahd4ADXn$e^G1x5y8j6WsKgw?8sw)$rFEl%fV$SK>aP8uUF3EPkE&XtTmz~)y zib7BTlHNSc#eEjs%l;L4Iu_8q+{<%wcPu|qWa}S1xbbh;N1`r%ZYG*ioV=Q2bBnV& zX34u}dxr`^xzQEv7zC9CvOH!&irqa8pol`pa~wD&n5VK$ZoR|cN-um)RT}4Ls4m|1f_Dja^Def?$X*v||C{%x%R7d4gU|q_h zSw(x(`ebgdAp&{zI|AQc@W5}S-oOyV|J}|m_H;7FC^(V|Y($&jZPnT>iVQiv(s zSDV{@6A@iQUxOIIhesjGaMPPqt_>SMUo&?4>kk$^l>erQ_Dq~MoJ_-Oo0@aKfdiZhDX2c5-rs*%p8?<+D<;-K>hEt1|6a6<#a#mHf3O$q{IhT@Hg4inFhgqAtpSPEO z$fM!yD2@I(`Vkh6*uIK88hwtOoFf0u_sQbv&198kh1y2S^5VsRYZ03)wc*Vr)FgKU*J}@d(B69&9 z>v^Qgi$0Jv^b|%!`D|)2qx%?5FFJ3It2mg!_8#|~Hcx@=>ED&DV(>~9gWkOVu3+{^ zHM~>_xOZ&d?$kAn<5Y^Ip6a-+HAD@=^PFZHRGDCpMMXR}8m=KGd`=R}m+N^>BB~%m zTCfN?4@5~_c@IgmKx)tp*h@K=kf2b5?tH6V3nB(FLsxd{6OswfOegYk5XL(*(`Y+p zR3imgGcg_xJSKDLf1>|d>oQZ)>Ewgm_!EFY_w4pwzssw;14>kAHhu40GjC~)mn)jA zd8eXY(p*-18>sVwxJcb20KfFXqR`?*J|{zv9M(hh@=-9Fn>Q%13$TF+Mbx00@qHRz zAv_WI3`+rv>?ntIRU9kK4LK#Z7ZhBjI6$rKr52VI^BE}(edb2M0#PKmlR-NreZ^M7 zEf8-}G5jM2rj8t+DP?0srtxq!w0St$&z@a{q@I4T-y8cp>c`wf9v&~`rFC8?BRf}uDi5Q3+SF{a=(~}>lw|MUAfn_>--^ALQJ3ID- zyBFZN9SRU%+(m>mE9W9P7tL{RX%FSlbiN`&MG~1sfViL*eNp#%XQ$!27!&QAv9|6K z^Ns|A5@=q@R;; zF*K*0{Gm2c+s$J1TMJD5!w(%@Yy}>7xDA71vhd7WVaOX6c2yu!`UixU0a(=W`VYzh zUrSUIBf;cfFC7O>B&q{H!X#$8TRa<(pOWylu~^CGMAqCc>-ITqu06ud$~riSQD5Sp zn%H(X6ZK;jW_}C&x;!A_PxX3e?-|NRTcw6dJg%kK!r>K32sS0;j{x4*FTtEpxO?KX zETsxQfy-U^Xo)e!=5b$b{rpqXm_}F`=Qg_2FQIYDt)u8jSeKF*l#oXMir^zyGD(up zqPY!VbH!AL52T@^zcnu5r;}=Gyzr0W3)W>ASUJ61HZzm*+8-g^ADK5nEcglW^Tzel zT3~O(7Hg72ES^)no$V?4QF@z;mea@kuuf@rsSx?H!Zh-%d5Qh1Q8O{F1mu@uXTjMN zn*d@^eE;U|NW>BV>p&U3hoym5t7VBOK-~Lx_zEuenZf;z+Fy;t(d--m1qzUNK+Jvn z@HOM_EGrSnM;xzmaGmW(jxK zHn_QEl-9OD) zmk{z6z7`L>4V+PiwAwyuVVsNn($In&D3#y5o?^C z&pU0WXgRA>t7AVec^xg`Qtm90bic3(P)Eiqk!J6?o)SJ+L)b%$_ZwL~kE*Ay2lMI;z zS`W$+MIFU&N|JxB{qNn?v-@z?i!?y!f98UuN0(l5?P=Ro5d1*soBnlTArGA+f)_a!yblBX zHDyvGu{fUY&EGYjx*TrBU)W@a$WaIWm`kva168(Av)7Q; z)|W(AYlm)FuE){FTigHgm1TEh4Q<6U9{JMOc(MJb#yhqPNH0#agOd?0m~7~S3tGAn z!`fla65V98e7-mI5u33FOX4h)x@^9T=QApIi`73Gb#V8Avx~>Uz!uq;^Ukw$Gm|@| zFI>C9T*?NrRW?`b^f2h;NEC0-IBaX=24L z(c#yf?_pR?ZmxmnmYRPUVH<1uXCAkYj~cXt@zj0NuDx$C`ZbA9_`negC;g*f_P{G% z-Ei=gR1c!K)S&IMb&D{GMm4OtUwTgoIN{X|_ki1@d>5Tow2|Kf?8~ zzjp6^RklR=@BJlo=aOoFm4or4PXMoD_t7ymUGNq1TtAS=)=r*i!bu<|wnK_`86=(V zeC5IbE&NAIKUA;{&8`gU#1?V@8$z`6s8pzC;K%N2I@}|1Sy#s9-$YBAyD*trdW%Lh zycU`y69L@IjJMypv>Y7SB_3PMn2_$JvLgoekR_cr35~V!5II(S7&9!7ipL%0ef&c z9{SY9&Ba|mq%?u2+Zoy|;e)t(fXS}cL zTVVlXNryEe0B^NSOc%bjKUr7M!#a3tK_>S2A7o(0~U!KCX}~h6S%i_CO8Dc9LWoebt{eMmXAB{hB0lH z!u2}O*+pQkc>D_e$6x?yZ~WWOR%x6zwLABrm;N31l_dmwu;X`~AXzwquO36=N7hAs z)Po_4=?zMRhkIWJ^gu?yML_8X!h$0q71b|)>2r7-Igp#wS9mV9q*4tDp~6bdVddFP z7|%AzYctqwPaDlhIq*uRo@YX3L!{^3g_LA?Ra~dqeh0;fH?bi%Ap@7M?HfZmrWaXT z`jiXyCI#z3VOI~!+igiy&&;DY)pU5BY>;B5Ie}U+w%yzcml!l5H&XQZd$i@CKByT$}=of<}En?lFl zC!?#_WL^eJJ8Y-DA7`j5-SL)xx{6+T6lpq|7_K|O5R-f;Bo#t5*}UDTlU0r z+}i`I&uSK}V&21&kv;J%Peje;b>nnRhV?f}1v{*Hpidk-!Q9F>8#)+7R~@7=PAbYq5(TlN+8Sgf*fHZqhySk89Y7)b=<;VGM>cgX++7$=X4{rK za^j9~m;@lj;}-@0k!#(ahnqlUaza?ivCkh^9|b<6UQm*uKivO8Y|4EL9IRomKo@e^ zB`r2QCN|Vw8;d5ahLhP4hQdnMa3^GD;Z2M>zsEy8StASj>foTP>|nHc6pZop$2^A? zy#ZNWl#GU;)Hi148GqKA_*c~R%rm9xsfBeH+7q)s4~Ag^3;JX~f?q@JQ*|0a!gLQL zc-*xmvVRHL*Ru51A%&FQXrKx^OE*99h8noH^+SYAW&$@eq?BSt=#x>0+Z<#m_~^ot zhXkpm4P^#dso}>g2e|}1&)-5d@CYW~pG{bewKoy3bMpE5%(Yj?-)W;M@hP+aOsRoj@2S)tJwg?59 zf#~l|^v)dQ(^Jwt_O$}q`*3#e2RyEJE@dpwUza*JbdFm)jy;^?vFU$|`pe%HWDBz! ziV;Z;QoBwQD*&k}y#pp5N)OtyiL8PId|9*B6umWFj~nvX=O`_#K|df-J`pQY`y0`2 z!!QIBTe9Ai<;+bF{@+TDn2ixqgT`Hen>pNmzPhXqyrAv)XDDQy+THXtaRW%5Bm?Ip z+8Okq3v>|6<8<$4uM8_Vpdy-RBJZ4zOk(6@b(81$EM&MN>7++2p*y*F7Zrjou1c3; za}Fixy7Wj$|FcJ&w421vnW9C9*4cRbZ!gu|i%JB7`q@15fuDE^J_1>6gh5^ys?+iw zPb0Qy;}Lg%!;$<|jS)HNE+E+g2uk8v(2X!&wD%hUo4g{VQQDhJJ8>2>n0b6ILHJe~ zOjzffozJN6DJ`#wos4;ZsrTWG=VRwZ8IzAd%0r8sv&|PlZ&&hBx=in5BBGrhi+4_| zVtxS?XPQ}X|B`|`b@E6O+hfW1@W}sYB-aaYHfz!?cj7faTG~AuJJ@{_167cIAL0U2 zYrw@51?pCGjvuQH21y9{9MnVJrnPSy;m!y}t}ceHGhaUeuqXuFvFouo57)*vTa1>q z5y^_eBVQsyp1bmj*f^>fzbW|@wIos?EB{^Ak-0YbW*U2+bMHg&Njw6E^mzQX$TyU_ zJBo^VmvYUn8$-#&EYyTs>%r=(@%@YTQOXN-B=Zh?QyD%D@vkFit1^~nI8Dt9NB0Ea zB#S=4QnP%bUwA3f!?}u%&>1s&mMAZH`B6arG1&MQifx{dT!nfwn=G25bqTRyMnwZV zPsa)Bn<7N4Xa@ZlR|f%l8&b|P_Ff(gNcFhVobo+7c{{;pE>opZ!3srCxBi#(7s}?y-kubbQ|=AYURwxLrca>p?L5y>84z!{rVz6A0Kh?wRyvxQxrK; zA%w=%3jUN2-^}5pLS|xW)9tLcKY;uh0MVHgslNc(SG6}5a(CwBSHN1n=hOJ**|~!% z#6do&3d}6JKCR!9@iB#s*s;iZ&pW(6v=C5`l6s*C!!1`;0!m1c6G=l>q^@jqkJ2I# z0`ReZ zz@^6&&5|#Dut`ZdG5i5V%H)qcIC+fi@@(Z?)Pakl$gN*5D&Ydc= z;_~yOr#BR6g*@aeuOoGhC2LJZrC=T)7(|$VFiD)JT_K+Yj@CEUH{cTh^N{z3h2gy6 z$Cj6t`Z2z)3_?UHNhB^%JGe!vqv3$A@9jtKUHNWE0^rMe6LAD;UxhwWB-LMRAg<>6 zYG0Tlvp_xHFLk_da(jq1{Y7nSuwd>lO$yoa4`1a(X%ddjE@WBNC3eg!RC7^MXb6UN zvj210Z8T|#m;HtBcUsfR*8qa5oC5{TO6(z)pT4aQwdZH;{!m{wW{)ROQ;ybfU1dD? z`05SbE58bBq^?UJwCLgW#db;h0&pEuP^ma}JO4!!7)8sD zjEqvO)^g&s-0aXXH{aXSQk%&oLOh6Lt3Qhx^6gU?${Xy|XfO%NIYy{2PD;7iKoo5J zA?p2bMS!5eTNKUC{)Z@l5)j>$y9rq5G2jRFF$u^GeW5E@FuTs zwOKyCSN7VrO7gg=WSyCuk3L+Qz7%!`=U%>tB}<8_DL?^A_d~csD2JHBfm4av))NQQ zFg#>YFnwzrw9tPHhNJ6IC+ z@B~lcmMR;TTYevjV$*{n8@f_b(nv_(d;dsH`Xa$Q#!}yuZvp!2hwm+FqHO0Q=28S) zZ0Q0*N2{Pne=9+Wdi?8M_%^|{)jt~wnsRBgTum$y!JxOR5u{`+arY41W zSK|#A$guM_|H`a4|4^($=uRPfoG(E%o<1rttynt5y{Kfh1vv~Nd`rY8r-0IFaNNs3 zf^&-)+`+ZHKh4;G_k(L;1*M$U4gy~j@=yo?L44XJIF9mSONq5$xgbiMFYLm9m`1Y4 z;EEQgizr1rFDObhqgb4I8tUig8)gZ(i3T(agZGx3A9c4!Ar#iuwoHL)*J_8p2p^cn zm&ZQTwPeE@QDpP;axE-`nPbLb`oKGf&ue(EQ}*)AkM^hT?d;j?!( z>mu+ym#Wh((uO%at_TUMlXD^vgH=AsvA0OCq@1?wN7 zz#Y0^It^Nx{BCRn;LljG(p9+n6F2qe>T6A`3VS!qhN!xEjXJJCRW9h%vQ*1bz#?Hp zP?2zs>htkZnS(-rl|1&`w2bx>!0_XQ@GYwJo8Q64f%s1@Eh(dvuLF*TF_2kn&}Y_S z%fN$7UrJ6t)+@FzFNp_ZHt+W3BkXnMXSPnG&o*E7z@h?vZ=PN4y-jq~+W-E>^pbtn z@2nBp`ic6mkmS(?(J{>_)T9@LTq6Dn0PAY27!icj4W8sByaLrEElT-R)JVD3HDks% z6w^QoeDefgjvY@r4Mc4lY06l?Yd&$YYp>6vbZ*AW8LtwM>fr;q| ztQ2L-!35zhv%N%vSE{D%g4g>X_fT@x-QX-_y2f5TmJK8D z51;tNb--`I+I70bkLJA}eV~lLO*yFrp7Io>g7FRE|J|B#))01VIc8}h#PFB!$jY-r ziun-T4b6tgz0@BseR6M8TE?HgpneqEx*bL-M$~`Rvf}2-97P`~)%%1V1E4O+?zDm1 zsnb1@N83UuQTyB7kilBS#3z4iA}wips^${C5RB`{CG%lB?wyvts(>IH64aLxkC^3i zYju)4kHCl0$&U`JBXgMm!lV`H!diY?7JEzF~pM>`%L%h%5e zGK!CFp@x$)fK<<9{612N{6Z(LASij?Htpl-n7u6W^3`#KSoN@M>Uc0H7%cqtX`z|5 zck`b^Gv_-y(!oEUCsWA2*N=^jrN5qj6??+?Q|CWh-{^I;y!@Q(RsF2)wbUx`Gbq!F z^>-Sttu*oyZcvv|wmFx!=8C5Lz9zFnjVq5;CrN(#@%zm_3MUt+6wb~<*R8EuvTagL z;IcfVv%}Jf-HU}xI#EFI$aV(x3h>5)*yPoWR92~4n0L?jWGdmx_um-OSNL1%&i7|R zgr$UW0_okwqcV)1ed#=FXp?Qiloi4J^`lY7F4p8C{qsq5J!V&&q&CG$ADj5IML(+* zm%g{6JV3z#=PZon-^WydwMd;a)-#3{L*>!KedlffS~5-ii!)(_4<@vp&c%n$bX7^! z=O4Uuhcs&r1CTY$Z`KArBys-g?0E5ayh>pF5RO>tns5A#B}4Rb4VDogbcn2Hk6OE9 zPb#^ud3N9WpS>h(AkLQ*bb;OXJ!#Hj_EFS3f`&}`1d<&|&UFjwflACIFG}Sm*LJ2D zr*r1hat#jfv}!{RHYfH6B&QpMVC%cFfwZ{VWA#cgC2tNdx?C>C@tKdG&OPFlwGa)D z5c+ne)rMo}&!)Oo5(`Cvj|>iW6+S=F(Kt@%LZ$&f*m%GhORk`=y{ChVp2$2t^ zd`~8)N<5tY06F);y%6~$_k)8O>LMooqvA@_OH*iEgHLr?qW`>>H&}?fWi^vrKgGSN zK~UAu4mi}=`8(Azv&1c|A+8xy<}Uz;WU(#cSPJZ^?hP`d0KZ;J(R?4MaF)Fbd<{ zdPrrg@xjHszRHDOMHZh?5RD0s3#I*5*lOlU7xx{%XAMaI?;H8UeoL^zgn&~L*w1H4 zb~xbR44{Dyj9=m3zg;44^Z*LA1tpnpd$ zn6k*M74aiaP&3D&ggoQJ`qPD;^poBlQ6y#^>$Pp?c$780-Uca6s*zEula2NuiLdV? zY)Y9h6K$C{5zc(ymc)*yh9>5hJ6k+er>^p+L`%|n({s2f-Kh%xvF67E zlZpwK04w#$!q#b#t`+zjm@+jT=M7HAVs{foNjYa`d@M1mzHqf3wKUi>%=%V&G`%5{ z^@&|Em2$9*b7Gz>O)26Tt6&}v%CyHPo5+9lSwWbeJv92v$92;W{cU#`pyR!TP3Pn2 z>|zv+yfE}f(L-HLE&E+`FV?uW$82OzCT4_?VwtYBe$R^nUPeh(za;i&pYx8TKXu%N z%Y0cSunkJe=*th$Q^&VkU|MzK`s&!CtUN`4>Xx@AiWQLJUD?f)nQFq#O}c`-TS)?{ z)cFcURl#`pdg~I|iH(!hs4HR&7wOLw{H*OS!Hzi7?qA69flE*O$AGM=BpQH!(1#u*C}>|*7#!O=+kj(>J|WY$HN zSkp#}oWu4mQdY+u(Q&o#!xIQ7us@DZs?LRfuYobJkIMh^gn*%#A6_E@H1wD3ZCz(X6gz$@p#pC0)^dLbu0ZTAmnvp?mLkqAu~jWazgFhM zTKJtm2RX1VeAFAq5e~<+LIteFk>Y$`Owth7po)t(c^>8?{`W0_-`9$nd+4 zAZR%~C?HhKs3(C(d*YGl&yNL;nRUjZy3c!7wUzZLQ&#O=+1-sP($^QW%X?2HhRd-@ z;*{uv5;L64%&W2*3~W6z(&GAa0M?ibZ=YQqlb2omuiCbjcsjFmI0RR+7p%-TS?8~< zu$DI8cwZ!cDtd9Q>Fe5+KY?wmNd_D!#}UOEkkD>phzlYC#{nw=-fuJ33;=s3sR9U? zx$1}L6;%UMj}t?{f))DiL|%r0ktOCIF*TRAuDQ}pdLe;ydxn~hU%H7e#TBQSzVUl< zVtY^j>b*PW{vlICf>`a_&MhPEH9a8y;bUe0T8bRME+&2IoRB~#;oo7ayTox!5M);V zEE9H=rIIef+d_zEkf@(>V;s4381?UJl-b4MVA?J~bNl1!H0d$r#ylXhFbDSNn=RNYLKH9 zGS~NaP7!d2yl3;0?s{KUSGs6|86i&Xn{R!%Q5JalWhS%*=noBg7P;LL?_qOV6*2?s zgyNB@rPy~Fg?T<>pmCdAV?i>}IfH-`==`C$vMU1~mvBqp+`jeQlKE$O4yOqCcaZri zJn#A2*tM<-J5>i9GBffRh~44WD5T`Xmor=^vewrsoXt#6O~hmD7T?-19sX?b1Dnb6 zrc&@G7(-nx^)m=Kg$(Ks*-tt`FX5H~ZdcK@7W?)&50A|C{f@$bt82i_$fE4WH-HYL zEkV@*hx$xXNB2D)2xvnERH{^#@IzYSW=G&DwR;1tlZ`)=TYEH{y*T067e&z1kPS2Z z@+>Zsnm)&{tl910OSq*EUqYK;OSCa=kAnB!{EAk^0oTxlIT_oeFDz{`{APExs<##B zn>mHnOTZX=3TSJVPmKlh{$h6cTD#pTCHVDm9`P03;;q@e(ic8L(D8}a`SJ`ej4iRx zaZx0xzJyyEdsTPe44+I3>ob9;VmlfQt{C9ICk5OP4X#S(kWx%xzQIs5?$)(~; zxS?fKCkcNE1Q_M;Dk6p`+1$Y&DZ;nxjIISnnZbLhc+-U(&o?*oRlIKqY>~x1qw_0G zor;}UI-9a%+FPpKPGztnXdT0qOg$E51hG3&(rz&IGmSSCE~=|z*cp$TFX5JEPxEiS z@#F~U-tdmgXo{@U}L6$f00Vhb;^r)A|$=1#oaY*%%_%~N}xz86)75#?TE9TP$h*=uKiJJ`eDOxdXg zF#j9tTQdA~`tZg^UYJ9tt?u~&+!a`>`a7E&T>@_0zWH*33vA`#WwcSY6rJM&PPK$r zn$y6LEXw&=hjS|4`KxIbzbxL|TVzMc1zZm@`j4KOf9PbbbOSbEbdGhdZWM2dvI~d! z46-*$>-+%j7#F?}>gH^EY0PFicbLToHXSfCr+7>1u>p6_geQ*$rlV*p`^DJ?RR`Rr zdEp>DJIOU&F5nnTmP5p1*-{S{Shy&8_krX$ZgpVlBs98{Y)diGRX;y~J9ysOE(vrq z)4v3~VRq5p3Jo`NYL)4JY``tj;dZcrsoAU`(UiGrTPJHfw}ix0l|FaOkqfv8zwk`9DZgA8YMfJ@@EM+y_@~4d%;pwe)x{Raf&tC;bHn9Mnk6r$j+4_)c1+bc^Ex zuIn8I-$h0}CHc*^zbQzks4(EPR!L-HoDWaF(IkotT#^&#`;}e81&!ZEW(oD}{g12s zp7ZU=?t148aAwktrMcQ_+Qqh3g(fP4J8>uo zSXKB{t?l1CJ^S`W7{gXB;8ygApbXK2hpDHKUvp~dnvQ(!m&XR-H%0fH0dAi>d3$uY z#O-1`FG@AiSNEck0NhqO_UL4#4}Q0no{l73Y-?3xT0%kFR`v%Z0C$%H{u4FD z)*ngh*k}{@fJgbPY&JFr`>XJs)VEuh&kpk9k*(wc?k-HayD6S4Qu5eyZJ=){>5fTs z8Do$w(5DMG(3t_tcO5V#5Q8>B;jJhn5|!X?Yinx(W)*@3jVrX0Hmkz$f74|F!;E?H zU^Vta1CI3#s2I4HaX$+FEjE#jr24*sfPeo;w*~)kDd&_Pc8nC;sjx||zQi;Vm$XICLa;nN(~|O@H*wew+>{#klMh+Y zi4wl5yfMFBbg==)1=cUSgfq#o-sQ&ajYKorG5wcEJ&tVr<9ZaPIC7yC-*Uh5uB#v zB+p8}x08FX%RW|#L{(L9UMFT}Y6&Kq(**T#1>Czid zb`AodLI3&QAE_z4e)2tJ9+*tN%U+CRxrC;|fG2Fv?t}p&B>B;94ku&2y&!>Rs#L%Y zY?fnIlYlF-1x8EbbdAo{b-?~j$Ru`h9oYAylL|Lp-Yr|dGyiz$=Ja*()$421OEFKv zt5*G7fT?SW#fdu{wJiJiO>tERJ+*( zwe-%ZDJM!7nM_V$^)Z+{As-yflU?FUXA*Zpu|N^pHCCiY`? zmdmR!AvcAXo@qfv86NkPp+O)sBl1?a+O01%;7%1!AM9r&J6gbm>%Py2rdQEtFNo}W9MVuPm8yw2HM+3 zT5DS>YV%v$1{+4NO>Z5p-^lj!40?4xLdc{?xgWPvLc=PD#hb{u*L|_g(ZRT^*j3L7 zdjdShz|afn|M3I0V*?ICG96f5F6yMdh`dtKqwWM%2K<^R&6OTSPyq1zD>3 z_b*wN#FWKNFfs{vL#22#X<@8vbBHVkPssL~XnG!$R+zQn=jT_Nv64NxS5|c^JT~&) zX3XQIY4Np?sfTmJJ+<}4@d4GT!NIAi)$z@B`EAP`g6r?WQ1Y@#VA1ZQQ2pUI9t#XL zGsU$se8K5L10MPi8kaRjhu72v4rH=j_#}Yq8tTD&$gIeY6E2hUqp7M4I51okLSqEv z0$y`}W~(;T%|>~EYumM5+x+MkEsO%A#*~v^(?Pk{q;MVhVIQ7@6k2I^;>Z2j@bEja zPd2w6Op66m1IvT$!@VQ<74^-<@zuehxpr>;G@7+DSk~4wCtr_*;DC~r*2abHtB+#K zR^p=BeeTCRYN+dC@b26fqNi>b8u04=$QjToNQBvzt!JovQow=nB22(d(z&iaezVt9 z*kVsVQ2ZvzL7|Fs&BV-=iUct7TzP;8H-H9{JT{&3rLvYTC6ml`jPOZLtIU{uy&fBL zAQ5c$KkXQ39BC;Cbu!b}{BP?Ui}j${%`UihbSZqVvWb^@f`XY=&CqLs-Gv6cKrD*$ za-e6TVFHep9raEExSk0bo|O#7GR2<1Shd!yx-FwJz=_@zJp};IRwCe<2Bv1T{OjRw zfd?NEb@Gr5RJuS0jbPyo(r4sO7K={r<8m1cdwV96$8&ISh00$paegbSW$WShwhqMo z19QuRjl-=i%>kjl&ZdgpCru+Wnq5Kr_R=9}h>5UI$)RF&j+OG)${A0*TCM!PdKF&H z(`7FlxkPt(ev3M26TOoH4m^rbx-hqkoD}=y#HBiIZB->40A7~FQvtyB&1oJ13!8gs zUJfkF6L)~C>zYuYLN<%bbZ}*Rf#lhEQ}pxXyr3khTqUk@V|N9_+M?OW`K_fj$#&OV zZ*5CmU43&wbzrWWwW2mk;BADnPAF=hx_*0ovNAc$A%zM?tsLXHr;+J1c~DQY!CqX# zi{;U8>o--R{nTAMZcTr&m}&!E=f6~+#lt8BETGJu;0<}a-6XK~0U zXb{oWgS0CsJl={_!?G7jQ)n*}MX|RZ-MlJzy3pM|0!7$%{y4;a4mGh(!Oa8Uy~K;M zAfdGsb|2EP1iIhR3g9n)A)OaN%YlARWSj&1F;r-ROf!5kz}+no0Gye2Yf2f<*6AnN ze3S+_NJ7$Do<6>nk>{Fz{4mHOoecGc@W&#&IO9M-zO$RX_i;Zm=B7k2x&ZCkbtUns z3BLX|=0=DEZe(MZnlCwg_Ts)PgGe$l)K%>8p<&C8yCrU~PcXZPfNL9>JNqxpF7gln z+=6g&!1XLL;WveA*(bdbmjt`v3{(~Hk1rG~lPL{wV85qtH}_ryGSXbz;|5{C%$djM z3?&s-Zj`>vUVZmbG zQ6Nn z*b61lAf<|juM-q$n*pKmKexE1tHU4N438AdO+P%tg4K@h&!yDexerd>p9 zRgh3^?pfN)V;}&yEk)}jJNOTNA39x=EK%?Q?|YTKxzJPWYpl9}LrONxw+XnufpNj~ zUNUfC!ym71p{{O1bhw}7w-^3M&^4G}k{S#$;vRM&dq#tx2Dvk=sj0ECk&yvNb1I`& zDb2RoxP`_K+`bzG#-A!6`IQ1rb;!$(U3*yXbP)kJ_ATgH*vua4LjZ8u1^@jY924-L z{BP*#K~v$!;94x7(s0SciUh2R0)9=j=t?hF;K78HY)X-;LRDqj$nA_UONC=tplAVI zVR({zCQCS;_VP{SbXP6tWIgtu27-T(@6k7aRprpsHZa1*3qW5zFwU@23~&g+ z(`9Kwimr~LEhc(amQi%q4=#SIqQl4H(PiK?;}3LU$BqpE-ZnHhk6c)z!XUyyd-J3H zm!Jxu&_k<^r?c~RfysQZ(FFt?SJE&YJNbf5gb%oEL-?m392@ZO|58Rce89_v$-AN} zPwSjj6!4JnEDn#ADc`awhx2l?Hy{^zzzytx&EovCWF|`SLNeNx$OYDBdyz}xslnQk z>Rcxr*7VpTWVC@=#m31aFrXmN4R`Wr7&_F(^RL%B&ZM%-hm(hGilzdm!%rL*hhZO<72%A7_YGRu^9__zP zVy7r3LDw=wk!(91!jj|m<^?St{y1aJPaVOr=H_NNoDJybrujR$+2tk#rUn!j)m1Q_3-M`wt4fB&pVDJG&zN>1)&g}MZQ34KO zzO`*e)@ENOahNrVWjypqHJ$bm&*QR1o8rc55P5%d!-fGCXAPM&ga%g!#1}W$)dJV0 zhf~{@nt(69=iUz5(oCY7?NQ36F$ZuiLA*ItDfkL9< zA_8u=@MPr`*igE6ql<*R*$!LfVTFO(sAIXt$@cm26g&t%+h68W>^uxUAfIuuxx} z3kEyt>wjZvO%v-MS^#X+8s{21o^DI7-+UDFWcK6g%N>{J_anx@oDv5fkH@sPXK)={ zs>H$ia0r)H+)|g<4igI}81m=ZX#n3QZ(-JxUh@kGc<|MC&&fd63$GPiT@Ry&0N`jm z8g8ynT^;W=a}ckRwl3QK!#8j326-tkJ{ZgC)2D zB6+R6kJpDSb@MM85YOLD5-Mf|jNzt*H=13veo=7K;tyuL@ak|gY#JC820q|AcoGV} z-Uh`kjTy0qBc@Oq;Iy8rcb=u)x3`r0D+!KyGqKYh6~2gO&_T0C(bD8AGTKl9!vx@> zMY8SldNDKmpug5lQ{I~cS3SJFG#?oozAqAee7$!!JHxNi<+%?VI0f0F48Iy%s%2H|%?HYrzd`e34vTG!1}wzcyx0?1}_oqkO0&G6Xg}$kowOyO|$-9@kej7WLah{85NkPd&AHv2Q?dhOB7W1p` z)3dTDX9SgrgW+q{&F$jzyCO3_q?lk7n0l;752^|Yrs0e)P)C`zF%a(0MP~8g_i2K? zS9ZAm?4*EyAwB3*DDdZuqJ^I8*DB)ea4OeYplQ?6A5&Et?U*C?HAY}IZB*U9)|QLp z_v1WDdip_eDMv?30n%3JE^o7>5_H59TUTX)32Y*2Fb;EzQmZxu(kn zoNDhAcjL*`c0|ho*46n9YgL|O78;5SiZb-(x_*c&yE5QG!3u9-y)RvoNF2bm& zsPgpmnwpxNOm9mITLQ@ng*MdF`t|qW)B7BKN@JfQFn>lHC|^AUA{Qo@FD&0dL$5PB z@t`Nb!}$W~(e<4J>xb8>(i|{I04^Ef5hE8)61bqe!pAMoMdw~Nk~v2SE-?eCkw|t??wumK4cybF%kmI?DCDW%cF?MY^RescJ7Fstbn9cH%ZvjQ1yZS8N*y=`T&)-PhZXKUxjvX` zs(OG2kBlyfD#OTf0})DJL{f(6K?9;#q;k9 zIdlX7x03cQ{O-vC|G}R?50;@7{1{v}Wh^K|^thuyX>QAaI2?3A$^Dg9bawK_ z$E~hvB)>nPYwIHzR>YF))TFM9B4lzu?1l^4nsae-vtgS4bq&*z&w_-Oa&L||ljE{7 zyViz~fXBFKd;Uh{kSkg4zMxa?6<78CXz?=heMvc9PgBS#qliuP~45%QvpbReTm>O+hxLm zD7R{&Zb;1`J0`t5Xt4tWNaTO8?}*@b)kYIfzKLUwLsQ%yX!o;52=IXJ>Dbl9FuL3* zQ>SJuZEs$@T!6bcfSc6|B3BDPI7Y#*J!?sYs$ZOZ0|#gH@5z!o@c$NX20J=SG~J5R zR5`%i;zv3*XPQ{@0Z$QrSX`a&FF^9^>#nb7jq@2ba%s@O=g@f*e&HdZSR;M;Cv?rw z?xpqJBrh&i?#)RTJ}<3`328w{V{a7Nw*5%t*Tj%p2-3+E2F-*obrsoM7``=eM*)mC z{9RL4=KSYBfC2dTfA)oxaQJ@x1BY8zsny<*7?icmxcPEz)v zpcu)o&tH1?g3nB`ko)ag1eVapb1!DV&RBr~B%0a*+mS2D3e7Q$;s>qFzMrZ`2r~nZ ziiWF)E602fu~jpLI-7ix8mW^D~Ul4a$hZ4w)XeI zPrBYlyD)s~J2k}md2xxBC=F!D`qQ7N!CF5;=FfnJURv0@i2ChRZb+Gdbzsrp`&9)1 zN2fFR;~V?pA|&s5;}bu2xdjC+_r#`K&QHpo1?O3u{8uFOB-L)sOr%>X;JxrA*{kq% zjASq#q5O!{VGg`qgz^C=a3k{kM5^iqf;`}$;m)pKP(8KnsBH`Zo!J%SA||pluGC&=Y9C}zWFnBY){`9p{`~te0ayDQ>BnJA^k5$;G`zzyHs^{%RcvCcKF%$$1q>jx zN6Fjnbge9jbf1jKhcslS`01P4_iw=7jBz+6gBog zdD}!+?8b1PPj1cC1~?(4GSq|yoeW0$vE^%bFrdwaT`0O1dLjBnp-HUu4NpqLEMWt# zu4f_(>i$Lz5x}9wH28p9Mq~k%MoF$}wfO6s({f8de*}-BCubkk!dSUyLgrJzL>!Ai z1C$XCjGzMpi|F9Zq9OO2qsHRaC9MH=HuAsOEPhaO`*oq0f|H0DL9f?ZkZbwSgv{AS zHg_W^3TSuSYZ%Elt_NQXz;U51%U9Rq*cR{sM^j~E!I1*oihzO-xGgkLvTLN;Mx}yq zZBu8rfT#PO4g`6_*nt{c4`ZKHb~OMDC_{h-W9x*1ibs<}opKw=fPq;ii&J{oP_58> z0_O_BX4yuxP{B#W%rsGds4pV#Ea`I$oLtT7ue|i4$bTes^w2e&?4{}p0l2nx0cd;J zb8&Tt4Y&r%oq`nLUr0ZXfQSFq0gfoykzn4OziI()Y-Sz05FY1hX@yo`Fc@oS@=8xp zpg#fuE7qyHZus`fxcrS)my$_lMn8)g_Qhd89UMSo46&gDkE%An6d?=w_XKpXpoNup z257iXc(WcmcW7W#@IISEP^bfz#LjpWe=z`es~CO1pApTY!rv^d+@)qN|MVl+fPeOT z(qM^T1s`w<1N2kh6Svu^RDZuFuokwPi`K3@_H$shLtno8=Oac10fgYWZ(oX-}+Do7-FV#GB(?B2pT6r)u4c-XA>4s z68{qLUk8J^?Q5}j7dc!j_<&Pn!!rNk2e1ME{O3{~v^xbp;3(Eua@L#24S}i!xV{mV zHoTd^VdW4^d>vdJyZ ze>xBP+wD`l<%`%Li*-iw>Z4YudWj_9)d!Owaugb+cyRzX2=0n`4Z3hT5eRoF?$S=O zfBPIZ;A%gXChaH)9MLi5%!uTSSV4eF8F)aCBd+zzvnB@7QUUk59ARF@{^R~ye*^$e zsBZ^zlQ{ALHzD%Ef@Ti41by#W)Jcb~KE(=qS?$IINBehi;)wf`jz!u1RhNbTFEFe4T}f~QHf z)T)}Arggwa%z;&-fH{>VbHZ~ne68IMzJVDouwqUyyTOT)>K1^O<;cQV=V<9lm!6)U zA)yaUe=6H*2sQY$O|qu8X=r}OTI@=)0}0dwxjp;U?j1oqlJY`GN0+*`7fmMN zG4kJ-q%i=v_W37VQ`4vj==&m=WLpGE&W2J)^e_Gw0)YSE?`29f_|iIEQcfo?`tIWq z8wAgTh%BS#wKr*O=+evm5d=E_RpH+4scIwGqFb9_Fpu-rPFNHqWC6)86Fh}Vu(0&b ztf@&aClbkIa!O|>i{8g&2z^{i-$jbsd_Q?U*9ZDFkNp1k;ge}zEX7PZC@j||&l@pa zfyh3}n%aR^%YwL>1O*Neq_NT~B}V$^9C46%G`1Oed^eicnS+4G;Sr91{{sX7|IUB? zlS~^2Uws3rp7i?}Pr5yv5fO?Y2zY^He`DO0n&BEmTLeSF57qVs}W;@-ZSjShO|3nu zYqw*nGFb8cKGyQF2b9YX6QB1q9ZV7lYc=ee7~4Fb5(ogBc4GA;sB5C zCmHwYHSP$^8IaNVPyh8D1OQk2{LjBYsHMyhPc7$H&i2RKSz}cy(PmT~5}BRE;SuF~ z*<#$I=)9oBtwuZ8e%{Ujz5NFt<08tTRvgFL<|xDh=Dx)Bxg6R>rNE?vJ8(&~orex;ckGP@I@P@a$C zx-p;cY;JnKryuBJt?lCbXDj*TRJ9*AZ?0CP`r=e7 z(FWx=-%0bE@(W9loGr{Rwjt>}^SwOAznZw3|BI z^$~K*trP$}>q(oFGuGf-18#uxO|7{4#)U^U)YU?!k?hN#A;h=k~6b0M)J3}@uzdfx74#c3;XN)zg1}=+tR`P`2 z3e63II@GkHyms~_-4%g|dnUOx%s8DIk6C{CB?Ramwq7_L?+BTap$im9bpNJOX@ z8=YQ@d-vA5i*c}OW#+yC`OA`+{nd<>$;5XbZ-qy0#=M`tD%gHH)ito(-qu=MS5y)o z>;dup&G|g3^xLkur{UVx{@tCtFlLmAg3k$xYROC5TdJt`utwaj-oFu?O`fwE@;zPg z4vXvC^{Kw+dw!8w{IYm{Z;>4ZKZCAga^$A^8DfC{&R@yIE+qJ`ADwhpU;wt%)vQuR zn%dUIgV#0_lZ5Vy0bcId6qgt&X{BkyAsiYm)ZDuuIk@s@Y5KZY5Yo}m-8ei_+frBG zTpS;e8W@`EVdn&TQ%#LN;lc){1>vj%dbgJjUzfh%fVrUr#qN?8nwm)jBgw7>I@w?m z&xly}uFbx6;V|X9vg3I!AH_W-2{z{%aGREpn2&ynOu$n>eJB&T{MGLu2DsW^%9?j= z;g4I<@#c*~Y}7id6yTsF{cyUfkZ-FP;1+cLc;V~Eb8fJ_UGzbli(77Bd^5yzb#P#= zov)h{jppoZgTtAbnPah7Q)6QzsNVjmZ-JU+d|O5z>_3Yea%H(wOcV^Hbbw7>AEz|( zA5ur51ZI3TmClOm+^o$`o*aS> z*XCwsIDj)i*~myAkgN^C{NLAaNvVN<1Hx`&V`HqjjkCX9a7jh)_LgX7vB{NA0QnaM zb2z%d=yohA@ll(RGVa4y9jj6D#dOTP#0L$n0siNA0wK6%zTGiQ2yB4FHx3c2LHum zq@cGb)LH+en>a|1L70LiZ{~G|ev8g%E#@gS_F1Vnsb#O{@GiG+r?}ZPaQI0>x zMv%@7%gX>SDW!mAQ};ARRGRE6UuTc9Prkb~)mGqiZUKkdXG5RH?v4w&>F`@RfD*$B zdP{uo7YG9WqrZ~|;duB%$~4dxWJW}xNL&CKkX1(80Nk?tb8DyHB{4HWi-!DrfFXGk z854zxPu99>a}7=!heMie1L@M2@~x@RI|1z7<~B4pkI>Zk=8?Hk@zVVMyP2IAO%V=# z#N)(JCY@|BP3losyi$(FHuY1FZoLfR6V>Gd{`}cye|w4Bxg9YIdG7^?MT@TVa(DQB zCSMxjr6Ks={Rlz8rCBzRmVuvSgC=ZwbE6ZNT7boX%4i$FVcFa!RdB1&m7GIG%Lg2q z1DNhOUbq^5@G#!^#BsRvwEe4Nxx$-1a76M53@E8sX(Lv%6-IjvZfe*Nz z%#97n92=0j{7_0b`~X6#uW*kj-R$wTHZxKoZG)z!^+0547?*6Rh*TJe4NS<6K55yp zk`}D?>CJM`lsd6G<))U@jkFIuot|G$+z1NemD^H5C?CN2`s=h;Y|XM?%9Uqwt6Ss)p$L`H>P$1BpM8Kr4ugC-FZQo=T7 zAqz|!rM#SQ#RF@RiHZUK>gBlxTpQ~jTHJM~(v^h3?x^uq7WL=I@~!sczmSE{T3QGw z<*giC%5HYordq31UImxGcFQk0g5j-LAfiJcGK3!rC&LdymRkay%}kLP=%6Xhpg~~M z{GHtF5`qJY>uY<4mj}8=Lj>aM(>IqMT-n+@oE5#^OPtJpnU$9JA;N*4gHovZ`@dOl z5Ykz~pw-(0&7n?Mr2uYL+?e}$A~%%++`K4c^WDynFiNphq6W$~isk6zlJO>Tx~s*`A7_dH;Lr&i z=S*|5%S{LkOf4v??P+{CDiBY<-`b44Gb{R7b|dlbgPw2v6_d=@^voa#X{ zM<5-oZG^>HJ3%{lL2)z4q76(5t}n&h3txY;_bkJ&($gggfc?RX&*O6Y=yVpDn4W1% zMPam#7u{)5!JyK`#LcNx9GKDa|0xIXW%1^_!mv(7V({|~xN$H0FXF}Ip(MW~(8=7$ z0E)yl<=84|{yKTC4+3rwaT^&)>){~m#?jnzgX2r;@_TyQ2fI52R}Z%Cg^S)zW@Ht< zNN(ap@P!Ucdpa9tLMs6kT{V_n0o+Eb_;IB&-gmOCX{$lq2 z1B=KPb` zS<#!l$(Md{i%H2%6JBFNo;|mZ)k*ZGoV=W>uA_&cbVekt>_3>Q$7w1L@XHS$zGz&03YLxWF9Y`u3}$ zoiLUq$wa|=r4HVr9Q>BN%4b!F?*#*G_0<6JZ#E}^#!CVX8k9hD^YzVzQfT>YjR5NH zYaoMm@cwbkz1Z1XRj(7Dt-O7iQR=r7=jjrZ{K|*pHRkHTWb}bEc~p9i1qpR>+dj}l zM#|(3mEL*}29=sC5Ab8e;O7`{s8Qdk{n5KLjswdAfkrYblFSbM-<1Hk+P_GJXznEV zfNSA_)DxJq4Y;Y2*`Bt!Q)uzRy_skxIg@0luHcyoPXNEgF`~)yZPmS-g6`S?51QFG z3V8ITA~d_)(BRbSfPj*gk@oH>a16h4d;TzdU-af(;n_c@%f2sYnU z=)kiFXs3_?+LpHNR1(F?#PHB#$k=e$W7o8&o3T-Ph;$E&dLBEHN9T&wshF?uVvNkqSVuL17vfYfGbWu#I zx)Leru0M}}YZ{pOdsG~(HW88WS=6P-jseO6{9k`hR%=J*Z`COGnTZ)J$hB4-FD^)B z656l@rpxf@$8GD=@#c=bO3TVFn|*R+`r2sM!|vtA;oi0pXh9kAx$c373tjz^>o*_8 zY(~b0htJOLi#~!gImnN@W8T6E>Ooe8oow!5^6t;_#k=rFWrFQd4n@uwE z6lgZV+dl_d^ugxy*leO{>Q>#-buZ(7Ix^5`VWh`^fA~+O0Iv44qcRIJfY*d=gbRj& z6|m|wje=G!-(GR#UgbE?@|b(51}Tam^!kvTR=GP_wjXnL z`S~Yz_MrqCh_iPpD=Xs)7eQG&di=f@+ZC#QabPEWchjET6t$m@-PSf!>v zoGZ2!><7o&Cr{o6-DKynT~r$vSo?5oJuV^#nHzef6#toW_*VP(KSuCDQ}-V8EPLGF z8=ykd!ht)fb7pEL2|sjCezXaq|mHTCK$wwb$`opcXip@lq@$p z87Z|y>6|Z#TrC`TP{h$CZ}mz?Tl{$hT;IB6PCTFZ!qpPV8~Trbsiv&;{~`#u1(+6o zXS%D7rczct<_Rrx;&8wF#N*a9G=S+l#sq~Y<*<0{3CJXM$8Yy-_A{_%GB)DUl7f<> zK?cp$fx#l?5GYpA!sAiW+!;uoNwa6VIyzu9nTCeC^7#JJJFN7{LS3qxl1)sld#;B= zo@_Y^03Nh=UL9TZo$`U#j^7Z^9l<;L&%aO_-$#46h7JO8xH{GTzUST8wRR7c8bxUA zR9*29bd~Wk6*f2f4bUM+3kQD0ed)}hv_-JeAel;-7btmw{5Uz?f}+F_`;&hfhGZG# z=u$SFAL@ita;q+_@%_ijp)sz7e8720ucrrFg00UR;6Siw96Gmj>t&J`mjoa1ui8NV zhUa}p zy7x(bC73ftwM-|HS#&PLp2?FgS)2_5?HX@eDkM`;|5gCU5M86Q-rbY*jA+W{5?n)?_R?l z&%TmxV`QK@c{boOZst@g2I65KM>6^(AZqAhP*xeLViCpUxV#i?iW{qy zj}qw03oPl1-SD!|Q)G-WiSKv2#mrQNx{i=}&6$SgFHD1S49gIiyQnKm%_ab($Qopr!<@V4o6w##Is_+e|cweknb zXxrqL^hiX7e3C*=QdIWtl@e8I8%F3M!b<0fdU}!d5V?y-D%Jn}pK7PEg{x~IlQPna z;s?#lE_F2HROG#u!O?MMcDmikSe0JkP}hld{pjQMnY0OJ4Z#Ynb5{8_1hvRcUPP12+x?q^sh|V= z6cXqLxvirIv%5p~a_5w*YXN_DR@3Tq>UrC~!2lYk_Jj4(ATNdm0uPVISDVaVtErt5 z;lRKZfn&NBHN_z;Y4YAwpqa4>6~mzke`djL{Y$gY(!v;u`@5)K_>Ir(wC6XaWxPJT zxlnKCd@8AGqw0a_JCkW%bd3D>4^aI%B)t&_o;Setjj#z*PqOnOm}Ca%FQlmpeyXSdMa>2<#*J|oKN zi~_EeV;_;cQMS2V3;DK7XA~>{(qZ$bMLSJnj7(km2aG6teso6Ul*c&>z=4R3R`h;y zywl1=4}sQS4MUk(`TtNmMZnQiiY_uwq3u{!Y!paBefF$2Em?1XM? z;~U)m#E)%@(0kfM*8Fj*fMW;*ga9W9)2gmR%SvBxm_#s|_w3Zm zfHgAJB8tUuU`NMggX;HkfwPgpsQ_+ZZtYtjnDv`rvT`VLFPN4)*DGju{h;0HoMq5$ zLhIYX30+7)=6>puD5nbe|NJggT_q9pklE8n%;fBQ;(>ZM)zT_Lg!>l{UVD6NCXK_R zr&D#$4B$}ZyOTNQlUKO%F%k;DJXEMLs=|mGg}mE! z%h`+XZc7H^apx?@7T@(qlo7=4L?LruwPcc$KRhkI)qeWBN9r0x7CMT@c`ebMzVlV~wAz4YbC)oz{RyY0@IJ zZTs>5ZnT5DVkZq^Sl0gZLTjM;dD6HT7@5_I@65d5@S>1tBm=5Z*}L+Ge|2hr%eL?@ z5qj7SEm)46#T!?a-GI@E%EjSErhz^GKYLdK*5sM3u~;qEdRuMnV)w;vb7!WVna+%t z7?VIkLV&OaLRiASZ-VTrvdX>)C=^))Sp@_UL=Zt-5J5!{Q4~c*aaTm^(tG|SAleP< zpOEEypXbipPTL6izxV&ndCxiTxprbOrTT^)2uB=A9zB7!5xoOewssD;U2{*}jf`Ja zUs#%KEH1lo{^sL4%q%(0&U|{YDaFt~J9^FjGM5=aZQGYqpoCy>C5>_ThigPtA_5Cr|$MN*Oz1|ot1BG zb#(U)*W3#a$A^Yn+gj>y+FCxn#8U&NL{AS?B>KBKLGZSYE3v0C z{cS2GSxV;`I!AS#D^Iz!a{iYw_+(Y8+xzBU->U|nf8&HZ&0>$Hb! z>%#4|Wyp?AP0J&^WaOT!t)C8yhC{qZ6pq|36)(RPUY}5Pa1w_Md-AUAFAFzSm%K-Y z-Qrq1+a8VQWkxu$_`CmRRBjX4KVf1TyxoaJ5{XQvP{3K8R%zv%mUuOGXr!$hqFz<3 zGPYc7FT&+eAuB5!PDwjJn%=hqzXQW5HMS$fQKrmX)ZuH`e?`)SIgnmyz-BRK$oUwH*kHi|oysv{ zb9KxN{PMG649%UuzSYLo(_vHMsR~HF+xBBouNcj!m&4j~lY+X_?!#LXeW$r+4~yGk zT&^eddW$j25W`oY6;@ck>Qc3D7EW(-I*V^``mKVv!8d1PvZ*)`+|Moa>Vy8X+f60# zSpdF3LBGTGq!v)R|9Jm{hk>a*QMOKcIilSE`TLR!^q{i1UIw+5dWL(f4_I0`d)hhl z+z3t0^hwN4iH#l@S+lpfEX+eoWx4nWz5?spuR1;)IhNStoHM->K{CqU<9s{s$CeKfzxXG`lcyBDj}@e{sr#wcP=d_^e@PnHI06?ojKM z!IVH(n4{QJ%cjf>!AT6Nkyj3OYg<~`*t$eT_{XItmgm7HwDHK%M~z2L@2@Hi;{|D{ zi*uU<<}X-M-x&+-0yc)zTjHTiF|f9Y@VR%t&_q?1++3FPx?T|m;{2zjgWt7yiBCA zxcXVJImN~k$h~_Z`OSl_tj?4jnJVLT606Kzd(H8FAq;v3Vjx|UUgcWzsx z*K(&<8d7G&SVe^Xv~hKrrX(%4dGTN-q-}J}r^nOU2&W^!;5P&+Ef71wzgZ**8F4zx z)GSMv9f9MmJ2fR~4Z_pV;Fa!bU%wGb;trlpF*Qy{P=>3ShV0yTeEpWKeSw*A5pK>-hWU6Kr$dfSp)pxT{KY8w zSy-ZNegIY=frRGf;&Rk3%EAA3T54u-E-WtHJa%{MrN{@P!;NhX&D)DY0)n(ORK(0~ zRdp@<@S?)ABcmJgTz#EDd?Zbi;4IivzHUoncY*Be99*FeW}OWy$8Ne=8tOCfWXGJP z;^()*H%n*Z_$yG1attkd$|K#Yg1sFj^qH%`VNPm3=)V5P$cnsN*SH8zCp|wlu5K@| z_lU{S(a(=DOt(JZWZ}$@#Qk^NfZN)qII;Tr@2gJpwW?&0Nz)vgS2l7^JC!hUw$4L#YT%d@QFm?Q zogO$A96TE)W-pzA3motrjtnO;I9|0bnRh#Tp?z9SQs2b*&CY&4{817%SdQIEegQpL5?>b!Aw7oPV zIUvZ`L|a2$%&q*eeM{Fkths#z+WbPJV4{{y###iXM{urN=Dqv9g&B^rQv+8Es%biZ zzryEez7B_hW0ht0cM3CvMH5O89)c2uxV#fSb=wdN070xqlt-@wx)&}_&KPEX(AM>8bW8l3KbPt zz6JjA?fubrbK^W?xKsvtnz|!=10;Rl%L&KpGCX8xC7A}a0<4a{5NE-pknr&TnK(_0 z6lRp*1TqCDrHyFldoCq<Qe>h{}* z91b?**fdbi_`(@i$IHwh2YOZX456rv;Q+Q+92B&)o0&e;D4?WHy0JbPm;kRrugToTe6Ab81{+6ROuZ9jb8edS1+=*3VB5bLG)5RqRQ9%)_EzPDvx)%Kl5!5QJ+f;yO(3>2TR8@sYq zR8`f~)O8*0y~B#OH+T158yPrxDW&{emz_n{bJR1KKdj>2mAI&8W~HVBRl7JKY! zj7~}1VUvYZ(njO(O>t(wH)8~Ue=$Z&Dw~cI!M)5e4?ZY{>uRV;bmXRP;*p$Gc>YY| zqoKjA7jNbIgzj*#v$eD~tkq{@D>Z-Xu#@N<7}(}3XqYtaX6L(mM_j0D@%6x4d7Cd@ zOi5W+vGvkm!j|~X`~4$p8(ZDi9BDszXn%84NojCcIE3Z)Sh5Wvxp?`_H;U(zTSHS* z+t@o}XJNxx_mPzeTQ`^cgz|g)p2wh1nXPAGmzEcOqz0Q0mJNc#UU}V+_R$pZ4KVk@ ziQsfLzlm+}`!hyxh57tu7b;FA0cFglA8fK)i{Qaaw77~b$TbcK58l~)`pl|FL*sW( z>{(SDQQ6qZ-MUb;Cnm}2)fw3vc|R(>j_;!@<6E1ko`!}qa7`^?$X z-OWvPbtOB?N{fPPfY>|_dsAabwzYLNH9$(^vs;XvsC<3{yMf-i+9t-l;JW?wP)gW% z??Q2$uP0Osv-FJ^&vB@g{Vc(6CU&?XK;j%eUf@LNnv^!iCPrBr8sOF4$)NH}u=8h* z-wLnK=C@DcR1#3e&c9_^%86!g=(UvOC(n;qu^Y|AJE^MW$VmJkzitM%xP`f47I0hu z>IC?I#o=(k3(?8S*3AwJ$>TP;7UyPPT^Boe^2++gGkY7l_wU+Q*i=$f6CPlyt-*)7 zy1E(&XrQ2B8XAV>LWop8!!B#!vpW0)nwq-0x>_d2rXC(VUO{+BMom#&cfEUm{KlXA zazi7W4gFxV({pM{gi71n*B=hKH<>J#l_s|3Py+WpJkS?sZpLQf)ES{HSPnM(^%*4i zKNkz6Biw3bEUw}1z>OV+McyV-@#s~xJVHwM)wd3hMsB^BecdPZ#$$&l7h4-=KCG-P zFj!ex!C%+_T%w@66w>VK+`#f%r#7$Kx*>8){P0@$w$r=n;JPkK$_OtAuy>rku?B+zxTJ$T0(b?<;b9pyNu^~abydx~T2A-2AGzkfy0vlD`juNEW7nO!eC~#? zbGjF%oj-3XmJVX-$&u5+vg6dW+{C-6a82aph)OI&!=+1k!l`NTKWC8O3ja{Tbrupd zs9L+sbywCjlzB)+`9ww2(IdIEu%XR;q;vGa_|}J;FWk9Y?UU(>;bv;+CJdpWsjjY> znVIL#RfB$Zaa~31I8?N;R+UHVK|yQV+j6+BG%P&1Kv4UF{A9Yy6VP%ZV1MC&1iQD@ zAp|!KNDfOX+ul^TZ-2}Az4gaC+*{YKe{^LuI&#C-in|XVj$O>lzMPo3X@|p6%)@Hh zy=zk*^MM`N35~r?-m>G=w8EpTVa=5>R~J7zjfBH}2dgWDL6Oow6lN6v_yWg{Rcsj2 z%egBs_KLftnJE9Jwt^+&AxR~L`_I=Oac^AT`Qw&^!Ar4QG2E+IH^#@qihEmQ0nmUp z1p3)Xqx-dvBgfn751wzqN?&EcVFdv}rcl*(G||!pfpOZIDdzB}CUACG{zCi~N@&`S zrXI;PJF9jz>^*zr+Umv;KC?H%i|gX4^6Jdc8zA&|?eKT-wR5wzvb5GSFoNE-=iaVN zv+Rx zy+|sa{zUH!7S-|!fau$R=*O?EZUr>1?Y}?#2r#@JI!af&1FPE(HtgEAy)-xkyRE%> z0Uq|iYey4IJj0T0;Og@=tYD)a@Nd4LcMJcQz$7$i)Z>Lir{3wdHLWA}2jYhwz^%P* z^Myd{!j5pWvepB{RA$xY`01O$unoT?`21~7MBCzx2YIGiGGyeUTGZZo=~il#IhBCR zHu;HtqKbc2m~qVGM_nWmUd2B>n`5qdk*k_buv)M5Bw-l9Mm>lZUQ<@L4NwS)>-mGd z0RBb2t*LH%Noh@TfGNK=wEQ{LvWb5b3!@=N*45S4(lT*0HZ}!1W+XvzJS5rM9wK{w zuj;RT=;R0RKLNBeP{Xm$Fo91o4YK#}P7bRHPAc8GecR#gLuc1Ct{?dEWWr$V&ks}j zek!l_xq0Jpgo}-no*Com+0{SQyusk;)E+xE(4?*=D`Vi;$c;(!s>nRoV>Ws?wS*Aq z0C@T1WcVHoC8AhgtB90(%%I zTk*>hny>{;MTM`R!D}HoBqO+}Y-h=KzI=A*VEY+}#`}jmSH_PHK|mf`G1ixNt30>5 z*vBYyJ`9@z2iILcoC->0juGEcL=p)8 zt)QKaiqo$~VrQ8<`(M5^QW#udEM+PTw)Y)0X!`)3H=qD`RD&TS46axn1mvKgX+8H$ zh~Vai92t9g6l9b(9qvAV5EN}lkWUP4jC}}ZE*l2HN40%dT}^=2uQjC$KY;%U_Pmhb zolVVbv9dg1 z4Yh7I4h!LzVe1CVV~0;CuaFs^2Myzb;KGqhm;JGE8=S5=3WvX(Tj>)CAo&0ClW-CZ zr(cc0Fw)Pm3GExLFD&9|OJB66rml&F&={})m=8#^;V+?2MORb(xtqwB3o7pFSoj}O z)U^K~XnFm^1E6ZhR`dn>Y{Di|a`U#r7P8Y-H9_j?f-bk^zw!y1TBf|@nv%kngOFpd zg&P~PY>31wE<%#+x~a=QBFfJ0sEeB?RQar|EG?a!%+0OS4fSHO@(s*%jQ&JD>{n3h za3ljVz9RtyS6IZ?(TPNyb{WAu22C&G z`lVIaETOcWg5?wOv;e9CO#G#=Q)L-O#KXdDLd3uu{g zsys3D@lgv)XSXPaO}QzNovpovVVGp6$rs)xfd%ILmkqoiK<;lid#!Q(2`tGTkAE&52wHOZO*%{_oz7s;Xo7LM7gdjxv9;yaJwKg1yQ`F^DKi!D z<&GJJy{j%=kI;ijBfL67i2Pt_MtfYI;J=C!&yRqY_ko#bXkK)GdzH7!isiE8*fqV1 zl{yS-83);8y(S@H!KEdTD0eqNSl+Q(&}33Ew)s?cZn5j8+rG9=Svh(zUK)k15>2== za{N#?bi-{g!&+R!!a_noJS!?Kftq%A%c0YdYs2N=`D1kCB`hL8^;34>b)TDQP|&uq z+>>QS74g;3al>9 zbPdI{FJBku1A6*8ep!arR(3t9)pz>tUgA4KU_LKL+Sksdsp= zFVn%2jTgZQ!UwVV1IggG!bcw{2?#D&!hi#)hPM8$c?qpm+7j%+D6+La{10@tkWarhWAs1LfIx#g(dLPj72rl(a$k-a(0P$ENE|s8S>b{ zgrU*+_>~i-Z1@0ve;r2ZxE=nx9ektgT->m1+seYpJY6pz+UM~#m-{sVo&QiHNA`Qj z%q|n?Gt$IXiRPv5wlTzMS1|0h5D;AHdj*NX_e%Wccp6@NPG|j0dwm;hEsY?jHq-9f6YWPgG|qIN$rasIorgO z9bH95)0h|15gF)^4iW}VWh7-Xh5t!P3X(?fWn>l;r!q(vOVhS-*Y?eM%r!6ZN}LNKEQ}h znz@CE1g2M(wP#xP;KT5&UR45uAXT zi&}Nv86Roem!Ty`1lI@(FFo8kboX-VrW?2ULmgNT862PKX2{A6wm~IkDS;WOA3f>@ zsk+mim>e$-lSZ65f)ma5*!XVBj(yZym?U-04Zj1ejD2k*p=j)F>q1goVFY9!@EI%(JCWA6v zzi~311)^Im*h1|AA4ka8v-0(^E)@!iFk}2)Mvk%Z&pdT$;5e*+H&K_J$7NdAHoWnw zYm_yUM#1a-Nf3}o=^Ke6xWbqGZWr7N;m{L7s2D&D*knjF4d`CG zvCrqRbN-9B0Zlpj*niGhC|Ueg_(5rMP#v$ELdV=?2TYwDDbkgx1+%{kU0%`Qvs?0R zSQ+S0A*TLQQ(M1WSvZ5##*8Le+)9_!yp8LRH;1dsj!6^Nu~2jbW=wXtnCsxBRS+iL zI7{L|(wpj2uDHObRI&kzXj`n~zUrR`U+(_vfK_O+k*2iAnVe3@MCM}Z%P;>TJ z*@gZze!p#3k-ZFAJZOT^N6T<*ZqHE*Jq}(kLkd|S)h+&;g2dq+K^o3r;*!IqX61$p zsi54*1i>pk<1SZV17z5^y6j|H>H($u+g3jG@zwL=;x#G_1gB#JpOIyve~ef89?A^7 zT+$(zB$8;BJMIjQv=xSE$_K%*X%n@AZS5lox8f`~GC}Y?4%J&9U292lRF$c*0?m-Z zwvoX*J1l9?0*IH$K@vJ8&yq-j3%Xqh6g(qKf}vgNslm=ORY6i^;PgUR5tOvAZFp<- zZYStIBP&ZMt+8d2431f?p?O5{x*yLpl*o{UD&M3jsOn7T;HgwQLp-aG6AGJT@>}8G zf>Ift+7Kb%DkAkxY-ewn%DZ&R}C5&s1AoP6)1H z>Rq$1F?y`J3konq=_EKd{9S3`8ydJS@`U^TqGWq**{OppSJyV>)in;@>2k5qW8)uU z&3;2d39j(j9Nd3d=)8=v+H~&5_bt8HuGIV|_IB z!eIZJ^GzY9u+B=l3j0<+s8sZ+tgLAdlhK*8{UsUUt=k zXPSa}+VV3vx|{eM7B#xAW9i$cul|a*gDs-o}#`&qY`o z<`|Ksi{IGjn1!1|oNM-mM+Y+?x00nM2CU4%+rGDTsBe=E3(t^;A+Rl-qafK35S+@Q z;P|^Uog92p68aA&X{gAHfzxtz`dNdrw7(d4@S;zOIDXb#RT>gc?7Q> zzaC{CqmQf4v`|Tv^ax!+;Xfi!ZLnIIZRqCF_U0m$DM$$fuXQpR&m4uSXXT6e z?j8;@(UhlM2rG0w!glsvxm$b;+|4Voz;LD$aRP}(r*hajW(I!wwOKKGhKAM_wsx@p za9u+G@m)#AvRcT5turP;`}#Ko#@SiKQ1SdiDMF?wNEN}A$+)(&(fzEQqg?x<-M1xq zo2bbV!J+XvtkC_(t=T@C{Exy4YVHj8wJDRCTmx8#=455#>0%cZajd5+?WRxeosV!PQK>leW1>Urn{M+GBuc?-5Cu&CgemHiqL_Mj#vIr&}INyc^%qu#+c8 zyAYPE={nli?1M!7(&o!IA7g!OGaIKX)3~*JEN%F!&~Bbf%+1cb_;BlZ!qC9lj`LMT z$)++p5~RV~+0gOh!(s;~oV$l9LPr<{DI++DV|eCyG?q?|O;=#-fO~h1wj2?hzi%|T zXxpLH@f-RQyWI9rXO`durr#bb7l*FY#PSQ9A8s9tjvrp-ey0A=zNXSJUXY1~%r+`$ z*L1rN#0K7W29G8hu6LJEj+Y{WD=ZW+9A~MGsOJ`XYy8CV5|jUvFTjMu3ia@oRncRK z$1IIzHVG%NVk}(zLld*dVk3tJ`rYey?F8FfU9}Y}u$^Nv+(~Rwa{R>jtxz{TBF^#} zLHhWu@X~x?eT#;t@JsNsa&W!1;Zc2(v9^Zla`_^;ihbSL{^)hNH(V^7tPNvuwEBCh zBMr6$QjNG~ezll-2J2C*t<4WOIayj*SUEe}V6e6G-{cdR_izJT-D};CpKjh6;sJI$ zGOc?q$ILK;dxytwxjI<+;rN2ZHu4IqZ67K~7sG}16BZ3ef-7_P*f@kbVS-Pr0G*^ZvH zKtMk;nv!V;?^PzAF)5uR&`e){Ny-SWFqc1dLZ;z)gF``qt#25S`17Oo!@)tSaz=0! zO%r<%+Zx&%;|IsU@6SRX?_`_+J;7#`=FTn=w^I}E^rehd{2V*JF?#6Aqy9$sBlYLI z_hD$R+P5ynB)Rb_olU&S~>&~0Q0jR<%af0b!8exfyJuC(!6;iYed zQ6Jvd48tPsR^&+gwgSx+a%1rFgyrD(7f^b-aWpnN^k_PZNoO!gAQO)sT>`M&MiHCccdm}r^F_l9F0G5f26ge{q(LXP{>VnV-=y*A#l2=&Gy88N-*WYHFE= z6rOFo0wuG!DA@mPV`X{3+Azz2ONG5wzwh1#DK>=Quv|C`mJ4Ir877@!+8MS>+zwLi z2nYWiaj8DJw>IA!Ke=-KNMoz}nf8N+c5N$3f=FCTV}(5O8}v03?`>yJ3|@8hwWi=r zaNz@!z6%@({uTZ%%KR`r-@XVaN+5W{-F(Hw=O51OHJFc zJIc-ZfSx{;{s;4<(1XUtRuNb_+q&8LIvjhvqYIPIQeDp#S6>b+&%Sl)Di)T}+2dTOJx=RV$hgr~U(&GsyhvHXu4zKSYS=+dJ&2dP#o9oI-i-K#yLXr!3 z9zj^DttM~blHeQHFbywl>Aw`X!_z5-D-xG_rLUxt-0vCqMo?>F;a>=R4y#yEw$%EWUhe^SYm7 z2eCAJ;L%9ynckMeRVBdZjEu05@B;4u50KAHOtiGLwRJT$HPqE%I80vrE}#9vv6bx| zTTXR38Hi*89DLAUQIJ}^CP@8ocOoGgxSXpv(a~LGs=7ix&z+#T%|5C5p!@yN!HNsT zH+-Ef5A4y)s?E>I@$>UD0O$)~VBqJMV9KbAP&65xa3q{E78zu_U{< zrLZgv%um%<{2#)z0n-Xq)1vN<6BXxN4Di0ai6nu-wsfxa68sgRwuAR~L*QCHzFslZ z*pQ(GH5$2PxSC@@Y2o=JjrV`#*T!8#H^trF(c^#2!672TcM=f}yN~%l?&;Za8>YUl zXZJniC)w*)wO%_?zxPnfuIBAUAv{w#O|kz#@laLQ%4ldDs<{5xii`IxMWGA2Jf-*o zS9nE9*a3-mn9fS~>?yt&y}HR>ZVx8(eXHo276g|xH`I4D4#z(jzZAQ*;_leRzPz7q zWtRsEQC@xr#Iwy8Q&Ps(-NUNd7`IoiY3n@?)UK*4DJ$YjXxf_Ua{8kD9l!**mVMLe zXmF?ZOlRR<4iW_XO43a5x&KfUiR`FMGuUJ0>$+~BAsKcO%InRuoNqzEOU@`NsoHm_ z_xO>HHSVh$M}|+tj}C3Yn$DshK<^pIXD5a+@eGPyYmT({o^IJy*t8vZogv7!p7=HnuA!-`ZQ^JQFbyimC~G>r|Ipt0`m=!ggL_Xm9EL$oz7`&2Y7E+$P&otXOkGV) zO;r`s&sHp7j_CahsAwAVl8!{?M(LSx7`O}Q0)D?P%@;Vv@Xx;H|1ua?em24>RLhGAsIS`zgf9`juu6NnK7a_?76mb^*aE4SKDW z!_Dm2&iY_uExDTx|83z{T@%7}(;yE4>>(~UfoV<^6y!YL_o%9&WgJ}J8Jm66!K#)H zz5aNfUNV!zXM^Gr>F2k?YYPN1ItkY#2Bs#+>=;Y8p3CEFVS}Z%8alqhn@0tD-LR~j z4^2(1PeoNl4(D=SG!lZTo~pIumwVhSW7uSzJ(5Xefy4d3WZ(i9#^@rLI#DK5b^H$O z$QwNr#xvGHG5Rw#v?oAc$DeplY8dmv4vpsRIN&D&J9;4(Wa0t`f-jmft%$48Mx%1| z?9M%0+0jtK(^OSK97n(@3R2bNl{9p$e0a`I4|7<=_1Hck!N;#D$Ogj~P9)9*oRxGs z%g@TcI3;0y{Z3PeL=nRg@Zh(qx`ye_`t=DZ#r{@)ESy)uO_D%yp=?~>fL9kT6e?o` ze6Mga&Bzd3+U{)VZz(WAy_N_#3Fw+81ugv>?u0tn7#h*Y_+H=yp4m@8JEzW1&`HO^y42=mZDm$rizvye<6gaR0tY z3>MdXclFlJj_%SRxg9M-!0q~0RSzod?&#cFz1y72Vvz7BxZo4tUZNmdSGb~xYGu%~ zO0Bf*y1p)YRYQn2FdQ9Hgg+19w{}Rws_1psyKF0|BG>^wQ6ZD93mkN|1z(6{>I75T zC_2`j{@CKt5>s7u)Y69V0vEWdx~^%7dvu?xzo)ehg-jID9=I(e({2T~fyex(l%3QN(bBKc9bVn-+8rjHS9*8tT&txF1!)=P7;r`D+TYhgl!< zm2?vRuSF8otJXZ?`lYqqB_ToT(3gphD#D*AkF8Kq4+<&iUVG_!gn6wOm4tt=DKIbl zc$R`p;s-v#$qd|;N&a-W?TzwF1MUr_#@OT(I;{xL&2LpT4dc=V_km00H*7^Q0j^A8 z2!=#|kWGFoe6(0F3rog-rxu-MW`6X>^|9zx-QHT@K7@`d!gK3uU{>qh4J(?j-#BV+ z#-fvPHyR@gY^@i6B%=g>^+QqB%7`Qi)6d*CBDF8NBN&#@tD@tI@VrpfFbN9oi0(^` zur>E%QbL3a7A@Y?r$C7nn&!e62!!RmTL&#vmR zg#P*xV{PQ(gfM-5O-)1FxTL;6VXV5#(~!R*2KPdb5uGpEef<4v3bKrMz7&B&o3IAK zpz2%O?heh~u)YC|{56o$hA>@yO+(9+*RXy=cIa+fYkew11eIL6VDHhF?{AaU(+=X2{`se>7?;oiVDv8U+W*JPaF z3h(@TLTJN(vm1KJ=Wi1uiuo}DjVY`deevcj1v$Wy|1J>Tw)jUwSj&r!p_Sc^%d!3YcxWXq!XFY` z9rU$*{jryK*jX9sh@ia%tB?tzf(8Fwq97l5Yk_d=1ph1?`V(kIetHLbvZIeDCEIJM zBHv(y-we+Is#^BRNynqJdk*ON8PSxL@t+SR2uDm7yrm#FcvpDc67cm|6$+L#7T3@1 zW=i~#hNcWtSZjn5afIJUzcqACGnyKX#HZYJ^W(B;xR-XY3x^;K3f`3;ek**ic(Sr3 zf{=(zr|MWb`1C~%tZpd6;&eoCgkK{#7M&M0tR9H$^Kr1$q2fPYGPOf>{`Yc3@K--o zdU`?@XQhosjj{4g%Uu`U*j*HEuZt3KgkMX)b?w88x*Ma{<)-;s#ZYM!5nMLJiJJQ2 ze=LzBf-B7W=f4yMni&2BhfgJv*|pYIQLYzm>_~9{2IYc3Q7-m3|(}Mva+sa zlZhhmXPO}R;t#)hRYATm>uo^@BZ3$mOMJ+5j*gyham9&_mYv=jXtyT9GvPV5p2)kT zrQ<|Jv9F#E2ZU}B=xZP(3+}JC-%yY{yg6~(ip19r_J=dfta`3jZ0T>`=535R(-EG6 zs-{U$L1A0}$%^YeR%Q%}2m;Ber~6I$wo`=b zso2rAy(Kj~6E$?a5!6h0H6`^UTYkQk>U+RQWCxEZG&T8Hj`^+d$|pj*CD9R_iM703 zPl+5p-o4XX6CG~^P4AuE#~(#*PK=APsAP&PLnP4!#%>D~l95PRh zpKxzTGC{{1!6d1{{lta~t`Qd2`D}{lZg9Z}nOq9!PcV1MQV~k&!fsd!-Ow)e*7!ij zwjgx85rVdL42<6jwKHUhtUC7O()#NCxeD@)_rDT4DbvWJ`?B>d99(b3{^-6hjAyE= zicHhx5@3Cm7-{8yMKbGN1pYP((;@ zrokR7x7)>6H^jG|E_GB>MHAw3NN^QZHOHbus|N=A61&{2_82flNN|C^_Vt@{5xwCK z|3pb3JBp6rBqrBS&)Fe0@a|CSJ`b>fKm~F6D}RH%gGaOb=)G*$V>WtzTqa3$1Q#6T z*-H_>1;w(r6@_gnBI_8$T3-B|?Bc5L#Hk`p~u{p07itADH7=4xq#dA2i!VBu_{~$&` zgO|RV=mKKWMfZXwFxUn$7RP-02Cp>sR)qu@YobJ4w$pD-} z(Zz^FI&-2M^Q)H-qkqBh_mqT}EK7t^I)%yBH?(osRDE%<^GsoBvN4(jexTKZJn`qHrd%Y>6wXQx8T$Y8BNfj`V!*zZ&3UTL69!GG>PBwLZUHQURGUq z21nYOLy%XSOhY%Mxou?dPM4Jzi%BDiuD^vJdkO;dFA%+d6JJbxQ#2Y$lr~wAjK{d7 zo*G=~-cl4`3ZBX<(1e+6X=~VMiH4SGKv9eP%E42qE-?g=9w%iIOhXFqr7sYVe;e~B zvKb?$XrBndz#<~`&clS^Bi(fw_L^#{XuwRS2);s9P18Q3uKUPv!oxeM5f%m_K2A)d z3FT-$V(}j{T$#zCiujew)`KnLKA2lu+rAoOw1QODs$*&z#x?ue){e%W@`26YdTbE~ zgj5bw8S#5M_+Xwu?WT*E;0$)Yp{4Jp+_8_Kn(svhAWDCcyw~?ho)!S9N(LiFU2Ql;f(1_&p6Q7AkEFCY>zW$3pURI=aK>>Ud{I!?q-Em?A|3X3~!psxTMo zowTi?qjUVK&yJ%`ek9SJA~K!H5dIO15qqb7g+r9iGNOz2(Ga6 z9_nk80YL8>F9UklRz^N7cYW+)p~oeP_7u^LSiSS5$&dj?s3azU};T|UHDyU>8jioUabrX;9B4|w=y_A=^ z+agN`_J)dBrDam-!sDrkIQx7-x}x9?r*K4RzrinIQs^8r%s2gd-=)!2?fc8TwbW7D zi!`>jsB3wb?QdT-da3U^=6i0&p;JWLOaUfA96@|OTM-55&mE;J36(Yx6P!O_rf+Cz z8xeYWEV9$Rp(scf)yt%@I;I;`)ZpG3Id(ZT!q(DIU$moR0)h+mH6;|E|Cvi%aEFsc zTnt~vpD&}b&Gc;ieey0{SySk3qN|PwE^P!?*ER7jTyy18o{ztco*A3UpB)qN(IE>2 zyxHjb{&UqbVWLAKlSTb1=D&`!oOiNeqUbd^f z^~AcW>1%(wr){yIFC9`HlIR~9$tcU*CaTNza$oFdz^A|0(QCf-R^2Uq<#o)VbZ6=h?dWh9Q%0^*RM|9mm(UwZ+H3uenmWHH>}V94kP zjcqOwafvC>t4=p%1R=jRseqb&aC7}g!dP|MZaZjQ^An}9;*%SkOhWTxcrbiI2!sC< zIm5w8hRXG;G>^(m8Cre5u0R8AFq8b=mgOrn!>f8%MPEDzbD_0fRB%=iIlq-B{m+*n ze!n2*Pq2?nA&Wt2BarDVGfV%(bcCZrVm zTjX=8G%+#&<#iEnNaYmR_nlj=yZumlA#YpDR#qjWy2_y>Bz}&_+&gah9 z_~=M`VYr7Q+F~Y=+L|ti=iAP%{c(J(JoC1%jd>1B^sOxd`xcHsKmP*xE8+s7UpkQ_ z27+U4FJz`yR=UN}o|~7)64uw3L3cV*+ayt2gVJ|dZ~udJfv!C+So+PPkO*SnH$-_v zq5nDJCQb|&>^xECLkt{;At53&-^tD2XLG`;{UsS5+NzkbGUAlv2x~AlrtOhYvcK^` zO7RXC%UULpKoHN_m^_0@h~Kyo{Jjb1D+WUhJq&zMbo4CUda&Nrku~SHC1FEmu&EG{ zeCFv5Qzg2_0pUs8&aWA{vf(Q5+rrR`BBod zbn@ICTAgQFTX59+sEfl#s1jZ0tGY7Jsm~q zGh6(I#`ENogKLLkPn~;gYnbKdWkjV@NXp`R?+e;fznqI0i95p=2vv?JYu3dAWj_mt zo7q1PHMW%0B-?9gVu3m$`OH+lRn;}M0y4HAKHDE%ap$Ikg`ct*4+3V-B-GayAbyL2 z;V&x+of4U3aS~j|+SVbo`fBXSM~%l@nv%lpwbWD*$Hgz5uTar7_0A}1I5QF-S#hB{ z)WOzTN1OyFO~eU`FC%`7hT(4uZJg*7aT1)BZ|!X7zsV=CFZSg9j`M}V0lH|F*$nVo zRn0VH`~J56lUq+!yWTiv=WLzN5-Y)l>9^9`h~FZ@D@(r?q{l=tKG$V5j(*G@CudJP ztY{YBc(ysi1noc(f9?(I1iiPPzcxJB=kwUb*2-y5j6R1Z&T}AaqM856D~O3AyTjjH zG%?L1mX?>v_H-(Ttz)*wZd3Wzq5k%51s=xQ>MF=!S!|a##%^5`)6zq&1F-Bn%G!%- z#G%q@BynjmQx4mEe?j-RC>j3w7ZbE25(xxxMrg~Ham=Ga%f|-e8xQWUDh;DfzHx#~2OucJ%7PhPzj^298HNweAtdAY*Yn-%q`|34BLeWO)?|wDmiA5rbS59BX zjIr`fgH-%pDV9KWIXJ zFMS`~-=e<5-~V!Q?u$$kE5RvdhL)bb{&A^3w<;bCUpu|61`L+fP%vkPHvI_cIux$pl%3^=cBnoBHlK+!85bwl?kG`IG1au~i zDE0@hlkV)>bu%&h;?@TzS`Y3k2?^3rN6u~d-QOx|n%K1WzJslgPF`Af>ax$K-JaH7 zVkbC(@?p3~QMeW{kv;1Mg{cGo&!nGh!M+C>~ z0$0=2GS1kx*ZqFN-R#Ub|A?cu7U_O0u|HPsEHH7F|*W?y{#(;ub$g&p;uY!r_W_E$l@osP~cH~ z`_1=J{w;RA@!=EgizMcr7ru25Jb$jGLuOtq*4?%rck!Wja`L1yfw&e!c|KljVi~nuXXl6ZmHFL?RA8w&K6WF;ER{j=APuy|*!b zee03)&D(nk7k`Q_@R^d@zJGUtuv$i*8G@5o`jysBR<>?YamBYPHV(Azt;^s! zsw0B`8G@@j@-phqyF0+X7ZO}@cyGt5frN?+i8rDw{RlJmD3ys&91~s^U;Gy_Y^KBXzfVYQ z6b50%s-kdvZB@kZKjgQrX+h2QUG?rG11AUXZ7wek z?Xj~m)S1CYNoG(cx?527TLP+O|9o3X*p@(=!BfFB(=)g7jPj2I!EN);k?|u(TAIR4 z)ltptk1Av8#^Gg$dm9H5e%_o7R!siBZq81I`qUYGl%xqk=ii?rc}*hn@PB?R>`PcS zb0E_>ItI0R>E_NZyW=wN+)a4oetx^RE~<+EQRQ1RpmbOJ$d-HA=i+v|I3L)fhdCkB z$usyUh3DwYci%zo4w6FgkEaSGGxGAsd_PDqY{uYLnmb3`sNOstzp8#)7!QnJv^6!< z(Q>nAJ6hB=G_|#i?RjBMr$IPh2f~`Oc_o)YA!8jTgqeAUQxDI_h~5%}?-xEj;5T!x ze`OlCc8`@^*SYMmOD8)UJL(&nw-<#K*gI;gqb0;bsA_1LdL(BQZEtRC?lDE-65 zPhP|`c}$2jD%&gze3sqpB93*r25yEHH&|Y{J;Os65nMoUEnZU9p)+d-qGLA)x_0?T zM7h{nT34E}sWjpY-{8VOe({H>{4H^K^`jp?R$4amfQtY!aVm%FrEicEW8u3g_u{3Y z{v+M6o)i&WKyc%XD#*J}#%|8tVAB}rMp)Hi$fpVS?C!NCEziU z>64>l%f9#=@knyDwgrk4Qy?6cBoLgyG%&QZwR5<=DYH2D&Z&nRKv-W>-(6LdY_GdQ ze)z4Xq$<; zXT3d7c!kr*5^!>q$y6P`m~?YXXB$r!JKr0{7w%!QdhfoS$&T_ua433f1cjCC>%~O# zdl!mt_}aO7+E`hdg9Wk2 zL$}+BeOnU-8qe-a3R005f`daUuWbKW=tkYzmw4OF5T?ZF;C~D)EkuGu$ZE@k`TxRM zvrzB36yOuZ$*~}cBxHC`&XL&xm)o%W=;z4M;nipN6*iUZEUF3jwl{Uu(v>0IP2jww z?PzN6ot%-hv#xO0q2v5^mcBrr+b##plqKnzOtth|h`1va_@BwPHVU02Q3N-Nv2^jj zaT7XV#z1r%T{+y}*wNckRTdml5MTlnlf4=$_f-g{*A$nce+gbnvn z^2!r$-tc#^j4_fZf|H))2n$hkE-hjD#}jurS)y+6WpuL`b67MU;or3>^;}}$g^Lxj z(JR-UIlX^dNpP~gjI_EfSJyV>g_Sn#I)7%>iJ`%*DHkpmXQrmz_K&dhbT*GMqf68y zAx@rB0sW*k=c$XGWDywpgRv_>aSlXAbVdnprh8)Ya87!zUG(KI5A{N%*C{oNu^< zSuR21tp-25hK6oXcr14$x zGej3@Wccfo45x8eG|4+;6po*sx%1IuX|6uif!TSR$0}k6AB+yHZ#}bjSJn2iq?&M^ zDYg4!zW}0lOlPCjKtu0<>;AP*g^|T#O}vC;?hFT<=(n@FLHFfd;8vo zU3}$Df|s5x$M|iZ99*((*P-6yt;0iu_b%SbJr|l5ce}^m!Pm~k*6M&^mVu;Y-GY}Z zb8;1u65_YCV(u%iES)Wk(utCH$oQViEF&HLoc!9#7(G2hLu7D+s-!45EWE&*7ZBhvA;B#dF}qb@&J*J_^rZ#x3c|yJi%P2YHSBHg zSiP$M{_u$_K<(IjW1COisdnx1^|Un9rz=bNmrQ*?lV7X|8@|BkLupWF*$TO)@$vDEzF z`G)RYhpS*;ae%3|`U;Wqdxa{b*#QON8NsDkOZmaJHLW9^LxVqG%&tzoeQdXbLxgXX zor{~T4YabD8&>-1a2O;>|Bff-TjqQ_7x7y*@Y3AZmq`b(UFT#P0|w7H93vw(m#gDt zke{VzZtHv7_4y$gY9iw0|oB* z=<#(wRi{Ezd8L_`mzRzXm&-OX;;>j$CWA&MNrvmvbnyAymk={#hvIKed4t3BCP`Y3 zAttpmm|g;#*6SBiuu}QSq0#u2!*H3m@9l1`E7`eoXIW`cQgBU1SV(wsa)CELNB6J~ z0$mQ^=x74!+_TWq(lRkIaddQqf5Ox>D9GN!BY@}aU67m{9uk&O6P#33TDG%fd)+oH z-#)U&y>;#S&iElHa#y5WsJ?mI*Vf#Ru}qqvOoI8;ClTEImk_;W3m-mt)MO@$L6Dl0 zNgz=eMmg!=3$wc`)h98x{MMeu*3k%D@NDLeX5^t}o+E#dY-~NU}rw`V*A3pxdUmFFhUB3cv@Ui2O54OPN-Z{Kp zNcXn(v-Q2F8@l&37e0mN=EM7T?Qc1>_h4`RSw5#%H;(iVcdi6NKZqQU-C8kr@#=-2 zvhS1!=2j;b`}kyLx~6WLXkhWQa@vz+#v)1A4Njv@(f1J>WD@fyx*SN-6Qc7?VaN;? z+sm&u#&D0d`2kByOA8AND`y+f;XsHxiYamax6@L=^{xCTA=BY*-!gjT1YGR>BaN%q z964M66wbD{9mnGC#*vZ!_4gkQT={VbE@}aF*yt5kER~GWtOR|H@A317;_lySWMKT`sm3 z=6X3gMl3o7`xBo0dBlmSFoIuWxh8*xjFF$DhH5OR+%ehhr(5v0`>MMB<4)u29VGITm5(W@B+6z0!cq zWKf98(*EthGY0=R65_Yq5d4!V)Brndiu4m4&M=M2)z633#gA51 z-gM18$4}L#;_~I(-0RiV#aL?XdNVZ?vgZG!R4-qjOQpfvPwELyq%b+u zDG&K&L~vOT(*HAO&SYB&jETzt!LiaglfyOh%dgZ+ha}y}5;Al_rwnB1Sc>l8u=^=E z03smAj6&hyRxz} ztF|^j$In3D%u5HlR-k2tPQw<35tOB#-`He{;4KA@{NHG@M1JtbRC-ANMTPJyx+G!h zE9yJ6utdHHK6~;VPk~Ha7NSvvsmdd?2QjCV^5(pO&b)kK*6cZxJx)|C-$VqLA%0`R zBb`N`sC>_v{TT|+JmYUllT~pdox`CcwN2VV zVp3_7UFUO@{)W!DoZsOKCn-*%8qty3CjA6wk|yc>Xv( zk@FB;@BrbVE=1Qif&kwuO%Z3%6)po%`W~HXgeeSvqPD^G^_0C;2+|>&!~QwOl)(a} z573!Ln2HY+CwkkINmMq6f(R~M1gCJ=)JYqUIf`$8gpM@A(|Y>riW6}5Qx?Z6{R5p~gg;>T;@M9UJC+WM zLLwqbU1AANXS1HjC9@YJek1%L{`va+363i>s0`+XZE5+@4b)CEy8o)yV+ADTK=RNlGY_dFDDYog2BJZ z|84en=)594FP6@Ea;Tv9h0UbNfQ!2H1B}k8MmjpIDa&c*EJddk;koh6(nU&7)LJ7W z4rVoq?(iAUy1|QytHWkYK8ZPtmVSdyE5e_l_=0c0{dSS?4yVz`$k<5&2oCW%w4G1f z-}AnG`C~+HgclLqmVQ0iQUPfne@7SrX>Q_I)v(=c{H175np@s`{Y`X05ndFZ&6_Im zkm*!917+i427yFlFsan1cba~Q&L#pL_;k?}hLc!2Yz}p5`xJuc0e)I+t{HbqSIaWR zPteFW0zUX)!B&YR_&Z&#Gz6rQ}1O;Uw!f^I+qBz;h%2<77L?v0@!Y& z5MA6MI%PuQoClBMU#Mvf0eAfUyQdndFhQ5Uf)hz@A`{j~B;l~nlP~#8B&;Eb3Lnm! zdaE#uxNL0CE-H_Udd5EMOVpBzAi_)h-%sgnTr*%eorVH-Q53wfwdY1& z9MV*NFZvYm8$qPW_@|$Kx^VIg(wGbYBDg3na3U}qRtVB2`91&JPd`O|4hW*h_iw)W z=0c(1hRr@e{{?l-ugqev*My$)ab=cr{3L2UT%w@=5D6dHry|AMmd7o;^T_NFsH zGJooe{0CZLfFNdk^VL%Xr?b5D&Dc+OS|L1tU`}DO&Gfxswf9tlzmAR@g4pr?XJ1Zj zwW4rz%#5fsMDQ0QIE`v#ro*93Z4`X@Gjx9=%!uIjm%sewJ;f(cI)g$+a@&hGw2&|%sk$C z?-`+p#xjD|X*vZpz)Yv!4HhjdjuDIYj6nI`JLqH~NC?9}U-Z;-LIdGL8%!&+z{)efkn7kZCNgkrCU73JjNbf|F=W7MpEk zq~pbTrYUIN(*GiUBS-<}zVX95e|_)ksbML$i-QjQCZii1^EIbaAVi<~uABGr=kNUR z#$0rE5TxZAf8(u>KKkh0uau@Va}Wt=`H{fziZG>}W#PNV zj8fq;r!whu8rIn=)12qC8G28_rIH1GKfmnbo%h{aZ@q@j34-)u$zQ*n_bkI1T!Z`^ zeawBCPLXBZ4GLfsc$smyUIsa}23*E3_&xu#SJ4SUkn&sn)maM^pJ6zi?PrGZn+bML zWLYLSB-~6U%ZTfx@5iP;!|&M(Kc9teZv+{@tFva!`flny4x7&Sg>lla6@z6dLI;LZ zz!()IM%q*LgLxmqSMmm;H-hYh>a%9O1^Cw&f~Ca5(=O{HXINXyvMImt?63ZgeG9W@ zEkP#&K{k2*ccovAWtnUY92QktqjvZm7)&PC!=l6GvYEg7J1G4f1?32`o|FF?!yzsA z(lPVP$}uqG8iDjCg|-m{kki;YW(GM~G5Pvl^k4f8l>UzBjUf9BpY@l2&-umShgKMd zk-it#h=naLl}3VNJ*XVMp2nq9ez}`*&cFYHu5Sdnz$;7Mn1$ivXEiAjwyB2*M$A%3 zaQ^;oBK8}QpOFne=Kr#9EJ3|22=ayhd4rEn=l_x|6A~4et^?)y*6RXSqp6-oVpq)g z5d0+k9}4@?ep@D-|Eb{j`yceA5#;+qpZ}X-FO_SMW1z2ZV4!cN!!_b-a5L1=4k8+~ zr14cWu8tY@6Y0Z`#-);fE83Wku51JZ!Bzh0yx(96k*T9^W|osxS(%mZr;l~Vz|<+o z?BXXll(ZRwo)rVXeC+4RF*DQGVgBY%@*TRk5fFr!``T+uKA!(uekWv*r@eHzY$N^! zj`hgQ2*JrfalStyT;X0iY%2M;JZt8E{FncE4PD;|2v3px6#-uT&sV?FFEW{j3$oxD zP{}9$XhHt{%hY?`ce5sbg}G?(69M73@X}nsOD}!&;ru_;yRbQPXfJ^V6F#7~olfWP zI|Wdtfcz_%`uDMa9{cy;Uw`shOt7FKlZk(*?9Ko1qnEIs8F?)sAUqHL_TF^5y{TL- z*DJp=CZ;m0Hb2J?)8ov{4D>++GZVtgOXpYMU28g-$RRq5D@+x-uZCRAIsZNdZuyp1=I#A12Ne;22Vl%SMl^eqr--O5oj-D{-#nk{PaeD+swzl+o}1cVvF zU;n>dJ5&J>2!a5bPQkDkE?qc~^Qz7N|209gP0{dPowhJAVQU}WD)-Rq=ECs#Xpb~K z+wCcZK@Pt(uC3*|N6e>^Zj>uuVz0Ti)prU2000000000000000000000002LcK|gM V$Zxm?H0uBW002ovPDHLkV1lE`BG>=` literal 0 HcmV?d00001 diff --git a/lib/collections/assets.gen.dart b/lib/collections/assets.gen.dart index 2587800e..8a2950fb 100644 --- a/lib/collections/assets.gen.dart +++ b/lib/collections/assets.gen.dart @@ -9,6 +9,21 @@ import 'package:flutter/widgets.dart'; +class $AssetsLogosGen { + const $AssetsLogosGen(); + + /// File path: assets/logos/songlink-transparent.png + AssetGenImage get songlinkTransparent => + const AssetGenImage('assets/logos/songlink-transparent.png'); + + /// File path: assets/logos/songlink.png + AssetGenImage get songlink => + const AssetGenImage('assets/logos/songlink.png'); + + /// List of all assets + List get values => [songlinkTransparent, songlink]; +} + class $AssetsTutorialGen { const $AssetsTutorialGen(); @@ -37,6 +52,7 @@ class Assets { static const AssetGenImage jiosaavn = AssetGenImage('assets/jiosaavn.png'); static const AssetGenImage likedTracks = AssetGenImage('assets/liked-tracks.jpg'); + static const $AssetsLogosGen logos = $AssetsLogosGen(); static const AssetGenImage placeholder = AssetGenImage('assets/placeholder.png'); static const AssetGenImage spotubeHeroBanner = diff --git a/lib/components/player/player.dart b/lib/components/player/player.dart index 298458b5..a43fcbca 100644 --- a/lib/components/player/player.dart +++ b/lib/components/player/player.dart @@ -25,6 +25,7 @@ import 'package:spotube/pages/lyrics/lyrics.dart'; import 'package:spotube/provider/authentication_provider.dart'; import 'package:spotube/provider/proxy_playlist/proxy_playlist_provider.dart'; import 'package:spotube/utils/type_conversion_utils.dart'; +import 'package:url_launcher/url_launcher_string.dart'; class PlayerView extends HookConsumerWidget { final PanelController panelController; @@ -137,6 +138,21 @@ class PlayerView extends HookConsumerWidget { onPressed: panelController.close, ), actions: [ + IconButton( + icon: Assets.logos.songlink.image( + width: 20, + height: 20, + ), + tooltip: context.l10n.song_link, + onPressed: currentTrack == null + ? null + : () { + final url = + "https://song.link/s/${currentTrack.id}"; + + launchUrlString(url); + }, + ), IconButton( icon: const Icon(SpotubeIcons.info, size: 18), tooltip: context.l10n.details, diff --git a/lib/components/shared/track_tile/track_options.dart b/lib/components/shared/track_tile/track_options.dart index 419f61a4..a094259d 100644 --- a/lib/components/shared/track_tile/track_options.dart +++ b/lib/components/shared/track_tile/track_options.dart @@ -7,6 +7,7 @@ import 'package:flutter_hooks/flutter_hooks.dart'; import 'package:go_router/go_router.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:spotify/spotify.dart'; +import 'package:spotube/collections/assets.gen.dart'; import 'package:spotube/collections/spotube_icons.dart'; import 'package:spotube/components/library/user_local_tracks.dart'; import 'package:spotube/components/shared/adaptive/adaptive_pop_sheet_list.dart'; @@ -26,10 +27,12 @@ import 'package:spotube/provider/spotify_provider.dart'; import 'package:spotube/services/mutations/mutations.dart'; import 'package:spotube/services/queries/search.dart'; import 'package:spotube/utils/type_conversion_utils.dart'; +import 'package:url_launcher/url_launcher_string.dart'; enum TrackOptionValue { album, share, + songlink, addToPlaylist, addToQueue, removeFromPlaylist, @@ -165,6 +168,7 @@ class TrackOptions extends HookConsumerWidget { final scaffoldMessenger = ScaffoldMessenger.of(context); final mediaQuery = MediaQuery.of(context); final router = GoRouter.of(context); + final ThemeData(:colorScheme) = Theme.of(context); final playlist = ref.watch(ProxyPlaylistNotifier.provider); final playback = ref.watch(ProxyPlaylistNotifier.notifier); @@ -276,6 +280,10 @@ class TrackOptions extends HookConsumerWidget { case TrackOptionValue.share: actionShare(context, track); break; + case TrackOptionValue.songlink: + final url = "https://song.link/s/${track.id}"; + await launchUrlString(url); + break; case TrackOptionValue.details: showDialog( context: context, @@ -418,6 +426,15 @@ class TrackOptions extends HookConsumerWidget { leading: const Icon(SpotubeIcons.share), title: Text(context.l10n.share), ), + PopSheetEntry( + value: TrackOptionValue.songlink, + leading: Assets.logos.songlinkTransparent.image( + width: 22, + height: 22, + color: colorScheme.onSurface.withOpacity(0.5), + ), + title: Text(context.l10n.song_link), + ), PopSheetEntry( value: TrackOptionValue.details, leading: const Icon(SpotubeIcons.info), diff --git a/lib/l10n/app_en.arb b/lib/l10n/app_en.arb index a3c93546..6b684d48 100644 --- a/lib/l10n/app_en.arb +++ b/lib/l10n/app_en.arb @@ -294,5 +294,6 @@ "endless_playback": "Endless Playback", "delete_playlist": "Delete Playlist", "delete_playlist_confirmation": "Are you sure you want to delete this playlist?", - "local_tracks": "Local Tracks" + "local_tracks": "Local Tracks", + "song_link": "Song Link" } \ No newline at end of file diff --git a/lib/services/song_link/model.dart b/lib/services/song_link/model.dart new file mode 100644 index 00000000..ae9d3833 --- /dev/null +++ b/lib/services/song_link/model.dart @@ -0,0 +1,19 @@ +part of './song_link.dart'; + +@freezed +class SongLink with _$SongLink { + const factory SongLink({ + required String displayName, + required String linkId, + required String platform, + required bool show, + required String? uniqueId, + required String? country, + required String? url, + required String? nativeAppUriMobile, + required String? nativeAppUriDesktop, + }) = _SongLink; + + factory SongLink.fromJson(Map json) => + _$SongLinkFromJson(json); +} diff --git a/lib/services/song_link/song_link.dart b/lib/services/song_link/song_link.dart new file mode 100644 index 00000000..c3d73f23 --- /dev/null +++ b/lib/services/song_link/song_link.dart @@ -0,0 +1,47 @@ +library song_link; + +import 'dart:convert'; + +import 'package:dio/dio.dart'; +import 'package:freezed_annotation/freezed_annotation.dart'; +import 'package:html/parser.dart'; + +part 'model.dart'; + +part 'song_link.freezed.dart'; +part 'song_link.g.dart'; + +abstract class SongLinkService { + static Future> links(String spotifyId) async { + final dio = Dio(); + + final res = await dio.get( + "https://song.link/s/$spotifyId", + options: Options( + headers: { + "Accept": + "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8", + "User-Agent": + "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/122.0.0.0 Safari/537.36" + }, + responseType: ResponseType.plain, + ), + ); + + final document = parse(res.data); + + final script = document.getElementById("__NEXT_DATA__")?.text; + + if (script == null) { + return []; + } + + final pageProps = jsonDecode(script) as Map; + final songLinks = + pageProps["props"]["pageProps"]["pageData"]["sections"].firstWhere( + (section) => section["sectionId"] == "section|auto|links|listen", + )["links"] as List; + + return songLinks.map((link) => SongLink.fromJson(link)).toList(); + } +} diff --git a/lib/services/song_link/song_link.freezed.dart b/lib/services/song_link/song_link.freezed.dart new file mode 100644 index 00000000..a8230eeb --- /dev/null +++ b/lib/services/song_link/song_link.freezed.dart @@ -0,0 +1,320 @@ +// coverage:ignore-file +// GENERATED CODE - DO NOT MODIFY BY HAND +// ignore_for_file: type=lint +// ignore_for_file: unused_element, deprecated_member_use, deprecated_member_use_from_same_package, use_function_type_syntax_for_parameters, unnecessary_const, avoid_init_to_null, invalid_override_different_default_values_named, prefer_expression_function_bodies, annotate_overrides, invalid_annotation_target, unnecessary_question_mark + +part of 'song_link.dart'; + +// ************************************************************************** +// FreezedGenerator +// ************************************************************************** + +T _$identity(T value) => value; + +final _privateConstructorUsedError = UnsupportedError( + 'It seems like you constructed your class using `MyClass._()`. This constructor is only meant to be used by freezed and you are not supposed to need it nor use it.\nPlease check the documentation here for more information: https://github.com/rrousselGit/freezed#custom-getters-and-methods'); + +SongLink _$SongLinkFromJson(Map json) { + return _SongLink.fromJson(json); +} + +/// @nodoc +mixin _$SongLink { + String get displayName => throw _privateConstructorUsedError; + String get linkId => throw _privateConstructorUsedError; + String get platform => throw _privateConstructorUsedError; + bool get show => throw _privateConstructorUsedError; + String? get uniqueId => throw _privateConstructorUsedError; + String? get country => throw _privateConstructorUsedError; + String? get url => throw _privateConstructorUsedError; + String? get nativeAppUriMobile => throw _privateConstructorUsedError; + String? get nativeAppUriDesktop => throw _privateConstructorUsedError; + + Map toJson() => throw _privateConstructorUsedError; + @JsonKey(ignore: true) + $SongLinkCopyWith get copyWith => + throw _privateConstructorUsedError; +} + +/// @nodoc +abstract class $SongLinkCopyWith<$Res> { + factory $SongLinkCopyWith(SongLink value, $Res Function(SongLink) then) = + _$SongLinkCopyWithImpl<$Res, SongLink>; + @useResult + $Res call( + {String displayName, + String linkId, + String platform, + bool show, + String? uniqueId, + String? country, + String? url, + String? nativeAppUriMobile, + String? nativeAppUriDesktop}); +} + +/// @nodoc +class _$SongLinkCopyWithImpl<$Res, $Val extends SongLink> + implements $SongLinkCopyWith<$Res> { + _$SongLinkCopyWithImpl(this._value, this._then); + + // ignore: unused_field + final $Val _value; + // ignore: unused_field + final $Res Function($Val) _then; + + @pragma('vm:prefer-inline') + @override + $Res call({ + Object? displayName = null, + Object? linkId = null, + Object? platform = null, + Object? show = null, + Object? uniqueId = freezed, + Object? country = freezed, + Object? url = freezed, + Object? nativeAppUriMobile = freezed, + Object? nativeAppUriDesktop = freezed, + }) { + return _then(_value.copyWith( + displayName: null == displayName + ? _value.displayName + : displayName // ignore: cast_nullable_to_non_nullable + as String, + linkId: null == linkId + ? _value.linkId + : linkId // ignore: cast_nullable_to_non_nullable + as String, + platform: null == platform + ? _value.platform + : platform // ignore: cast_nullable_to_non_nullable + as String, + show: null == show + ? _value.show + : show // ignore: cast_nullable_to_non_nullable + as bool, + uniqueId: freezed == uniqueId + ? _value.uniqueId + : uniqueId // ignore: cast_nullable_to_non_nullable + as String?, + country: freezed == country + ? _value.country + : country // ignore: cast_nullable_to_non_nullable + as String?, + url: freezed == url + ? _value.url + : url // ignore: cast_nullable_to_non_nullable + as String?, + nativeAppUriMobile: freezed == nativeAppUriMobile + ? _value.nativeAppUriMobile + : nativeAppUriMobile // ignore: cast_nullable_to_non_nullable + as String?, + nativeAppUriDesktop: freezed == nativeAppUriDesktop + ? _value.nativeAppUriDesktop + : nativeAppUriDesktop // ignore: cast_nullable_to_non_nullable + as String?, + ) as $Val); + } +} + +/// @nodoc +abstract class _$$SongLinkImplCopyWith<$Res> + implements $SongLinkCopyWith<$Res> { + factory _$$SongLinkImplCopyWith( + _$SongLinkImpl value, $Res Function(_$SongLinkImpl) then) = + __$$SongLinkImplCopyWithImpl<$Res>; + @override + @useResult + $Res call( + {String displayName, + String linkId, + String platform, + bool show, + String? uniqueId, + String? country, + String? url, + String? nativeAppUriMobile, + String? nativeAppUriDesktop}); +} + +/// @nodoc +class __$$SongLinkImplCopyWithImpl<$Res> + extends _$SongLinkCopyWithImpl<$Res, _$SongLinkImpl> + implements _$$SongLinkImplCopyWith<$Res> { + __$$SongLinkImplCopyWithImpl( + _$SongLinkImpl _value, $Res Function(_$SongLinkImpl) _then) + : super(_value, _then); + + @pragma('vm:prefer-inline') + @override + $Res call({ + Object? displayName = null, + Object? linkId = null, + Object? platform = null, + Object? show = null, + Object? uniqueId = freezed, + Object? country = freezed, + Object? url = freezed, + Object? nativeAppUriMobile = freezed, + Object? nativeAppUriDesktop = freezed, + }) { + return _then(_$SongLinkImpl( + displayName: null == displayName + ? _value.displayName + : displayName // ignore: cast_nullable_to_non_nullable + as String, + linkId: null == linkId + ? _value.linkId + : linkId // ignore: cast_nullable_to_non_nullable + as String, + platform: null == platform + ? _value.platform + : platform // ignore: cast_nullable_to_non_nullable + as String, + show: null == show + ? _value.show + : show // ignore: cast_nullable_to_non_nullable + as bool, + uniqueId: freezed == uniqueId + ? _value.uniqueId + : uniqueId // ignore: cast_nullable_to_non_nullable + as String?, + country: freezed == country + ? _value.country + : country // ignore: cast_nullable_to_non_nullable + as String?, + url: freezed == url + ? _value.url + : url // ignore: cast_nullable_to_non_nullable + as String?, + nativeAppUriMobile: freezed == nativeAppUriMobile + ? _value.nativeAppUriMobile + : nativeAppUriMobile // ignore: cast_nullable_to_non_nullable + as String?, + nativeAppUriDesktop: freezed == nativeAppUriDesktop + ? _value.nativeAppUriDesktop + : nativeAppUriDesktop // ignore: cast_nullable_to_non_nullable + as String?, + )); + } +} + +/// @nodoc +@JsonSerializable() +class _$SongLinkImpl implements _SongLink { + const _$SongLinkImpl( + {required this.displayName, + required this.linkId, + required this.platform, + required this.show, + required this.uniqueId, + required this.country, + required this.url, + required this.nativeAppUriMobile, + required this.nativeAppUriDesktop}); + + factory _$SongLinkImpl.fromJson(Map json) => + _$$SongLinkImplFromJson(json); + + @override + final String displayName; + @override + final String linkId; + @override + final String platform; + @override + final bool show; + @override + final String? uniqueId; + @override + final String? country; + @override + final String? url; + @override + final String? nativeAppUriMobile; + @override + final String? nativeAppUriDesktop; + + @override + String toString() { + return 'SongLink(displayName: $displayName, linkId: $linkId, platform: $platform, show: $show, uniqueId: $uniqueId, country: $country, url: $url, nativeAppUriMobile: $nativeAppUriMobile, nativeAppUriDesktop: $nativeAppUriDesktop)'; + } + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other.runtimeType == runtimeType && + other is _$SongLinkImpl && + (identical(other.displayName, displayName) || + other.displayName == displayName) && + (identical(other.linkId, linkId) || other.linkId == linkId) && + (identical(other.platform, platform) || + other.platform == platform) && + (identical(other.show, show) || other.show == show) && + (identical(other.uniqueId, uniqueId) || + other.uniqueId == uniqueId) && + (identical(other.country, country) || other.country == country) && + (identical(other.url, url) || other.url == url) && + (identical(other.nativeAppUriMobile, nativeAppUriMobile) || + other.nativeAppUriMobile == nativeAppUriMobile) && + (identical(other.nativeAppUriDesktop, nativeAppUriDesktop) || + other.nativeAppUriDesktop == nativeAppUriDesktop)); + } + + @JsonKey(ignore: true) + @override + int get hashCode => Object.hash(runtimeType, displayName, linkId, platform, + show, uniqueId, country, url, nativeAppUriMobile, nativeAppUriDesktop); + + @JsonKey(ignore: true) + @override + @pragma('vm:prefer-inline') + _$$SongLinkImplCopyWith<_$SongLinkImpl> get copyWith => + __$$SongLinkImplCopyWithImpl<_$SongLinkImpl>(this, _$identity); + + @override + Map toJson() { + return _$$SongLinkImplToJson( + this, + ); + } +} + +abstract class _SongLink implements SongLink { + const factory _SongLink( + {required final String displayName, + required final String linkId, + required final String platform, + required final bool show, + required final String? uniqueId, + required final String? country, + required final String? url, + required final String? nativeAppUriMobile, + required final String? nativeAppUriDesktop}) = _$SongLinkImpl; + + factory _SongLink.fromJson(Map json) = + _$SongLinkImpl.fromJson; + + @override + String get displayName; + @override + String get linkId; + @override + String get platform; + @override + bool get show; + @override + String? get uniqueId; + @override + String? get country; + @override + String? get url; + @override + String? get nativeAppUriMobile; + @override + String? get nativeAppUriDesktop; + @override + @JsonKey(ignore: true) + _$$SongLinkImplCopyWith<_$SongLinkImpl> get copyWith => + throw _privateConstructorUsedError; +} diff --git a/lib/services/song_link/song_link.g.dart b/lib/services/song_link/song_link.g.dart new file mode 100644 index 00000000..911849e3 --- /dev/null +++ b/lib/services/song_link/song_link.g.dart @@ -0,0 +1,33 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +part of 'song_link.dart'; + +// ************************************************************************** +// JsonSerializableGenerator +// ************************************************************************** + +_$SongLinkImpl _$$SongLinkImplFromJson(Map json) => + _$SongLinkImpl( + displayName: json['displayName'] as String, + linkId: json['linkId'] as String, + platform: json['platform'] as String, + show: json['show'] as bool, + uniqueId: json['uniqueId'] as String?, + country: json['country'] as String?, + url: json['url'] as String?, + nativeAppUriMobile: json['nativeAppUriMobile'] as String?, + nativeAppUriDesktop: json['nativeAppUriDesktop'] as String?, + ); + +Map _$$SongLinkImplToJson(_$SongLinkImpl instance) => + { + 'displayName': instance.displayName, + 'linkId': instance.linkId, + 'platform': instance.platform, + 'show': instance.show, + 'uniqueId': instance.uniqueId, + 'country': instance.country, + 'url': instance.url, + 'nativeAppUriMobile': instance.nativeAppUriMobile, + 'nativeAppUriDesktop': instance.nativeAppUriDesktop, + }; diff --git a/lib/services/sourced_track/sources/youtube.dart b/lib/services/sourced_track/sources/youtube.dart index 5f75c4db..3fc78f0b 100644 --- a/lib/services/sourced_track/sources/youtube.dart +++ b/lib/services/sourced_track/sources/youtube.dart @@ -3,6 +3,7 @@ import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:http/http.dart'; import 'package:spotify/spotify.dart'; import 'package:spotube/models/source_match.dart'; +import 'package:spotube/services/song_link/song_link.dart'; import 'package:spotube/services/sourced_track/enums.dart'; import 'package:spotube/services/sourced_track/exceptions.dart'; import 'package:spotube/services/sourced_track/models/source_info.dart'; @@ -216,6 +217,20 @@ class YoutubeSourcedTrack extends SourcedTrack { required Track track, required Ref ref, }) async { + final links = await SongLinkService.links(track.id!); + final ytLink = links.firstWhereOrNull((link) => link.platform == "youtube"); + + if (ytLink?.url != null) { + return [ + await toSiblingType( + 0, + YoutubeVideoInfo.fromVideo( + await youtubeClient.videos.get(ytLink!.url!), + ), + ) + ]; + } + final query = SourcedTrack.getSearchTerm(track); final searchResults = await youtubeClient.search.search( diff --git a/lib/songlink.dart b/lib/songlink.dart new file mode 100644 index 00000000..65aae7e3 --- /dev/null +++ b/lib/songlink.dart @@ -0,0 +1,43 @@ +import 'dart:convert'; + +import 'package:html/parser.dart'; +import 'package:dio/dio.dart'; + +void main(List args) async { + final dio = Dio(); + + final spotifyId = args[0]; + + print("Fetching song link for $spotifyId"); + + final res = await dio.get( + "https://song.link/s/$spotifyId", + options: Options( + headers: { + "Accept": + "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8", + "User-Agent": + "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/122.0.0.0 Safari/537.36" + }, + responseType: ResponseType.plain, + ), + ); + + final document = parse(res.data); + + final script = document.getElementById("__NEXT_DATA__")?.text; + + if (script == null) { + throw Exception("Could not find __NEXT_DATA__ script tag."); + } + + final pageProps = jsonDecode(script) as Map; + final songLinks = + pageProps["props"]["pageProps"]["pageData"]["sections"].firstWhere( + (section) => section["sectionId"] == "section|auto|links|listen", + )["links"]; + + for (final link in songLinks) { + print("${link["platform"]} - ${link["url"]}"); + } +} diff --git a/pubspec.yaml b/pubspec.yaml index 82377d08..9bacf6dd 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -153,6 +153,7 @@ flutter: assets: - assets/ - assets/tutorial/ + - assets/logos/ - LICENSE flutter_launcher_icons: diff --git a/untranslated_messages.json b/untranslated_messages.json index 41251435..cc14528c 100644 --- a/untranslated_messages.json +++ b/untranslated_messages.json @@ -7,7 +7,8 @@ "endless_playback", "delete_playlist", "delete_playlist_confirmation", - "local_tracks" + "local_tracks", + "song_link" ], "bn": [ @@ -18,7 +19,8 @@ "endless_playback", "delete_playlist", "delete_playlist_confirmation", - "local_tracks" + "local_tracks", + "song_link" ], "ca": [ @@ -29,7 +31,8 @@ "endless_playback", "delete_playlist", "delete_playlist_confirmation", - "local_tracks" + "local_tracks", + "song_link" ], "de": [ @@ -40,7 +43,8 @@ "endless_playback", "delete_playlist", "delete_playlist_confirmation", - "local_tracks" + "local_tracks", + "song_link" ], "es": [ @@ -51,7 +55,8 @@ "endless_playback", "delete_playlist", "delete_playlist_confirmation", - "local_tracks" + "local_tracks", + "song_link" ], "fa": [ @@ -62,7 +67,8 @@ "endless_playback", "delete_playlist", "delete_playlist_confirmation", - "local_tracks" + "local_tracks", + "song_link" ], "fr": [ @@ -73,7 +79,8 @@ "endless_playback", "delete_playlist", "delete_playlist_confirmation", - "local_tracks" + "local_tracks", + "song_link" ], "hi": [ @@ -84,7 +91,8 @@ "endless_playback", "delete_playlist", "delete_playlist_confirmation", - "local_tracks" + "local_tracks", + "song_link" ], "it": [ @@ -95,7 +103,8 @@ "endless_playback", "delete_playlist", "delete_playlist_confirmation", - "local_tracks" + "local_tracks", + "song_link" ], "ja": [ @@ -106,7 +115,8 @@ "endless_playback", "delete_playlist", "delete_playlist_confirmation", - "local_tracks" + "local_tracks", + "song_link" ], "ne": [ @@ -117,7 +127,8 @@ "endless_playback", "delete_playlist", "delete_playlist_confirmation", - "local_tracks" + "local_tracks", + "song_link" ], "nl": [ @@ -129,7 +140,8 @@ "endless_playback", "delete_playlist", "delete_playlist_confirmation", - "local_tracks" + "local_tracks", + "song_link" ], "pl": [ @@ -140,7 +152,8 @@ "endless_playback", "delete_playlist", "delete_playlist_confirmation", - "local_tracks" + "local_tracks", + "song_link" ], "pt": [ @@ -151,7 +164,8 @@ "endless_playback", "delete_playlist", "delete_playlist_confirmation", - "local_tracks" + "local_tracks", + "song_link" ], "ru": [ @@ -162,7 +176,8 @@ "endless_playback", "delete_playlist", "delete_playlist_confirmation", - "local_tracks" + "local_tracks", + "song_link" ], "tr": [ @@ -173,7 +188,8 @@ "endless_playback", "delete_playlist", "delete_playlist_confirmation", - "local_tracks" + "local_tracks", + "song_link" ], "uk": [ @@ -184,7 +200,8 @@ "endless_playback", "delete_playlist", "delete_playlist_confirmation", - "local_tracks" + "local_tracks", + "song_link" ], "zh": [ @@ -195,6 +212,7 @@ "endless_playback", "delete_playlist", "delete_playlist_confirmation", - "local_tracks" + "local_tracks", + "song_link" ] } From ca7140650512d88743f7fe2f8d8596b8f757e3b9 Mon Sep 17 00:00:00 2001 From: Kingkor Roy Tirtho Date: Sun, 25 Feb 2024 11:14:00 +0600 Subject: [PATCH 156/195] chore: remove residual files --- lib/songlink.dart | 43 ------------------------------------------- 1 file changed, 43 deletions(-) delete mode 100644 lib/songlink.dart diff --git a/lib/songlink.dart b/lib/songlink.dart deleted file mode 100644 index 65aae7e3..00000000 --- a/lib/songlink.dart +++ /dev/null @@ -1,43 +0,0 @@ -import 'dart:convert'; - -import 'package:html/parser.dart'; -import 'package:dio/dio.dart'; - -void main(List args) async { - final dio = Dio(); - - final spotifyId = args[0]; - - print("Fetching song link for $spotifyId"); - - final res = await dio.get( - "https://song.link/s/$spotifyId", - options: Options( - headers: { - "Accept": - "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8", - "User-Agent": - "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/122.0.0.0 Safari/537.36" - }, - responseType: ResponseType.plain, - ), - ); - - final document = parse(res.data); - - final script = document.getElementById("__NEXT_DATA__")?.text; - - if (script == null) { - throw Exception("Could not find __NEXT_DATA__ script tag."); - } - - final pageProps = jsonDecode(script) as Map; - final songLinks = - pageProps["props"]["pageProps"]["pageData"]["sections"].firstWhere( - (section) => section["sectionId"] == "section|auto|links|listen", - )["links"]; - - for (final link in songLinks) { - print("${link["platform"]} - ${link["url"]}"); - } -} From 96a2a1f5a622cb3c580041417d5023e37fa69716 Mon Sep 17 00:00:00 2001 From: Kingkor Roy Tirtho Date: Sun, 25 Feb 2024 22:01:38 +0600 Subject: [PATCH 157/195] feat: add getting started page --- lib/collections/intents.dart | 3 +- lib/collections/language_codes.dart | 5 + lib/collections/routes.dart | 313 ++++++++++-------- lib/collections/spotube_icons.dart | 3 + lib/components/getting_started/blur_card.dart | 31 ++ lib/hooks/configurators/use_deep_linking.dart | 2 + lib/main.dart | 5 + .../getting_started/getting_started.dart | 93 ++++++ .../getting_started/sections/greeting.dart | 54 +++ .../getting_started/sections/playback.dart | 154 +++++++++ .../getting_started/sections/region.dart | 129 ++++++++ .../getting_started/sections/support.dart | 131 ++++++++ lib/pages/settings/sections/appearance.dart | 179 +++++----- lib/services/kv_store/kv_store.dart | 15 + lib/utils/persisted_state_notifier.dart | 4 +- 15 files changed, 896 insertions(+), 225 deletions(-) create mode 100644 lib/components/getting_started/blur_card.dart create mode 100644 lib/pages/getting_started/getting_started.dart create mode 100644 lib/pages/getting_started/sections/greeting.dart create mode 100644 lib/pages/getting_started/sections/playback.dart create mode 100644 lib/pages/getting_started/sections/region.dart create mode 100644 lib/pages/getting_started/sections/support.dart create mode 100644 lib/services/kv_store/kv_store.dart diff --git a/lib/collections/intents.dart b/lib/collections/intents.dart index abccb3ad..6f42113c 100644 --- a/lib/collections/intents.dart +++ b/lib/collections/intents.dart @@ -4,8 +4,8 @@ import 'package:flutter/cupertino.dart'; import 'package:flutter/services.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:go_router/go_router.dart'; -import 'package:spotube/components/player/player_controls.dart'; import 'package:spotube/collections/routes.dart'; +import 'package:spotube/components/player/player_controls.dart'; import 'package:spotube/models/logger.dart'; import 'package:spotube/provider/proxy_playlist/proxy_playlist_provider.dart'; import 'package:spotube/services/audio_player/audio_player.dart'; @@ -64,6 +64,7 @@ class HomeTabIntent extends Intent { class HomeTabAction extends Action { @override invoke(intent) { + final router = intent.ref.read(routerProvider); switch (intent.tab) { case HomeTabs.browse: router.go("/"); diff --git a/lib/collections/language_codes.dart b/lib/collections/language_codes.dart index 4554de63..e3b71d3f 100644 --- a/lib/collections/language_codes.dart +++ b/lib/collections/language_codes.dart @@ -6,6 +6,11 @@ class ISOLanguageName { required this.name, required this.nativeName, }); + + @override + String toString() { + return "$name ($nativeName)"; + } } // Uncomment the languages as we add support for them diff --git a/lib/collections/routes.dart b/lib/collections/routes.dart index 3e2c42e0..7b0d836d 100644 --- a/lib/collections/routes.dart +++ b/lib/collections/routes.dart @@ -2,8 +2,10 @@ import 'package:catcher_2/catcher_2.dart'; import 'package:flutter/foundation.dart' hide Category; import 'package:flutter/widgets.dart'; import 'package:go_router/go_router.dart'; +import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:spotify/spotify.dart' hide Search; import 'package:spotube/pages/album/album.dart'; +import 'package:spotube/pages/getting_started/getting_started.dart'; import 'package:spotube/pages/home/genres/genre_playlists.dart'; import 'package:spotube/pages/home/genres/genres.dart'; import 'package:spotube/pages/home/home.dart'; @@ -18,6 +20,8 @@ import 'package:spotube/pages/settings/blacklist.dart'; import 'package:spotube/pages/settings/about.dart'; import 'package:spotube/pages/settings/logs.dart'; import 'package:spotube/pages/track/track.dart'; +import 'package:spotube/provider/authentication_provider.dart'; +import 'package:spotube/services/kv_store/kv_store.dart'; import 'package:spotube/utils/platform.dart'; import 'package:spotube/components/shared/spotube_page_route.dart'; import 'package:spotube/pages/artist/artist.dart'; @@ -31,157 +35,180 @@ import 'package:spotube/pages/mobile_login/mobile_login.dart'; final rootNavigatorKey = Catcher2.navigatorKey; final shellRouteNavigatorKey = GlobalKey(); -final router = GoRouter( - navigatorKey: rootNavigatorKey, - routes: [ - ShellRoute( - navigatorKey: shellRouteNavigatorKey, - builder: (context, state, child) => RootApp(child: child), - routes: [ - GoRoute( - path: "/", - pageBuilder: (context, state) => const SpotubePage(child: HomePage()), - routes: [ - GoRoute( - path: "genres", - pageBuilder: (context, state) => - const SpotubePage(child: GenrePage()), - ), - GoRoute( - path: "genre/:categoryId", - pageBuilder: (context, state) => SpotubePage( - child: GenrePlaylistsPage( - category: state.extra as Category, - ), - ), - ), - ], - ), - GoRoute( - path: "/search", - name: "Search", - pageBuilder: (context, state) => - const SpotubePage(child: SearchPage()), - ), - GoRoute( - path: "/library", - name: "Library", +final routerProvider = Provider((ref) { + return GoRouter( + navigatorKey: rootNavigatorKey, + routes: [ + ShellRoute( + navigatorKey: shellRouteNavigatorKey, + builder: (context, state, child) => RootApp(child: child), + routes: [ + GoRoute( + path: "/", + redirect: (context, state) async { + final authNotifier = + ref.read(AuthenticationNotifier.provider.notifier); + final json = await authNotifier.box.get(authNotifier.cacheKey); + + if (json["cookie"] == null && + !KVStoreService.doneGettingStarted) { + return "/getting-started"; + } + + return null; + }, pageBuilder: (context, state) => - const SpotubePage(child: LibraryPage()), + const SpotubePage(child: HomePage()), routes: [ GoRoute( - path: "generate", - pageBuilder: (context, state) => - const SpotubePage(child: PlaylistGeneratorPage()), - routes: [ - GoRoute( - path: "result", - pageBuilder: (context, state) => SpotubePage( - child: PlaylistGenerateResultPage( - state: - state.extra as PlaylistGenerateResultRouteState, - ), - ), - ), - ]), - ]), - GoRoute( - path: "/lyrics", - name: "Lyrics", - pageBuilder: (context, state) => - const SpotubePage(child: LyricsPage()), - ), - GoRoute( - path: "/settings", - pageBuilder: (context, state) => const SpotubePage( - child: SettingsPage(), - ), - routes: [ - GoRoute( - path: "blacklist", - pageBuilder: (context, state) => SpotubeSlidePage( - child: const BlackListPage(), + path: "genres", + pageBuilder: (context, state) => + const SpotubePage(child: GenrePage()), ), - ), - if (!kIsWeb) GoRoute( - path: "logs", - pageBuilder: (context, state) => SpotubeSlidePage( - child: const LogsPage(), + path: "genre/:categoryId", + pageBuilder: (context, state) => SpotubePage( + child: GenrePlaylistsPage( + category: state.extra as Category, + ), ), ), - GoRoute( - path: "about", - pageBuilder: (context, state) => SpotubeSlidePage( - child: const AboutSpotube(), - ), + ], + ), + GoRoute( + path: "/search", + name: "Search", + pageBuilder: (context, state) => + const SpotubePage(child: SearchPage()), + ), + GoRoute( + path: "/library", + name: "Library", + pageBuilder: (context, state) => + const SpotubePage(child: LibraryPage()), + routes: [ + GoRoute( + path: "generate", + pageBuilder: (context, state) => + const SpotubePage(child: PlaylistGeneratorPage()), + routes: [ + GoRoute( + path: "result", + pageBuilder: (context, state) => SpotubePage( + child: PlaylistGenerateResultPage( + state: + state.extra as PlaylistGenerateResultRouteState, + ), + ), + ), + ]), + ]), + GoRoute( + path: "/lyrics", + name: "Lyrics", + pageBuilder: (context, state) => + const SpotubePage(child: LyricsPage()), + ), + GoRoute( + path: "/settings", + pageBuilder: (context, state) => const SpotubePage( + child: SettingsPage(), ), - ], - ), - GoRoute( - path: "/album/:id", - pageBuilder: (context, state) { - assert(state.extra is AlbumSimple); - return SpotubePage( - child: AlbumPage(album: state.extra as AlbumSimple), - ); - }, - ), - GoRoute( - path: "/artist/:id", - pageBuilder: (context, state) { - assert(state.pathParameters["id"] != null); - return SpotubePage(child: ArtistPage(state.pathParameters["id"]!)); - }, - ), - GoRoute( - path: "/playlist/:id", - pageBuilder: (context, state) { - assert(state.extra is PlaylistSimple); - return SpotubePage( - child: state.pathParameters["id"] == "user-liked-tracks" - ? LikedPlaylistPage(playlist: state.extra as PlaylistSimple) - : PlaylistPage(playlist: state.extra as PlaylistSimple), - ); - }, - ), - GoRoute( - path: "/track/:id", - pageBuilder: (context, state) { - final id = state.pathParameters["id"]!; - return SpotubePage( - child: TrackPage(trackId: id), - ); - }, - ), - ], - ), - GoRoute( - path: "/mini-player", - parentNavigatorKey: rootNavigatorKey, - pageBuilder: (context, state) => SpotubePage( - child: MiniLyricsPage(prevSize: state.extra as Size), + routes: [ + GoRoute( + path: "blacklist", + pageBuilder: (context, state) => SpotubeSlidePage( + child: const BlackListPage(), + ), + ), + if (!kIsWeb) + GoRoute( + path: "logs", + pageBuilder: (context, state) => SpotubeSlidePage( + child: const LogsPage(), + ), + ), + GoRoute( + path: "about", + pageBuilder: (context, state) => SpotubeSlidePage( + child: const AboutSpotube(), + ), + ), + ], + ), + GoRoute( + path: "/album/:id", + pageBuilder: (context, state) { + assert(state.extra is AlbumSimple); + return SpotubePage( + child: AlbumPage(album: state.extra as AlbumSimple), + ); + }, + ), + GoRoute( + path: "/artist/:id", + pageBuilder: (context, state) { + assert(state.pathParameters["id"] != null); + return SpotubePage( + child: ArtistPage(state.pathParameters["id"]!)); + }, + ), + GoRoute( + path: "/playlist/:id", + pageBuilder: (context, state) { + assert(state.extra is PlaylistSimple); + return SpotubePage( + child: state.pathParameters["id"] == "user-liked-tracks" + ? LikedPlaylistPage(playlist: state.extra as PlaylistSimple) + : PlaylistPage(playlist: state.extra as PlaylistSimple), + ); + }, + ), + GoRoute( + path: "/track/:id", + pageBuilder: (context, state) { + final id = state.pathParameters["id"]!; + return SpotubePage( + child: TrackPage(trackId: id), + ); + }, + ), + ], ), - ), - GoRoute( - path: "/login", - parentNavigatorKey: rootNavigatorKey, - pageBuilder: (context, state) => SpotubePage( - child: kIsMobile ? const WebViewLogin() : const DesktopLoginPage(), + GoRoute( + path: "/mini-player", + parentNavigatorKey: rootNavigatorKey, + pageBuilder: (context, state) => SpotubePage( + child: MiniLyricsPage(prevSize: state.extra as Size), + ), ), - ), - GoRoute( - path: "/login-tutorial", - parentNavigatorKey: rootNavigatorKey, - pageBuilder: (context, state) => const SpotubePage( - child: LoginTutorial(), + GoRoute( + path: "/getting-started", + parentNavigatorKey: rootNavigatorKey, + pageBuilder: (context, state) => const SpotubePage( + child: GettingStarting(), + ), ), - ), - GoRoute( - path: "/lastfm-login", - parentNavigatorKey: rootNavigatorKey, - pageBuilder: (context, state) => - const SpotubePage(child: LastFMLoginPage()), - ), - ], -); + GoRoute( + path: "/login", + parentNavigatorKey: rootNavigatorKey, + pageBuilder: (context, state) => SpotubePage( + child: kIsMobile ? const WebViewLogin() : const DesktopLoginPage(), + ), + ), + GoRoute( + path: "/login-tutorial", + parentNavigatorKey: rootNavigatorKey, + pageBuilder: (context, state) => const SpotubePage( + child: LoginTutorial(), + ), + ), + GoRoute( + path: "/lastfm-login", + parentNavigatorKey: rootNavigatorKey, + pageBuilder: (context, state) => + const SpotubePage(child: LastFMLoginPage()), + ), + ], + ); +}); diff --git a/lib/collections/spotube_icons.dart b/lib/collections/spotube_icons.dart index c00643ce..6cf92085 100644 --- a/lib/collections/spotube_icons.dart +++ b/lib/collections/spotube_icons.dart @@ -112,4 +112,7 @@ abstract class SpotubeIcons { static const discord = SimpleIcons.discord; static const youtube = SimpleIcons.youtube; static const radio = FeatherIcons.radio; + static const github = SimpleIcons.github; + static const openCollective = SimpleIcons.opencollective; + static const anonymous = FeatherIcons.user; } diff --git a/lib/components/getting_started/blur_card.dart b/lib/components/getting_started/blur_card.dart new file mode 100644 index 00000000..db887013 --- /dev/null +++ b/lib/components/getting_started/blur_card.dart @@ -0,0 +1,31 @@ +import 'dart:ui'; + +import 'package:flutter/material.dart'; +import 'package:hooks_riverpod/hooks_riverpod.dart'; + +class BlurCard extends HookConsumerWidget { + final Widget child; + const BlurCard({super.key, required this.child}); + + @override + Widget build(BuildContext context, ref) { + return Container( + margin: const EdgeInsets.all(16.0), + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(16), + ), + constraints: const BoxConstraints(maxWidth: 400), + clipBehavior: Clip.antiAlias, + child: SizedBox( + width: double.infinity, + child: BackdropFilter( + filter: ImageFilter.blur(sigmaX: 20, sigmaY: 20), + child: Padding( + padding: const EdgeInsets.all(16.0), + child: child, + ), + ), + ), + ); + } +} diff --git a/lib/hooks/configurators/use_deep_linking.dart b/lib/hooks/configurators/use_deep_linking.dart index 3b7ec3f3..f11a1cff 100644 --- a/lib/hooks/configurators/use_deep_linking.dart +++ b/lib/hooks/configurators/use_deep_linking.dart @@ -19,6 +19,8 @@ void useDeepLinking(WidgetRef ref) { final spotify = ref.watch(spotifyProvider); final queryClient = useQueryClient(); + final router = ref.watch(routerProvider); + useEffect(() { void uriListener(List files) async { for (final file in files) { diff --git a/lib/main.dart b/lib/main.dart index b6afa85c..31c1da57 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -29,6 +29,7 @@ import 'package:spotube/provider/user_preferences/user_preferences_provider.dart import 'package:spotube/services/audio_player/audio_player.dart'; import 'package:spotube/services/cli/cli.dart'; import 'package:spotube/services/connectivity_adapter.dart'; +import 'package:spotube/services/kv_store/kv_store.dart'; import 'package:spotube/themes/theme.dart'; import 'package:spotube/utils/persisted_state_notifier.dart'; import 'package:system_theme/system_theme.dart'; @@ -68,6 +69,9 @@ Future main(List rawArgs) async { DiscordRPC.initialize(); } + await KVStoreService.initialize(); + KVStoreService.doneGettingStarted = false; + final hiveCacheDir = kIsWeb ? null : (await getApplicationSupportDirectory()).path; @@ -184,6 +188,7 @@ class SpotubeState extends ConsumerState { final locale = ref.watch(userPreferencesProvider.select((s) => s.locale)); final paletteColor = ref.watch(paletteProvider.select((s) => s?.dominantColor?.color)); + final router = ref.watch(routerProvider); useDisableBatteryOptimizations(); useInitSysTray(ref); diff --git a/lib/pages/getting_started/getting_started.dart b/lib/pages/getting_started/getting_started.dart new file mode 100644 index 00000000..47cfda03 --- /dev/null +++ b/lib/pages/getting_started/getting_started.dart @@ -0,0 +1,93 @@ +import 'package:flutter/material.dart'; +import 'package:flutter_hooks/flutter_hooks.dart'; +import 'package:hooks_riverpod/hooks_riverpod.dart'; +import 'package:spotube/collections/assets.gen.dart'; +import 'package:spotube/components/shared/page_window_title_bar.dart'; +import 'package:spotube/pages/getting_started/sections/greeting.dart'; +import 'package:spotube/pages/getting_started/sections/playback.dart'; +import 'package:spotube/pages/getting_started/sections/region.dart'; +import 'package:spotube/pages/getting_started/sections/support.dart'; + +class GettingStarting extends HookConsumerWidget { + const GettingStarting({super.key}); + + @override + Widget build(BuildContext context, ref) { + final ThemeData(:colorScheme) = Theme.of(context); + final pageController = usePageController(); + + final onNext = useCallback(() { + pageController.nextPage( + duration: const Duration(milliseconds: 300), + curve: Curves.easeInOut, + ); + }, [pageController]); + + final onPrevious = useCallback(() { + pageController.previousPage( + duration: const Duration(milliseconds: 300), + curve: Curves.easeInOut, + ); + }, [pageController]); + + return Scaffold( + appBar: PageWindowTitleBar( + backgroundColor: Colors.transparent, + actions: [ + ListenableBuilder( + listenable: pageController, + builder: (context, _) { + return AnimatedSwitcher( + duration: const Duration(milliseconds: 300), + child: pageController.hasClients && + (pageController.page == 0 || pageController.page == 3) + ? const SizedBox() + : TextButton( + onPressed: () { + pageController.animateToPage( + 3, + duration: const Duration(milliseconds: 300), + curve: Curves.easeInOut, + ); + }, + child: Text( + "Skip this nonsense", + style: TextStyle( + decoration: TextDecoration.underline, + decorationColor: colorScheme.primary, + ), + ), + ), + ); + }, + ), + ], + ), + extendBodyBehindAppBar: true, + body: DecoratedBox( + decoration: BoxDecoration( + image: DecorationImage( + image: Assets.bengaliPatternsBg.provider(), + fit: BoxFit.cover, + colorFilter: ColorFilter.mode( + colorScheme.background.withOpacity(0.2), + BlendMode.srcOver, + ), + ), + ), + child: PageView( + controller: pageController, + children: [ + GettingStartedPageGreetingSection(onNext: onNext), + GettingStartedPageLanguageRegionSection(onNext: onNext), + GettingStartedPagePlaybackSection( + onNext: onNext, + onPrevious: onPrevious, + ), + const GettingStartedScreenSupportSection(), + ], + ), + ), + ); + } +} diff --git a/lib/pages/getting_started/sections/greeting.dart b/lib/pages/getting_started/sections/greeting.dart new file mode 100644 index 00000000..459500e3 --- /dev/null +++ b/lib/pages/getting_started/sections/greeting.dart @@ -0,0 +1,54 @@ +import 'dart:ui'; + +import 'package:flutter/material.dart'; +import 'package:gap/gap.dart'; +import 'package:hooks_riverpod/hooks_riverpod.dart'; +import 'package:spotube/collections/assets.gen.dart'; +import 'package:spotube/collections/spotube_icons.dart'; +import 'package:spotube/components/getting_started/blur_card.dart'; +import 'package:spotube/utils/platform.dart'; + +class GettingStartedPageGreetingSection extends HookConsumerWidget { + final VoidCallback onNext; + const GettingStartedPageGreetingSection({super.key, required this.onNext}); + + @override + Widget build(BuildContext context, ref) { + final ThemeData(:textTheme) = Theme.of(context); + + return Center( + child: BlurCard( + child: Column( + mainAxisSize: MainAxisSize.min, + children: [ + Assets.spotubeLogoPng.image(height: 200), + const Gap(24), + Text( + "Spotube", + style: + textTheme.titleLarge?.copyWith(fontWeight: FontWeight.bold), + ), + const Gap(4), + Text( + "“Freedom of music${kIsMobile ? "in the palm of your hands" : ""}”", + textAlign: TextAlign.center, + style: textTheme.titleMedium?.copyWith( + fontWeight: FontWeight.w300, + fontStyle: FontStyle.italic, + ), + ), + const Gap(84), + Directionality( + textDirection: TextDirection.rtl, + child: FilledButton.icon( + onPressed: onNext, + icon: const Icon(SpotubeIcons.angleRight), + label: const Text("Let's get started"), + ), + ), + ], + ), + ), + ); + } +} diff --git a/lib/pages/getting_started/sections/playback.dart b/lib/pages/getting_started/sections/playback.dart new file mode 100644 index 00000000..03d11f9b --- /dev/null +++ b/lib/pages/getting_started/sections/playback.dart @@ -0,0 +1,154 @@ +import 'package:flutter/material.dart'; +import 'package:gap/gap.dart'; +import 'package:hooks_riverpod/hooks_riverpod.dart'; +import 'package:spotube/collections/assets.gen.dart'; +import 'package:spotube/collections/spotube_icons.dart'; +import 'package:spotube/components/getting_started/blur_card.dart'; +import 'package:spotube/extensions/context.dart'; +import 'package:spotube/provider/user_preferences/user_preferences_provider.dart'; +import 'package:spotube/provider/user_preferences/user_preferences_state.dart'; + +final audioSourceToIconMap = { + AudioSource.youtube: const Icon( + SpotubeIcons.youtube, + color: Colors.red, + size: 30, + ), + AudioSource.piped: const Icon(SpotubeIcons.piped, size: 30), + AudioSource.jiosaavn: Assets.jiosaavn.image(width: 48, height: 48), +}; + +final audioSourceToDescription = { + AudioSource.youtube: + "Recommended and works best.\nHighest quality: 148kbps mp4, 128kbps opus", + AudioSource.piped: "Feeling free? Same as YouTube but a lot free", + AudioSource.jiosaavn: + "Best for South Asian region.\nHighest quality: 320kbps mp4", +}; + +class GettingStartedPagePlaybackSection extends HookConsumerWidget { + final VoidCallback onNext; + final VoidCallback onPrevious; + + const GettingStartedPagePlaybackSection({ + super.key, + required this.onNext, + required this.onPrevious, + }); + + @override + Widget build(BuildContext context, ref) { + final ThemeData(:textTheme, :colorScheme, :dividerColor) = + Theme.of(context); + final preferences = ref.watch(userPreferencesProvider); + final preferencesNotifier = ref.read(userPreferencesProvider.notifier); + + return Center( + child: BlurCard( + child: Column( + mainAxisSize: MainAxisSize.min, + children: [ + Row( + children: [ + const Icon(SpotubeIcons.album, size: 16), + const Gap(8), + Text(context.l10n.playback, style: textTheme.titleMedium), + ], + ), + const Gap(16), + ListTile( + title: Text("Select Audio Source", style: textTheme.titleMedium), + ), + const Gap(16), + ToggleButtons( + isSelected: [ + for (final source in AudioSource.values) + preferences.audioSource == source, + ], + onPressed: (index) { + preferencesNotifier.setAudioSource(AudioSource.values[index]); + }, + borderRadius: BorderRadius.circular(8), + children: [ + for (final source in AudioSource.values) + SizedBox.square( + dimension: 84, + child: Column( + mainAxisSize: MainAxisSize.min, + mainAxisAlignment: MainAxisAlignment.center, + children: [ + audioSourceToIconMap[source]!, + const Gap(8), + Text( + source.name, + style: textTheme.bodySmall!.copyWith( + color: preferences.audioSource == source + ? colorScheme.primary + : null, + ), + ), + ], + ), + ), + ], + ), + ListTile( + title: Align( + alignment: switch (preferences.audioSource) { + AudioSource.youtube => Alignment.centerLeft, + AudioSource.piped => Alignment.center, + AudioSource.jiosaavn => Alignment.centerRight, + }, + child: Text( + audioSourceToDescription[preferences.audioSource]!, + style: textTheme.bodySmall?.copyWith( + color: dividerColor, + ), + ), + ), + ), + const Gap(16), + ListTile( + title: Text(context.l10n.endless_playback), + subtitle: Text( + "Automatically append new songs\nto the end of the queue", + style: textTheme.bodySmall?.copyWith( + color: dividerColor, + ), + ), + onTap: () { + preferencesNotifier + .setEndlessPlayback(!preferences.endlessPlayback); + }, + trailing: Switch( + value: preferences.endlessPlayback, + onChanged: (value) { + preferencesNotifier.setEndlessPlayback(value); + }, + ), + ), + const Gap(34), + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + FilledButton.icon( + icon: const Icon(SpotubeIcons.angleLeft), + label: Text(context.l10n.previous), + onPressed: onPrevious, + ), + Directionality( + textDirection: TextDirection.rtl, + child: FilledButton.icon( + icon: const Icon(SpotubeIcons.angleRight), + label: Text(context.l10n.next), + onPressed: onNext, + ), + ), + ], + ), + ], + ), + ), + ); + } +} diff --git a/lib/pages/getting_started/sections/region.dart b/lib/pages/getting_started/sections/region.dart new file mode 100644 index 00000000..23885d50 --- /dev/null +++ b/lib/pages/getting_started/sections/region.dart @@ -0,0 +1,129 @@ +import 'package:flutter/material.dart'; +import 'package:gap/gap.dart'; +import 'package:hooks_riverpod/hooks_riverpod.dart'; +import 'package:spotube/collections/language_codes.dart'; +import 'package:spotube/collections/spotify_markets.dart'; +import 'package:spotube/collections/spotube_icons.dart'; +import 'package:spotube/components/getting_started/blur_card.dart'; +import 'package:spotube/extensions/context.dart'; +import 'package:spotube/l10n/l10n.dart'; +import 'package:spotube/provider/user_preferences/user_preferences_provider.dart'; + +class GettingStartedPageLanguageRegionSection extends HookConsumerWidget { + final void Function() onNext; + const GettingStartedPageLanguageRegionSection( + {super.key, required this.onNext}); + + @override + Widget build(BuildContext context, ref) { + final ThemeData(:textTheme, :dividerColor) = Theme.of(context); + final preferences = ref.watch(userPreferencesProvider); + + return SafeArea( + child: Center( + child: BlurCard( + child: Column( + mainAxisSize: MainAxisSize.min, + children: [ + Row( + children: [ + const Icon( + SpotubeIcons.language, + size: 16, + ), + const SizedBox(width: 8), + Text( + "Language and Region", + style: textTheme.titleMedium, + ), + ], + ), + const Gap(48), + Column( + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisSize: MainAxisSize.min, + children: [ + Text( + "Choose your region", + style: textTheme.titleSmall, + ), + Text( + "This will help us show you the right content\nfor your location.", + style: textTheme.bodySmall?.copyWith( + color: dividerColor, + ), + ), + const Gap(16), + DropdownMenu( + initialSelection: preferences.recommendationMarket, + onSelected: (value) { + if (value == null) return; + ref + .read(userPreferencesProvider.notifier) + .setRecommendationMarket(value); + }, + hintText: preferences.recommendationMarket.name, + label: Text(context.l10n.market_place_region), + inputDecorationTheme: + const InputDecorationTheme(isDense: true), + dropdownMenuEntries: [ + for (final market in spotifyMarkets) + DropdownMenuEntry( + value: market.$1, + label: market.$2, + ), + ], + ), + const Gap(36), + Text( + "Choose your language", + style: textTheme.titleSmall, + ), + const Gap(16), + DropdownMenu( + initialSelection: preferences.locale, + onSelected: (locale) { + if (locale == null) return; + ref + .read(userPreferencesProvider.notifier) + .setLocale(locale); + }, + hintText: context.l10n.system_default, + label: Text(context.l10n.language), + inputDecorationTheme: + const InputDecorationTheme(isDense: true), + dropdownMenuEntries: [ + DropdownMenuEntry( + value: const Locale("system", "system"), + label: context.l10n.system_default, + ), + for (final locale in L10n.all) + DropdownMenuEntry( + value: locale, + label: LanguageLocals.getDisplayLanguage( + locale.languageCode) + .toString(), + ), + ], + ), + ], + ), + const Gap(48), + Align( + alignment: Alignment.centerRight, + child: Directionality( + textDirection: TextDirection.rtl, + child: FilledButton.icon( + icon: const Icon(SpotubeIcons.angleRight), + label: Text(context.l10n.next), + onPressed: onNext, + ), + ), + ), + ], + ), + ), + ), + ); + } +} diff --git a/lib/pages/getting_started/sections/support.dart b/lib/pages/getting_started/sections/support.dart new file mode 100644 index 00000000..9b798f56 --- /dev/null +++ b/lib/pages/getting_started/sections/support.dart @@ -0,0 +1,131 @@ +import 'package:flutter/material.dart'; +import 'package:gap/gap.dart'; +import 'package:go_router/go_router.dart'; +import 'package:hooks_riverpod/hooks_riverpod.dart'; +import 'package:spotube/collections/spotube_icons.dart'; +import 'package:spotube/components/getting_started/blur_card.dart'; +import 'package:spotube/services/kv_store/kv_store.dart'; +import 'package:url_launcher/url_launcher_string.dart'; + +class GettingStartedScreenSupportSection extends HookConsumerWidget { + const GettingStartedScreenSupportSection({super.key}); + + @override + Widget build(BuildContext context, ref) { + final ThemeData(:textTheme, :colorScheme) = Theme.of(context); + + return Center( + child: Column( + mainAxisSize: MainAxisSize.min, + children: [ + BlurCard( + child: Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Row( + children: [ + const Icon(SpotubeIcons.heartFilled, color: Colors.pink), + const SizedBox(width: 8), + Text( + "Help this project grow", + style: + textTheme.titleMedium?.copyWith(color: Colors.pink), + ), + ], + ), + const Gap(16), + const Text( + "Spotube is an open-source project. You can help this project grow by contributing to the project, reporting bugs, or suggesting new features.", + ), + const Gap(16), + Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.stretch, + children: [ + FilledButton.icon( + icon: const Icon(SpotubeIcons.github), + label: const Text("Contribute on GitHub"), + style: FilledButton.styleFrom( + backgroundColor: Colors.black, + foregroundColor: Colors.white, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(8), + ), + ), + onPressed: () async { + await launchUrlString( + "https://github.com/KRTirtho/spotube", + mode: LaunchMode.externalApplication, + ); + }, + ), + const Gap(16), + FilledButton.icon( + icon: const Icon(SpotubeIcons.openCollective), + label: const Text("Donate on Open Collective"), + style: FilledButton.styleFrom( + backgroundColor: const Color(0xff4cb7f6), + foregroundColor: Colors.white, + ), + onPressed: () async { + await launchUrlString( + "https://opencollective.com/spotube", + mode: LaunchMode.externalApplication, + ); + }, + ), + ], + ), + ], + ), + ), + const Gap(48), + ConstrainedBox( + constraints: const BoxConstraints(maxWidth: 250), + child: Column( + crossAxisAlignment: CrossAxisAlignment.stretch, + children: [ + DecoratedBox( + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(8), + gradient: LinearGradient( + colors: [ + colorScheme.primary, + colorScheme.secondary, + ], + ), + ), + child: TextButton.icon( + icon: const Icon(SpotubeIcons.anonymous), + label: const Text("Browse anonymously"), + style: TextButton.styleFrom( + foregroundColor: Colors.white, + ), + onPressed: () { + KVStoreService.doneGettingStarted = true; + context.go("/"); + }, + ), + ), + const Gap(16), + FilledButton.icon( + icon: const Icon(SpotubeIcons.spotify), + label: const Text("Connect Spotify Account"), + style: FilledButton.styleFrom( + backgroundColor: const Color(0xff1db954), + foregroundColor: Colors.white, + ), + onPressed: () { + KVStoreService.doneGettingStarted = true; + context.push("/login"); + }, + ), + ], + ), + ), + ], + ), + ); + } +} diff --git a/lib/pages/settings/sections/appearance.dart b/lib/pages/settings/sections/appearance.dart index 5de36c63..3d941212 100644 --- a/lib/pages/settings/sections/appearance.dart +++ b/lib/pages/settings/sections/appearance.dart @@ -1,5 +1,6 @@ import 'package:flutter/material.dart'; import 'package:flutter_hooks/flutter_hooks.dart'; +import 'package:gap/gap.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:spotube/collections/spotube_icons.dart'; import 'package:spotube/components/settings/color_scheme_picker_dialog.dart'; @@ -10,7 +11,11 @@ import 'package:spotube/provider/user_preferences/user_preferences_provider.dart import 'package:spotube/provider/user_preferences/user_preferences_state.dart'; class SettingsAppearanceSection extends HookConsumerWidget { - const SettingsAppearanceSection({Key? key}) : super(key: key); + final bool isGettingStarted; + const SettingsAppearanceSection({ + Key? key, + this.isGettingStarted = false, + }) : super(key: key); @override Widget build(BuildContext context, ref) { @@ -24,87 +29,101 @@ class SettingsAppearanceSection extends HookConsumerWidget { }); }, []); + final children = [ + AdaptiveSelectTile( + secondary: const Icon(SpotubeIcons.dashboard), + title: Text(context.l10n.layout_mode), + subtitle: Text(context.l10n.override_layout_settings), + value: preferences.layoutMode, + onChanged: (value) { + if (value != null) { + preferencesNotifier.setLayoutMode(value); + } + }, + options: [ + DropdownMenuItem( + value: LayoutMode.adaptive, + child: Text(context.l10n.adaptive), + ), + DropdownMenuItem( + value: LayoutMode.compact, + child: Text(context.l10n.compact), + ), + DropdownMenuItem( + value: LayoutMode.extended, + child: Text(context.l10n.extended), + ), + ], + ), + AdaptiveSelectTile( + secondary: const Icon(SpotubeIcons.darkMode), + title: Text(context.l10n.theme), + value: preferences.themeMode, + options: [ + DropdownMenuItem( + value: ThemeMode.dark, + child: Text(context.l10n.dark), + ), + DropdownMenuItem( + value: ThemeMode.light, + child: Text(context.l10n.light), + ), + DropdownMenuItem( + value: ThemeMode.system, + child: Text(context.l10n.system), + ), + ], + onChanged: (value) { + if (value != null) { + preferencesNotifier.setThemeMode(value); + } + }, + ), + SwitchListTile( + secondary: const Icon(SpotubeIcons.amoled), + title: Text(context.l10n.use_amoled_mode), + subtitle: Text(context.l10n.pitch_dark_theme), + value: preferences.amoledDarkTheme, + onChanged: preferencesNotifier.setAmoledDarkTheme, + ), + ListTile( + leading: const Icon(SpotubeIcons.palette), + title: Text(context.l10n.accent_color), + contentPadding: const EdgeInsets.symmetric( + horizontal: 15, + vertical: 5, + ), + trailing: ColorTile.compact( + color: preferences.accentColorScheme, + onPressed: pickColorScheme(), + isActive: true, + ), + onTap: pickColorScheme(), + ), + SwitchListTile( + secondary: const Icon(SpotubeIcons.colorSync), + title: Text(context.l10n.sync_album_color), + subtitle: Text(context.l10n.sync_album_color_description), + value: preferences.albumColorSync, + onChanged: preferencesNotifier.setAlbumColorSync, + ), + ]; + + if (isGettingStarted) { + return Column( + mainAxisSize: MainAxisSize.min, + children: [ + for (final child in children) ...[ + child, + const Gap(16), + ], + ], + ); + } + return SectionCardWithHeading( heading: context.l10n.appearance, - children: [ - AdaptiveSelectTile( - secondary: const Icon(SpotubeIcons.dashboard), - title: Text(context.l10n.layout_mode), - subtitle: Text(context.l10n.override_layout_settings), - value: preferences.layoutMode, - onChanged: (value) { - if (value != null) { - preferencesNotifier.setLayoutMode(value); - } - }, - options: [ - DropdownMenuItem( - value: LayoutMode.adaptive, - child: Text(context.l10n.adaptive), - ), - DropdownMenuItem( - value: LayoutMode.compact, - child: Text(context.l10n.compact), - ), - DropdownMenuItem( - value: LayoutMode.extended, - child: Text(context.l10n.extended), - ), - ], - ), - AdaptiveSelectTile( - secondary: const Icon(SpotubeIcons.darkMode), - title: Text(context.l10n.theme), - value: preferences.themeMode, - options: [ - DropdownMenuItem( - value: ThemeMode.dark, - child: Text(context.l10n.dark), - ), - DropdownMenuItem( - value: ThemeMode.light, - child: Text(context.l10n.light), - ), - DropdownMenuItem( - value: ThemeMode.system, - child: Text(context.l10n.system), - ), - ], - onChanged: (value) { - if (value != null) { - preferencesNotifier.setThemeMode(value); - } - }, - ), - SwitchListTile( - secondary: const Icon(SpotubeIcons.amoled), - title: Text(context.l10n.use_amoled_mode), - subtitle: Text(context.l10n.pitch_dark_theme), - value: preferences.amoledDarkTheme, - onChanged: preferencesNotifier.setAmoledDarkTheme, - ), - ListTile( - leading: const Icon(SpotubeIcons.palette), - title: Text(context.l10n.accent_color), - contentPadding: const EdgeInsets.symmetric( - horizontal: 15, - vertical: 5, - ), - trailing: ColorTile.compact( - color: preferences.accentColorScheme, - onPressed: pickColorScheme(), - isActive: true, - ), - onTap: pickColorScheme(), - ), - SwitchListTile( - secondary: const Icon(SpotubeIcons.colorSync), - title: Text(context.l10n.sync_album_color), - subtitle: Text(context.l10n.sync_album_color_description), - value: preferences.albumColorSync, - onChanged: preferencesNotifier.setAlbumColorSync, - ), - ], + children: children, ); } } diff --git a/lib/services/kv_store/kv_store.dart b/lib/services/kv_store/kv_store.dart new file mode 100644 index 00000000..6f6807e0 --- /dev/null +++ b/lib/services/kv_store/kv_store.dart @@ -0,0 +1,15 @@ +import 'package:shared_preferences/shared_preferences.dart'; + +abstract class KVStoreService { + static SharedPreferences? _sharedPreferences; + static SharedPreferences get sharedPreferences => _sharedPreferences!; + + static Future initialize() async { + _sharedPreferences = await SharedPreferences.getInstance(); + } + + static bool get doneGettingStarted => + sharedPreferences.getBool('doneGettingStarted') ?? false; + static set doneGettingStarted(bool value) => + sharedPreferences.setBool('doneGettingStarted', value); +} diff --git a/lib/utils/persisted_state_notifier.dart b/lib/utils/persisted_state_notifier.dart index 218cd64a..60f7b96e 100644 --- a/lib/utils/persisted_state_notifier.dart +++ b/lib/utils/persisted_state_notifier.dart @@ -119,7 +119,9 @@ abstract class PersistedStateNotifier extends StateNotifier { Future _load() async { final json = await box.get(cacheKey); - if (json != null) { + if (json != null || + (json is Map && json.entries.isNotEmpty) || + (json is List && json.isNotEmpty)) { state = await fromJson(castNestedJson(json)); } } From a850ed270b9412a69fb4717cc0ce6368e59e1c65 Mon Sep 17 00:00:00 2001 From: Kingkor Roy Tirtho Date: Sun, 25 Feb 2024 22:06:47 +0600 Subject: [PATCH 158/195] chore: add error handling in song link --- lib/services/song_link/song_link.dart | 55 +++++++++++++++------------ 1 file changed, 31 insertions(+), 24 deletions(-) diff --git a/lib/services/song_link/song_link.dart b/lib/services/song_link/song_link.dart index c3d73f23..b02f60cb 100644 --- a/lib/services/song_link/song_link.dart +++ b/lib/services/song_link/song_link.dart @@ -2,6 +2,7 @@ library song_link; import 'dart:convert'; +import 'package:catcher_2/catcher_2.dart'; import 'package:dio/dio.dart'; import 'package:freezed_annotation/freezed_annotation.dart'; import 'package:html/parser.dart'; @@ -12,36 +13,42 @@ part 'song_link.freezed.dart'; part 'song_link.g.dart'; abstract class SongLinkService { + static final dio = Dio(); static Future> links(String spotifyId) async { - final dio = Dio(); + try { + final res = await dio.get( + "https://song.link/s/$spotifyId", + options: Options( + headers: { + "Accept": + "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8", + "User-Agent": + "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/122.0.0.0 Safari/537.36" + }, + responseType: ResponseType.plain, + ), + ); - final res = await dio.get( - "https://song.link/s/$spotifyId", - options: Options( - headers: { - "Accept": - "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8", - "User-Agent": - "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/122.0.0.0 Safari/537.36" - }, - responseType: ResponseType.plain, - ), - ); + final document = parse(res.data); - final document = parse(res.data); + final script = document.getElementById("__NEXT_DATA__")?.text; - final script = document.getElementById("__NEXT_DATA__")?.text; + if (script == null) { + return []; + } - if (script == null) { + final pageProps = jsonDecode(script) as Map; + final songLinks = pageProps["props"]?["pageProps"]?["pageData"] + ?["sections"] + ?.firstWhere( + (section) => section?["sectionId"] == "section|auto|links|listen", + )?["links"] as List?; + + return songLinks?.map((link) => SongLink.fromJson(link)).toList() ?? + []; + } catch (e, stackTrace) { + Catcher2.reportCheckedError(e, stackTrace); return []; } - - final pageProps = jsonDecode(script) as Map; - final songLinks = - pageProps["props"]["pageProps"]["pageData"]["sections"].firstWhere( - (section) => section["sectionId"] == "section|auto|links|listen", - )["links"] as List; - - return songLinks.map((link) => SongLink.fromJson(link)).toList(); } } From 17105a640bf5107bd5d333b9b4d097c14a3949a2 Mon Sep 17 00:00:00 2001 From: olivier2 Date: Sun, 25 Feb 2024 11:26:06 -0500 Subject: [PATCH 159/195] fix(android): audio issue when screen is off and broadcast audio session id (#1221 & #1247) * this change fixes the garbled audio on my Pixel 6a while the screen is off. Not familiar with libmpv, but seems to favor audiotrack audio output over opensles. KRTirtho/spotube#571 * get audio session id, send it to AudioTrack in libmpv, broadcast it to other apps. Fixes KRTirtho/spotube#1221 --------- Co-authored-by: Kingkor Roy Tirtho --- .../audio_player/mk_state_player.dart | 46 ++++++++++++++++++- pubspec.yaml | 1 + 2 files changed, 45 insertions(+), 2 deletions(-) diff --git a/lib/services/audio_player/mk_state_player.dart b/lib/services/audio_player/mk_state_player.dart index a556afec..04df7111 100644 --- a/lib/services/audio_player/mk_state_player.dart +++ b/lib/services/audio_player/mk_state_player.dart @@ -1,8 +1,11 @@ import 'dart:async'; - +import 'package:flutter_desktop_tools/flutter_desktop_tools.dart'; import 'package:catcher_2/catcher_2.dart'; import 'package:collection/collection.dart'; import 'package:media_kit/media_kit.dart'; +import 'package:flutter_broadcasts/flutter_broadcasts.dart'; +import 'package:package_info_plus/package_info_plus.dart'; +import 'package:audio_session/audio_session.dart'; // ignore: implementation_imports import 'package:spotube/services/audio_player/playback_state.dart'; @@ -14,6 +17,13 @@ class MkPlayerWithState extends Player { final StreamController _shuffleStream; final StreamController _loopModeStream; + static const String EXTRA_PACKAGE_NAME = "android.media.extra.PACKAGE_NAME"; + static const String EXTRA_AUDIO_SESSION = "android.media.extra.AUDIO_SESSION"; + static const String ACTION_OPEN_AUDIO_EFFECT_CONTROL_SESSION = + "android.media.action.OPEN_AUDIO_EFFECT_CONTROL_SESSION"; + static const String ACTION_CLOSE_AUDIO_EFFECT_CONTROL_SESSION = + "android.media.action.CLOSE_AUDIO_EFFECT_CONTROL_SESSION"; + late final List _subscriptions; bool _shuffled; @@ -21,6 +31,9 @@ class MkPlayerWithState extends Player { Playlist? _playlist; List? _tempMedias; + int _androidAudioSessionId = 0; + String _packageName = ""; + AndroidAudioManager? _androidAudioManager; MkPlayerWithState({super.configuration}) : _playerStateStream = StreamController.broadcast(), @@ -64,6 +77,34 @@ class MkPlayerWithState extends Player { Catcher2.reportCheckedError('[MediaKitError] \n$event', null); }), ]; + PackageInfo.fromPlatform().then((packageInfo) { + _packageName = packageInfo.packageName; + }); + if (DesktopTools.platform.isAndroid) { + _androidAudioManager = AndroidAudioManager(); + AudioSession.instance.then((s) async { + _androidAudioSessionId = + await _androidAudioManager!.generateAudioSessionId(); + notifyAudioSessionUpdate(true); + + nativePlayer.setProperty( + "audiotrack-session-id", _androidAudioSessionId.toString()); + nativePlayer.setProperty("ao", "audiotrack,opensles,"); + }); + } + } + + Future notifyAudioSessionUpdate(bool active) async { + if (DesktopTools.platform.isAndroid) { + sendBroadcast(BroadcastMessage( + name: active + ? ACTION_OPEN_AUDIO_EFFECT_CONTROL_SESSION + : ACTION_CLOSE_AUDIO_EFFECT_CONTROL_SESSION, + data: { + EXTRA_AUDIO_SESSION: _androidAudioSessionId, + EXTRA_PACKAGE_NAME: _packageName + })); + } } bool get shuffled => _shuffled; @@ -140,10 +181,11 @@ class MkPlayerWithState extends Player { } @override - Future dispose() { + Future dispose() async { for (var element in _subscriptions) { element.cancel(); } + await notifyAudioSessionUpdate(false); return super.dispose(); } diff --git a/pubspec.yaml b/pubspec.yaml index 9bacf6dd..53da7ba7 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -124,6 +124,7 @@ dependencies: app_links: ^3.5.0 win32_registry: ^1.1.2 flutter_sharing_intent: ^1.1.0 + flutter_broadcasts: ^0.4.0 freezed_annotation: ^2.4.1 dev_dependencies: From 4d6af8c0a7c685840b5c28ff95a0f4aec4b9e0c3 Mon Sep 17 00:00:00 2001 From: Kingkor Roy Tirtho Date: Sun, 25 Feb 2024 22:48:27 +0600 Subject: [PATCH 160/195] chore: add translations for getting started screen --- lib/l10n/app_en.arb | 20 +- .../getting_started/getting_started.dart | 3 +- .../getting_started/sections/greeting.dart | 9 +- .../getting_started/sections/playback.dart | 27 +- .../getting_started/sections/region.dart | 8 +- .../getting_started/sections/support.dart | 15 +- untranslated_messages.json | 360 +++++++++++++++++- 7 files changed, 396 insertions(+), 46 deletions(-) diff --git a/lib/l10n/app_en.arb b/lib/l10n/app_en.arb index 6b684d48..8257eac9 100644 --- a/lib/l10n/app_en.arb +++ b/lib/l10n/app_en.arb @@ -295,5 +295,23 @@ "delete_playlist": "Delete Playlist", "delete_playlist_confirmation": "Are you sure you want to delete this playlist?", "local_tracks": "Local Tracks", - "song_link": "Song Link" + "song_link": "Song Link", + "skip_this_nonsense": "Skip this nonsense", + "freedom_of_music": "“Freedom of Music”", + "freedom_of_music_palm": "“Freedom of Music in the palm of your hand”", + "get_started": "Let's get started", + "youtube_source_description": "Recommended and works best.", + "piped_source_description": "Feeling free? Same as YouTube but a lot free.", + "jiosaavn_source_description": "Best for South Asian region.", + "highest_quality": "Highest Quality: {quality}", + "select_audio_source": "Select Audio Source", + "endless_playback_description": "Automatically append new songs\nto the end of the queue", + "choose_your_region": "Choose your region", + "choose_your_region_description": "This will help Spotube show you the right content\nfor your location.", + "choose_your_language": "Choose your language", + "help_project_grow": "Help this project grow", + "help_project_grow_description": "Spotube is an open-source project. You can help this project grow by contributing to the project, reporting bugs, or suggesting new features.", + "contribute_on_github": "Contribute on GitHub", + "donate_on_open_collective": "Donate on Open Collective", + "browse_anonymously": "Browse Anonymously" } \ No newline at end of file diff --git a/lib/pages/getting_started/getting_started.dart b/lib/pages/getting_started/getting_started.dart index 47cfda03..724fb346 100644 --- a/lib/pages/getting_started/getting_started.dart +++ b/lib/pages/getting_started/getting_started.dart @@ -3,6 +3,7 @@ import 'package:flutter_hooks/flutter_hooks.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:spotube/collections/assets.gen.dart'; import 'package:spotube/components/shared/page_window_title_bar.dart'; +import 'package:spotube/extensions/context.dart'; import 'package:spotube/pages/getting_started/sections/greeting.dart'; import 'package:spotube/pages/getting_started/sections/playback.dart'; import 'package:spotube/pages/getting_started/sections/region.dart'; @@ -51,7 +52,7 @@ class GettingStarting extends HookConsumerWidget { ); }, child: Text( - "Skip this nonsense", + context.l10n.skip_this_nonsense, style: TextStyle( decoration: TextDecoration.underline, decorationColor: colorScheme.primary, diff --git a/lib/pages/getting_started/sections/greeting.dart b/lib/pages/getting_started/sections/greeting.dart index 459500e3..563e43de 100644 --- a/lib/pages/getting_started/sections/greeting.dart +++ b/lib/pages/getting_started/sections/greeting.dart @@ -1,11 +1,10 @@ -import 'dart:ui'; - import 'package:flutter/material.dart'; import 'package:gap/gap.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:spotube/collections/assets.gen.dart'; import 'package:spotube/collections/spotube_icons.dart'; import 'package:spotube/components/getting_started/blur_card.dart'; +import 'package:spotube/extensions/context.dart'; import 'package:spotube/utils/platform.dart'; class GettingStartedPageGreetingSection extends HookConsumerWidget { @@ -30,7 +29,9 @@ class GettingStartedPageGreetingSection extends HookConsumerWidget { ), const Gap(4), Text( - "“Freedom of music${kIsMobile ? "in the palm of your hands" : ""}”", + kIsMobile + ? context.l10n.freedom_of_music_palm + : context.l10n.freedom_of_music, textAlign: TextAlign.center, style: textTheme.titleMedium?.copyWith( fontWeight: FontWeight.w300, @@ -43,7 +44,7 @@ class GettingStartedPageGreetingSection extends HookConsumerWidget { child: FilledButton.icon( onPressed: onNext, icon: const Icon(SpotubeIcons.angleRight), - label: const Text("Let's get started"), + label: Text(context.l10n.get_started), ), ), ], diff --git a/lib/pages/getting_started/sections/playback.dart b/lib/pages/getting_started/sections/playback.dart index 03d11f9b..e94a06cc 100644 --- a/lib/pages/getting_started/sections/playback.dart +++ b/lib/pages/getting_started/sections/playback.dart @@ -1,4 +1,5 @@ import 'package:flutter/material.dart'; +import 'package:flutter_hooks/flutter_hooks.dart'; import 'package:gap/gap.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:spotube/collections/assets.gen.dart'; @@ -18,14 +19,6 @@ final audioSourceToIconMap = { AudioSource.jiosaavn: Assets.jiosaavn.image(width: 48, height: 48), }; -final audioSourceToDescription = { - AudioSource.youtube: - "Recommended and works best.\nHighest quality: 148kbps mp4, 128kbps opus", - AudioSource.piped: "Feeling free? Same as YouTube but a lot free", - AudioSource.jiosaavn: - "Best for South Asian region.\nHighest quality: 320kbps mp4", -}; - class GettingStartedPagePlaybackSection extends HookConsumerWidget { final VoidCallback onNext; final VoidCallback onPrevious; @@ -43,6 +36,17 @@ class GettingStartedPagePlaybackSection extends HookConsumerWidget { final preferences = ref.watch(userPreferencesProvider); final preferencesNotifier = ref.read(userPreferencesProvider.notifier); + final audioSourceToDescription = useMemoized( + () => { + AudioSource.youtube: "${context.l10n.youtube_source_description}\n" + "${context.l10n.highest_quality("148kbps mp4, 128kbps opus")}", + AudioSource.piped: context.l10n.piped_source_description, + AudioSource.jiosaavn: + "${context.l10n.jiosaavn_source_description}\n" + "${context.l10n.highest_quality("320kbps mp")}", + }, + []); + return Center( child: BlurCard( child: Column( @@ -57,7 +61,10 @@ class GettingStartedPagePlaybackSection extends HookConsumerWidget { ), const Gap(16), ListTile( - title: Text("Select Audio Source", style: textTheme.titleMedium), + title: Text( + context.l10n.select_audio_source, + style: textTheme.titleMedium, + ), ), const Gap(16), ToggleButtons( @@ -111,7 +118,7 @@ class GettingStartedPagePlaybackSection extends HookConsumerWidget { ListTile( title: Text(context.l10n.endless_playback), subtitle: Text( - "Automatically append new songs\nto the end of the queue", + context.l10n.endless_playback_description, style: textTheme.bodySmall?.copyWith( color: dividerColor, ), diff --git a/lib/pages/getting_started/sections/region.dart b/lib/pages/getting_started/sections/region.dart index 23885d50..9303392c 100644 --- a/lib/pages/getting_started/sections/region.dart +++ b/lib/pages/getting_started/sections/region.dart @@ -33,7 +33,7 @@ class GettingStartedPageLanguageRegionSection extends HookConsumerWidget { ), const SizedBox(width: 8), Text( - "Language and Region", + context.l10n.language_region, style: textTheme.titleMedium, ), ], @@ -44,11 +44,11 @@ class GettingStartedPageLanguageRegionSection extends HookConsumerWidget { mainAxisSize: MainAxisSize.min, children: [ Text( - "Choose your region", + context.l10n.choose_your_region, style: textTheme.titleSmall, ), Text( - "This will help us show you the right content\nfor your location.", + context.l10n.choose_your_region_description, style: textTheme.bodySmall?.copyWith( color: dividerColor, ), @@ -76,7 +76,7 @@ class GettingStartedPageLanguageRegionSection extends HookConsumerWidget { ), const Gap(36), Text( - "Choose your language", + context.l10n.choose_your_language, style: textTheme.titleSmall, ), const Gap(16), diff --git a/lib/pages/getting_started/sections/support.dart b/lib/pages/getting_started/sections/support.dart index 9b798f56..1be7ca34 100644 --- a/lib/pages/getting_started/sections/support.dart +++ b/lib/pages/getting_started/sections/support.dart @@ -4,6 +4,7 @@ import 'package:go_router/go_router.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:spotube/collections/spotube_icons.dart'; import 'package:spotube/components/getting_started/blur_card.dart'; +import 'package:spotube/extensions/context.dart'; import 'package:spotube/services/kv_store/kv_store.dart'; import 'package:url_launcher/url_launcher_string.dart'; @@ -28,16 +29,14 @@ class GettingStartedScreenSupportSection extends HookConsumerWidget { const Icon(SpotubeIcons.heartFilled, color: Colors.pink), const SizedBox(width: 8), Text( - "Help this project grow", + context.l10n.help_project_grow, style: textTheme.titleMedium?.copyWith(color: Colors.pink), ), ], ), const Gap(16), - const Text( - "Spotube is an open-source project. You can help this project grow by contributing to the project, reporting bugs, or suggesting new features.", - ), + Text(context.l10n.help_project_grow_description), const Gap(16), Column( mainAxisSize: MainAxisSize.min, @@ -45,7 +44,7 @@ class GettingStartedScreenSupportSection extends HookConsumerWidget { children: [ FilledButton.icon( icon: const Icon(SpotubeIcons.github), - label: const Text("Contribute on GitHub"), + label: Text(context.l10n.contribute_on_github), style: FilledButton.styleFrom( backgroundColor: Colors.black, foregroundColor: Colors.white, @@ -63,7 +62,7 @@ class GettingStartedScreenSupportSection extends HookConsumerWidget { const Gap(16), FilledButton.icon( icon: const Icon(SpotubeIcons.openCollective), - label: const Text("Donate on Open Collective"), + label: Text(context.l10n.donate_on_open_collective), style: FilledButton.styleFrom( backgroundColor: const Color(0xff4cb7f6), foregroundColor: Colors.white, @@ -98,7 +97,7 @@ class GettingStartedScreenSupportSection extends HookConsumerWidget { ), child: TextButton.icon( icon: const Icon(SpotubeIcons.anonymous), - label: const Text("Browse anonymously"), + label: Text(context.l10n.browse_anonymously), style: TextButton.styleFrom( foregroundColor: Colors.white, ), @@ -111,7 +110,7 @@ class GettingStartedScreenSupportSection extends HookConsumerWidget { const Gap(16), FilledButton.icon( icon: const Icon(SpotubeIcons.spotify), - label: const Text("Connect Spotify Account"), + label: Text(context.l10n.connect_with_spotify), style: FilledButton.styleFrom( backgroundColor: const Color(0xff1db954), foregroundColor: Colors.white, diff --git a/untranslated_messages.json b/untranslated_messages.json index cc14528c..3ff7a2f1 100644 --- a/untranslated_messages.json +++ b/untranslated_messages.json @@ -8,7 +8,25 @@ "delete_playlist", "delete_playlist_confirmation", "local_tracks", - "song_link" + "song_link", + "skip_this_nonsense", + "freedom_of_music", + "freedom_of_music_palm", + "get_started", + "youtube_source_description", + "piped_source_description", + "jiosaavn_source_description", + "highest_quality", + "select_audio_source", + "endless_playback_description", + "choose_your_region", + "choose_your_region_description", + "choose_your_language", + "help_project_grow", + "help_project_grow_description", + "contribute_on_github", + "donate_on_open_collective", + "browse_anonymously" ], "bn": [ @@ -20,7 +38,25 @@ "delete_playlist", "delete_playlist_confirmation", "local_tracks", - "song_link" + "song_link", + "skip_this_nonsense", + "freedom_of_music", + "freedom_of_music_palm", + "get_started", + "youtube_source_description", + "piped_source_description", + "jiosaavn_source_description", + "highest_quality", + "select_audio_source", + "endless_playback_description", + "choose_your_region", + "choose_your_region_description", + "choose_your_language", + "help_project_grow", + "help_project_grow_description", + "contribute_on_github", + "donate_on_open_collective", + "browse_anonymously" ], "ca": [ @@ -32,7 +68,25 @@ "delete_playlist", "delete_playlist_confirmation", "local_tracks", - "song_link" + "song_link", + "skip_this_nonsense", + "freedom_of_music", + "freedom_of_music_palm", + "get_started", + "youtube_source_description", + "piped_source_description", + "jiosaavn_source_description", + "highest_quality", + "select_audio_source", + "endless_playback_description", + "choose_your_region", + "choose_your_region_description", + "choose_your_language", + "help_project_grow", + "help_project_grow_description", + "contribute_on_github", + "donate_on_open_collective", + "browse_anonymously" ], "de": [ @@ -44,7 +98,25 @@ "delete_playlist", "delete_playlist_confirmation", "local_tracks", - "song_link" + "song_link", + "skip_this_nonsense", + "freedom_of_music", + "freedom_of_music_palm", + "get_started", + "youtube_source_description", + "piped_source_description", + "jiosaavn_source_description", + "highest_quality", + "select_audio_source", + "endless_playback_description", + "choose_your_region", + "choose_your_region_description", + "choose_your_language", + "help_project_grow", + "help_project_grow_description", + "contribute_on_github", + "donate_on_open_collective", + "browse_anonymously" ], "es": [ @@ -56,7 +128,25 @@ "delete_playlist", "delete_playlist_confirmation", "local_tracks", - "song_link" + "song_link", + "skip_this_nonsense", + "freedom_of_music", + "freedom_of_music_palm", + "get_started", + "youtube_source_description", + "piped_source_description", + "jiosaavn_source_description", + "highest_quality", + "select_audio_source", + "endless_playback_description", + "choose_your_region", + "choose_your_region_description", + "choose_your_language", + "help_project_grow", + "help_project_grow_description", + "contribute_on_github", + "donate_on_open_collective", + "browse_anonymously" ], "fa": [ @@ -68,7 +158,25 @@ "delete_playlist", "delete_playlist_confirmation", "local_tracks", - "song_link" + "song_link", + "skip_this_nonsense", + "freedom_of_music", + "freedom_of_music_palm", + "get_started", + "youtube_source_description", + "piped_source_description", + "jiosaavn_source_description", + "highest_quality", + "select_audio_source", + "endless_playback_description", + "choose_your_region", + "choose_your_region_description", + "choose_your_language", + "help_project_grow", + "help_project_grow_description", + "contribute_on_github", + "donate_on_open_collective", + "browse_anonymously" ], "fr": [ @@ -80,7 +188,25 @@ "delete_playlist", "delete_playlist_confirmation", "local_tracks", - "song_link" + "song_link", + "skip_this_nonsense", + "freedom_of_music", + "freedom_of_music_palm", + "get_started", + "youtube_source_description", + "piped_source_description", + "jiosaavn_source_description", + "highest_quality", + "select_audio_source", + "endless_playback_description", + "choose_your_region", + "choose_your_region_description", + "choose_your_language", + "help_project_grow", + "help_project_grow_description", + "contribute_on_github", + "donate_on_open_collective", + "browse_anonymously" ], "hi": [ @@ -92,7 +218,25 @@ "delete_playlist", "delete_playlist_confirmation", "local_tracks", - "song_link" + "song_link", + "skip_this_nonsense", + "freedom_of_music", + "freedom_of_music_palm", + "get_started", + "youtube_source_description", + "piped_source_description", + "jiosaavn_source_description", + "highest_quality", + "select_audio_source", + "endless_playback_description", + "choose_your_region", + "choose_your_region_description", + "choose_your_language", + "help_project_grow", + "help_project_grow_description", + "contribute_on_github", + "donate_on_open_collective", + "browse_anonymously" ], "it": [ @@ -104,7 +248,25 @@ "delete_playlist", "delete_playlist_confirmation", "local_tracks", - "song_link" + "song_link", + "skip_this_nonsense", + "freedom_of_music", + "freedom_of_music_palm", + "get_started", + "youtube_source_description", + "piped_source_description", + "jiosaavn_source_description", + "highest_quality", + "select_audio_source", + "endless_playback_description", + "choose_your_region", + "choose_your_region_description", + "choose_your_language", + "help_project_grow", + "help_project_grow_description", + "contribute_on_github", + "donate_on_open_collective", + "browse_anonymously" ], "ja": [ @@ -116,7 +278,25 @@ "delete_playlist", "delete_playlist_confirmation", "local_tracks", - "song_link" + "song_link", + "skip_this_nonsense", + "freedom_of_music", + "freedom_of_music_palm", + "get_started", + "youtube_source_description", + "piped_source_description", + "jiosaavn_source_description", + "highest_quality", + "select_audio_source", + "endless_playback_description", + "choose_your_region", + "choose_your_region_description", + "choose_your_language", + "help_project_grow", + "help_project_grow_description", + "contribute_on_github", + "donate_on_open_collective", + "browse_anonymously" ], "ne": [ @@ -128,7 +308,25 @@ "delete_playlist", "delete_playlist_confirmation", "local_tracks", - "song_link" + "song_link", + "skip_this_nonsense", + "freedom_of_music", + "freedom_of_music_palm", + "get_started", + "youtube_source_description", + "piped_source_description", + "jiosaavn_source_description", + "highest_quality", + "select_audio_source", + "endless_playback_description", + "choose_your_region", + "choose_your_region_description", + "choose_your_language", + "help_project_grow", + "help_project_grow_description", + "contribute_on_github", + "donate_on_open_collective", + "browse_anonymously" ], "nl": [ @@ -141,7 +339,25 @@ "delete_playlist", "delete_playlist_confirmation", "local_tracks", - "song_link" + "song_link", + "skip_this_nonsense", + "freedom_of_music", + "freedom_of_music_palm", + "get_started", + "youtube_source_description", + "piped_source_description", + "jiosaavn_source_description", + "highest_quality", + "select_audio_source", + "endless_playback_description", + "choose_your_region", + "choose_your_region_description", + "choose_your_language", + "help_project_grow", + "help_project_grow_description", + "contribute_on_github", + "donate_on_open_collective", + "browse_anonymously" ], "pl": [ @@ -153,7 +369,25 @@ "delete_playlist", "delete_playlist_confirmation", "local_tracks", - "song_link" + "song_link", + "skip_this_nonsense", + "freedom_of_music", + "freedom_of_music_palm", + "get_started", + "youtube_source_description", + "piped_source_description", + "jiosaavn_source_description", + "highest_quality", + "select_audio_source", + "endless_playback_description", + "choose_your_region", + "choose_your_region_description", + "choose_your_language", + "help_project_grow", + "help_project_grow_description", + "contribute_on_github", + "donate_on_open_collective", + "browse_anonymously" ], "pt": [ @@ -165,7 +399,25 @@ "delete_playlist", "delete_playlist_confirmation", "local_tracks", - "song_link" + "song_link", + "skip_this_nonsense", + "freedom_of_music", + "freedom_of_music_palm", + "get_started", + "youtube_source_description", + "piped_source_description", + "jiosaavn_source_description", + "highest_quality", + "select_audio_source", + "endless_playback_description", + "choose_your_region", + "choose_your_region_description", + "choose_your_language", + "help_project_grow", + "help_project_grow_description", + "contribute_on_github", + "donate_on_open_collective", + "browse_anonymously" ], "ru": [ @@ -177,7 +429,25 @@ "delete_playlist", "delete_playlist_confirmation", "local_tracks", - "song_link" + "song_link", + "skip_this_nonsense", + "freedom_of_music", + "freedom_of_music_palm", + "get_started", + "youtube_source_description", + "piped_source_description", + "jiosaavn_source_description", + "highest_quality", + "select_audio_source", + "endless_playback_description", + "choose_your_region", + "choose_your_region_description", + "choose_your_language", + "help_project_grow", + "help_project_grow_description", + "contribute_on_github", + "donate_on_open_collective", + "browse_anonymously" ], "tr": [ @@ -189,7 +459,25 @@ "delete_playlist", "delete_playlist_confirmation", "local_tracks", - "song_link" + "song_link", + "skip_this_nonsense", + "freedom_of_music", + "freedom_of_music_palm", + "get_started", + "youtube_source_description", + "piped_source_description", + "jiosaavn_source_description", + "highest_quality", + "select_audio_source", + "endless_playback_description", + "choose_your_region", + "choose_your_region_description", + "choose_your_language", + "help_project_grow", + "help_project_grow_description", + "contribute_on_github", + "donate_on_open_collective", + "browse_anonymously" ], "uk": [ @@ -201,7 +489,25 @@ "delete_playlist", "delete_playlist_confirmation", "local_tracks", - "song_link" + "song_link", + "skip_this_nonsense", + "freedom_of_music", + "freedom_of_music_palm", + "get_started", + "youtube_source_description", + "piped_source_description", + "jiosaavn_source_description", + "highest_quality", + "select_audio_source", + "endless_playback_description", + "choose_your_region", + "choose_your_region_description", + "choose_your_language", + "help_project_grow", + "help_project_grow_description", + "contribute_on_github", + "donate_on_open_collective", + "browse_anonymously" ], "zh": [ @@ -213,6 +519,24 @@ "delete_playlist", "delete_playlist_confirmation", "local_tracks", - "song_link" + "song_link", + "skip_this_nonsense", + "freedom_of_music", + "freedom_of_music_palm", + "get_started", + "youtube_source_description", + "piped_source_description", + "jiosaavn_source_description", + "highest_quality", + "select_audio_source", + "endless_playback_description", + "choose_your_region", + "choose_your_region_description", + "choose_your_language", + "help_project_grow", + "help_project_grow_description", + "contribute_on_github", + "donate_on_open_collective", + "browse_anonymously" ] } From 1fa6d1f8199b3029b2a90e399bc9eeed522c3a64 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sun, 25 Feb 2024 22:50:08 +0600 Subject: [PATCH 161/195] chore(deps): bump dio from 5.3.3 to 5.4.1 (#1243) Bumps [dio](https://github.com/cfug/dio) from 5.3.3 to 5.4.1. - [Release notes](https://github.com/cfug/dio/releases) - [Commits](https://github.com/cfug/dio/compare/dio_v5.3.3...dio_v5.4.1) --- updated-dependencies: - dependency-name: dio dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- pubspec.lock | 4 ++-- pubspec.yaml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/pubspec.lock b/pubspec.lock index b9268b56..eb410177 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -470,10 +470,10 @@ packages: dependency: "direct main" description: name: dio - sha256: "417e2a6f9d83ab396ec38ff4ea5da6c254da71e4db765ad737a42af6930140b7" + sha256: "49af28382aefc53562459104f64d16b9dfd1e8ef68c862d5af436cc8356ce5a8" url: "https://pub.dev" source: hosted - version: "5.3.3" + version: "5.4.1" disable_battery_optimization: dependency: "direct main" description: diff --git a/pubspec.yaml b/pubspec.yaml index 53da7ba7..e953f442 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -27,7 +27,7 @@ dependencies: dbus: ^0.7.8 device_info_plus: ^9.0.3 device_preview: ^1.1.0 - dio: ^5.3.2 + dio: ^5.4.1 disable_battery_optimization: ^1.1.0+1 duration: ^3.0.12 envied: ^0.3.0 From 59a819be9cf07b9d4c0f1cd0b30a04df878bacdd Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sun, 25 Feb 2024 22:50:40 +0600 Subject: [PATCH 162/195] chore(deps): bump flutter_riverpod from 2.4.3 to 2.4.10 (#1212) Bumps [flutter_riverpod](https://github.com/rrousselGit/riverpod) from 2.4.3 to 2.4.10. - [Commits](https://github.com/rrousselGit/riverpod/compare/flutter_riverpod-v2.4.3...flutter_riverpod-v2.4.10) --- updated-dependencies: - dependency-name: flutter_riverpod dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- pubspec.lock | 80 +++++++++++++++++++++------------------------------- pubspec.yaml | 2 +- 2 files changed, 33 insertions(+), 49 deletions(-) diff --git a/pubspec.lock b/pubspec.lock index eb410177..c31f6dec 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -543,10 +543,10 @@ packages: dependency: transitive description: name: file - sha256: "5fc22d7c25582e38ad9a8515372cd9a93834027aacf1801cf01164dac0ffa08c" + sha256: "1b92bec4fc2a72f59a8e15af5f52cd441e4a7860b49499d69dfa817af20e925d" url: "https://pub.dev" source: hosted - version: "7.0.0" + version: "6.1.4" file_picker: dependency: "direct main" description: @@ -855,10 +855,10 @@ packages: dependency: "direct main" description: name: flutter_riverpod - sha256: e667e406a74d67715f1fa0bd941d9ded49aff72f3a9f4440a36aece4e8d457a7 + sha256: "4bce556b7ecbfea26109638d5237684538d4abc509d253e6c5c4c5733b360098" url: "https://pub.dev" source: hosted - version: "2.4.3" + version: "2.4.10" flutter_rust_bridge: dependency: transitive description: @@ -1078,10 +1078,10 @@ packages: dependency: "direct main" description: name: hooks_riverpod - sha256: "69dcb88acbc68c81fc27ec15a89a4e24b7812c83c13a6307a1a9366ada758541" + sha256: "758b07eba336e3cbacbd81dba481f2228a14102083fdde07045e8514e8054c49" url: "https://pub.dev" source: hosted - version: "2.4.3" + version: "2.4.10" html: dependency: "direct main" description: @@ -1263,30 +1263,6 @@ packages: url: "https://pub.dev" source: hosted version: "0.4.2" - leak_tracker: - dependency: transitive - description: - name: leak_tracker - sha256: "78eb209deea09858f5269f5a5b02be4049535f568c07b275096836f01ea323fa" - url: "https://pub.dev" - source: hosted - version: "10.0.0" - leak_tracker_flutter_testing: - dependency: transitive - description: - name: leak_tracker_flutter_testing - sha256: b46c5e37c19120a8a01918cfaf293547f47269f7cb4b0058f21531c2465d6ef0 - url: "https://pub.dev" - source: hosted - version: "2.0.1" - leak_tracker_testing: - dependency: transitive - description: - name: leak_tracker_testing - sha256: a597f72a664dbd293f3bfc51f9ba69816f84dcd403cdac7066cb3f6003f3ab47 - url: "https://pub.dev" - source: hosted - version: "2.0.1" lints: dependency: transitive description: @@ -1331,18 +1307,18 @@ packages: dependency: transitive description: name: matcher - sha256: d2323aa2060500f906aa31a895b4030b6da3ebdcc5619d14ce1aada65cd161cb + sha256: "1803e76e6653768d64ed8ff2e1e67bea3ad4b923eb5c56a295c3e634bad5960e" url: "https://pub.dev" source: hosted - version: "0.12.16+1" + version: "0.12.16" material_color_utilities: dependency: transitive description: name: material_color_utilities - sha256: "0e0a020085b65b6083975e499759762399b4475f766c21668c4ecca34ea74e5a" + sha256: "9528f2f296073ff54cb9fee677df673ace1218163c3bc7628093e7eed5203d41" url: "https://pub.dev" source: hosted - version: "0.8.0" + version: "0.5.0" media_kit: dependency: "direct main" description: @@ -1411,10 +1387,10 @@ packages: dependency: transitive description: name: meta - sha256: d584fa6707a52763a52446f02cc621b077888fb63b93bbcb1143a7be5a0c0c04 + sha256: a6e590c838b18133bb482a2745ad77c5bb7715fb0451209e1a7567d416678b8e url: "https://pub.dev" source: hosted - version: "1.11.0" + version: "1.10.0" metadata_god: dependency: "direct main" description: @@ -1499,10 +1475,10 @@ packages: dependency: "direct main" description: name: path - sha256: "087ce49c3f0dc39180befefc60fdb4acd8f8620e5682fe2476afd0b3688bb4af" + sha256: "8829d8a55c13fc0e37127c29fedf290c102f4e40ae94ada574091fe0ff96c917" url: "https://pub.dev" source: hosted - version: "1.9.0" + version: "1.8.3" path_drawing: dependency: transitive description: @@ -1628,10 +1604,10 @@ packages: dependency: transitive description: name: platform - sha256: "12220bb4b65720483f8fa9450b4332347737cf8213dd2840d8b2c823e47243ec" + sha256: ae68c7bfcd7383af3629daafb32fb4e8681c7154428da4febcff06200585f102 url: "https://pub.dev" source: hosted - version: "3.1.4" + version: "3.1.2" plugin_platform_interface: dependency: transitive description: @@ -1668,10 +1644,10 @@ packages: dependency: transitive description: name: process - sha256: "21e54fd2faf1b5bdd5102afd25012184a6793927648ea81eea80552ac9405b32" + sha256: "53fd8db9cec1d37b0574e12f07520d582019cb6c44abf5479a01505099a34a09" url: "https://pub.dev" source: hosted - version: "5.0.2" + version: "4.2.4" provider: dependency: transitive description: @@ -1732,10 +1708,10 @@ packages: dependency: transitive description: name: riverpod - sha256: "494bf2cfb4df30000273d3052bdb1cc1de738574c6b678f0beb146ea56f5e208" + sha256: "548e2192eb7aeb826eb89387f814edb76594f3363e2c0bb99dd733d795ba3589" url: "https://pub.dev" source: hosted - version: "2.4.3" + version: "2.5.0" rxdart: dependency: transitive description: @@ -2250,10 +2226,10 @@ packages: dependency: transitive description: name: vm_service - sha256: b3d56ff4341b8f182b96aceb2fa20e3dcb336b9f867bc0eafc0de10f1048e957 + sha256: c538be99af830f478718b51630ec1b6bee5e74e52c8a802d328d9e71d35d2583 url: "https://pub.dev" source: hosted - version: "13.0.0" + version: "11.10.0" watcher: dependency: transitive description: @@ -2262,6 +2238,14 @@ packages: url: "https://pub.dev" source: hosted version: "1.1.0" + web: + dependency: transitive + description: + name: web + sha256: afe077240a270dcfd2aafe77602b4113645af95d0ad31128cc02bce5ac5d5152 + url: "https://pub.dev" + source: hosted + version: "0.3.0" web_socket_channel: dependency: transitive description: @@ -2274,10 +2258,10 @@ packages: dependency: transitive description: name: webdriver - sha256: "003d7da9519e1e5f329422b36c4dcdf18d7d2978d1ba099ea4e45ba490ed845e" + sha256: "3c923e918918feeb90c4c9fdf1fe39220fa4c0e8e2c0fffaded174498ef86c49" url: "https://pub.dev" source: hosted - version: "3.0.3" + version: "3.0.2" wikipedia_api: dependency: "direct main" description: diff --git a/pubspec.yaml b/pubspec.yaml index e953f442..86366aa7 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -50,7 +50,7 @@ dependencies: flutter_localizations: sdk: flutter flutter_native_splash: ^2.3.3 - flutter_riverpod: ^2.4.3 + flutter_riverpod: ^2.4.10 flutter_secure_storage: ^9.0.0 flutter_svg: ^1.1.6 form_validator: ^2.1.1 From 920d4219f04e43a28172fa84a24525adc6d9a5e9 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sun, 25 Feb 2024 22:53:25 +0600 Subject: [PATCH 163/195] chore(deps): bump flutter_native_splash from 2.3.3 to 2.3.10 (#1176) Bumps [flutter_native_splash](https://github.com/jonbhanson/flutter_native_splash) from 2.3.3 to 2.3.10. - [Release notes](https://github.com/jonbhanson/flutter_native_splash/releases) - [Changelog](https://github.com/jonbhanson/flutter_native_splash/blob/master/CHANGELOG.md) - [Commits](https://github.com/jonbhanson/flutter_native_splash/commits) --- updated-dependencies: - dependency-name: flutter_native_splash dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Kingkor Roy Tirtho --- pubspec.lock | 24 ++++++++++++++++-------- pubspec.yaml | 2 +- 2 files changed, 17 insertions(+), 9 deletions(-) diff --git a/pubspec.lock b/pubspec.lock index c31f6dec..0c42b3ef 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -17,6 +17,14 @@ packages: url: "https://pub.dev" source: hosted version: "5.13.0" + ansicolor: + dependency: transitive + description: + name: ansicolor + sha256: "8bf17a8ff6ea17499e40a2d2542c2f481cd7615760c6d34065cb22bfd22e6880" + url: "https://pub.dev" + source: hosted + version: "2.0.2" app_links: dependency: "direct main" description: @@ -839,10 +847,10 @@ packages: dependency: "direct main" description: name: flutter_native_splash - sha256: "91004565166dbbc7a85e7e99b84124a287839830ca957cfe45004793fe6fe69f" + sha256: "558f10070f03ee71f850a78f7136ab239a67636a294a44a06b6b7345178edb1e" url: "https://pub.dev" source: hosted - version: "2.3.3" + version: "2.3.10" flutter_plugin_android_lifecycle: dependency: transitive description: @@ -1587,10 +1595,10 @@ packages: dependency: transitive description: name: petitparser - sha256: cb3798bef7fc021ac45b308f4b51208a152792445cce0448c9a4ba5879dd8750 + sha256: c15605cd28af66339f8eb6fbe0e541bfe2d1b72d5825efc6598f3e0a31b9ad27 url: "https://pub.dev" source: hosted - version: "5.4.0" + version: "6.0.2" piped_client: dependency: "direct main" description: @@ -1692,10 +1700,10 @@ packages: dependency: transitive description: name: puppeteer - sha256: "59e723cc5b69537159a7c34efd645dc08a6a1ac4647d7d7823606802c0f93cdb" + sha256: eedeaae6ec5d2e54f9ae22ab4d6b3dda2e8791c356cc783046d06c287ffe11d8 url: "https://pub.dev" source: hosted - version: "3.2.0" + version: "3.6.0" quiver: dependency: transitive description: @@ -2315,10 +2323,10 @@ packages: dependency: transitive description: name: xml - sha256: "5bc72e1e45e941d825fd7468b9b4cc3b9327942649aeb6fc5cdbf135f0a86e84" + sha256: b015a8ad1c488f66851d762d3090a21c600e479dc75e68328c52774040cf9226 url: "https://pub.dev" source: hosted - version: "6.3.0" + version: "6.5.0" yaml: dependency: transitive description: diff --git a/pubspec.yaml b/pubspec.yaml index 86366aa7..5802b341 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -49,7 +49,7 @@ dependencies: flutter_inappwebview: ^5.7.2+3 flutter_localizations: sdk: flutter - flutter_native_splash: ^2.3.3 + flutter_native_splash: ^2.3.10 flutter_riverpod: ^2.4.10 flutter_secure_storage: ^9.0.0 flutter_svg: ^1.1.6 From befaf59f0c173b3a60637c1ce49e2e935f77fbed Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sun, 25 Feb 2024 22:53:47 +0600 Subject: [PATCH 164/195] chore(deps): bump flutter_lints from 2.0.3 to 3.0.1 (#1147) Bumps [flutter_lints](https://github.com/flutter/packages/tree/main/packages) from 2.0.3 to 3.0.1. - [Release notes](https://github.com/flutter/packages/releases) - [Commits](https://github.com/flutter/packages/commits/flutter_lints-v3.0.1/packages) --- updated-dependencies: - dependency-name: flutter_lints dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- pubspec.lock | 8 ++++---- pubspec.yaml | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/pubspec.lock b/pubspec.lock index 0c42b3ef..1a0278a2 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -826,10 +826,10 @@ packages: dependency: "direct dev" description: name: flutter_lints - sha256: a25a15ebbdfc33ab1cd26c63a6ee519df92338a9c10f122adda92938253bef04 + sha256: e2a421b7e59244faef694ba7b30562e489c2b489866e505074eb005cd7060db7 url: "https://pub.dev" source: hosted - version: "2.0.3" + version: "3.0.1" flutter_localizations: dependency: "direct main" description: flutter @@ -1275,10 +1275,10 @@ packages: dependency: transitive description: name: lints - sha256: "0a217c6c989d21039f1498c3ed9f3ed71b354e69873f13a8dfc3c9fe76f1b452" + sha256: cbf8d4b858bb0134ef3ef87841abdf8d63bfc255c266b7bf6b39daa1085c4290 url: "https://pub.dev" source: hosted - version: "2.1.1" + version: "3.0.0" local_notifier: dependency: transitive description: diff --git a/pubspec.yaml b/pubspec.yaml index 5802b341..5c05ed1c 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -133,7 +133,7 @@ dev_dependencies: flutter_distributor: ^0.0.2 flutter_gen_runner: ^5.1.0+1 flutter_launcher_icons: ^0.13.1 - flutter_lints: ^2.0.1 + flutter_lints: ^3.0.1 flutter_test: sdk: flutter integration_test: From 27e7d532f0c758670d4b7ac21437511e91ee96c3 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sun, 25 Feb 2024 22:54:11 +0600 Subject: [PATCH 165/195] chore(deps): bump audio_session from 0.1.16 to 0.1.18 (#1146) Bumps [audio_session](https://github.com/ryanheise/audio_session) from 0.1.16 to 0.1.18. - [Release notes](https://github.com/ryanheise/audio_session/releases) - [Changelog](https://github.com/ryanheise/audio_session/blob/master/CHANGELOG.md) - [Commits](https://github.com/ryanheise/audio_session/compare/v0.1.16...v0.1.18) --- updated-dependencies: - dependency-name: audio_session dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- pubspec.lock | 4 ++-- pubspec.yaml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/pubspec.lock b/pubspec.lock index 1a0278a2..fdc8d627 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -157,10 +157,10 @@ packages: dependency: "direct main" description: name: audio_session - sha256: "8a2bc5e30520e18f3fb0e366793d78057fb64cd5287862c76af0c8771f2a52ad" + sha256: "6fdf255ed3af86535c96452c33ecff1245990bb25a605bfb1958661ccc3d467f" url: "https://pub.dev" source: hosted - version: "0.1.16" + version: "0.1.18" auto_size_text: dependency: "direct main" description: diff --git a/pubspec.yaml b/pubspec.yaml index 5c05ed1c..a434a2f0 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -16,7 +16,7 @@ dependencies: args: ^2.3.2 async: ^2.9.0 audio_service: ^0.18.9 - audio_session: ^0.1.13 + audio_session: ^0.1.18 auto_size_text: ^3.0.0 buttons_tabbar: ^1.3.6 cached_network_image: ^3.3.0 From 019ba865e20a8b54ea3490c01e47158eaf3a4c8d Mon Sep 17 00:00:00 2001 From: 0x00646f616e6e63 <54035120+doannc2212@users.noreply.github.com> Date: Sun, 25 Feb 2024 23:59:54 +0700 Subject: [PATCH 166/195] feat(translations): Added Vietnamese (#1135) * feat: Added Vietnamese * fix: better translation * fix: better translation * fix: better translation * chore: add translator credit --------- Co-authored-by: Kingkor Roy Tirtho --- lib/collections/language_codes.dart | 8 +- lib/l10n/app_vi.arb | 288 ++++++++++++++++++++++++++++ lib/l10n/l10n.dart | 2 + 3 files changed, 294 insertions(+), 4 deletions(-) create mode 100644 lib/l10n/app_vi.arb diff --git a/lib/collections/language_codes.dart b/lib/collections/language_codes.dart index 4554de63..8f15069e 100644 --- a/lib/collections/language_codes.dart +++ b/lib/collections/language_codes.dart @@ -700,10 +700,10 @@ abstract class LanguageLocals { // name: "Venda", // nativeName: "Tshivenḓa", // ), - // "vi": const ISOLanguageName( - // name: "Vietnamese", - // nativeName: "Tiếng Việt", - // ), + "vi": const ISOLanguageName( + name: "Vietnamese", + nativeName: "Tiếng Việt", + ), // "vo": const ISOLanguageName( // name: "Volapük", // nativeName: "Volapük", diff --git a/lib/l10n/app_vi.arb b/lib/l10n/app_vi.arb new file mode 100644 index 00000000..d8d337c2 --- /dev/null +++ b/lib/l10n/app_vi.arb @@ -0,0 +1,288 @@ +{ + "guest": "Khách", + "browse": "Khám phá", + "search": "Tìm kiếm", + "library": "Thư viên", + "lyrics": "Lời bài hát", + "settings": "Cài đặt", + "genre_categories_filter": "Lọc theo thể loại nhạc...", + "genre": "Thể loại nhạc", + "personalized": "Cá nhân hóa", + "featured": "Nổi bật", + "new_releases": "Bản phát hành mới", + "songs": "Bài hát", + "playing_track": "Đang phát {track}", + "queue_clear_alert": "Điều này sẽ xóa hàng đợi hiện tại. {track_length} bài hát sẽ bị xóa\nBạn có muốn tiếp tục không?", + "load_more": "Tải thêm", + "playlists": "Danh sách phát", + "artists": "Nghệ sĩ", + "albums": "Album", + "tracks": "Bài hát", + "downloads": "Tải về", + "filter_playlists": "Lọc danh sách phát...", + "liked_tracks": "Bài hát được thích", + "liked_tracks_description": "Tất cả bài hát bạn đã thích", + "create_playlist": "Tạo danh sách phát", + "create_a_playlist": "Tạo danh sách phát", + "update_playlist": "Cập nhật danh sách phát", + "create": "Tạo", + "cancel": "Hủy", + "update": "Cập nhật", + "playlist_name": "Tên danh sách phát", + "name_of_playlist": "Tên của danh sách phát", + "description": "Mô tả", + "public": "Công khai", + "collaborative": "Hợp tác", + "search_local_tracks": "Tìm kiếm bài hát trong máy...", + "play": "Phát", + "delete": "Xóa", + "none": "Không có", + "sort_a_z": "Sắp xếp theo A-Z", + "sort_z_a": "Sắp xếp theo Z-A", + "sort_artist": "Sắp xếp theo Nghệ sĩ", + "sort_album": "Sắp xếp theo Album", + "sort_tracks": "Sắp xếp các bài hát", + "currently_downloading": "Đang tải về ({tracks_length} bài hát)", + "cancel_all": "Hủy tất cả", + "filter_artist": "Lọc nghệ sĩ...", + "followers": "{followers} Người theo dõi", + "add_artist_to_blacklist": "Thêm nghệ sĩ vào blacklist", + "top_tracks": "Bài hát nổi bật", + "fans_also_like": "Người hâm mộ cũng thích", + "loading": "Đang tải...", + "artist": "Nghệ sĩ", + "blacklisted": "Đã đưa vào blacklist", + "following": "Đang theo dõi", + "follow": "Theo dõi", + "artist_url_copied": "Đã sao chép URL nghệ sĩ", + "added_to_queue": "Đã thêm {tracks} bài hát vào hàng đợi", + "filter_albums": "Lọc album...", + "synced": "Đồng bộ", + "plain": "Bình thường", + "shuffle": "Trộn", + "search_tracks": "Tìm kiếm bài hát...", + "released": "Phát hành", + "error": "Lỗi {error}", + "title": "Đề mục", + "time": "Thời gian", + "more_actions": "Thao tác khác", + "download_count": "Tải xuống ({count})", + "add_count_to_playlist": "Thêm ({count}) vào danh sách phát", + "add_count_to_queue": "Thêm ({count}) vào hàng đợi", + "play_count_next": "Phát ({count}) tiếp theo", + "album": "Album", + "copied_to_clipboard": "Đã sao chép {data} vào clipboard", + "add_to_following_playlists": "Thêm {track} vào danh sách phát đang theo dõi", + "add": "Thêm", + "added_track_to_queue": "Đã thêm {track} vào hàng đợi", + "add_to_queue": "Thêm vào hàng đợi", + "track_will_play_next": "{track} sẽ được phát tiếp theo", + "play_next": "Phát tiếp theo", + "removed_track_from_queue": "Đã xóa {track} khỏi hàng đợi", + "remove_from_queue": "Xóa khỏi hàng đợi", + "remove_from_favorites": "Xóa khỏi bài hát yêu thích", + "save_as_favorite": "Thêm vào bài hát yêu thích", + "add_to_playlist": "Thêm vào danh sách phát", + "remove_from_playlist": "Xóa khỏi danh sách phát", + "add_to_blacklist": "Thêm vào blacklist", + "remove_from_blacklist": "Xóa khỏi blacklist", + "share": "Chia sẻ", + "mini_player": "Trình phát thu nhỏ", + "slide_to_seek": "Trượt để tìm kiếm tiến hoặc lùi", + "shuffle_playlist": "Xáo trộn bài hát", + "unshuffle_playlist": "Hủy xáo trộn bài hát", + "previous_track": "Bài hát trước", + "next_track": "Bài hát tiếp theo", + "pause_playback": "Tạm dừng phát", + "resume_playback": "Tiếp tục phát", + "loop_track": "Lặp lại bài hát", + "repeat_playlist": "Lặp lại danh sách phát", + "queue": "Hàng đợi", + "alternative_track_sources": "Đổi nguồn bài hát", + "download_track": "Tải xuống", + "tracks_in_queue": "{tracks} bài hát trong hàng đợi", + "clear_all": "Xóa tất cả", + "show_hide_ui_on_hover": "Hiển thị/Ẩn giao diện người dùng khi di chuột qua", + "always_on_top": "Luôn ở trên cùng", + "exit_mini_player": "Thoát khỏi trình phát thu nhỏ", + "download_location": "Vị trí tải xuống", + "account": "Tài khoản", + "login_with_spotify": "Đăng nhập bằng tài khoản Spotify của bạn", + "connect_with_spotify": "Liên kết với Spotify", + "logout": "Đăng xuất", + "logout_of_this_account": "Đăng xuất khỏi tài khoản này", + "language_region": "Ngôn ngữ và Khu vực", + "language": "Ngôn ngữ", + "system_default": "Mặc định hệ thống", + "market_place_region": "Khu vực Marketplace", + "recommendation_country": "Quốc gia gợi ý", + "appearance": "Giao diện", + "layout_mode": "Chế độ layout", + "override_layout_settings": "Ghi đè cài đặt layout", + "adaptive": "Tương thích", + "compact": "Nhỏ gọn", + "extended": "Mở rộng", + "theme": "Chủ đề", + "dark": "Tối", + "light": "Sáng", + "system": "Hệ thống", + "accent_color": "Màu nhấn", + "sync_album_color": "Đồng bộ màu album", + "sync_album_color_description": "Sử dụng màu chủ đạo của hình ảnh album làm màu nhấn", + "playback": "Phát", + "audio_quality": "Chất lượng âm thanh", + "high": "Cao", + "low": "Thấp", + "pre_download_play": "Tải xuống và phát", + "pre_download_play_description": "Thay vì stream âm thanh, tải xuống trước và phát (Khuyến nghị cho người dùng có băng thông cao)", + "skip_non_music": "Bỏ qua các đoạn không phải nhạc (SponsorBlock)", + "blacklist_description": "Các bài hát và nghệ sĩ trong blacklist", + "wait_for_download_to_finish": "Vui lòng đợi quá trình tải xuống hiện tại hoàn thành", + "desktop": "Máy tính", + "close_behavior": "Thao tác đóng", + "close": "Đóng", + "minimize_to_tray": "Thu nhỏ vào khay hệ thống", + "show_tray_icon": "Hiển thị biểu tượng trên khay hệ thống", + "about": "Về chúng tôi", + "u_love_spotube": "Chúng tôi biết bạn yêu Spotube", + "check_for_updates": "Kiểm tra cập nhật", + "about_spotube": "Về Spotube", + "blacklist": "blacklist", + "please_sponsor": "Vui lòng tài trợ/ủng hộ", + "spotube_description": "Spotube, một ứng dụng Spotify nhẹ, đa nền tảng và miễn phí", + "version": "Phiên bản", + "build_number": "Số phiên bản", + "founder": "Người sáng lập", + "repository": "Mã nguồn", + "bug_issues": "Báo cáo lỗi", + "made_with": "Được làm bằng ❤️ ở Băng-la-đét", + "kingkor_roy_tirtho": "Kingkor Roy Tirtho", + "copyright": "© 2021-{current_year} Kingkor Roy Tirtho", + "license": "Giấy phép", + "add_spotify_credentials": "Điền thông tin đăng nhập Spotify của bạn", + "credentials_will_not_be_shared_disclaimer": "Đừng lo, thông tin đăng nhập của bạn sẽ không được thu thập hoặc chia sẻ với bất kỳ ai", + "know_how_to_login": "Không biết cách lấy thông tin đăng nhập?", + "follow_step_by_step_guide": "Các bước lấy thông tin đăng nhập", + "spotify_cookie": "Cookie Spotify {name}", + "cookie_name_cookie": "Cookie {name}", + "fill_in_all_fields": "Vui lòng điền đầy đủ thông tin", + "submit": "Gửi", + "exit": "Thoát", + "previous": "Trước", + "next": "Tiếp", + "done": "Hoàn tất", + "step_1": "Bước 1", + "first_go_to": "Đầu tiên, truy cập", + "login_if_not_logged_in": "và Đăng nhập/Đăng ký nếu chưa có tài khoản", + "step_2": "Bước 2", + "step_2_steps": "1. Sau khi đăng nhập, nhấn F12 hoặc Chuột phải > Mở devtools của trình duyệt.\n2. Sau đó, chuyển đến Tab \"Ứng dụng/Application\" (Chrome, Edge, Brave, v.v.) hoặc Tab \"Lưu trữ/Storage\" (Firefox, Palemoon, v.v.)\n3. Chuyển đến phần \"Cookie\" sau đó phần con \"https://accounts.spotify.com\"", + "step_3": "Bước 3", + "step_3_steps": "Sao chép giá trị của Cookie \"sp_dc\" và \"sp_key\" (hoặc sp_gaid)", + "success_emoji": "Thành công🥳", + "success_message": "Bây giờ bạn đã đăng nhập thành công bằng tài khoản Spotify của mình. Làm tốt lắm!", + "step_4": "Bước 4", + "step_4_steps": "Dán giá trị đã sao chép của Cookie \"sp_dc\" và \"sp_key\" (hoặc sp_gaid) vào các trường tương ứng", + "something_went_wrong": "Đã xảy ra lỗi", + "piped_instance": "Phiên bản Server Piped", + "piped_description": "Phiên bản Piped để sử dụng cho Track matching", + "piped_warning": "Một số phiên bản Piped có thể không hoạt động tốt", + "generate_playlist": "Tạo danh sách phát", + "track_exists": "Bài hát {track} đã tồn tại", + "replace_downloaded_tracks": "Thay thế tất cả các bài hát đã tải", + "skip_download_tracks": "Bỏ qua tải xuống tất cả các bài hát đã tải", + "do_you_want_to_replace": "Bạn có muốn thay thế bài hát hiện có không?", + "replace": "Thay thế", + "skip": "Bỏ qua", + "select_up_to_count_type": "Chọn tối đa {count} {type}", + "select_genres": "Chọn Thể loại", + "add_genres": "Thêm Thể loại", + "country": "Quốc gia", + "number_of_tracks_generate": "Số lượng bài hát để tạo", + "acousticness": "Độ âm thanh", + "danceability": "Khả năng nhảy", + "energy": "Năng lượng", + "instrumentalness": "Độ nhạc cụ", + "liveness": "Sống động", + "loudness": "Độ ồn", + "speechiness": "Độ nói", + "valence": "Tính tích cực", + "popularity": "Độ phổ biến", + "key": "Tông", + "duration": "Thời lượng (giây)", + "tempo": "Nhịp độ (BPM)", + "mode": "Chế độ", + "time_signature": "Chữ ký thời gian", + "short": "Ngắn", + "medium": "Trung bình", + "long": "Dài", + "min": "Tối thiểu", + "max": "Tối đa", + "target": "Mục tiêu", + "moderate": "Trung bình", + "deselect_all": "Bỏ chọn tất cả", + "select_all": "Chọn tất cả", + "are_you_sure": "Bạn có chắc chắn?", + "generating_playlist": "Đang tạo danh sách phát tùy chỉnh của bạn...", + "selected_count_tracks": "Đã chọn {count} bài hát", + "download_warning": "Tải xuống tất cả các bài hát một lần, sẽ vi phạm bản quyền âm nhạc và gây thiệt hại cho xã hội sáng tạo âm nhạc. Hy vọng bạn nhận thức được điều này. Hãy luôn tôn trọng và ủng hộ công sức của nghệ sĩ", + "download_ip_ban_warning": "Địa chỉ IP của bạn có thể bị chặn trên YouTube do yêu cầu tải xuống quá mức so với bình thường. Chặn IP có nghĩa là bạn không thể sử dụng YouTube (ngay cả khi bạn đã đăng nhập) ít nhất 2-3 tháng từ thiết bị IP đó. Và Spotube không chịu trách nhiệm nếu điều này xảy ra", + "by_clicking_accept_terms": "Bằng cách nhấp vào 'Chấp nhận', bạn đồng ý với các điều khoản sau:", + "download_agreement_1": "Tôi biết mình đang vi phạm bản quyền âm nhạc. Đó là không tốt.", + "download_agreement_2": "Tôi sẽ ủng hộ nghệ sĩ bất cứ nơi nào tôi có thể và tôi chỉ làm điều này vì tôi không có tiền để mua tác phẩm của họ", + "download_agreement_3": "Tôi hoàn toàn nhận thức được rằng địa chỉ IP của tôi có thể bị chặn trên YouTube và tôi không đổ lỗi cho Spotube hoặc chủ sở hữu/người đóng góp của nó về bất kỳ tai nạn nào do hành động này của tôi", + "decline": "Từ chối", + "accept": "Chấp nhận", + "details": "Chi tiết", + "youtube": "YouTube", + "channel": "Kênh", + "likes": "Thích", + "dislikes": "Không thích", + "views": "Lượt xem", + "streamUrl": "URL phát trực tiếp", + "stop": "Dừng", + "sort_newest": "Sắp xếp theo mới nhất", + "sort_oldest": "Sắp xếp theo cũ nhất", + "sleep_timer": "Hẹn giờ tắt", + "mins": "{minutes} Phút", + "hours": "{hours} Giờ", + "hour": "{hours} Giờ", + "custom_hours": "Giờ Tùy chỉnh", + "logs": "Nhật ký", + "developers": "Nhà phát triển", + "not_logged_in": "Bạn chưa đăng nhập", + "search_mode": "Chế độ tìm kiếm", + "audio_source": "Nguồn âm thanh", + "ok": "Ok", + "failed_to_encrypt": "Mã hóa không thành công", + "encryption_failed_warning": "Spotube không thành công trong việc mã hóa nhằm lưu trữ dữ liêu an toàn. vậy nên sẽ chuyển về lưu trữ không an toàn\nNếu bạn đang sử dụng Linux, đảm bảo rằng bạn có sử dụng dịch vụ bảo mật (gnome-keyring, kde-wallet, keepassxc, v.v.)", + "querying_info": "Đang truy vấn thông tin...", + "piped_api_down": "API Piped đang gặp sự cố", + "piped_down_error_instructions": "Phiên bản Piped {pipedInstance} hiện đang gặp sự cố\n\nThay đổi phiên bản hoặc thay đổi 'Loại API' thành API YouTube official\n\nKhởi động lai ứng dụng sau khi thay đổi.", + "you_are_offline": "Bạn đang ngoại tuyến", + "connection_restored": "Kết nối internet của bạn đã được khôi phục", + "use_system_title_bar": "Sử dụng thanh tiêu đề hệ thống", + "crunching_results": "Đang tìm kiếm...", + "search_to_get_results": "Chưa tìm kiếm", + "use_amoled_mode": "Chủ đề tối hoàn toàn", + "pitch_dark_theme": "Chế độ AMOLED", + "normalize_audio": "Bình thường hóa âm thanh", + "change_cover": "Thay đổi ảnh bìa", + "add_cover": "Thêm ảnh bìa", + "restore_defaults": "Khôi phục mặc định", + "download_music_codec": "Định dạng tải xuống", + "streaming_music_codec": "Định dạng nghe", + "login_with_lastfm": "Đăng nhập bằng tài khoản Last.fm", + "connect": "Liên kết", + "disconnect_lastfm": "Dừng liên kết Last.fm", + "disconnect": "Ngắt kết nối", + "username": "Tên người dùng", + "password": "Mật khẩu", + "login": "Đăng nhập", + "login_with_your_lastfm": "Đăng nhập bằng tài khoản Last.fm của bạn", + "scrobble_to_lastfm": "Scrobble đến Last.fm", + "go_to_album": "Đi đến Album", + "discord_rich_presence": "Hiển thị trạng thái Discord", + "browse_all": "Duyệt tất cả", + "genres": "Thể loại", + "explore_genres": "Khám phá Thể loại" +} diff --git a/lib/l10n/l10n.dart b/lib/l10n/l10n.dart index 335be545..8f6900c2 100644 --- a/lib/l10n/l10n.dart +++ b/lib/l10n/l10n.dart @@ -9,6 +9,7 @@ /// energywave@github, ncvescera@github, OpenCode@github => Italian /// mdksec@github => Turkish /// SecularSteve@github => Dutch +/// doannc2212@github => Vietnamese import 'package:flutter/material.dart'; class L10n { @@ -32,5 +33,6 @@ class L10n { const Locale('uk', 'UA'), const Locale('tr', 'TR'), const Locale('zh', 'CN'), + const Locale('vi', 'VN'), ]; } From 0ae6af61c97de6e06e69fd9638544349622c5962 Mon Sep 17 00:00:00 2001 From: Kingkor Roy Tirtho Date: Sun, 25 Feb 2024 23:06:40 +0600 Subject: [PATCH 167/195] chore: untranslated messages --- .../settings/sections/language_region.dart | 2 +- pubspec.lock | 76 ++++++++++++------- untranslated_messages.json | 32 ++++++++ 3 files changed, 83 insertions(+), 27 deletions(-) diff --git a/lib/pages/settings/sections/language_region.dart b/lib/pages/settings/sections/language_region.dart index 9465feb3..fbfe1030 100644 --- a/lib/pages/settings/sections/language_region.dart +++ b/lib/pages/settings/sections/language_region.dart @@ -12,7 +12,7 @@ import 'package:spotube/l10n/l10n.dart'; import 'package:spotube/provider/user_preferences/user_preferences_provider.dart'; class SettingsLanguageRegionSection extends HookConsumerWidget { - const SettingsLanguageRegionSection({Key? key}) : super(key: key); + const SettingsLanguageRegionSection({super.key}); @override Widget build(BuildContext context, ref) { diff --git a/pubspec.lock b/pubspec.lock index fdc8d627..fbdb19fc 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -551,10 +551,10 @@ packages: dependency: transitive description: name: file - sha256: "1b92bec4fc2a72f59a8e15af5f52cd441e4a7860b49499d69dfa817af20e925d" + sha256: "5fc22d7c25582e38ad9a8515372cd9a93834027aacf1801cf01164dac0ffa08c" url: "https://pub.dev" source: hosted - version: "6.1.4" + version: "7.0.0" file_picker: dependency: "direct main" description: @@ -688,6 +688,14 @@ packages: url: "https://pub.dev" source: hosted version: "0.0.9" + flutter_broadcasts: + dependency: "direct main" + description: + name: flutter_broadcasts + sha256: "9e76eeeda4a9faef63e3b08af5664c79219a2eabffc8ce95296858ea70423b1e" + url: "https://pub.dev" + source: hosted + version: "0.4.0" flutter_cache_manager: dependency: "direct main" description: @@ -1271,6 +1279,30 @@ packages: url: "https://pub.dev" source: hosted version: "0.4.2" + leak_tracker: + dependency: transitive + description: + name: leak_tracker + sha256: "78eb209deea09858f5269f5a5b02be4049535f568c07b275096836f01ea323fa" + url: "https://pub.dev" + source: hosted + version: "10.0.0" + leak_tracker_flutter_testing: + dependency: transitive + description: + name: leak_tracker_flutter_testing + sha256: b46c5e37c19120a8a01918cfaf293547f47269f7cb4b0058f21531c2465d6ef0 + url: "https://pub.dev" + source: hosted + version: "2.0.1" + leak_tracker_testing: + dependency: transitive + description: + name: leak_tracker_testing + sha256: a597f72a664dbd293f3bfc51f9ba69816f84dcd403cdac7066cb3f6003f3ab47 + url: "https://pub.dev" + source: hosted + version: "2.0.1" lints: dependency: transitive description: @@ -1315,18 +1347,18 @@ packages: dependency: transitive description: name: matcher - sha256: "1803e76e6653768d64ed8ff2e1e67bea3ad4b923eb5c56a295c3e634bad5960e" + sha256: d2323aa2060500f906aa31a895b4030b6da3ebdcc5619d14ce1aada65cd161cb url: "https://pub.dev" source: hosted - version: "0.12.16" + version: "0.12.16+1" material_color_utilities: dependency: transitive description: name: material_color_utilities - sha256: "9528f2f296073ff54cb9fee677df673ace1218163c3bc7628093e7eed5203d41" + sha256: "0e0a020085b65b6083975e499759762399b4475f766c21668c4ecca34ea74e5a" url: "https://pub.dev" source: hosted - version: "0.5.0" + version: "0.8.0" media_kit: dependency: "direct main" description: @@ -1395,10 +1427,10 @@ packages: dependency: transitive description: name: meta - sha256: a6e590c838b18133bb482a2745ad77c5bb7715fb0451209e1a7567d416678b8e + sha256: d584fa6707a52763a52446f02cc621b077888fb63b93bbcb1143a7be5a0c0c04 url: "https://pub.dev" source: hosted - version: "1.10.0" + version: "1.11.0" metadata_god: dependency: "direct main" description: @@ -1483,10 +1515,10 @@ packages: dependency: "direct main" description: name: path - sha256: "8829d8a55c13fc0e37127c29fedf290c102f4e40ae94ada574091fe0ff96c917" + sha256: "087ce49c3f0dc39180befefc60fdb4acd8f8620e5682fe2476afd0b3688bb4af" url: "https://pub.dev" source: hosted - version: "1.8.3" + version: "1.9.0" path_drawing: dependency: transitive description: @@ -1612,10 +1644,10 @@ packages: dependency: transitive description: name: platform - sha256: ae68c7bfcd7383af3629daafb32fb4e8681c7154428da4febcff06200585f102 + sha256: "12220bb4b65720483f8fa9450b4332347737cf8213dd2840d8b2c823e47243ec" url: "https://pub.dev" source: hosted - version: "3.1.2" + version: "3.1.4" plugin_platform_interface: dependency: transitive description: @@ -1652,10 +1684,10 @@ packages: dependency: transitive description: name: process - sha256: "53fd8db9cec1d37b0574e12f07520d582019cb6c44abf5479a01505099a34a09" + sha256: "21e54fd2faf1b5bdd5102afd25012184a6793927648ea81eea80552ac9405b32" url: "https://pub.dev" source: hosted - version: "4.2.4" + version: "5.0.2" provider: dependency: transitive description: @@ -2234,10 +2266,10 @@ packages: dependency: transitive description: name: vm_service - sha256: c538be99af830f478718b51630ec1b6bee5e74e52c8a802d328d9e71d35d2583 + sha256: b3d56ff4341b8f182b96aceb2fa20e3dcb336b9f867bc0eafc0de10f1048e957 url: "https://pub.dev" source: hosted - version: "11.10.0" + version: "13.0.0" watcher: dependency: transitive description: @@ -2246,14 +2278,6 @@ packages: url: "https://pub.dev" source: hosted version: "1.1.0" - web: - dependency: transitive - description: - name: web - sha256: afe077240a270dcfd2aafe77602b4113645af95d0ad31128cc02bce5ac5d5152 - url: "https://pub.dev" - source: hosted - version: "0.3.0" web_socket_channel: dependency: transitive description: @@ -2266,10 +2290,10 @@ packages: dependency: transitive description: name: webdriver - sha256: "3c923e918918feeb90c4c9fdf1fe39220fa4c0e8e2c0fffaded174498ef86c49" + sha256: "003d7da9519e1e5f329422b36c4dcdf18d7d2978d1ba099ea4e45ba490ed845e" url: "https://pub.dev" source: hosted - version: "3.0.2" + version: "3.0.3" wikipedia_api: dependency: "direct main" description: diff --git a/untranslated_messages.json b/untranslated_messages.json index 3ff7a2f1..14eead0f 100644 --- a/untranslated_messages.json +++ b/untranslated_messages.json @@ -510,6 +510,38 @@ "browse_anonymously" ], + "vi": [ + "sort_duration", + "friends", + "no_lyrics_available", + "start_a_radio", + "how_to_start_radio", + "replace_queue_question", + "endless_playback", + "delete_playlist", + "delete_playlist_confirmation", + "local_tracks", + "song_link", + "skip_this_nonsense", + "freedom_of_music", + "freedom_of_music_palm", + "get_started", + "youtube_source_description", + "piped_source_description", + "jiosaavn_source_description", + "highest_quality", + "select_audio_source", + "endless_playback_description", + "choose_your_region", + "choose_your_region_description", + "choose_your_language", + "help_project_grow", + "help_project_grow_description", + "contribute_on_github", + "donate_on_open_collective", + "browse_anonymously" + ], + "zh": [ "sort_duration", "start_a_radio", From e6a20b5a1674b6af25121fafaefffa55d5557342 Mon Sep 17 00:00:00 2001 From: Kingkor Roy Tirtho Date: Mon, 26 Feb 2024 10:05:50 +0600 Subject: [PATCH 168/195] chore: fix add null check before accessing auth cookie from hive box #1264 --- lib/collections/routes.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/collections/routes.dart b/lib/collections/routes.dart index 7b0d836d..43d0cf2e 100644 --- a/lib/collections/routes.dart +++ b/lib/collections/routes.dart @@ -50,7 +50,7 @@ final routerProvider = Provider((ref) { ref.read(AuthenticationNotifier.provider.notifier); final json = await authNotifier.box.get(authNotifier.cacheKey); - if (json["cookie"] == null && + if (json?["cookie"] == null && !KVStoreService.doneGettingStarted) { return "/getting-started"; } From a9a1d4c9dc24aaf3181dc4090d1822ebfe755991 Mon Sep 17 00:00:00 2001 From: Kingkor Roy Tirtho Date: Fri, 1 Mar 2024 18:55:33 +0600 Subject: [PATCH 169/195] fix: album, artist page not loading #1282 --- lib/pages/album/album.dart | 9 +-- .../spotify_endpoints.dart | 55 ------------------- lib/services/queries/artist.dart | 7 +-- pubspec.lock | 25 ++++++--- pubspec.yaml | 8 ++- 5 files changed, 29 insertions(+), 75 deletions(-) diff --git a/lib/pages/album/album.dart b/lib/pages/album/album.dart index 72f9a9af..4578aea2 100644 --- a/lib/pages/album/album.dart +++ b/lib/pages/album/album.dart @@ -15,9 +15,9 @@ import 'package:spotube/utils/type_conversion_utils.dart'; class AlbumPage extends HookConsumerWidget { final AlbumSimple album; const AlbumPage({ - Key? key, + super.key, required this.album, - }) : super(key: key); + }); @override Widget build(BuildContext context, ref) { @@ -69,8 +69,9 @@ class AlbumPage extends HookConsumerWidget { shareUrl: album.externalUrls!.spotify!, isLiked: isLiked, onHeart: albumIsSaved.hasData - ? () { - toggleAlbumLike.mutate(isLiked); + ? () async { + await toggleAlbumLike.mutate(isLiked); + return null; } : null, child: const TrackView(), diff --git a/lib/services/custom_spotify_endpoints/spotify_endpoints.dart b/lib/services/custom_spotify_endpoints/spotify_endpoints.dart index e27b701b..d1c078a7 100644 --- a/lib/services/custom_spotify_endpoints/spotify_endpoints.dart +++ b/lib/services/custom_spotify_endpoints/spotify_endpoints.dart @@ -175,59 +175,4 @@ class CustomSpotifyEndpoints { ); return SpotifyFriends.fromJson(jsonDecode(res.body)); } - - Future artist({required String id}) async { - final pathQuery = "$_baseUrl/artists/$id"; - - final res = await _client.get( - Uri.parse(pathQuery), - headers: { - "content-type": "application/json", - if (accessToken.isNotEmpty) "authorization": "Bearer $accessToken", - "accept": "application/json", - }, - ); - final data = jsonDecode(res.body); - - return Artist.fromJson(_purifyArtistResponse(data)); - } - - Future> relatedArtists({required String id}) async { - final pathQuery = "$_baseUrl/artists/$id/related-artists"; - - final res = await _client.get( - Uri.parse(pathQuery), - headers: { - "content-type": "application/json", - if (accessToken.isNotEmpty) "authorization": "Bearer $accessToken", - "accept": "application/json", - }, - ); - - final data = jsonDecode(res.body); - - return List.castFrom( - data["artists"] - .map((artist) => Artist.fromJson(_purifyArtistResponse(artist))) - .toList(), - ); - } - - Map _purifyArtistResponse(Map data) { - if (data["popularity"] != null) { - data["popularity"] = data["popularity"].toInt(); - } - if (data["followers"]?["total"] != null) { - data["followers"]["total"] = data["followers"]["total"].toInt(); - } - if (data["images"] != null) { - data["images"] = data["images"].map((e) { - e["height"] = e["height"].toInt(); - e["width"] = e["width"].toInt(); - return e; - }).toList(); - } - - return data; - } } diff --git a/lib/services/queries/artist.dart b/lib/services/queries/artist.dart index 5ccc4955..1b939c82 100644 --- a/lib/services/queries/artist.dart +++ b/lib/services/queries/artist.dart @@ -4,7 +4,6 @@ import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:spotify/spotify.dart'; import 'package:spotube/hooks/spotify/use_spotify_infinite_query.dart'; import 'package:spotube/hooks/spotify/use_spotify_query.dart'; -import 'package:spotube/provider/custom_spotify_endpoint_provider.dart'; import 'package:spotube/provider/user_preferences/user_preferences_provider.dart'; import 'package:spotube/services/wikipedia/wikipedia.dart'; import 'package:wikipedia_api/wikipedia_api.dart'; @@ -16,10 +15,9 @@ class ArtistQueries { WidgetRef ref, String artist, ) { - final customSpotify = ref.watch(customSpotifyEndpointProvider); return useSpotifyQuery( "artist-profile/$artist", - (spotify) => customSpotify.artist(id: artist), + (spotify) => spotify.artists.get(artist), ref: ref, ); } @@ -127,11 +125,10 @@ class ArtistQueries { WidgetRef ref, String artist, ) { - final customSpotify = ref.watch(customSpotifyEndpointProvider); return useSpotifyQuery, dynamic>( "artist-related-artist-query/$artist", (spotify) { - return customSpotify.relatedArtists(id: artist); + return spotify.artists.relatedArtists(artist); }, ref: ref, ); diff --git a/pubspec.lock b/pubspec.lock index fbdb19fc..b3658253 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -1118,10 +1118,10 @@ packages: dependency: "direct main" description: name: http - sha256: "759d1a329847dd0f39226c688d3e06a6b8679668e350e2891a6474f8b4bb8525" + sha256: "761a297c042deedc1ffbb156d6e2af13886bb305c2a343a4d972504cd67dd938" url: "https://pub.dev" source: hosted - version: "1.1.0" + version: "1.2.1" http_multi_server: dependency: transitive description: @@ -1961,11 +1961,12 @@ packages: spotify: dependency: "direct main" description: - name: spotify - sha256: e967c5e295792e9d38f4c5e9e60d7c2868ed9cb2a8fac2a67c75303f8395e374 - url: "https://pub.dev" - source: hosted - version: "0.12.0" + path: "." + ref: fix-spotify-precision + resolved-ref: "1ddea720130203021a815253e37ebe5c06845dd2" + url: "https://github.com/KRTirtho/spotify-dart.git" + source: git + version: "0.13.1" sqflite: dependency: transitive description: @@ -2278,6 +2279,14 @@ packages: url: "https://pub.dev" source: hosted version: "1.1.0" + web: + dependency: transitive + description: + name: web + sha256: "1d9158c616048c38f712a6646e317a3426da10e884447626167240d45209cbad" + url: "https://pub.dev" + source: hosted + version: "0.5.0" web_socket_channel: dependency: transitive description: @@ -2368,5 +2377,5 @@ packages: source: hosted version: "2.0.2" sdks: - dart: ">=3.2.0 <4.0.0" + dart: ">=3.3.0 <4.0.0" flutter: ">=3.13.0" diff --git a/pubspec.yaml b/pubspec.yaml index a434a2f0..6fbfa8b7 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -61,7 +61,7 @@ dependencies: hive_flutter: ^1.1.0 hooks_riverpod: ^2.4.3 html: ^0.15.1 - http: ^1.1.0 + http: ^1.2.0 image_picker: ^1.0.4 intl: ^0.18.0 introduction_screen: ^3.0.2 @@ -89,7 +89,10 @@ dependencies: shared_preferences: ^2.2.2 skeleton_text: ^3.0.1 smtc_windows: ^0.1.1 - spotify: ^0.12.0 + spotify: + git: + url: https://github.com/KRTirtho/spotify-dart.git + ref: fix-spotify-precision stroke_text: ^0.0.2 system_theme: ^2.1.0 titlebar_buttons: ^1.0.0 @@ -145,7 +148,6 @@ dev_dependencies: freezed: ^2.4.6 dependency_overrides: - http: ^1.1.0 system_tray: 2.0.2 flutter: From b0970090b1bcc941d51603f4fc34e3a400decd40 Mon Sep 17 00:00:00 2001 From: Kingkor Roy Tirtho Date: Fri, 1 Mar 2024 19:16:52 +0600 Subject: [PATCH 170/195] chore: add song link text in player view shortcut --- lib/components/player/player.dart | 14 +- lib/pages/album/album.dart | 1 + lib/pages/home/genres/genre_playlists.dart | 212 ++++++++++----------- lib/pages/home/genres/genres.dart | 2 +- 4 files changed, 115 insertions(+), 114 deletions(-) diff --git a/lib/components/player/player.dart b/lib/components/player/player.dart index a43fcbca..01e38670 100644 --- a/lib/components/player/player.dart +++ b/lib/components/player/player.dart @@ -138,12 +138,17 @@ class PlayerView extends HookConsumerWidget { onPressed: panelController.close, ), actions: [ - IconButton( - icon: Assets.logos.songlink.image( + TextButton.icon( + icon: Assets.logos.songlinkTransparent.image( width: 20, height: 20, + color: bodyTextColor, + ), + label: Text(context.l10n.song_link), + style: TextButton.styleFrom( + foregroundColor: bodyTextColor, + padding: EdgeInsets.zero, ), - tooltip: context.l10n.song_link, onPressed: currentTrack == null ? null : () { @@ -157,7 +162,8 @@ class PlayerView extends HookConsumerWidget { icon: const Icon(SpotubeIcons.info, size: 18), tooltip: context.l10n.details, style: IconButton.styleFrom( - foregroundColor: bodyTextColor), + foregroundColor: bodyTextColor, + ), onPressed: currentTrack == null ? null : () { diff --git a/lib/pages/album/album.dart b/lib/pages/album/album.dart index 4578aea2..6cba99f6 100644 --- a/lib/pages/album/album.dart +++ b/lib/pages/album/album.dart @@ -47,6 +47,7 @@ class AlbumPage extends HookConsumerWidget { image: TypeConversionUtils.image_X_UrlString( album.images, placeholder: ImagePlaceholder.albumArt, + index: 0, ), title: album.name!, description: diff --git a/lib/pages/home/genres/genre_playlists.dart b/lib/pages/home/genres/genre_playlists.dart index 78f32245..bfb0843c 100644 --- a/lib/pages/home/genres/genre_playlists.dart +++ b/lib/pages/home/genres/genre_playlists.dart @@ -18,8 +18,7 @@ import 'package:flutter_desktop_tools/flutter_desktop_tools.dart'; class GenrePlaylistsPage extends HookConsumerWidget { final Category category; - const GenrePlaylistsPage({Key? key, required this.category}) - : super(key: key); + const GenrePlaylistsPage({super.key, required this.category}); @override Widget build(BuildContext context, ref) { @@ -51,123 +50,118 @@ class GenrePlaylistsPage extends HookConsumerWidget { ) : null, extendBodyBehindAppBar: true, - body: CustomScrollView( - controller: scrollController, - slivers: [ - SliverAppBar( - automaticallyImplyLeading: DesktopTools.platform.isMobile, - expandedHeight: mediaQuery.mdAndDown ? 200 : 150, - pinned: true, - floating: false, - title: const Text(""), - backgroundColor: Colors.brown.withOpacity(0.7), - flexibleSpace: FlexibleSpaceBar( - stretchModes: const [ - StretchMode.zoomBackground, - StretchMode.blurBackground, - ], - background: DecoratedBox( - decoration: BoxDecoration( - image: DecorationImage( - image: UniversalImage.imageProvider( - category.icons!.first.url!, - ), - fit: BoxFit.cover, + body: DecoratedBox( + decoration: BoxDecoration( + image: DecorationImage( + image: UniversalImage.imageProvider(category.icons!.first.url!), + alignment: Alignment.topCenter, + fit: BoxFit.cover, + colorFilter: ColorFilter.mode( + Colors.black.withOpacity(0.5), + BlendMode.darken, + ), + repeat: ImageRepeat.noRepeat, + matchTextDirection: true, + ), + ), + child: CustomScrollView( + controller: scrollController, + slivers: [ + SliverAppBar( + automaticallyImplyLeading: DesktopTools.platform.isMobile, + expandedHeight: mediaQuery.mdAndDown ? 200 : 150, + title: const Text(""), + backgroundColor: Colors.transparent, + flexibleSpace: FlexibleSpaceBar( + centerTitle: DesktopTools.platform.isDesktop, + title: Text( + category.name!, + style: Theme.of(context).textTheme.headlineMedium?.copyWith( + color: Colors.white, + letterSpacing: 3, + shadows: [ + const Shadow( + offset: Offset(-1.5, -1.5), + color: Colors.black54, + ), + const Shadow( + offset: Offset(1.5, -1.5), + color: Colors.black54, + ), + const Shadow( + offset: Offset(1.5, 1.5), + color: Colors.black54, + ), + const Shadow( + offset: Offset(-1.5, 1.5), + color: Colors.black54, + ), + ], ), ), - child: BackdropFilter( - filter: ImageFilter.blur(sigmaX: 10, sigmaY: 10), - child: const ColoredBox(color: Colors.transparent), - ), + collapseMode: CollapseMode.parallax, ), - centerTitle: DesktopTools.platform.isDesktop, - title: Text( - category.name!, - style: Theme.of(context).textTheme.headlineMedium?.copyWith( - color: Colors.white, - letterSpacing: 3, - shadows: [ - const Shadow( - offset: Offset(-1.5, -1.5), - color: Colors.black54, - ), - const Shadow( - offset: Offset(1.5, -1.5), - color: Colors.black54, - ), - const Shadow( - offset: Offset(1.5, 1.5), - color: Colors.black54, - ), - const Shadow( - offset: Offset(-1.5, 1.5), - color: Colors.black54, - ), - ], - ), - ), - collapseMode: CollapseMode.parallax, ), - ), - const SliverGap(20), - SliverSafeArea( - top: false, - sliver: SliverPadding( - padding: EdgeInsets.symmetric( - horizontal: mediaQuery.mdAndDown ? 12 : 24, - ), - sliver: playlists.isEmpty - ? Skeletonizer.sliver( - child: SliverToBoxAdapter( - child: Wrap( - spacing: 12, - runSpacing: 12, - children: List.generate( - 6, - (index) => PlaylistCard(FakeData.playlist), + const SliverGap(20), + SliverSafeArea( + top: false, + sliver: SliverPadding( + padding: EdgeInsets.symmetric( + horizontal: mediaQuery.mdAndDown ? 12 : 24, + ), + sliver: playlists.isEmpty + ? Skeletonizer.sliver( + child: SliverToBoxAdapter( + child: Wrap( + spacing: 12, + runSpacing: 12, + children: List.generate( + 6, + (index) => PlaylistCard(FakeData.playlist), + ), ), ), - ), - ) - : SliverGrid.builder( - gridDelegate: SliverGridDelegateWithMaxCrossAxisExtent( - maxCrossAxisExtent: 190, - mainAxisExtent: mediaQuery.mdAndDown ? 225 : 250, - crossAxisSpacing: 12, - mainAxisSpacing: 12, - ), - itemCount: playlists.length + 1, - itemBuilder: (context, index) { - final playlist = playlists.elementAtOrNull(index); + ) + : SliverGrid.builder( + gridDelegate: SliverGridDelegateWithMaxCrossAxisExtent( + maxCrossAxisExtent: 190, + mainAxisExtent: mediaQuery.mdAndDown ? 225 : 250, + crossAxisSpacing: 12, + mainAxisSpacing: 12, + ), + itemCount: playlists.length + 1, + itemBuilder: (context, index) { + final playlist = playlists.elementAtOrNull(index); - if (playlist == null) { - if (!playlistsQuery.hasNextPage) { - return const SizedBox.shrink(); + if (playlist == null) { + if (!playlistsQuery.hasNextPage) { + return const SizedBox.shrink(); + } + return Skeletonizer( + enabled: true, + child: Waypoint( + controller: scrollController, + isGrid: true, + onTouchEdge: () async { + if (playlistsQuery.hasNextPage) { + await playlistsQuery.fetchNext(); + } + }, + child: PlaylistCard(FakeData.playlist), + ), + ); } - return Skeletonizer( - enabled: true, - child: Waypoint( - controller: scrollController, - isGrid: true, - onTouchEdge: () async { - if (playlistsQuery.hasNextPage) { - await playlistsQuery.fetchNext(); - } - }, - child: PlaylistCard(FakeData.playlist), - ), - ); - } - return Skeleton.keep( - child: PlaylistCard(playlist), - ); - }, - ), + return Skeleton.keep( + child: PlaylistCard(playlist), + ); + }, + ), + ), ), - ), - const SliverGap(20), - ], + const SliverGap(20), + ], + ), ), ); } diff --git a/lib/pages/home/genres/genres.dart b/lib/pages/home/genres/genres.dart index dc165fe4..17a67beb 100644 --- a/lib/pages/home/genres/genres.dart +++ b/lib/pages/home/genres/genres.dart @@ -15,7 +15,7 @@ import 'package:spotube/provider/user_preferences/user_preferences_provider.dart import 'package:spotube/services/queries/queries.dart'; class GenrePage extends HookConsumerWidget { - const GenrePage({Key? key}) : super(key: key); + const GenrePage({super.key}); @override Widget build(BuildContext context, ref) { From 09fac66d26adc61d34ce15344eb1f0121ac8a3da Mon Sep 17 00:00:00 2001 From: Kingkor Roy Tirtho Date: Mon, 4 Mar 2024 09:47:45 +0600 Subject: [PATCH 171/195] cd: debug upload artifact --- .github/workflows/spotube-release-binary.yml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/.github/workflows/spotube-release-binary.yml b/.github/workflows/spotube-release-binary.yml index 772c9fe2..25fcda31 100644 --- a/.github/workflows/spotube-release-binary.yml +++ b/.github/workflows/spotube-release-binary.yml @@ -424,6 +424,11 @@ jobs: RELEASE.md5sum RELEASE.sha256sum + - name: Debug With SSH + uses: mxschmitt/action-tmate@v3 + with: + limit-access-to-actor: true + - name: Upload Release Binaries (stable) if: ${{ !inputs.dry_run && inputs.channel == 'stable' }} uses: ncipollo/release-action@v1 From f09ab004bf6b9c6f16622a4e9f7a920a48fb8b9b Mon Sep 17 00:00:00 2001 From: Kingkor Roy Tirtho Date: Mon, 4 Mar 2024 10:51:41 +0600 Subject: [PATCH 172/195] cd: fix nightly linux tar not getting updated --- .github/workflows/spotube-release-binary.yml | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/.github/workflows/spotube-release-binary.yml b/.github/workflows/spotube-release-binary.yml index 25fcda31..aca07c4e 100644 --- a/.github/workflows/spotube-release-binary.yml +++ b/.github/workflows/spotube-release-binary.yml @@ -181,6 +181,7 @@ jobs: - uses: actions/upload-artifact@v3 + if: ${{ inputs.channel = 'release' }} with: if-no-files-found: error name: Spotube-Release-Binaries @@ -188,6 +189,16 @@ jobs: dist/Spotube-linux-x86_64.deb dist/Spotube-linux-x86_64.rpm dist/spotube-linux-${{ env.BUILD_VERSION }}-x86_64.tar.xz + + - uses: actions/upload-artifact@v3 + if: ${{ inputs.channel = 'nightly' }} + with: + if-no-files-found: error + name: Spotube-Release-Binaries + path: | + dist/Spotube-linux-x86_64.deb + dist/Spotube-linux-x86_64.rpm + dist/spotube-linux-nightly-x86_64.tar.xz - name: Debug With SSH When fails if: ${{ failure() && inputs.debug && inputs.channel == 'nightly' }} From 2c0b1a57e5a2103ef54c5b45e5a870e0613fc5ff Mon Sep 17 00:00:00 2001 From: Kingkor Roy Tirtho Date: Mon, 4 Mar 2024 10:53:00 +0600 Subject: [PATCH 173/195] cd: fix syntax error --- .github/workflows/spotube-release-binary.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/spotube-release-binary.yml b/.github/workflows/spotube-release-binary.yml index aca07c4e..adb99003 100644 --- a/.github/workflows/spotube-release-binary.yml +++ b/.github/workflows/spotube-release-binary.yml @@ -181,7 +181,7 @@ jobs: - uses: actions/upload-artifact@v3 - if: ${{ inputs.channel = 'release' }} + if: ${{ inputs.channel == 'release' }} with: if-no-files-found: error name: Spotube-Release-Binaries @@ -191,7 +191,7 @@ jobs: dist/spotube-linux-${{ env.BUILD_VERSION }}-x86_64.tar.xz - uses: actions/upload-artifact@v3 - if: ${{ inputs.channel = 'nightly' }} + if: ${{ inputs.channel == 'nightly' }} with: if-no-files-found: error name: Spotube-Release-Binaries From 649d6acfe2d88cceb34eaecd7b5a164aae31cde3 Mon Sep 17 00:00:00 2001 From: Kingkor Roy Tirtho Date: Tue, 5 Mar 2024 18:24:16 +0600 Subject: [PATCH 174/195] chore(macos): enable macos hardened runtime and use spotify from pub --- macos/Runner.xcodeproj/project.pbxproj | 1 + pubspec.lock | 11 +++++------ pubspec.yaml | 5 +---- 3 files changed, 7 insertions(+), 10 deletions(-) diff --git a/macos/Runner.xcodeproj/project.pbxproj b/macos/Runner.xcodeproj/project.pbxproj index e2e72334..0ee2c9fa 100644 --- a/macos/Runner.xcodeproj/project.pbxproj +++ b/macos/Runner.xcodeproj/project.pbxproj @@ -582,6 +582,7 @@ CODE_SIGN_STYLE = Automatic; COMBINE_HIDPI_IMAGES = YES; DEVELOPMENT_TEAM = 88NVGSJ5N3; + ENABLE_HARDENED_RUNTIME = YES; INFOPLIST_FILE = Runner/Info.plist; INFOPLIST_KEY_CFBundleDisplayName = Spotube; INFOPLIST_KEY_LSApplicationCategoryType = "public.app-category.music"; diff --git a/pubspec.lock b/pubspec.lock index b3658253..cc69663d 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -1961,12 +1961,11 @@ packages: spotify: dependency: "direct main" description: - path: "." - ref: fix-spotify-precision - resolved-ref: "1ddea720130203021a815253e37ebe5c06845dd2" - url: "https://github.com/KRTirtho/spotify-dart.git" - source: git - version: "0.13.1" + name: spotify + sha256: "2308a84511c18ec1e72515a57e28abb1467389549d571c460732b4538c2e34de" + url: "https://pub.dev" + source: hosted + version: "0.13.3" sqflite: dependency: transitive description: diff --git a/pubspec.yaml b/pubspec.yaml index 6fbfa8b7..5ccc5bb1 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -89,10 +89,6 @@ dependencies: shared_preferences: ^2.2.2 skeleton_text: ^3.0.1 smtc_windows: ^0.1.1 - spotify: - git: - url: https://github.com/KRTirtho/spotify-dart.git - ref: fix-spotify-precision stroke_text: ^0.0.2 system_theme: ^2.1.0 titlebar_buttons: ^1.0.0 @@ -129,6 +125,7 @@ dependencies: flutter_sharing_intent: ^1.1.0 flutter_broadcasts: ^0.4.0 freezed_annotation: ^2.4.1 + spotify: ^0.13.3 dev_dependencies: build_runner: ^2.3.2 From af1ce932a19ea061caf8085f3e78cd6b03a99193 Mon Sep 17 00:00:00 2001 From: Kingkor Roy Tirtho Date: Tue, 5 Mar 2024 18:36:46 +0600 Subject: [PATCH 175/195] docs: add hacker news link in both website and readme --- README.md | 2 ++ website/src/routes/+page.svelte | 6 +++++- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 18eb55aa..c59240b2 100644 --- a/README.md +++ b/README.md @@ -13,6 +13,8 @@ Btw it's not just another Electron app 😉 Support me on Patron Buy me a Coffee +[![HackerNews](https://hackerbadge.vercel.app/api?id=39066136&type=dark)](https://news.ycombinator.com/item?id=39066136) + Donate to our Open Collective --- diff --git a/website/src/routes/+page.svelte b/website/src/routes/+page.svelte index 8b78dbc5..7fe0a36f 100644 --- a/website/src/routes/+page.svelte +++ b/website/src/routes/+page.svelte @@ -62,8 +62,12 @@ Download on Flathub +
    + + HackerNews + -
    +
    Download From fdea9307bbfb8f3f62cfb795bfb3ca58c38c33d9 Mon Sep 17 00:00:00 2001 From: TAE-IN Sappho KIM Date: Tue, 5 Mar 2024 23:52:48 +0900 Subject: [PATCH 176/195] feat(translations): add Korean translation (#1275) * Create Korean translation * More natrual translation on Korean * Add credit of Korean translation --- lib/collections/language_codes.dart | 8 +- lib/l10n/app_ko.arb | 291 ++++++++++++++++++++++++++++ lib/l10n/l10n.dart | 2 + 3 files changed, 297 insertions(+), 4 deletions(-) create mode 100644 lib/l10n/app_ko.arb diff --git a/lib/collections/language_codes.dart b/lib/collections/language_codes.dart index 4754de46..4b7a3a90 100644 --- a/lib/collections/language_codes.dart +++ b/lib/collections/language_codes.dart @@ -353,10 +353,10 @@ abstract class LanguageLocals { // name: "Kongo", // nativeName: "KiKongo", // ), - // "ko": const ISOLanguageName( - // name: "Korean", - // nativeName: "한국어 (韓國語), 조선말 (朝鮮語)", - // ), + "ko": const ISOLanguageName( + name: "Korean", + nativeName: "한국어 (韓國語), 조선말 (朝鮮語)", + ), // "ku": const ISOLanguageName( // name: "Kurdish", // nativeName: "Kurdî, كوردی‎", diff --git a/lib/l10n/app_ko.arb b/lib/l10n/app_ko.arb new file mode 100644 index 00000000..dac5b72a --- /dev/null +++ b/lib/l10n/app_ko.arb @@ -0,0 +1,291 @@ +{ + "guest": "게스트", + "browse": "찾아보기", + "search": "검색", + "library": "라이브러리", + "lyrics": "가사", + "settings": "설정", + "genre_categories_filter": "카테고리 혹은 장르별로 불러오기", + "genre": "장르", + "personalized": "맞춤 추천", + "featured": "인기", + "new_releases": "신곡", + "songs": "노래", + "playing_track": "{track} 을 재생", + "queue_clear_alert": "현재 재생 대기열을 없앱니다。{track_length} 곡이 제거됩니다。\n계속 진행할까요?", + "load_more": "더 불러오기", + "playlists": "플레이리스트", + "artists": "아티스트", + "albums": "앨범", + "tracks": "곡", + "downloads": "다운로드한 곡", + "filter_playlists": "플레이리스트를 필터링", + "liked_tracks": "좋아하는 곡", + "liked_tracks_description": "좋아요를 남긴 곡들", + "create_playlist": "플레이리스트 생성", + "create_a_playlist": "플레이리스트를 생성", + "create": "생성", + "cancel": "취소", + "playlist_name": "플레이리스트명", + "name_of_playlist": "플레이리스트의 이름", + "description": "설명", + "public": "공개", + "collaborative": "공유 플레이리스트", + "search_local_tracks": "기기에 저장된 곡을 검색하기", + "play": "재생", + "delete": "삭제", + "none": "없음", + "sort_a_z": "A-Z 순으로 정렬", + "sort_z_a": "Z-A 순으로 정렬", + "sort_artist": "아티스트 순으로 정렬", + "sort_album": "앨범 순으로 정렬", + "sort_tracks": "곡명 순으로 정렬", + "currently_downloading": "현재 ({tracks_length}) 곡 다운로드 중", + "cancel_all": "모두 취소", + "filter_artist": "아티스트 필터링", + "followers": "{followers} 팔로워", + "add_artist_to_blacklist": "이 아티스트를 블랙리스트에 추가", + "top_tracks": "인기곡", + "fans_also_like": "애청자들이 좋아하는 곡", + "loading": "불러오는 중...", + "artist": "아티스트", + "blacklisted": "블랙리스트", + "following": "팔로우 중", + "follow": "팔로우하기", + "artist_url_copied": "아티스트의 URL 주소를 클립보드에 복사함", + "added_to_queue": "{tracks} 곡을 대기열에 추가함", + "filter_albums": "앨범 필터링", + "synced": "동기화됨", + "plain": "그대로", + "shuffle": "셔플", + "search_tracks": "곡 검색하기", + "released": "공개일", + "error": "에러", + "title": "타이틀", + "time": "길이", + "more_actions": "다른 작업", + "download_count": "({count}) 곡 다운로드", + "add_count_to_playlist": "플레이리스트에 ({count}) 곡을 추가", + "add_count_to_queue": "대기열에 ({count}) 곡을 추가", + "play_count_next": "이 다음에 ({count}) 곡을 재생", + "album": "앨범", + "copied_to_clipboard": "{data} 를 클립보드에 복사함", + "add_to_following_playlists": "{track} 을 이 플레이리스트에 추가", + "add": "추가", + "added_track_to_queue": "대기열에 {track} 을 추가함", + "add_to_queue": "대기열에 추가", + "track_will_play_next": "{track} 을 이 다음에 재생", + "play_next": "이 다음에 재생", + "removed_track_from_queue": "대기열에서 {track} 를 제거함", + "remove_from_queue": "대기열에서 제거", + "remove_from_favorites": "즐겨찾기에서 제거", + "save_as_favorite": "즐겨찾기에 추가", + "add_to_playlist": "플레이리스트에 추가", + "remove_from_playlist": "플레이리스트에서 제거", + "add_to_blacklist": "블랙리스트에 추가", + "remove_from_blacklist": "블랙리스트에서 제거", + "share": "공유", + "mini_player": "미니 플레이어", + "slide_to_seek": "앞뒤로 슬라이드하여 탐색", + "shuffle_playlist": "플레이리스트를 섞기", + "unshuffle_playlist": "플레이리스트를 섞지 않기", + "previous_track": "이전 곡", + "next_track": "다음 곡", + "pause_playback": "일시정지", + "resume_playback": "재개", + "loop_track": "반복 재생", + "repeat_playlist": "플레이리스트 반복", + "queue": "재생 대기열", + "alternative_track_sources": "대체가능한 음악 서버", + "download_track": "곡 다운로드", + "tracks_in_queue": "대기열에 {tracks} 곡이 있음", + "clear_all": "모두 제거", + "show_hide_ui_on_hover": "마우스를 올리면 UI를 표시/숨김", + "always_on_top": "항상 위에 표시", + "exit_mini_player": "미니 플레이어 닫기", + "download_location": "다운로드 경로", + "account": "계정", + "login_with_spotify": "Spotify 계정으로 로그인", + "connect_with_spotify": "Spotify에 연결", + "logout": "로그아웃", + "logout_of_this_account": "이 계정에서 로그아웃", + "language_region": "언어 & 지역", + "language": "언어", + "system_default": "시스템 기본설정", + "market_place_region": "마켓플레이스 지역", + "recommendation_country": "추천 국가", + "appearance": "디자인", + "layout_mode": "레이아웃 모드", + "override_layout_settings": "반응형 레이아웃 모드 설정 덮어씌우기", + "adaptive": "적응형", + "compact": "컴팩트", + "extended": "확장", + "theme": "테마", + "dark": "다크", + "light": "라이트", + "system": "시스템과 동일", + "accent_color": "보조색", + "sync_album_color": "앨범 색상", + "sync_album_color_description": "앨범아트의 주요 색상을 보조색으로 사용", + "playback": "재생", + "audio_quality": "음질", + "high": "높음", + "low": "낮음", + "pre_download_play": "재생할 곡을 미리 다운로드", + "pre_download_play_description": "스트리밍 방식을 쓰는 대신 파일 단위로 다운로드 받고 재생 (인터넷 대역폭이 높은 환경에서 추천)", + "skip_non_music": "음악이 아닌 부분을 스킵 (SponsorBlock)", + "blacklist_description": "블랙리스트에 추가된 곡과 아티스트", + "wait_for_download_to_finish": "현재 진행중인 다운로드가 끝날 때까지 기다려주세요", + "desktop": "데스크톱", + "close_behavior": "닫을 때의 동작", + "close": "닫기", + "minimize_to_tray": "트레이로 최소화", + "show_tray_icon": "시스템 트레이 아이콘 표시", + "about": "앱 정보", + "u_love_spotube": "Spotube... 사랑하시죠?", + "check_for_updates": "업데이트 확인", + "about_spotube": "Spotube에 관해", + "blacklist": "블랙리스트", + "please_sponsor": "후원해주시면 감사하겠습니다.", + "spotube_description": "Spotube는, 경량에 크로스플랫폼인데다 무료이기까지한 스포티파이 클라이언트입니다", + "version": "버전", + "build_number": "빌드 번호", + "founder": "창시자", + "repository": "리포지토리", + "bug_issues": "버그 및 이슈", + "made_with": "❤️을 담아 방글라데시에서 만듦", + "kingkor_roy_tirtho": "Kingkor Roy Tirtho", + "copyright": "© 2021-{current_year} Kingkor Roy Tirtho", + "license": "라이선스", + "add_spotify_credentials": "먼저 Spotify의 로그인정보를 추가하기", + "credentials_will_not_be_shared_disclaimer": "걱정마세요. 개인정보를 수집하거나 공유하지 않습니다.", + "know_how_to_login": "어떻게 하는건지 모르겠나요?", + "follow_step_by_step_guide": "사용법 확인하기", + "spotify_cookie": "Spotify {name} Cookies", + "cookie_name_cookie": "{name} Cookies", + "fill_in_all_fields": "모든 필드에 정보를 입력해주세요", + "submit": "제출", + "exit": "종료", + "previous": "이전으로", + "next": "다음으로", + "done": "완료", + "step_1": "1단계", + "first_go_to": "가장 먼저 먼저 들어갈 곳은 ", + "login_if_not_logged_in": "그리고 로그인을 하지 않았다면 로그인해주세요", + "step_2": "2단계", + "step_2_steps": "1. 로그인에 성공하면、F12나 마우스 우클릭 > 검사(Inspect)을 눌러 브라우저의 개발자 도구(devtools)를 열어주세요.\n2. 애플리케이션 (Application) 탭 (Chrome, Edge, Brave 등) 또는 스토리지 탭 (Firefox, Palemoon 등)을 열어주세요.\n3. 쿠키 (Cookies) 섹션으로 들어가서, https://accounts.spotify.com 서브섹션으로 들어가주세요.", + "step_3": "3단계", + "success_emoji": "성공🥳", + "success_message": "성공적으로 스포티파이 게정으로 로그인했습니다. 잘했어요!", + "step_4": "4단계", + "something_went_wrong": "알 수 없는 이유로 동작에 실패했습니다.", + "piped_instance": "Piped 서버의 인스턴스", + "piped_description": "곡 탐색에 사용할 Piped 서버 인스턴스", + "piped_warning": "몇몇 서버는 제대로 동작하지 않을 수 있습니다. 본인 책임 하에 이용해주세요.", + "generate_playlist": "플레이리스트 생성", + "track_exists": "곡 {track} 은 이미 리스트에 있습니다", + "replace_downloaded_tracks": "다운로드한 모든 곡을 교체", + "skip_download_tracks": "다운로드가 끝난 곡을 모두 건너뛰기", + "do_you_want_to_replace": "현재 곡을 교체하시겠습니까?", + "replace": "교체", + "skip": "건너뛰기", + "select_up_to_count_type": "{type}을 {count}개까지 선택", + "select_genres": "장르 선택", + "add_genres": "장르 추가", + "country": "국가", + "number_of_tracks_generate": "생성할 곡 수", + "acousticness": "반주 구간 (Acousticness)", + "danceability": "흥겨운 정도 (Danceability)", + "energy": "에너지 (Energy)", + "instrumentalness": "기악성 (Instrumentalness)", + "liveness": "생동감 (Liveness)", + "loudness": "라우드니스 (Loudness)", + "speechiness": "회화성 (Speechniss)", + "valence": "감정가 (Valence)", + "popularity": "인기도 (Popularity)", + "key": "조성 (키)", + "duration": "길이 (초)", + "tempo": "템포 (BPM)", + "mode": "장조", + "time_signature": "박자", + "short": "짧음", + "medium": "중간", + "long": "긺", + "min": "최소", + "max": "최대", + "target": "목표", + "moderate": "보통", + "deselect_all": "모두 선택해제", + "select_all": "모두 선택", + "are_you_sure": "괜찮겠습니까?", + "generating_playlist": "커스텀 플레이리스트를 생성하는 중...", + "selected_count_tracks": "{count} 곡이 선택되었습니다.", + "download_warning": "모든 트랙을 대량으로 다운로드하는 것은 명백한 불법 복제이며 음악 창작 사회에 피해를 입히는 행위입니다. 이 점을 알아주셨으면 합니다. 항상 아티스트의 노력을 존중하고 응원해 주세요.", + "download_ip_ban_warning": "참고로, 평소보다 과도한 다운로드 요청으로 인해 YouTube에서 IP가 차단될 수 있습니다. IP 차단은 해당 IP 기기에서 최소 2~3개월 동안 (로그인한 상태에서도) YouTube를 사용할 수 없음을 의미합니다. 그리고 이런 일이 발생하더라도 스포튜브는 어떠한 책임도 지지 않습니다.", + "by_clicking_accept_terms": "'동의'를 클릭하면 다음 약관에 동의하는 것입니다:", + "download_agreement_1": "알고 있습니다. 전 나쁜 사람입니다.", + "download_agreement_2": "제가 할 수 있는 모든 곳에서 아티스트를 지원할 것이며, 저는 그들의 작품을 살 돈이 없기 때문에 이렇게 하는 것뿐입니다.", + "download_agreement_3": "본인은 YouTube에서 내 IP가 차단될 수 있음을 완전히 알고 있으며, 현재 내 행동으로 인해 발생하는 사고에 대해 Spotube 또는 그 소유자/기여자에게 책임을 묻지 않습니다.", + "decline": "거절", + "accept": "동의", + "details": "상세", + "youtube": "YouTube", + "channel": "채널", + "likes": "좋아요", + "dislikes": "싫어요", + "views": "조회수", + "streamUrl": "스트림 URL", + "stop": "중지", + "sort_newest": "최근에 추가된 순으로 정렬", + "sort_oldest": "예전에 추가된 순으로 정렬", + "sleep_timer": "취침 타이머", + "mins": "{minutes} 분", + "hours": "{hours} 시간", + "hour": "{hours} 시간", + "custom_hours": "시간 설정", + "logs": "로그", + "developers": "개발", + "not_logged_in": "로그인하지 않았습니다", + "search_mode": "검색 모드", + "audio_source": "오디오 출처", + "ok": "알겠습니다", + "failed_to_encrypt": "암호화에 실패했습니다", + "encryption_failed_warning": "Spotube는 암호화를 사용하여 데이터를 안전하게 저장합니다. 하지만 그렇게 하지 못했습니다. 따라서 안전하지 않은 저장소로 대체됩니다.\n리눅스를 사용하는 경우, 비밀 서비스(gnome-keyring, kde-wallet, keepassxc 등)가 설치되어 있는지 확인하세요.", + "querying_info": "정보를 얻는 중...", + "piped_api_down": "Piped API가 응답하지 않습니다", + "piped_down_error_instructions": "Piped 인스턴스 {pipedInstance}가 현재 다운되었습니다.\n\n인스턴스를 변경하거나 'API 유형'을 공식 YouTube API로 변경하세요.\n\n변경 후 앱을 다시 시작해야 합니다.", + "you_are_offline": "현재 오프라인입니다", + "connection_restored": "인터넷에 다시 연결되었습니다", + "use_system_title_bar": "시스템 타이틀바를 사용", + "update_playlist": "플레이리스트를 업데이트", + "update": "업데이트", + "crunching_results": "결과를 처리하는 중...", + "search_to_get_results": "결과를 얻으려면 검색해주세요", + "use_amoled_mode": "AMOLED모드를 사용", + "pitch_dark_theme": "검정색 기반의 어두운 테마", + "normalize_audio": "오디오 노멀라이즈", + "change_cover": "커버 변경", + "add_cover": "커버 추가", + "restore_defaults": "기본값으로 복원", + "download_music_codec": "다운로드 음악 코덱", + "streaming_music_codec": "스트리밍 음악 코덱", + "login_with_lastfm": "Last.fm에 로그인", + "connect": "연결", + "disconnect_lastfm": "Last.fm에서 연결 해제", + "disconnect": "연결 해제", + "username": "사용자명", + "password": "비밀번호", + "login": "로그인", + "login_with_your_lastfm": "내 Last.fm 계정으로로그인", + "scrobble_to_lastfm": "Scrobble to Last.fm", + "go_to_album": "앨범으로 이동", + "discord_rich_presence": "Discord Rich Presence", + "browse_all": "모두 탐색", + "genres": "장르", + "explore_genres": "장르 탐색", + "step_3_steps": "\"sp_dc\" 쿠키의 값을 복사", + "step_4_steps": "복사한 \"sp_dc\"값을 붙여넣기", + "friends": "친구", + "no_lyrics_available": "죄송하지만 이 곡의 가사를 찾지 못했습니다", + "@@locale": "ko" +} diff --git a/lib/l10n/l10n.dart b/lib/l10n/l10n.dart index 364e542a..7aec682a 100644 --- a/lib/l10n/l10n.dart +++ b/lib/l10n/l10n.dart @@ -10,6 +10,7 @@ /// mdksec@github => Turkish /// Stephan-P@github, SecularSteve@github => Dutch /// doannc2212@github => Vietnamese +/// sappho192@github => Korean import 'package:flutter/material.dart'; class L10n { @@ -26,6 +27,7 @@ class L10n { const Locale('hi', 'IN'), const Locale('it', 'IT'), const Locale('ja', 'JP'), + const Locale('ko', 'KR'), const Locale('nl', 'NL'), const Locale('pl', 'PL'), const Locale('pt', 'PT'), From d0f6f9d9f6130b91986c3f2d03f60501cf848f36 Mon Sep 17 00:00:00 2001 From: Kingkor Roy Tirtho Date: Tue, 5 Mar 2024 22:09:52 +0600 Subject: [PATCH 177/195] chore: add test macos cask definition --- Casks/spotube.rb | 22 ++++++++++++++++++++++ linux/spotube.desktop | 1 + 2 files changed, 23 insertions(+) create mode 100644 Casks/spotube.rb diff --git a/Casks/spotube.rb b/Casks/spotube.rb new file mode 100644 index 00000000..32a92802 --- /dev/null +++ b/Casks/spotube.rb @@ -0,0 +1,22 @@ +cask "spotube" do + version "3.4.1" + sha256 "5686cb0b1b261399062250c36b7bf9c481e4c36c76615d787e01c77036fe6cba" + + url "https://github.com/KRTirtho/spotube/releases/download/v#{version}/Spotube-macos-universal.dmg", + verified: "github.com/KRTirtho/spotube/" + name "Spotube" + desc "🎧 Open source Spotify client that doesn't require Premium nor uses Electron! Available for both desktop & mobile!" + homepage "https://spotube.krtirtho.dev/" + + livecheck do + url :url + strategy :github_latest + end + + app "spotube.app" + + zap trash: [ + "~/Library/Application Scripts/oss.krtirtho.spotube", + "~/Library/Containers/oss.krtirtho.spotube", + ] +end \ No newline at end of file diff --git a/linux/spotube.desktop b/linux/spotube.desktop index 0bda851f..53f381e1 100644 --- a/linux/spotube.desktop +++ b/linux/spotube.desktop @@ -6,3 +6,4 @@ Icon=/usr/share/icons/spotube/spotube-logo.png Comment=A music streaming app combining the power of Spotify & YouTube Terminal=false Categories=Audio;Music;Player;AudioVideo; +MimeType=x-scheme-handler/spotify; \ No newline at end of file From d1f0e778f6998cfcf182dc2a607472ab0e17b8b3 Mon Sep 17 00:00:00 2001 From: Kingkor Roy Tirtho Date: Tue, 5 Mar 2024 22:17:56 +0600 Subject: [PATCH 178/195] chore: remove casks --- Casks/spotube.rb | 22 ---------------------- 1 file changed, 22 deletions(-) delete mode 100644 Casks/spotube.rb diff --git a/Casks/spotube.rb b/Casks/spotube.rb deleted file mode 100644 index 32a92802..00000000 --- a/Casks/spotube.rb +++ /dev/null @@ -1,22 +0,0 @@ -cask "spotube" do - version "3.4.1" - sha256 "5686cb0b1b261399062250c36b7bf9c481e4c36c76615d787e01c77036fe6cba" - - url "https://github.com/KRTirtho/spotube/releases/download/v#{version}/Spotube-macos-universal.dmg", - verified: "github.com/KRTirtho/spotube/" - name "Spotube" - desc "🎧 Open source Spotify client that doesn't require Premium nor uses Electron! Available for both desktop & mobile!" - homepage "https://spotube.krtirtho.dev/" - - livecheck do - url :url - strategy :github_latest - end - - app "spotube.app" - - zap trash: [ - "~/Library/Application Scripts/oss.krtirtho.spotube", - "~/Library/Containers/oss.krtirtho.spotube", - ] -end \ No newline at end of file From bda76a59ecc59be79b858de0cc0399b98ffd8332 Mon Sep 17 00:00:00 2001 From: Kingkor Roy Tirtho Date: Tue, 5 Mar 2024 22:45:06 +0600 Subject: [PATCH 179/195] docs: add installation through homebrew instruction in README --- README.md | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/README.md b/README.md index 18eb55aa..b8f0c9b8 100644 --- a/README.md +++ b/README.md @@ -136,6 +136,15 @@ This handy table lists all the methods you can use to install Spotube:

    + + + + + + + + com.github.KRTirtho.Spotube.desktop From f4dce2f6116e57458803d4291560156c52f74b5f Mon Sep 17 00:00:00 2001 From: MerkomassDev <70111455+MerkomassDev@users.noreply.github.com> Date: Wed, 20 Mar 2024 16:20:09 +0100 Subject: [PATCH 195/195] docs: broken link in README.md (fixes #1310) (#1311) --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index de00054f..4ad4e1be 100644 --- a/README.md +++ b/README.md @@ -7,7 +7,7 @@ eliminating the need for Spotify Premium Btw it's not just another Electron app 😉 -Visit the website +Visit the website Discord Server Support me on Patron
    Macos - Homebrew +
    +brew tap krtirtho/apps
    +brew install --cask spotube
    +
    +
    Windows - Chocolatey From 88c6822555822998f744d76d235a772acf4ee40c Mon Sep 17 00:00:00 2001 From: Kingkor Roy Tirtho Date: Tue, 5 Mar 2024 22:09:52 +0600 Subject: [PATCH 180/195] chore: add test macos cask definition --- Casks/spotube.rb | 22 ++++++++++++++++++++++ linux/spotube.desktop | 1 + 2 files changed, 23 insertions(+) create mode 100644 Casks/spotube.rb diff --git a/Casks/spotube.rb b/Casks/spotube.rb new file mode 100644 index 00000000..32a92802 --- /dev/null +++ b/Casks/spotube.rb @@ -0,0 +1,22 @@ +cask "spotube" do + version "3.4.1" + sha256 "5686cb0b1b261399062250c36b7bf9c481e4c36c76615d787e01c77036fe6cba" + + url "https://github.com/KRTirtho/spotube/releases/download/v#{version}/Spotube-macos-universal.dmg", + verified: "github.com/KRTirtho/spotube/" + name "Spotube" + desc "🎧 Open source Spotify client that doesn't require Premium nor uses Electron! Available for both desktop & mobile!" + homepage "https://spotube.krtirtho.dev/" + + livecheck do + url :url + strategy :github_latest + end + + app "spotube.app" + + zap trash: [ + "~/Library/Application Scripts/oss.krtirtho.spotube", + "~/Library/Containers/oss.krtirtho.spotube", + ] +end \ No newline at end of file diff --git a/linux/spotube.desktop b/linux/spotube.desktop index 0bda851f..53f381e1 100644 --- a/linux/spotube.desktop +++ b/linux/spotube.desktop @@ -6,3 +6,4 @@ Icon=/usr/share/icons/spotube/spotube-logo.png Comment=A music streaming app combining the power of Spotify & YouTube Terminal=false Categories=Audio;Music;Player;AudioVideo; +MimeType=x-scheme-handler/spotify; \ No newline at end of file From 06a7ecf393ff382900e904fff7b42b2b3737a321 Mon Sep 17 00:00:00 2001 From: Kingkor Roy Tirtho Date: Tue, 5 Mar 2024 22:17:56 +0600 Subject: [PATCH 181/195] chore: remove casks --- Casks/spotube.rb | 22 ---------------------- 1 file changed, 22 deletions(-) delete mode 100644 Casks/spotube.rb diff --git a/Casks/spotube.rb b/Casks/spotube.rb deleted file mode 100644 index 32a92802..00000000 --- a/Casks/spotube.rb +++ /dev/null @@ -1,22 +0,0 @@ -cask "spotube" do - version "3.4.1" - sha256 "5686cb0b1b261399062250c36b7bf9c481e4c36c76615d787e01c77036fe6cba" - - url "https://github.com/KRTirtho/spotube/releases/download/v#{version}/Spotube-macos-universal.dmg", - verified: "github.com/KRTirtho/spotube/" - name "Spotube" - desc "🎧 Open source Spotify client that doesn't require Premium nor uses Electron! Available for both desktop & mobile!" - homepage "https://spotube.krtirtho.dev/" - - livecheck do - url :url - strategy :github_latest - end - - app "spotube.app" - - zap trash: [ - "~/Library/Application Scripts/oss.krtirtho.spotube", - "~/Library/Containers/oss.krtirtho.spotube", - ] -end \ No newline at end of file From 0742e898e3b5ca93597d19b0606524f9c43f5c56 Mon Sep 17 00:00:00 2001 From: Kingkor Roy Tirtho Date: Tue, 5 Mar 2024 22:45:06 +0600 Subject: [PATCH 182/195] docs: add installation through homebrew instruction in README --- README.md | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/README.md b/README.md index c59240b2..469d03ac 100644 --- a/README.md +++ b/README.md @@ -138,6 +138,15 @@ This handy table lists all the methods you can use to install Spotube:
    Macos - Homebrew +
    +brew tap krtirtho/apps
    +brew install --cask spotube
    +
    +
    Windows - Chocolatey From 60f2911eb9ffcda9df45ca3bfc6444242bc1834b Mon Sep 17 00:00:00 2001 From: Kingkor Roy Tirtho Date: Tue, 5 Mar 2024 22:55:33 +0600 Subject: [PATCH 183/195] website: add homebrew instructions --- .../src/routes/downloads/packages/+page.svx | 23 ++++++++++++++----- 1 file changed, 17 insertions(+), 6 deletions(-) diff --git a/website/src/routes/downloads/packages/+page.svx b/website/src/routes/downloads/packages/+page.svx index e7da4e74..0ab570c2 100644 --- a/website/src/routes/downloads/packages/+page.svx +++ b/website/src/routes/downloads/packages/+page.svx @@ -4,7 +4,7 @@ author: Kingkor Roy Tirtho --- @@ -15,7 +15,7 @@ author: Kingkor Roy Tirtho ## Linux -### Flatpak +### Flatpak📦 Make sure [Flatpak](https://flatpak.org) is installed in your Linux device & Run the following command in the terminal: @@ -23,7 +23,7 @@ Make sure [Flatpak](https://flatpak.org) is installed in your Linux device & Run $ flatpak install com.github.KRTirtho.Spotube ``` -### Arch User Repository (AUR) +### Arch User Repository (AUR)♾️ If you're an Arch Linux user, you can also install Spotube from AUR. Make sure you have `yay`/`pamac`/`paru` installed in your system. And Run the Following command in the Terminal: @@ -40,9 +40,20 @@ $ pamac install spotube-bin $ paru -Sy spotube-bin ``` +## MacOS + +### Homebrew🍻 + +Spotube can be installed through Homebrew. We host our own cask definition thus you'll need to add our tap first: + +```bash +$ brew tap krtirtho/apps +$ brew install --cask spotube +``` + ## Windows -### Chocolatey +### Chocolatey🍫 Spotube is available in [community.chocolatey.org](https://community.chocolatey.org) repo. If you have chocolatey install in your system just run following command in an Elevated Command Prompt or PowerShell: @@ -50,7 +61,7 @@ Spotube is available in [community.chocolatey.org](https://community.chocolatey. $ choco install spotube ``` -### WinGet +### WinGet💫 Spotube is also available in the Official Windows PackageManager WinGet. Make sure you have WinGet installed in your Windows machine and run following in a Terminal: @@ -58,7 +69,7 @@ Spotube is also available in the Official Windows PackageManager WinGet. Make su $ winget install --id KRTirtho.Spotube ``` -### Scoop +### Scoop🥄 Spotube is also available in [Scoop](https://scoop.sh) bucket. Make sure you have Scoop installed in your Windows machine and run following in a Terminal: From ca76a39910b1a5af91aa7882a0d33c9d71db58a2 Mon Sep 17 00:00:00 2001 From: Kingkor Roy Tirtho Date: Fri, 8 Mar 2024 19:10:33 +0600 Subject: [PATCH 184/195] fix: album images are small in certain places --- lib/components/album/album_card.dart | 4 ++-- lib/pages/album/album.dart | 1 - lib/utils/type_conversion_utils.dart | 9 +++++++-- untranslated_messages.json | 30 ++++++++++++++++++++++++++++ 4 files changed, 39 insertions(+), 5 deletions(-) diff --git a/lib/components/album/album_card.dart b/lib/components/album/album_card.dart index c7ae2f9a..4d2e12d6 100644 --- a/lib/components/album/album_card.dart +++ b/lib/components/album/album_card.dart @@ -21,8 +21,8 @@ class AlbumCard extends HookConsumerWidget { final AlbumSimple album; const AlbumCard( this.album, { - Key? key, - }) : super(key: key); + super.key, + }); @override Widget build(BuildContext context, ref) { diff --git a/lib/pages/album/album.dart b/lib/pages/album/album.dart index 6cba99f6..4578aea2 100644 --- a/lib/pages/album/album.dart +++ b/lib/pages/album/album.dart @@ -47,7 +47,6 @@ class AlbumPage extends HookConsumerWidget { image: TypeConversionUtils.image_X_UrlString( album.images, placeholder: ImagePlaceholder.albumArt, - index: 0, ), title: album.name!, description: diff --git a/lib/utils/type_conversion_utils.dart b/lib/utils/type_conversion_utils.dart index 662b611c..cd594a2a 100644 --- a/lib/utils/type_conversion_utils.dart +++ b/lib/utils/type_conversion_utils.dart @@ -2,6 +2,7 @@ import 'dart:io'; +import 'package:collection/collection.dart'; import 'package:flutter/widgets.dart' hide Image; import 'package:metadata_god/metadata_god.dart'; import 'package:path/path.dart'; @@ -32,8 +33,12 @@ abstract class TypeConversionUtils { "https://avatars.dicebear.com/api/bottts/${PrimitiveUtils.uuid.v4()}.png", }[placeholder]!; - return images != null && images.isNotEmpty - ? images[index > images.length - 1 ? images.length - 1 : index].url! + final sortedImage = images?.sorted((a, b) => a.width!.compareTo(b.width!)); + + return sortedImage != null && sortedImage.isNotEmpty + ? sortedImage[ + index > sortedImage.length - 1 ? sortedImage.length - 1 : index] + .url! : placeholderUrl; } diff --git a/untranslated_messages.json b/untranslated_messages.json index 14eead0f..a6724f2b 100644 --- a/untranslated_messages.json +++ b/untranslated_messages.json @@ -299,6 +299,36 @@ "browse_anonymously" ], + "ko": [ + "sort_duration", + "start_a_radio", + "how_to_start_radio", + "replace_queue_question", + "endless_playback", + "delete_playlist", + "delete_playlist_confirmation", + "local_tracks", + "song_link", + "skip_this_nonsense", + "freedom_of_music", + "freedom_of_music_palm", + "get_started", + "youtube_source_description", + "piped_source_description", + "jiosaavn_source_description", + "highest_quality", + "select_audio_source", + "endless_playback_description", + "choose_your_region", + "choose_your_region_description", + "choose_your_language", + "help_project_grow", + "help_project_grow_description", + "contribute_on_github", + "donate_on_open_collective", + "browse_anonymously" + ], + "ne": [ "sort_duration", "start_a_radio", From b354f57d4e6eb0a471ae23cd4e3dcbb9e7e9a0cd Mon Sep 17 00:00:00 2001 From: Kingkor Roy Tirtho Date: Fri, 8 Mar 2024 19:12:40 +0600 Subject: [PATCH 185/195] chore: hide songlink when not youtube track --- lib/components/player/player.dart | 38 +++++++++++++++---------------- 1 file changed, 19 insertions(+), 19 deletions(-) diff --git a/lib/components/player/player.dart b/lib/components/player/player.dart index 01e38670..458676e3 100644 --- a/lib/components/player/player.dart +++ b/lib/components/player/player.dart @@ -24,6 +24,7 @@ import 'package:spotube/models/local_track.dart'; import 'package:spotube/pages/lyrics/lyrics.dart'; import 'package:spotube/provider/authentication_provider.dart'; import 'package:spotube/provider/proxy_playlist/proxy_playlist_provider.dart'; +import 'package:spotube/services/sourced_track/sources/youtube.dart'; import 'package:spotube/utils/type_conversion_utils.dart'; import 'package:url_launcher/url_launcher_string.dart'; @@ -138,26 +139,25 @@ class PlayerView extends HookConsumerWidget { onPressed: panelController.close, ), actions: [ - TextButton.icon( - icon: Assets.logos.songlinkTransparent.image( - width: 20, - height: 20, - color: bodyTextColor, - ), - label: Text(context.l10n.song_link), - style: TextButton.styleFrom( - foregroundColor: bodyTextColor, - padding: EdgeInsets.zero, - ), - onPressed: currentTrack == null - ? null - : () { - final url = - "https://song.link/s/${currentTrack.id}"; + if (currentTrack is YoutubeSourcedTrack) + TextButton.icon( + icon: Assets.logos.songlinkTransparent.image( + width: 20, + height: 20, + color: bodyTextColor, + ), + label: Text(context.l10n.song_link), + style: TextButton.styleFrom( + foregroundColor: bodyTextColor, + padding: EdgeInsets.zero, + ), + onPressed: () { + final url = + "https://song.link/s/${currentTrack.id}"; - launchUrlString(url); - }, - ), + launchUrlString(url); + }, + ), IconButton( icon: const Icon(SpotubeIcons.info, size: 18), tooltip: context.l10n.details, From 5019c14c443908f1245c07a84b38adc8b2caf257 Mon Sep 17 00:00:00 2001 From: Kingkor Roy Tirtho Date: Fri, 8 Mar 2024 19:50:57 +0600 Subject: [PATCH 186/195] chore: fix getting started screen theme and bump version and generate changelogs --- CHANGELOG.md | 31 +++++ lib/extensions/string.dart | 6 + .../getting_started/getting_started.dart | 116 ++++++++++-------- .../getting_started/sections/playback.dart | 3 +- .../audio_player/mk_state_player.dart | 30 +++-- pubspec.yaml | 2 +- 6 files changed, 117 insertions(+), 71 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8f48b39e..02624a7f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,37 @@ All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines. +## [3.5.0](https://github.com/krtirtho/spotube/compare/v3.4.1...v3.5.0) (2024-03-08) + + +### Features + +* add endless playback support [#285](https://github.com/krtirtho/spotube/issues/285) ([9dfd49c](https://github.com/krtirtho/spotube/commit/9dfd49ca04f0e915e333e205b17ac70456873f6e)) +* add getting started page ([96a2a1f](https://github.com/krtirtho/spotube/commit/96a2a1f5a622cb3c580041417d5023e37fa69716)) +* Add iOS background play support ([#1166](https://github.com/krtirtho/spotube/issues/1166)) ([095587e](https://github.com/krtirtho/spotube/commit/095587ee84f7d867c69fcf4b09ed608d63478e1e)) +* add songlink based track matching for youtube and open song link button ([9095a8c](https://github.com/krtirtho/spotube/commit/9095a8c8f849e42daabb7efcc20085cfb863c974)) +* **playlist:** show confirmation before deleting user playlist [#1222](https://github.com/krtirtho/spotube/issues/1222) ([9f92440](https://github.com/krtirtho/spotube/commit/9f9244062a39759aa0ce28d2d5f7c8fa53d73003)) +* Sort by Duration ([#1238](https://github.com/krtirtho/spotube/issues/1238)) ([6f8271f](https://github.com/krtirtho/spotube/commit/6f8271f5e9394cb4053e41dd222aa2844c34d609)) +* start radio support ([4defeef](https://github.com/krtirtho/spotube/commit/4defeefe7e5947aa00a2afb2a06577ec141cdc52)) +* **translations:** add Korean translation ([#1275](https://github.com/krtirtho/spotube/issues/1275)) ([fdea930](https://github.com/krtirtho/spotube/commit/fdea9307bbfb8f3f62cfb795bfb3ca58c38c33d9)) +* **translations:** Added Vietnamese ([#1135](https://github.com/krtirtho/spotube/issues/1135)) ([019ba86](https://github.com/krtirtho/spotube/commit/019ba865e20a8b54ea3490c01e47158eaf3a4c8d)) +* **windows:** Install Visual C++ 2015-2022 Redistributable if missing when installing ([ba69496](https://github.com/krtirtho/spotube/commit/ba69496dcc9a1b7f6ea4e104e71764a854d27f1f)) + + +### Bug Fixes + +* album images are small in certain places ([ca76a39](https://github.com/krtirtho/spotube/commit/ca76a39910b1a5af91aa7882a0d33c9d71db58a2)) +* album, artist page not loading [#1282](https://github.com/krtirtho/spotube/issues/1282) ([a9a1d4c](https://github.com/krtirtho/spotube/commit/a9a1d4c9dc24aaf3181dc4090d1822ebfe755991)) +* **android:** audio issue when screen is off and broadcast audio session id ([#1221](https://github.com/krtirtho/spotube/issues/1221) & [#1247](https://github.com/krtirtho/spotube/issues/1247)) ([17105a6](https://github.com/krtirtho/spotube/commit/17105a640bf5107bd5d333b9b4d097c14a3949a2)), closes [KRTirtho/spotube#571](https://github.com/KRTirtho/spotube/issues/571) +* **android:** pressing back button in any other tab other than home exits the app ([c3289a0](https://github.com/krtirtho/spotube/commit/c3289a0ba4e7de094a15246677ffcb940504ebde)) +* **android:** system back button in player page exits the app ([3294f65](https://github.com/krtirtho/spotube/commit/3294f657fe8a03b18d9be8974968b6508465963d)) +* cleanTitle removing feat and ft from words instead of whole words ([8612345](https://github.com/krtirtho/spotube/commit/86123456f2ff577921cf62cffca180427dfe1dd5)) +* friends list not scrollable with mouse drag ([ab08c82](https://github.com/krtirtho/spotube/commit/ab08c82c8dd501263049f3adcbd48907ba13e3a9)) +* no draggable scrollbar in playlist/album page [#1158](https://github.com/krtirtho/spotube/issues/1158) ([6f71e52](https://github.com/krtirtho/spotube/commit/6f71e52ea8a5712d2c3527f2a524af9fbb718bef)) +* non-banger songs breaking the queue if sources not found ([90f7c53](https://github.com/krtirtho/spotube/commit/90f7c531cdc8640afdbabf5a0592159715ea1e6f)) +* track loading when not found in Youtube ([e964f61](https://github.com/krtirtho/spotube/commit/e964f61d38cb303e3d3fd60c866414f57207181c)) +* **translations:** Update app_nl.arb ([#1168](https://github.com/krtirtho/spotube/issues/1168)) ([8167963](https://github.com/krtirtho/spotube/commit/8167963212eeb5dfb0b4fb2eadf81d466659a9f1)) + ## [3.4.1](https://personal.github.com/krtirtho/spotube/compare/v3.4.0...v3.4.1) (2024-01-27) diff --git a/lib/extensions/string.dart b/lib/extensions/string.dart index b7ab7514..0aa41dc6 100644 --- a/lib/extensions/string.dart +++ b/lib/extensions/string.dart @@ -9,3 +9,9 @@ extension UnescapeHtml on String { extension NullableUnescapeHtml on String? { String? unescapeHtml() => this == null ? null : htmlEscape.convert(this!); } + +extension StringExtension on String { + String capitalize() { + return "${this[0].toUpperCase()}${substring(1)}"; + } +} diff --git a/lib/pages/getting_started/getting_started.dart b/lib/pages/getting_started/getting_started.dart index 724fb346..cbab03b9 100644 --- a/lib/pages/getting_started/getting_started.dart +++ b/lib/pages/getting_started/getting_started.dart @@ -8,13 +8,20 @@ import 'package:spotube/pages/getting_started/sections/greeting.dart'; import 'package:spotube/pages/getting_started/sections/playback.dart'; import 'package:spotube/pages/getting_started/sections/region.dart'; import 'package:spotube/pages/getting_started/sections/support.dart'; +import 'package:spotube/provider/user_preferences/user_preferences_provider.dart'; +import 'package:spotube/themes/theme.dart'; class GettingStarting extends HookConsumerWidget { const GettingStarting({super.key}); @override Widget build(BuildContext context, ref) { - final ThemeData(:colorScheme) = Theme.of(context); + final preferences = ref.watch(userPreferencesProvider); + final themeData = theme( + preferences.accentColorScheme, + Brightness.dark, + preferences.amoledDarkTheme, + ); final pageController = usePageController(); final onNext = useCallback(() { @@ -31,63 +38,66 @@ class GettingStarting extends HookConsumerWidget { ); }, [pageController]); - return Scaffold( - appBar: PageWindowTitleBar( - backgroundColor: Colors.transparent, - actions: [ - ListenableBuilder( - listenable: pageController, - builder: (context, _) { - return AnimatedSwitcher( - duration: const Duration(milliseconds: 300), - child: pageController.hasClients && - (pageController.page == 0 || pageController.page == 3) - ? const SizedBox() - : TextButton( - onPressed: () { - pageController.animateToPage( - 3, - duration: const Duration(milliseconds: 300), - curve: Curves.easeInOut, - ); - }, - child: Text( - context.l10n.skip_this_nonsense, - style: TextStyle( - decoration: TextDecoration.underline, - decorationColor: colorScheme.primary, + return Theme( + data: themeData, + child: Scaffold( + appBar: PageWindowTitleBar( + backgroundColor: Colors.transparent, + actions: [ + ListenableBuilder( + listenable: pageController, + builder: (context, _) { + return AnimatedSwitcher( + duration: const Duration(milliseconds: 300), + child: pageController.hasClients && + (pageController.page == 0 || pageController.page == 3) + ? const SizedBox() + : TextButton( + onPressed: () { + pageController.animateToPage( + 3, + duration: const Duration(milliseconds: 300), + curve: Curves.easeInOut, + ); + }, + child: Text( + context.l10n.skip_this_nonsense, + style: TextStyle( + decoration: TextDecoration.underline, + decorationColor: themeData.colorScheme.primary, + ), ), ), - ), - ); - }, - ), - ], - ), - extendBodyBehindAppBar: true, - body: DecoratedBox( - decoration: BoxDecoration( - image: DecorationImage( - image: Assets.bengaliPatternsBg.provider(), - fit: BoxFit.cover, - colorFilter: ColorFilter.mode( - colorScheme.background.withOpacity(0.2), - BlendMode.srcOver, + ); + }, ), - ), - ), - child: PageView( - controller: pageController, - children: [ - GettingStartedPageGreetingSection(onNext: onNext), - GettingStartedPageLanguageRegionSection(onNext: onNext), - GettingStartedPagePlaybackSection( - onNext: onNext, - onPrevious: onPrevious, - ), - const GettingStartedScreenSupportSection(), ], ), + extendBodyBehindAppBar: true, + body: DecoratedBox( + decoration: BoxDecoration( + image: DecorationImage( + image: Assets.bengaliPatternsBg.provider(), + fit: BoxFit.cover, + colorFilter: const ColorFilter.mode( + Colors.black38, + BlendMode.srcOver, + ), + ), + ), + child: PageView( + controller: pageController, + children: [ + GettingStartedPageGreetingSection(onNext: onNext), + GettingStartedPageLanguageRegionSection(onNext: onNext), + GettingStartedPagePlaybackSection( + onNext: onNext, + onPrevious: onPrevious, + ), + const GettingStartedScreenSupportSection(), + ], + ), + ), ), ); } diff --git a/lib/pages/getting_started/sections/playback.dart b/lib/pages/getting_started/sections/playback.dart index e94a06cc..298cf839 100644 --- a/lib/pages/getting_started/sections/playback.dart +++ b/lib/pages/getting_started/sections/playback.dart @@ -6,6 +6,7 @@ import 'package:spotube/collections/assets.gen.dart'; import 'package:spotube/collections/spotube_icons.dart'; import 'package:spotube/components/getting_started/blur_card.dart'; import 'package:spotube/extensions/context.dart'; +import 'package:spotube/extensions/string.dart'; import 'package:spotube/provider/user_preferences/user_preferences_provider.dart'; import 'package:spotube/provider/user_preferences/user_preferences_state.dart'; @@ -87,7 +88,7 @@ class GettingStartedPagePlaybackSection extends HookConsumerWidget { audioSourceToIconMap[source]!, const Gap(8), Text( - source.name, + source.name.capitalize(), style: textTheme.bodySmall!.copyWith( color: preferences.audioSource == source ? colorScheme.primary diff --git a/lib/services/audio_player/mk_state_player.dart b/lib/services/audio_player/mk_state_player.dart index 04df7111..8b796d66 100644 --- a/lib/services/audio_player/mk_state_player.dart +++ b/lib/services/audio_player/mk_state_player.dart @@ -17,13 +17,6 @@ class MkPlayerWithState extends Player { final StreamController _shuffleStream; final StreamController _loopModeStream; - static const String EXTRA_PACKAGE_NAME = "android.media.extra.PACKAGE_NAME"; - static const String EXTRA_AUDIO_SESSION = "android.media.extra.AUDIO_SESSION"; - static const String ACTION_OPEN_AUDIO_EFFECT_CONTROL_SESSION = - "android.media.action.OPEN_AUDIO_EFFECT_CONTROL_SESSION"; - static const String ACTION_CLOSE_AUDIO_EFFECT_CONTROL_SESSION = - "android.media.action.CLOSE_AUDIO_EFFECT_CONTROL_SESSION"; - late final List _subscriptions; bool _shuffled; @@ -87,23 +80,28 @@ class MkPlayerWithState extends Player { await _androidAudioManager!.generateAudioSessionId(); notifyAudioSessionUpdate(true); - nativePlayer.setProperty( - "audiotrack-session-id", _androidAudioSessionId.toString()); - nativePlayer.setProperty("ao", "audiotrack,opensles,"); + await nativePlayer.setProperty( + "audiotrack-session-id", + _androidAudioSessionId.toString(), + ); + await nativePlayer.setProperty("ao", "audiotrack,opensles,"); }); } } Future notifyAudioSessionUpdate(bool active) async { if (DesktopTools.platform.isAndroid) { - sendBroadcast(BroadcastMessage( + sendBroadcast( + BroadcastMessage( name: active - ? ACTION_OPEN_AUDIO_EFFECT_CONTROL_SESSION - : ACTION_CLOSE_AUDIO_EFFECT_CONTROL_SESSION, + ? "android.media.action.OPEN_AUDIO_EFFECT_CONTROL_SESSION" + : "android.media.action.CLOSE_AUDIO_EFFECT_CONTROL_SESSION", data: { - EXTRA_AUDIO_SESSION: _androidAudioSessionId, - EXTRA_PACKAGE_NAME: _packageName - })); + "android.media.extra.AUDIO_SESSION": _androidAudioSessionId, + "android.media.extra.PACKAGE_NAME": _packageName + }, + ), + ); } } diff --git a/pubspec.yaml b/pubspec.yaml index 5ccc5bb1..04d3f1a4 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -3,7 +3,7 @@ description: Open source Spotify client that doesn't require Premium nor uses El publish_to: "none" -version: 3.4.1+28 +version: 3.5.0+29 homepage: https://spotube.krtirtho.dev repository: https://github.com/KRTirtho/spotube From a6164c5791eef6f66b9b7585a0b3ab9a8749835b Mon Sep 17 00:00:00 2001 From: Kingkor Roy Tirtho Date: Fri, 8 Mar 2024 20:53:04 +0600 Subject: [PATCH 187/195] chore: add untranslated messages --- bin/translated_messages.dart | 26 ++++++++++++++++++++++++++ lib/l10n/app_ar.arb | 29 ++++++++++++++++++++++++++++- lib/l10n/app_bn.arb | 29 ++++++++++++++++++++++++++++- lib/l10n/app_ca.arb | 29 ++++++++++++++++++++++++++++- lib/l10n/app_de.arb | 29 ++++++++++++++++++++++++++++- lib/l10n/app_es.arb | 29 ++++++++++++++++++++++++++++- lib/l10n/app_fa.arb | 29 ++++++++++++++++++++++++++++- lib/l10n/app_fr.arb | 29 ++++++++++++++++++++++++++++- lib/l10n/app_hi.arb | 29 ++++++++++++++++++++++++++++- lib/l10n/app_it.arb | 29 ++++++++++++++++++++++++++++- lib/l10n/app_ja.arb | 29 ++++++++++++++++++++++++++++- lib/l10n/app_ko.arb | 31 +++++++++++++++++++++++++++++-- lib/l10n/app_ne.arb | 29 ++++++++++++++++++++++++++++- lib/l10n/app_nl.arb | 32 ++++++++++++++++++++++++++++++-- lib/l10n/app_pl.arb | 29 ++++++++++++++++++++++++++++- lib/l10n/app_pt.arb | 29 ++++++++++++++++++++++++++++- lib/l10n/app_ru.arb | 29 ++++++++++++++++++++++++++++- lib/l10n/app_tr.arb | 29 ++++++++++++++++++++++++++++- lib/l10n/app_uk.arb | 29 ++++++++++++++++++++++++++++- lib/l10n/app_vi.arb | 31 +++++++++++++++++++++++++++++-- lib/l10n/app_zh.arb | 29 ++++++++++++++++++++++++++++- 21 files changed, 590 insertions(+), 23 deletions(-) create mode 100644 bin/translated_messages.dart diff --git a/bin/translated_messages.dart b/bin/translated_messages.dart new file mode 100644 index 00000000..0de398df --- /dev/null +++ b/bin/translated_messages.dart @@ -0,0 +1,26 @@ +import 'dart:convert'; +import 'dart:io'; + +void main(List args) async { + final translatedFile = + jsonDecode(await File('tm.json').readAsString()) as Map; + + for (final MapEntry(:key, :value) in translatedFile.entries) { + print('Updating locale: $key'); + final file = File('lib/l10n/app_$key.arb'); + + final fileContent = + jsonDecode(await file.readAsString()) as Map; + + final newContent = { + ...fileContent, + ...value, + }; + + await file.writeAsString( + const JsonEncoder.withIndent(' ').convert(newContent), + ); + + print('✅ Updated locale: $key'); + } +} diff --git a/lib/l10n/app_ar.arb b/lib/l10n/app_ar.arb index eebede99..41fab083 100644 --- a/lib/l10n/app_ar.arb +++ b/lib/l10n/app_ar.arb @@ -286,5 +286,32 @@ "step_3_steps": "انسخ قيمة الكوكي \"sp_dc\"", "step_4_steps": "الصق قيمة \"sp_dc\" المنسوخة", "friends": "أصدقاء", - "no_lyrics_available": "عذرًا، تعذر العثور على كلمات الأغنية لهذه العنصر" + "no_lyrics_available": "عذرًا، تعذر العثور على كلمات الأغنية لهذه العنصر", + "sort_duration": "ترتيب حسب المدة", + "start_a_radio": "بدء راديو", + "how_to_start_radio": "كيف تريد بدء الراديو؟", + "replace_queue_question": "هل تريد استبدال قائمة التشغيل الحالية أم إضافة إليها؟", + "endless_playback": "تشغيل بلا نهاية", + "delete_playlist": "حذف قائمة التشغيل", + "delete_playlist_confirmation": "هل أنت متأكد أنك تريد حذف هذه قائمة التشغيل؟", + "local_tracks": "المسارات المحلية", + "song_link": "رابط الأغنية", + "skip_this_nonsense": "تخطي هذه الهراء", + "freedom_of_music": "“حرية الموسيقى”", + "freedom_of_music_palm": "“حرية الموسيقى في متناول يدك”", + "get_started": "لنبدأ", + "youtube_source_description": "موصى به ويعمل بشكل أفضل.", + "piped_source_description": "تشعر بالحرية؟ نفس يوتيوب ولكن أكثر حرية.", + "jiosaavn_source_description": "الأفضل لمنطقة جنوب آسيا.", + "highest_quality": "أعلى جودة: {quality}", + "select_audio_source": "اختر مصدر الصوت", + "endless_playback_description": "إلحاق الأغاني الجديدة تلقائيًا\nإلى نهاية قائمة التشغيل", + "choose_your_region": "اختر منطقتك", + "choose_your_region_description": "سيساعدك هذا في عرض المحتوى المناسب\nلموقعك.", + "choose_your_language": "اختر لغتك", + "help_project_grow": "ساعد في نمو هذا المشروع", + "help_project_grow_description": "Spotube هو مشروع مفتوح المصدر. يمكنك مساعدة هذا المشروع في النمو عن طريق المساهمة في المشروع، أو الإبلاغ عن الأخطاء، أو اقتراح ميزات جديدة.", + "contribute_on_github": "المساهمة على GitHub", + "donate_on_open_collective": "التبرع على Open Collective", + "browse_anonymously": "تصفح بشكل مجهول" } \ No newline at end of file diff --git a/lib/l10n/app_bn.arb b/lib/l10n/app_bn.arb index 2711f8d2..353ca617 100644 --- a/lib/l10n/app_bn.arb +++ b/lib/l10n/app_bn.arb @@ -286,5 +286,32 @@ "step_3_steps": "কুকি \"sp_dc\" এর মানটি কপি করুন", "step_4_steps": "কপি করা \"sp_dc\" মানটি পেস্ট করুন", "friends": "বন্ধু", - "no_lyrics_available": "দুঃখিত, এই ট্র্যাকের জন্য কথা খুঁজে পাওয়া গেলনা" + "no_lyrics_available": "দুঃখিত, এই ট্র্যাকের জন্য কথা খুঁজে পাওয়া গেলনা", + "sort_duration": "দৈর্ঘ্য অনুযায়ী বাছাই করুন", + "start_a_radio": "রেডিও শুরু করুন", + "how_to_start_radio": "রেডিও কিভাবে শুরু করতে চান?", + "replace_queue_question": "আপনি বর্তমান কিউটি প্রতিস্থাপন করতে চান কিনা বা এর সাথে যুক্ত করতে চান?", + "endless_playback": "অবিরাম প্রচার", + "delete_playlist": "প্লেলিস্ট মুছুন", + "delete_playlist_confirmation": "আপনি কি নিশ্চিত যে আপনি এই প্লেলিস্টটি মুছতে চান?", + "local_tracks": "স্থানীয় ট্র্যাক", + "song_link": "গানের লিংক", + "skip_this_nonsense": "এই বাকবাস পালান", + "freedom_of_music": "“সংগীতের স্বাধীনতা”", + "freedom_of_music_palm": "“তোমার হাতের কাছে সংগীতের স্বাধীনতা”", + "get_started": "শুরু করা যাক", + "youtube_source_description": "প্রস্তাবিত এবং সেরা কাজ করে।", + "piped_source_description": "মন খারাপ? ইউটিউবের মতো আবার ফ্রি।", + "jiosaavn_source_description": "দক্ষিণ এশিয়ান অঞ্চলের জন্য সেরা।", + "highest_quality": "সর্বোচ্চ গুণগতি: {quality}", + "select_audio_source": "অডিও উৎস নির্বাচন করুন", + "endless_playback_description": "নতুন গান নিজে নিজে প্লেলিস্টের শেষে\nসংযুক্ত করুন", + "choose_your_region": "আপনার অঞ্চল নির্বাচন করুন", + "choose_your_region_description": "এটি স্পটুবে আপনাকে আপনার অবস্থানের জন্য ঠিক কন্টেন্ট দেখানোর সাহায্য করবে।", + "choose_your_language": "আপনার ভাষা নির্বাচন করুন", + "help_project_grow": "এই প্রকল্পের বৃদ্ধি করুন", + "help_project_grow_description": "স্পটুব একটি ওপেন সোর্স প্রকল্প। আপনি প্রকল্পে অবদান রাখেন, বাগ রিপোর্ট করেন, বা নতুন বৈশিষ্ট্যগুলি সুপারিশ করেন।", + "contribute_on_github": "গিটহাবে অবদান রাখুন", + "donate_on_open_collective": "ওপেন কলেক্টিভে অনুদান করুন", + "browse_anonymously": "অজানে ব্রাউজ করুন" } \ No newline at end of file diff --git a/lib/l10n/app_ca.arb b/lib/l10n/app_ca.arb index f46cfae4..9848954a 100644 --- a/lib/l10n/app_ca.arb +++ b/lib/l10n/app_ca.arb @@ -286,5 +286,32 @@ "step_3_steps": "Copia el valor de la cookie \"sp_dc\"", "step_4_steps": "Pega el valor copiado de \"sp_dc\"", "friends": "Amics", - "no_lyrics_available": "Ho sentim, no es poden trobar les lletres d'aquesta pista" + "no_lyrics_available": "Ho sentim, no es poden trobar les lletres d'aquesta pista", + "sort_duration": "Ordenar per Durada", + "start_a_radio": "Inicia una ràdio", + "how_to_start_radio": "Com vols començar la ràdio?", + "replace_queue_question": "Voleu substituir la cua actual o afegir-hi?", + "endless_playback": "Reproducció infinita", + "delete_playlist": "Suprimeix la llista de reproducció", + "delete_playlist_confirmation": "Esteu segur que voleu suprimir aquesta llista de reproducció?", + "local_tracks": "Pistes locals", + "song_link": "Enllaç de la cançó", + "skip_this_nonsense": "Omet aquesta tonteria", + "freedom_of_music": "“Llibertat de la música”", + "freedom_of_music_palm": "“Llibertat de la música a la palma de la mà”", + "get_started": "Comencem", + "youtube_source_description": "Recomanat i funciona millor.", + "piped_source_description": "Et sents lliure? El mateix que YouTube però més lliure.", + "jiosaavn_source_description": "El millor per a la regió del sud d'Àsia.", + "highest_quality": "Qualitat més alta: {quality}", + "select_audio_source": "Seleccioneu la font d'àudio", + "endless_playback_description": "Afegiu automàticament noves cançons\nal final de la cua", + "choose_your_region": "Trieu la vostra regió", + "choose_your_region_description": "Això ajudarà a Spotube a mostrar-vos el contingut adequat\nper a la vostra ubicació.", + "choose_your_language": "Trieu el vostre idioma", + "help_project_grow": "Ajuda a fer créixer aquest projecte", + "help_project_grow_description": "Spotube és un projecte de codi obert. Podeu ajudar a fer créixer aquest projecte contribuint al projecte, informant d'errors o suggerint noves funcionalitats.", + "contribute_on_github": "Contribueix a GitHub", + "donate_on_open_collective": "Fes una donació a Open Collective", + "browse_anonymously": "Navega de manera anònima" } \ No newline at end of file diff --git a/lib/l10n/app_de.arb b/lib/l10n/app_de.arb index ebaa0329..b058d41a 100644 --- a/lib/l10n/app_de.arb +++ b/lib/l10n/app_de.arb @@ -286,5 +286,32 @@ "step_3_steps": "Kopiere den Wert des Cookies \"sp_dc\"", "step_4_steps": "Füge den kopierten Wert von \"sp_dc\" ein", "friends": "Freunde", - "no_lyrics_available": "Entschuldigung, Texte für diesen Track konnten nicht gefunden werden" + "no_lyrics_available": "Entschuldigung, Texte für diesen Track konnten nicht gefunden werden", + "sort_duration": "Nach Dauer sortieren", + "start_a_radio": "Radio starten", + "how_to_start_radio": "Wie möchten Sie das Radio starten?", + "replace_queue_question": "Möchten Sie die aktuelle Wiedergabeliste ersetzen oder hinzufügen?", + "endless_playback": "Endlose Wiedergabe", + "delete_playlist": "Wiedergabeliste löschen", + "delete_playlist_confirmation": "Sind Sie sicher, dass Sie diese Wiedergabeliste löschen möchten?", + "local_tracks": "Lokale Titel", + "song_link": "Lied-Link", + "skip_this_nonsense": "Diesen Unsinn überspringen", + "freedom_of_music": "“Freiheit der Musik”", + "freedom_of_music_palm": "“Freiheit der Musik in Ihrer Handfläche”", + "get_started": "Lass uns anfangen", + "youtube_source_description": "Empfohlen und funktioniert am besten.", + "piped_source_description": "Fühlen Sie sich frei? Wie YouTube, aber viel freier.", + "jiosaavn_source_description": "Am besten für die südasiatische Region.", + "highest_quality": "Höchste Qualität: {quality}", + "select_audio_source": "Audioquelle auswählen", + "endless_playback_description": "Neue Lieder automatisch\nam Ende der Wiedergabeliste hinzufügen", + "choose_your_region": "Wählen Sie Ihre Region", + "choose_your_region_description": "Dies wird Spotube helfen, Ihnen den richtigen Inhalt\nfür Ihren Standort anzuzeigen.", + "choose_your_language": "Wählen Sie Ihre Sprache", + "help_project_grow": "Helfen Sie diesem Projekt zu wachsen", + "help_project_grow_description": "Spotube ist ein Open-Source-Projekt. Sie können diesem Projekt helfen, indem Sie zum Projekt beitragen, Fehler melden oder neue Funktionen vorschlagen.", + "contribute_on_github": "Auf GitHub beitragen", + "donate_on_open_collective": "Auf Open Collective spenden", + "browse_anonymously": "Anonym durchsuchen" } \ No newline at end of file diff --git a/lib/l10n/app_es.arb b/lib/l10n/app_es.arb index 476056cb..0b4cbb2a 100644 --- a/lib/l10n/app_es.arb +++ b/lib/l10n/app_es.arb @@ -286,5 +286,32 @@ "step_3_steps": "Copia el valor de la cookie \"sp_dc\"", "step_4_steps": "Pega el valor copiado de \"sp_dc\"", "friends": "Amigos", - "no_lyrics_available": "Lo siento, no se pueden encontrar las letras de esta pista" + "no_lyrics_available": "Lo siento, no se pueden encontrar las letras de esta pista", + "sort_duration": "Ordenar por Duración", + "start_a_radio": "Iniciar una Radio", + "how_to_start_radio": "¿Cómo quieres iniciar la radio?", + "replace_queue_question": "¿Quieres reemplazar la lista de reproducción actual o añadir a ella?", + "endless_playback": "Reproducción Infinita", + "delete_playlist": "Eliminar Lista de Reproducción", + "delete_playlist_confirmation": "¿Estás seguro de que quieres eliminar esta lista de reproducción?", + "local_tracks": "Pistas Locales", + "song_link": "Enlace de la Canción", + "skip_this_nonsense": "Saltar esta tontería", + "freedom_of_music": "“Libertad de la Música”", + "freedom_of_music_palm": "“Libertad de la Música en la palma de tu mano”", + "get_started": "Empecemos", + "youtube_source_description": "Recomendado y funciona mejor.", + "piped_source_description": "¿Te sientes libre? Igual que YouTube pero más libre.", + "jiosaavn_source_description": "Lo mejor para la región del sur de Asia.", + "highest_quality": "Mayor Calidad: {quality}", + "select_audio_source": "Seleccionar Fuente de Audio", + "endless_playback_description": "Añadir automáticamente nuevas canciones\nal final de la cola de reproducción", + "choose_your_region": "Elige tu región", + "choose_your_region_description": "Esto ayudará a Spotube a mostrarte el contenido adecuado\npara tu ubicación.", + "choose_your_language": "Elige tu idioma", + "help_project_grow": "Ayuda a que este proyecto crezca", + "help_project_grow_description": "Spotube es un proyecto de código abierto. Puedes ayudar a que este proyecto crezca contribuyendo al proyecto, informando errores o sugiriendo nuevas funciones.", + "contribute_on_github": "Contribuir en GitHub", + "donate_on_open_collective": "Donar en Open Collective", + "browse_anonymously": "Navegar Anónimamente" } \ No newline at end of file diff --git a/lib/l10n/app_fa.arb b/lib/l10n/app_fa.arb index 3a2bcb4b..629238cc 100644 --- a/lib/l10n/app_fa.arb +++ b/lib/l10n/app_fa.arb @@ -286,5 +286,32 @@ "step_3_steps": "مقدار کوکی \"sp_dc\" را کپی کنید", "step_4_steps": "مقدار کپی شده \"sp_dc\" را الصاق کنید", "friends": "دوستان", - "no_lyrics_available": "متاسفیم، قادر به یافتن متن این قطعه نیستیم" + "no_lyrics_available": "متاسفیم، قادر به یافتن متن این قطعه نیستیم", + "sort_duration": "مرتب کردن بر اساس مدت زمان", + "start_a_radio": "شروع یک رادیو", + "how_to_start_radio": "چگونه می‌خواهید رادیو را شروع کنید؟", + "replace_queue_question": "آیا می‌خواهید لیست پخش فعلی را جایگزین کنید یا به آن اضافه کنید؟", + "endless_playback": "پخش بی‌پایان", + "delete_playlist": "حذف لیست پخش", + "delete_playlist_confirmation": "آیا مطمئن هستید که می‌خواهید این لیست پخش را حذف کنید؟", + "local_tracks": "موسیقی‌های محلی", + "song_link": "پیوند آهنگ", + "skip_this_nonsense": "این احمقانه را بگذرانید", + "freedom_of_music": "“آزادی موسیقی”", + "freedom_of_music_palm": "“آزادی موسیقی در دستان شما”", + "get_started": "بیایید شروع کنیم", + "youtube_source_description": "پیشنهاد شده و بهترین عمل می‌کند.", + "piped_source_description": "احساس آزادی می‌کنید؟ مانند یوتیوب اما بیشتر آزاد.", + "jiosaavn_source_description": "بهترین برای منطقه جنوب آسیا.", + "highest_quality": "بالاترین کیفیت: {quality}", + "select_audio_source": "انتخاب منبع صوتی", + "endless_playback_description": "خودکار اضافه کردن آهنگ‌های جدید\nبه انتهای صف", + "choose_your_region": "منطقه خود را انتخاب کنید", + "choose_your_region_description": "این به Spotube کمک می‌کند تا محتوای مناسبی را برای موقعیت شما نشان دهد.", + "choose_your_language": "زبان خود را انتخاب کنید", + "help_project_grow": "کمک به رشد این پروژه", + "help_project_grow_description": "Spotube یک پروژه متن باز است. شما می‌توانید با به پروژه کمک کردن، گزارش دادن اشکالات یا پیشنهاد ویژگی‌های جدید، به این پروژه کمک کنید.", + "contribute_on_github": "مشارکت در GitHub", + "donate_on_open_collective": "کمک مالی در Open Collective", + "browse_anonymously": "مرور به صورت ناشناس" } \ No newline at end of file diff --git a/lib/l10n/app_fr.arb b/lib/l10n/app_fr.arb index 5c24d0fe..69b2bb69 100644 --- a/lib/l10n/app_fr.arb +++ b/lib/l10n/app_fr.arb @@ -286,5 +286,32 @@ "step_3_steps": "Copiez la valeur du cookie \"sp_dc\"", "step_4_steps": "Collez la valeur copiée de \"sp_dc\"", "friends": "Amis", - "no_lyrics_available": "Désolé, impossible de trouver les paroles de cette piste" + "no_lyrics_available": "Désolé, impossible de trouver les paroles de cette piste", + "sort_duration": "Trier par durée", + "start_a_radio": "Démarrer une radio", + "how_to_start_radio": "Comment voulez-vous démarrer la radio ?", + "replace_queue_question": "Voulez-vous remplacer la file d'attente actuelle ou y ajouter ?", + "endless_playback": "Lecture sans fin", + "delete_playlist": "Supprimer la playlist", + "delete_playlist_confirmation": "Êtes-vous sûr de vouloir supprimer cette playlist ?", + "local_tracks": "Titres locaux", + "song_link": "Lien de la chanson", + "skip_this_nonsense": "Passer cette absurdité", + "freedom_of_music": "“Liberté de la musique”", + "freedom_of_music_palm": "“Liberté de la musique dans la paume de votre main”", + "get_started": "Commençons", + "youtube_source_description": "Recommandé et fonctionne mieux.", + "piped_source_description": "Vous vous sentez libre ? Comme YouTube mais beaucoup plus gratuit.", + "jiosaavn_source_description": "Le meilleur pour la région d'Asie du Sud.", + "highest_quality": "Meilleure qualité : {quality}", + "select_audio_source": "Sélectionner la source audio", + "endless_playback_description": "Ajouter automatiquement de nouvelles chansons à la fin de la file d'attente", + "choose_your_region": "Choisissez votre région", + "choose_your_region_description": "Cela aidera Spotube à vous montrer le bon contenu pour votre emplacement.", + "choose_your_language": "Choisissez votre langue", + "help_project_grow": "Aidez ce projet à grandir", + "help_project_grow_description": "Spotube est un projet open-source. Vous pouvez aider ce projet à grandir en contribuant au projet, en signalant des bugs ou en suggérant de nouvelles fonctionnalités.", + "contribute_on_github": "Contribuer sur GitHub", + "donate_on_open_collective": "Faire un don sur Open Collective", + "browse_anonymously": "Naviguer anonymement" } \ No newline at end of file diff --git a/lib/l10n/app_hi.arb b/lib/l10n/app_hi.arb index 1cf62398..b442da37 100644 --- a/lib/l10n/app_hi.arb +++ b/lib/l10n/app_hi.arb @@ -286,5 +286,32 @@ "step_3_steps": "\"sp_dc\" कुकी का मूल्य कॉपी करें", "step_4_steps": "कॉपी किए गए \"sp_dc\" मूल्य को पेस्ट करें", "friends": "दोस्त", - "no_lyrics_available": "क्षमा करें, इस ट्रैक के लिए गाने नहीं मिल सके" + "no_lyrics_available": "क्षमा करें, इस ट्रैक के लिए गाने नहीं मिल सके", + "sort_duration": "समय के आधार पर क्रमबद्ध करें", + "start_a_radio": "रेडियो शुरू करें", + "how_to_start_radio": "रेडियो कैसे शुरू करना चाहते हैं?", + "replace_queue_question": "क्या आप वर्तमान कतार को बदलना चाहते हैं या इसे जोड़ना चाहते हैं?", + "endless_playback": "अंतहीन प्लेबैक", + "delete_playlist": "प्लेलिस्ट हटाएं", + "delete_playlist_confirmation": "क्या आप वाकई इस प्लेलिस्ट को हटाना चाहते हैं?", + "local_tracks": "स्थानीय ट्रैक्स", + "song_link": "गाने का लिंक", + "skip_this_nonsense": "इस माया को छोड़ें", + "freedom_of_music": "“संगीत की स्वतंत्रता”", + "freedom_of_music_palm": "“हाथ में संगीत की स्वतंत्रता”", + "get_started": "आइए शुरू करें", + "youtube_source_description": "सिफारिश किया गया और सबसे अच्छा काम करता है।", + "piped_source_description": "मुफ्त महसूस कर रहे हैं? YouTube के समान लेकिन काफी अधिक मुफ्त।", + "jiosaavn_source_description": "दक्षिण एशियाई क्षेत्र के लिए सर्वोत्तम।", + "highest_quality": "सर्वोत्तम गुणवत्ता: {quality}", + "select_audio_source": "ऑडियो स्रोत चुनें", + "endless_playback_description": "क्रमबद्ध कतार के अंत में नए गाने स्वचालित रूप से जोड़ें", + "choose_your_region": "अपना क्षेत्र चुनें", + "choose_your_region_description": "यह Spotube को आपके स्थान के लिए सही सामग्री दिखाने में मदद करेगा।", + "choose_your_language": "अपनी भाषा चुनें", + "help_project_grow": "इस परियोजना को बढ़ावा दें", + "help_project_grow_description": "Spotube एक ओपन सोर्स परियोजना है। आप इस परियोजना को योगदान देकर, बग रिपोर्ट करके या नई विशेषताओं का सुझाव देकर इस परियोजना को बढ़ा सकते हैं।", + "contribute_on_github": "GitHub पर योगदान करें", + "donate_on_open_collective": "ओपन कलेक्टिव पर दान करें", + "browse_anonymously": "बिना नाम के ब्राउज़ करें" } \ No newline at end of file diff --git a/lib/l10n/app_it.arb b/lib/l10n/app_it.arb index ec76b914..f8440cd0 100644 --- a/lib/l10n/app_it.arb +++ b/lib/l10n/app_it.arb @@ -287,5 +287,32 @@ "step_3_steps": "Copia il valore del cookie \"sp_dc\"", "step_4_steps": "Incolla il valore copiato di \"sp_dc\"", "friends": "Amici", - "no_lyrics_available": "Spiacente, impossibile trovare il testo di questa traccia" + "no_lyrics_available": "Spiacente, impossibile trovare il testo di questa traccia", + "sort_duration": "Ordina per Durata", + "start_a_radio": "Avvia una Radio", + "how_to_start_radio": "Come vuoi avviare la radio?", + "replace_queue_question": "Vuoi sostituire la coda attuale o aggiungerla?", + "endless_playback": "Riproduzione Infinita", + "delete_playlist": "Elimina Playlist", + "delete_playlist_confirmation": "Sei sicuro di voler eliminare questa playlist?", + "local_tracks": "Tracce Locali", + "song_link": "Link della Canzone", + "skip_this_nonsense": "Salta questa sciocchezza", + "freedom_of_music": "“Libertà della Musica”", + "freedom_of_music_palm": "“Libertà della Musica nel palmo della tua mano”", + "get_started": "Cominciamo", + "youtube_source_description": "Consigliato e funziona meglio.", + "piped_source_description": "Ti senti libero? Come YouTube ma molto più gratuito.", + "jiosaavn_source_description": "Il migliore per la regione dell'Asia meridionale.", + "highest_quality": "Massima Qualità: {quality}", + "select_audio_source": "Seleziona Sorgente Audio", + "endless_playback_description": "Aggiungi automaticamente nuove canzoni alla fine della coda", + "choose_your_region": "Scegli la tua regione", + "choose_your_region_description": "Questo aiuterà Spotube a mostrarti il contenuto giusto per la tua posizione.", + "choose_your_language": "Scegli la tua lingua", + "help_project_grow": "Aiuta questo progetto a crescere", + "help_project_grow_description": "Spotube è un progetto open-source. Puoi aiutare questo progetto a crescere contribuendo al progetto, segnalando bug o suggerendo nuove funzionalità.", + "contribute_on_github": "Contribuisci su GitHub", + "donate_on_open_collective": "Dona su Open Collective", + "browse_anonymously": "Naviga in modo anonimo" } \ No newline at end of file diff --git a/lib/l10n/app_ja.arb b/lib/l10n/app_ja.arb index d16708d7..ecdc77a2 100644 --- a/lib/l10n/app_ja.arb +++ b/lib/l10n/app_ja.arb @@ -286,5 +286,32 @@ "step_3_steps": "\"sp_dc\" Cookieの値をコピー", "step_4_steps": "コピーした\"sp_dc\"の値を貼り付け", "friends": "友達", - "no_lyrics_available": "申し訳ありませんが、このトラックの歌詞を見つけることができません" + "no_lyrics_available": "申し訳ありませんが、このトラックの歌詞を見つけることができません", + "sort_duration": "時間で並べ替え", + "start_a_radio": "ラジオを開始", + "how_to_start_radio": "ラジオをどのように開始しますか?", + "replace_queue_question": "現在のキューを置き換えるか、追加しますか?", + "endless_playback": "エンドレス再生", + "delete_playlist": "プレイリストを削除", + "delete_playlist_confirmation": "このプレイリストを削除してもよろしいですか?", + "local_tracks": "ローカルトラック", + "song_link": "曲のリンク", + "skip_this_nonsense": "この愚かなことをスキップ", + "freedom_of_music": "“音楽の自由”", + "freedom_of_music_palm": "“手のひらの中の音楽の自由”", + "get_started": "さあ始めましょう", + "youtube_source_description": "推奨され、最適に機能します。", + "piped_source_description": "自由に感じますか? YouTubeと同じですが、はるかに無料です。", + "jiosaavn_source_description": "南アジア地域向けの最適です。", + "highest_quality": "最高品質:{quality}", + "select_audio_source": "オーディオソースを選択", + "endless_playback_description": "新しい曲をキューの最後に自動的に追加", + "choose_your_region": "地域を選択", + "choose_your_region_description": "これにより、Spotubeがあなたの場所に適したコンテンツを表示できます。", + "choose_your_language": "言語を選択してください", + "help_project_grow": "このプロジェクトの成長を支援する", + "help_project_grow_description": "Spotubeはオープンソースプロジェクトです。プロジェクトに貢献したり、バグを報告したり、新しい機能を提案することで、このプロジェクトの成長に貢献できます。", + "contribute_on_github": "GitHubで貢献する", + "donate_on_open_collective": "Open Collectiveで寄付する", + "browse_anonymously": "匿名で閲覧する" } \ No newline at end of file diff --git a/lib/l10n/app_ko.arb b/lib/l10n/app_ko.arb index dac5b72a..5a3ee8bc 100644 --- a/lib/l10n/app_ko.arb +++ b/lib/l10n/app_ko.arb @@ -287,5 +287,32 @@ "step_4_steps": "복사한 \"sp_dc\"값을 붙여넣기", "friends": "친구", "no_lyrics_available": "죄송하지만 이 곡의 가사를 찾지 못했습니다", - "@@locale": "ko" -} + "@@locale": "ko", + "sort_duration": "시간순 정렬", + "start_a_radio": "라디오 시작", + "how_to_start_radio": "라디오를 어떻게 시작하시겠습니까?", + "replace_queue_question": "현재 큐를 대체하시겠습니까 아니면 추가하시겠습니까?", + "endless_playback": "끝없는 재생", + "delete_playlist": "재생 목록 삭제", + "delete_playlist_confirmation": "이 재생 목록을 삭제하시겠습니까?", + "local_tracks": "로컬 트랙", + "song_link": "곡 링크", + "skip_this_nonsense": "이 허튼소리 건너뛰기", + "freedom_of_music": "“음악의 자유”", + "freedom_of_music_palm": "“손바닥 안의 음악의 자유”", + "get_started": "시작합시다", + "youtube_source_description": "추천되며 가장 잘 작동합니다.", + "piped_source_description": "자유로운 기분이 듭니까? YouTube와 같지만 훨씬 더 무료합니다.", + "jiosaavn_source_description": "남아시아 지역에 최적입니다.", + "highest_quality": "최고 품질: {quality}", + "select_audio_source": "오디오 소스 선택", + "endless_playback_description": "자동으로 새로운 노래를 대기열의 끝에 추가", + "choose_your_region": "지역 선택", + "choose_your_region_description": "이것은 Spotube가 위치에 맞는 콘텐츠를 표시하는 데 도움이 됩니다.", + "choose_your_language": "언어 선택", + "help_project_grow": "이 프로젝트 성장에 도움을 주세요", + "help_project_grow_description": "Spotube는 오픈 소스 프로젝트입니다. 프로젝트에 기여하거나 버그를 보고하거나 새로운 기능을 제안하여이 프로젝트의 성장에 도움을 줄 수 있습니다.", + "contribute_on_github": "GitHub에서 기여하기", + "donate_on_open_collective": "Open Collective에 기부하기", + "browse_anonymously": "익명으로 둘러보기" +} \ No newline at end of file diff --git a/lib/l10n/app_ne.arb b/lib/l10n/app_ne.arb index 2d20fc9c..d921f3ba 100644 --- a/lib/l10n/app_ne.arb +++ b/lib/l10n/app_ne.arb @@ -286,5 +286,32 @@ "genres": "शैलीहरू", "explore_genres": "शैलीहरू अन्वेषण गर्नुहोस्", "friends": "साथीहरू", - "no_lyrics_available": "क्षमा गर्दैछौं, यस ट्र्याकका लागि गीतका शब्दहरू फेला परेन" + "no_lyrics_available": "क्षमा गर्दैछौं, यस ट्र्याकका लागि गीतका शब्दहरू फेला परेन", + "sort_duration": "अवधिको अनुसार क्रमबद्ध गर्नुहोस्", + "start_a_radio": "रेडियो सुरु गर्नुहोस्", + "how_to_start_radio": "तपाईं रेडियो कसरी सुरु गर्न चाहानुहुन्छ?", + "replace_queue_question": "के तपाईं वर्तमान कताक्ष कोट बदल्न चाहानुहुन्छ वा यसलाई थप्नुहुन्छ?", + "endless_playback": "अनन्त प्लेब्याक", + "delete_playlist": "प्लेलिस्ट मेटाउनुहोस्", + "delete_playlist_confirmation": "के तपाईं यो प्लेलिस्ट मेटाउन निश्चित हुनुहुन्छ?", + "local_tracks": "स्थानिय ट्र्याकहरू", + "song_link": "गीत लिंक", + "skip_this_nonsense": "यस अबश्यकता छोड्नुहोस्", + "freedom_of_music": "“संगीतको स्वतन्त्रता”", + "freedom_of_music_palm": "“तपाईंको हातमा संगीतको स्वतन्त्रता”", + "get_started": "आइयाँ प्रारम्भ गरौं", + "youtube_source_description": "सिफारिस गरिएको र बेस्ट काम गर्दछ।", + "piped_source_description": "मुक्त सुस्त? YouTube जस्तै तर धेरै मुक्त।", + "jiosaavn_source_description": "दक्षिण एशियाली क्षेत्रको लागि सर्वोत्तम।", + "highest_quality": "उच्चतम गुणस्तर: {quality}", + "select_audio_source": "आडियो स्रोत चयन गर्नुहोस्", + "endless_playback_description": "नयाँ गीतहरूलाई स्वचालित रूपमा कताक्षको अन्तमा जोड्नुहोस्", + "choose_your_region": "तपाईंको क्षेत्र छनौट गर्नुहोस्", + "choose_your_region_description": "यो Spotubeलाई तपाईंको स्थानका लागि सहि सामग्री देखाउने मद्दत गर्नेछ।", + "choose_your_language": "तपाईंको भाषा छनौट गर्नुहोस्", + "help_project_grow": "यस परियोजनामा वृद्धि गराउनुहोस्", + "help_project_grow_description": "Spotube एक खुला स्रोतको परियोजना हो। तपाईं परियोजनामा योगदान गरेर, त्रुटिहरू सूचिकै, वा नयाँ सुविधाहरू सुझाव दिएर यस परियोजनामा वृद्धि गर्न सक्नुहुन्छ।", + "contribute_on_github": "GitHubमा योगदान गर्नुहोस्", + "donate_on_open_collective": "खुला संगठनमा दान गर्नुहोस्", + "browse_anonymously": "अनामित रूपमा ब्राउज़ गर्नुहोस्" } \ No newline at end of file diff --git a/lib/l10n/app_nl.arb b/lib/l10n/app_nl.arb index 3bece8be..33e94a2e 100644 --- a/lib/l10n/app_nl.arb +++ b/lib/l10n/app_nl.arb @@ -286,5 +286,33 @@ "genres": "Genres", "explore_genres": "Genres verkennen", "friends": "Vrienden", - "no_lyrics_available": "Sorry, geen teksten gevonden voor dit nummer" -} + "no_lyrics_available": "Sorry, geen teksten gevonden voor dit nummer", + "sort_duration": "Sorteer op Duur", + "audio_source": "Audiobron", + "start_a_radio": "Start een Radio", + "how_to_start_radio": "Hoe wilt u de radio starten?", + "replace_queue_question": "Wilt u de huidige wachtrij vervangen of eraan toevoegen?", + "endless_playback": "Eindeloze Afspelen", + "delete_playlist": "Verwijder Afspeellijst", + "delete_playlist_confirmation": "Weet u zeker dat u deze afspeellijst wilt verwijderen?", + "local_tracks": "Lokale Nummers", + "song_link": "Nummer Link", + "skip_this_nonsense": "Sla deze onzin over", + "freedom_of_music": "“Vrijheid van Muziek”", + "freedom_of_music_palm": "“Vrijheid van Muziek in de palm van je hand”", + "get_started": "Laten we beginnen", + "youtube_source_description": "Aanbevolen en werkt het beste.", + "piped_source_description": "Voel je vrij? Hetzelfde als YouTube maar veel gratis.", + "jiosaavn_source_description": "Het beste voor de Zuid-Aziatische regio.", + "highest_quality": "Hoogste Kwaliteit: {quality}", + "select_audio_source": "Selecteer Audiobron", + "endless_playback_description": "Voeg automatisch nieuwe nummers toe aan het einde van de wachtrij", + "choose_your_region": "Kies uw regio", + "choose_your_region_description": "Dit zal Spotube helpen om de juiste inhoud voor uw locatie te tonen.", + "choose_your_language": "Kies uw taal", + "help_project_grow": "Help dit project groeien", + "help_project_grow_description": "Spotube is een open-source project. U kunt dit project helpen groeien door bij te dragen aan het project, bugs te melden of nieuwe functies voor te stellen.", + "contribute_on_github": "Bijdragen op GitHub", + "donate_on_open_collective": "Doneren op Open Collective", + "browse_anonymously": "Anoniem Bladeren" +} \ No newline at end of file diff --git a/lib/l10n/app_pl.arb b/lib/l10n/app_pl.arb index b7ce8923..a1bc5de6 100644 --- a/lib/l10n/app_pl.arb +++ b/lib/l10n/app_pl.arb @@ -286,5 +286,32 @@ "step_3_steps": "Skopiuj wartość ciasteczka \"sp_dc\"", "step_4_steps": "Wklej skopiowaną wartość \"sp_dc\"", "friends": "Przyjaciele", - "no_lyrics_available": "Przepraszamy, nie można znaleźć tekstu dla tego utworu" + "no_lyrics_available": "Przepraszamy, nie można znaleźć tekstu dla tego utworu", + "sort_duration": "Sortuj według Czasu Trwania", + "start_a_radio": "Uruchom radio", + "how_to_start_radio": "Jak chcesz uruchomić radio?", + "replace_queue_question": "Czy chcesz zastąpić bieżącą kolejkę czy dodać do niej?", + "endless_playback": "Nieskończona Odtwarzanie", + "delete_playlist": "Usuń Playlistę", + "delete_playlist_confirmation": "Czy na pewno chcesz usunąć tę listę odtwarzania?", + "local_tracks": "Lokalne Utwory", + "song_link": "Link do Utworu", + "skip_this_nonsense": "Pomiń tę bzdurę", + "freedom_of_music": "“Wolność Muzyki”", + "freedom_of_music_palm": "“Wolność Muzyki w Twojej dłoni”", + "get_started": "Zacznijmy", + "youtube_source_description": "Polecane i działa najlepiej.", + "piped_source_description": "Czujesz się wolny? To samo co YouTube, ale dużo za darmo.", + "jiosaavn_source_description": "Najlepszy dla regionu Azji Południowej.", + "highest_quality": "Najwyższa Jakość: {quality}", + "select_audio_source": "Wybierz Źródło Audio", + "endless_playback_description": "Automatycznie dodaj nowe utwory na koniec kolejki", + "choose_your_region": "Wybierz swoją region", + "choose_your_region_description": "To pomoże Spotube pokazać Ci odpowiednią treść dla Twojej lokalizacji.", + "choose_your_language": "Wybierz swój język", + "help_project_grow": "Pomóż temu projektowi rosnąć", + "help_project_grow_description": "Spotube to projekt open-source. Możesz pomóc temu projektowi rosnąć, przyczyniając się do projektu, zgłaszając błędy lub sugerując nowe funkcje.", + "contribute_on_github": "Przyczyniaj się na GitHubie", + "donate_on_open_collective": "Dotuj na Open Collective", + "browse_anonymously": "Przeglądaj Anonimowo" } \ No newline at end of file diff --git a/lib/l10n/app_pt.arb b/lib/l10n/app_pt.arb index 1c75f734..7f290a1d 100644 --- a/lib/l10n/app_pt.arb +++ b/lib/l10n/app_pt.arb @@ -286,5 +286,32 @@ "step_3_steps": "Copie o valor do cookie \"sp_dc\"", "step_4_steps": "Cole o valor copiado de \"sp_dc\"", "friends": "Amigos", - "no_lyrics_available": "Desculpe, não foi possível encontrar a letra desta faixa" + "no_lyrics_available": "Desculpe, não foi possível encontrar a letra desta faixa", + "sort_duration": "Ordenar por Duração", + "start_a_radio": "Iniciar uma Rádio", + "how_to_start_radio": "Como você deseja iniciar a rádio?", + "replace_queue_question": "Você deseja substituir a fila atual ou acrescentar a ela?", + "endless_playback": "Reprodução sem fim", + "delete_playlist": "Excluir Lista de Reprodução", + "delete_playlist_confirmation": "Tem certeza de que deseja excluir esta lista de reprodução?", + "local_tracks": "Faixas Locais", + "song_link": "Link da Música", + "skip_this_nonsense": "Pular essa bobagem", + "freedom_of_music": "“Liberdade da Música”", + "freedom_of_music_palm": "“Liberdade da Música na palma da sua mão”", + "get_started": "Vamos começar", + "youtube_source_description": "Recomendado e funciona melhor.", + "piped_source_description": "Sentindo-se livre? Igual ao YouTube, mas muito mais grátis.", + "jiosaavn_source_description": "Melhor para a região da Ásia do Sul.", + "highest_quality": "Melhor Qualidade: {quality}", + "select_audio_source": "Selecionar Fonte de Áudio", + "endless_playback_description": "Adicionar automaticamente novas músicas\nao final da fila", + "choose_your_region": "Escolha sua região", + "choose_your_region_description": "Isso ajudará o Spotube a mostrar o conteúdo certo\npara sua localização.", + "choose_your_language": "Escolha seu idioma", + "help_project_grow": "Ajude este projeto a crescer", + "help_project_grow_description": "Spotube é um projeto de código aberto. Você pode ajudar este projeto a crescer contribuindo para o projeto, relatando bugs ou sugerindo novos recursos.", + "contribute_on_github": "Contribuir no GitHub", + "donate_on_open_collective": "Doar no Open Collective", + "browse_anonymously": "Navegar Anonimamente" } \ No newline at end of file diff --git a/lib/l10n/app_ru.arb b/lib/l10n/app_ru.arb index 7ed67f4f..c9139a90 100644 --- a/lib/l10n/app_ru.arb +++ b/lib/l10n/app_ru.arb @@ -286,5 +286,32 @@ "step_3_steps": "Скопируйте значение файла cookie \"sp_dc\"", "step_4_steps": "Вставьте скопированное значение \"sp_dc\"", "friends": "Друзья", - "no_lyrics_available": "Извините, не удается найти текст для этого трека" + "no_lyrics_available": "Извините, не удается найти текст для этого трека", + "sort_duration": "Сортировка по Длительности", + "start_a_radio": "Запустить радио", + "how_to_start_radio": "Как вы хотите запустить радио?", + "replace_queue_question": "Хотите заменить текущую очередь или добавить к ней?", + "endless_playback": "Бесконечное воспроизведение", + "delete_playlist": "Удалить плейлист", + "delete_playlist_confirmation": "Вы уверены, что хотите удалить этот плейлист?", + "local_tracks": "Локальные треки", + "song_link": "Ссылка на песню", + "skip_this_nonsense": "Пропустить этот бред", + "freedom_of_music": "“Свобода музыки”", + "freedom_of_music_palm": "“Свобода музыки в вашей ладони”", + "get_started": "Начнем", + "youtube_source_description": "Рекомендуется и лучше всего работает.", + "piped_source_description": "Чувствуете себя свободно? То же самое, что и YouTube, но намного бесплатно.", + "jiosaavn_source_description": "Лучший для Южно-Азиатского региона.", + "highest_quality": "Наивысшее качество: {quality}", + "select_audio_source": "Выберите аудиоисточник", + "endless_playback_description": "Автоматически добавляйте новые песни\nв конец очереди", + "choose_your_region": "Выберите ваш регион", + "choose_your_region_description": "Это поможет Spotube показать вам правильный контент\nдля вашего местоположения.", + "choose_your_language": "Выберите ваш язык", + "help_project_grow": "Помогите этому проекту расти", + "help_project_grow_description": "Spotube - это проект с открытым исходным кодом. Вы можете помочь этому проекту развиваться, внося вклад в проект, сообщая ошибках или предлагая новые функции.", + "contribute_on_github": "Внести вклад на GitHub", + "donate_on_open_collective": "Пожертвовать на Open Collective", + "browse_anonymously": "Анонимно просматривать" } \ No newline at end of file diff --git a/lib/l10n/app_tr.arb b/lib/l10n/app_tr.arb index 4d9066fd..94800023 100644 --- a/lib/l10n/app_tr.arb +++ b/lib/l10n/app_tr.arb @@ -286,5 +286,32 @@ "step_3_steps": "\"sp_dc\" Çerezinin değerini kopyala", "step_4_steps": "Kopyalanan \"sp_dc\" değerini yapıştır", "friends": "Arkadaşlar", - "no_lyrics_available": "Üzgünüz, bu parça için şarkı sözleri bulunamıyor" + "no_lyrics_available": "Üzgünüz, bu parça için şarkı sözleri bulunamıyor", + "sort_duration": "Süreye Göre Sırala", + "start_a_radio": "Radyo Başlat", + "how_to_start_radio": "Radyoyu nasıl başlatmak istersiniz?", + "replace_queue_question": "Mevcut kuyruğu değiştirmek mi yoksa eklemek mi istersiniz?", + "endless_playback": "Sonsuz Çalma", + "delete_playlist": "Çalma Listesini Sil", + "delete_playlist_confirmation": "Bu çalma listesini silmek istediğinizden emin misiniz?", + "local_tracks": "Yerel Parçalar", + "song_link": "Şarkı Bağlantısı", + "skip_this_nonsense": "Bu saçmalığı atla", + "freedom_of_music": "“Müziğin Özgürlüğü”", + "freedom_of_music_palm": "“Müziğin Özgürlüğü avucunuzun içinde”", + "get_started": "Başlayalım", + "youtube_source_description": "Tavsiye edilir ve en iyi çalışır.", + "piped_source_description": "Özgür hissediyor musunuz? YouTube ile aynı ama çok daha fazla ücretsiz.", + "jiosaavn_source_description": "Güney Asya bölgesi için en iyisi.", + "highest_quality": "En Yüksek Kalite: {quality}", + "select_audio_source": "Ses Kaynağını Seç", + "endless_playback_description": "Yeni şarkıları otomatik olarak sıraya ekle\nsonuna", + "choose_your_region": "Bölgenizi Seçin", + "choose_your_region_description": "Bu, Spotube'un konumunuza uygun doğru içeriği göstermesine yardımcı olacaktır.", + "choose_your_language": "Dilinizi Seçin", + "help_project_grow": "Bu projenin büyümesine yardımcı olun", + "help_project_grow_description": "Spotube açık kaynaklı bir projedir. Bu projenin büyümesine, projeye katkıda bulunarak, hataları raporlayarak veya yeni özellikler önererek yardımcı olabilirsiniz.", + "contribute_on_github": "GitHub'da Katkıda Bulun", + "donate_on_open_collective": "Açık Topluluğa Bağış Yapın", + "browse_anonymously": "Anonim Olarak Göz At" } \ No newline at end of file diff --git a/lib/l10n/app_uk.arb b/lib/l10n/app_uk.arb index a4586a5e..fe57e617 100644 --- a/lib/l10n/app_uk.arb +++ b/lib/l10n/app_uk.arb @@ -286,5 +286,32 @@ "step_3_steps": "Скопіюйте значення cookie \"sp_dc\"", "step_4_steps": "Вставте скопійоване значення \"sp_dc\"", "friends": "Друзі", - "no_lyrics_available": "Вибачте, не вдалося знайти текст для цього треку" + "no_lyrics_available": "Вибачте, не вдалося знайти текст для цього треку", + "sort_duration": "Сортувати за тривалістю", + "start_a_radio": "Запустити радіо", + "how_to_start_radio": "Як ви хочете запустити радіо?", + "replace_queue_question": "Ви хочете замінити поточну чергу чи додати до неї?", + "endless_playback": "Безкінечне відтворення", + "delete_playlist": "Видалити плейлист", + "delete_playlist_confirmation": "Ви впевнені, що хочете видалити цей плейлист?", + "local_tracks": "Місцеві треки", + "song_link": "Посилання на пісню", + "skip_this_nonsense": "Пропустити цей бред", + "freedom_of_music": "“Свобода музики”", + "freedom_of_music_palm": "“Свобода музики у вашій долоні”", + "get_started": "Давайте почнемо", + "youtube_source_description": "Рекомендовано та працює краще за все.", + "piped_source_description": "Чи почуваєте себе вільно? Те саме, що і на YouTube, але набагато безкоштовно.", + "jiosaavn_source_description": "Найкраще для регіону Південної Азії.", + "highest_quality": "Найвища якість: {quality}", + "select_audio_source": "Виберіть джерело аудіо", + "endless_playback_description": "Автоматично додавати нові пісні\nв кінець черги", + "choose_your_region": "Виберіть ваш регіон", + "choose_your_region_description": "Це допоможе Spotube показати вам правильний контент\nдля вашого місцезнаходження.", + "choose_your_language": "Виберіть свою мову", + "help_project_grow": "Допоможіть цьому проекту рости", + "help_project_grow_description": "Spotube - це проект з відкритим кодом. Ви можете допомогти цьому проекту зростати, вносячи свій внесок у проект, повідомляючи про помилки або пропонуючи нові функції.", + "contribute_on_github": "Долучайтесь на GitHub", + "donate_on_open_collective": "Пожертвуйте на Open Collective", + "browse_anonymously": "Анонімно переглядати" } \ No newline at end of file diff --git a/lib/l10n/app_vi.arb b/lib/l10n/app_vi.arb index d8d337c2..0e9b0b7c 100644 --- a/lib/l10n/app_vi.arb +++ b/lib/l10n/app_vi.arb @@ -284,5 +284,32 @@ "discord_rich_presence": "Hiển thị trạng thái Discord", "browse_all": "Duyệt tất cả", "genres": "Thể loại", - "explore_genres": "Khám phá Thể loại" -} + "explore_genres": "Khám phá Thể loại", + "sort_duration": "Sắp xếp theo Thời lượng", + "start_a_radio": "Bắt đầu Một Đài phát thanh", + "how_to_start_radio": "Bạn muốn bắt đầu đài phát thanh như thế nào?", + "replace_queue_question": "Bạn muốn thay thế hàng đợi hiện tại hay thêm vào?", + "endless_playback": "Phát không giới hạn", + "delete_playlist": "Xóa Danh sách phát", + "delete_playlist_confirmation": "Bạn có chắc chắn muốn xóa danh sách phát này không?", + "local_tracks": "Bài hát Địa phương", + "song_link": "Liên kết Bài hát", + "skip_this_nonsense": "Bỏ qua bớt rối này", + "freedom_of_music": "“Sự Tự do của Âm nhạc”", + "freedom_of_music_palm": "“Sự Tự do của Âm nhạc trong lòng bàn tay của bạn”", + "get_started": "Bắt đầu thôi", + "youtube_source_description": "Được đề xuất và hoạt động tốt nhất.", + "piped_source_description": "Cảm thấy tự do? Giống như YouTube nhưng miễn phí hơn rất nhiều.", + "jiosaavn_source_description": "Tốt nhất cho khu vực Nam Á.", + "highest_quality": "Chất lượng Tốt nhất: {quality}", + "select_audio_source": "Chọn Nguồn Âm thanh", + "endless_playback_description": "Tự động thêm các bài hát mới\nvào cuối hàng đợi", + "choose_your_region": "Chọn khu vực của bạn", + "choose_your_region_description": "Điều này sẽ giúp Spotube hiển thị nội dung phù hợp cho vị trí của bạn.", + "choose_your_language": "Chọn ngôn ngữ của bạn", + "help_project_grow": "Hãy giúp dự án này phát triển", + "help_project_grow_description": "Spotube là một dự án mã nguồn mở. Bạn có thể giúp dự án này phát triển bằng cách đóng góp vào dự án, báo cáo lỗi hoặc đề xuất tính năng mới.", + "contribute_on_github": "Đóng góp trên GitHub", + "donate_on_open_collective": "Quyên góp trên Open Collective", + "browse_anonymously": "Duyệt Anonymously" +} \ No newline at end of file diff --git a/lib/l10n/app_zh.arb b/lib/l10n/app_zh.arb index 20fdb329..506661f0 100644 --- a/lib/l10n/app_zh.arb +++ b/lib/l10n/app_zh.arb @@ -286,5 +286,32 @@ "step_3_steps": "复制\"sp_dc\" Cookie的值", "step_4_steps": "粘贴复制的\"sp_dc\"值", "friends": "朋友", - "no_lyrics_available": "抱歉,无法找到此曲的歌词" + "no_lyrics_available": "抱歉,无法找到此曲的歌词", + "sort_duration": "按时长排序", + "start_a_radio": "开始收听电台", + "how_to_start_radio": "您想如何开始收听电台?", + "replace_queue_question": "您想要替换当前队列还是追加到队列?", + "endless_playback": "无尽播放", + "delete_playlist": "删除播放列表", + "delete_playlist_confirmation": "您确定要删除此播放列表吗?", + "local_tracks": "本地音轨", + "song_link": "歌曲链接", + "skip_this_nonsense": "跳过此无聊内容", + "freedom_of_music": "“音乐的自由”", + "freedom_of_music_palm": "“音乐的自由掌握在您手中”", + "get_started": "让我们开始吧", + "youtube_source_description": "推荐并且效果最佳。", + "piped_source_description": "感觉自由?与YouTube一样但更自由。", + "jiosaavn_source_description": "最适合南亚地区。", + "highest_quality": "最高音质:{quality}", + "select_audio_source": "选择音频源", + "endless_playback_description": "自动将新歌曲添加到队列的末尾", + "choose_your_region": "选择您的地区", + "choose_your_region_description": "这将帮助Spotube为您的位置显示正确的内容。", + "choose_your_language": "选择您的语言", + "help_project_grow": "帮助这个项目成长", + "help_project_grow_description": "Spotube是一个开源项目。您可以通过为项目做出贡献、报告错误或建议新功能来帮助该项目成长。", + "contribute_on_github": "在GitHub上做出贡献", + "donate_on_open_collective": "在Open Collective上捐款", + "browse_anonymously": "匿名浏览" } \ No newline at end of file From 389a4fc704fef509c8321502150d5dfdf0295796 Mon Sep 17 00:00:00 2001 From: Kingkor Roy Tirtho Date: Fri, 8 Mar 2024 21:08:38 +0600 Subject: [PATCH 188/195] cd: remove debug step in upload task --- .github/workflows/spotube-release-binary.yml | 5 ----- 1 file changed, 5 deletions(-) diff --git a/.github/workflows/spotube-release-binary.yml b/.github/workflows/spotube-release-binary.yml index adb99003..14aeafa4 100644 --- a/.github/workflows/spotube-release-binary.yml +++ b/.github/workflows/spotube-release-binary.yml @@ -435,11 +435,6 @@ jobs: RELEASE.md5sum RELEASE.sha256sum - - name: Debug With SSH - uses: mxschmitt/action-tmate@v3 - with: - limit-access-to-actor: true - - name: Upload Release Binaries (stable) if: ${{ !inputs.dry_run && inputs.channel == 'stable' }} uses: ncipollo/release-action@v1 From 4a044498a40c070cb70b050f9a46e5fbb7b6ab95 Mon Sep 17 00:00:00 2001 From: Kingkor Roy Tirtho Date: Fri, 8 Mar 2024 23:03:56 +0600 Subject: [PATCH 189/195] chore: fix macos disable hardened runtime --- macos/Runner.xcodeproj/project.pbxproj | 4 +- macos/Runner/DebugProfile.entitlements | 2 - macos/Runner/RunnerDebug.entitlements | 2 - untranslated_messages.json | 600 +------------------------ 4 files changed, 4 insertions(+), 604 deletions(-) diff --git a/macos/Runner.xcodeproj/project.pbxproj b/macos/Runner.xcodeproj/project.pbxproj index 0ee2c9fa..a2dd74c4 100644 --- a/macos/Runner.xcodeproj/project.pbxproj +++ b/macos/Runner.xcodeproj/project.pbxproj @@ -428,6 +428,7 @@ CODE_SIGN_STYLE = Automatic; COMBINE_HIDPI_IMAGES = YES; DEVELOPMENT_TEAM = 88NVGSJ5N3; + ENABLE_HARDENED_RUNTIME = NO; INFOPLIST_FILE = Runner/Info.plist; INFOPLIST_KEY_CFBundleDisplayName = Spotube; INFOPLIST_KEY_LSApplicationCategoryType = "public.app-category.music"; @@ -558,6 +559,7 @@ CODE_SIGN_STYLE = Automatic; COMBINE_HIDPI_IMAGES = YES; DEVELOPMENT_TEAM = 88NVGSJ5N3; + ENABLE_HARDENED_RUNTIME = NO; INFOPLIST_FILE = Runner/Info.plist; INFOPLIST_KEY_CFBundleDisplayName = Spotube; INFOPLIST_KEY_LSApplicationCategoryType = "public.app-category.music"; @@ -582,7 +584,7 @@ CODE_SIGN_STYLE = Automatic; COMBINE_HIDPI_IMAGES = YES; DEVELOPMENT_TEAM = 88NVGSJ5N3; - ENABLE_HARDENED_RUNTIME = YES; + ENABLE_HARDENED_RUNTIME = NO; INFOPLIST_FILE = Runner/Info.plist; INFOPLIST_KEY_CFBundleDisplayName = Spotube; INFOPLIST_KEY_LSApplicationCategoryType = "public.app-category.music"; diff --git a/macos/Runner/DebugProfile.entitlements b/macos/Runner/DebugProfile.entitlements index e9de2261..f05277de 100644 --- a/macos/Runner/DebugProfile.entitlements +++ b/macos/Runner/DebugProfile.entitlements @@ -6,8 +6,6 @@ com.apple.security.assets.music.read-write - com.apple.security.cs.allow-jit - com.apple.security.files.downloads.read-write com.apple.security.files.user-selected.read-write diff --git a/macos/Runner/RunnerDebug.entitlements b/macos/Runner/RunnerDebug.entitlements index e9de2261..f05277de 100644 --- a/macos/Runner/RunnerDebug.entitlements +++ b/macos/Runner/RunnerDebug.entitlements @@ -6,8 +6,6 @@ com.apple.security.assets.music.read-write - com.apple.security.cs.allow-jit - com.apple.security.files.downloads.read-write com.apple.security.files.user-selected.read-write diff --git a/untranslated_messages.json b/untranslated_messages.json index a6724f2b..4275f461 100644 --- a/untranslated_messages.json +++ b/untranslated_messages.json @@ -1,604 +1,6 @@ { - "ar": [ - "sort_duration", - "start_a_radio", - "how_to_start_radio", - "replace_queue_question", - "endless_playback", - "delete_playlist", - "delete_playlist_confirmation", - "local_tracks", - "song_link", - "skip_this_nonsense", - "freedom_of_music", - "freedom_of_music_palm", - "get_started", - "youtube_source_description", - "piped_source_description", - "jiosaavn_source_description", - "highest_quality", - "select_audio_source", - "endless_playback_description", - "choose_your_region", - "choose_your_region_description", - "choose_your_language", - "help_project_grow", - "help_project_grow_description", - "contribute_on_github", - "donate_on_open_collective", - "browse_anonymously" - ], - - "bn": [ - "sort_duration", - "start_a_radio", - "how_to_start_radio", - "replace_queue_question", - "endless_playback", - "delete_playlist", - "delete_playlist_confirmation", - "local_tracks", - "song_link", - "skip_this_nonsense", - "freedom_of_music", - "freedom_of_music_palm", - "get_started", - "youtube_source_description", - "piped_source_description", - "jiosaavn_source_description", - "highest_quality", - "select_audio_source", - "endless_playback_description", - "choose_your_region", - "choose_your_region_description", - "choose_your_language", - "help_project_grow", - "help_project_grow_description", - "contribute_on_github", - "donate_on_open_collective", - "browse_anonymously" - ], - - "ca": [ - "sort_duration", - "start_a_radio", - "how_to_start_radio", - "replace_queue_question", - "endless_playback", - "delete_playlist", - "delete_playlist_confirmation", - "local_tracks", - "song_link", - "skip_this_nonsense", - "freedom_of_music", - "freedom_of_music_palm", - "get_started", - "youtube_source_description", - "piped_source_description", - "jiosaavn_source_description", - "highest_quality", - "select_audio_source", - "endless_playback_description", - "choose_your_region", - "choose_your_region_description", - "choose_your_language", - "help_project_grow", - "help_project_grow_description", - "contribute_on_github", - "donate_on_open_collective", - "browse_anonymously" - ], - - "de": [ - "sort_duration", - "start_a_radio", - "how_to_start_radio", - "replace_queue_question", - "endless_playback", - "delete_playlist", - "delete_playlist_confirmation", - "local_tracks", - "song_link", - "skip_this_nonsense", - "freedom_of_music", - "freedom_of_music_palm", - "get_started", - "youtube_source_description", - "piped_source_description", - "jiosaavn_source_description", - "highest_quality", - "select_audio_source", - "endless_playback_description", - "choose_your_region", - "choose_your_region_description", - "choose_your_language", - "help_project_grow", - "help_project_grow_description", - "contribute_on_github", - "donate_on_open_collective", - "browse_anonymously" - ], - - "es": [ - "sort_duration", - "start_a_radio", - "how_to_start_radio", - "replace_queue_question", - "endless_playback", - "delete_playlist", - "delete_playlist_confirmation", - "local_tracks", - "song_link", - "skip_this_nonsense", - "freedom_of_music", - "freedom_of_music_palm", - "get_started", - "youtube_source_description", - "piped_source_description", - "jiosaavn_source_description", - "highest_quality", - "select_audio_source", - "endless_playback_description", - "choose_your_region", - "choose_your_region_description", - "choose_your_language", - "help_project_grow", - "help_project_grow_description", - "contribute_on_github", - "donate_on_open_collective", - "browse_anonymously" - ], - - "fa": [ - "sort_duration", - "start_a_radio", - "how_to_start_radio", - "replace_queue_question", - "endless_playback", - "delete_playlist", - "delete_playlist_confirmation", - "local_tracks", - "song_link", - "skip_this_nonsense", - "freedom_of_music", - "freedom_of_music_palm", - "get_started", - "youtube_source_description", - "piped_source_description", - "jiosaavn_source_description", - "highest_quality", - "select_audio_source", - "endless_playback_description", - "choose_your_region", - "choose_your_region_description", - "choose_your_language", - "help_project_grow", - "help_project_grow_description", - "contribute_on_github", - "donate_on_open_collective", - "browse_anonymously" - ], - - "fr": [ - "sort_duration", - "start_a_radio", - "how_to_start_radio", - "replace_queue_question", - "endless_playback", - "delete_playlist", - "delete_playlist_confirmation", - "local_tracks", - "song_link", - "skip_this_nonsense", - "freedom_of_music", - "freedom_of_music_palm", - "get_started", - "youtube_source_description", - "piped_source_description", - "jiosaavn_source_description", - "highest_quality", - "select_audio_source", - "endless_playback_description", - "choose_your_region", - "choose_your_region_description", - "choose_your_language", - "help_project_grow", - "help_project_grow_description", - "contribute_on_github", - "donate_on_open_collective", - "browse_anonymously" - ], - - "hi": [ - "sort_duration", - "start_a_radio", - "how_to_start_radio", - "replace_queue_question", - "endless_playback", - "delete_playlist", - "delete_playlist_confirmation", - "local_tracks", - "song_link", - "skip_this_nonsense", - "freedom_of_music", - "freedom_of_music_palm", - "get_started", - "youtube_source_description", - "piped_source_description", - "jiosaavn_source_description", - "highest_quality", - "select_audio_source", - "endless_playback_description", - "choose_your_region", - "choose_your_region_description", - "choose_your_language", - "help_project_grow", - "help_project_grow_description", - "contribute_on_github", - "donate_on_open_collective", - "browse_anonymously" - ], - - "it": [ - "sort_duration", - "start_a_radio", - "how_to_start_radio", - "replace_queue_question", - "endless_playback", - "delete_playlist", - "delete_playlist_confirmation", - "local_tracks", - "song_link", - "skip_this_nonsense", - "freedom_of_music", - "freedom_of_music_palm", - "get_started", - "youtube_source_description", - "piped_source_description", - "jiosaavn_source_description", - "highest_quality", - "select_audio_source", - "endless_playback_description", - "choose_your_region", - "choose_your_region_description", - "choose_your_language", - "help_project_grow", - "help_project_grow_description", - "contribute_on_github", - "donate_on_open_collective", - "browse_anonymously" - ], - - "ja": [ - "sort_duration", - "start_a_radio", - "how_to_start_radio", - "replace_queue_question", - "endless_playback", - "delete_playlist", - "delete_playlist_confirmation", - "local_tracks", - "song_link", - "skip_this_nonsense", - "freedom_of_music", - "freedom_of_music_palm", - "get_started", - "youtube_source_description", - "piped_source_description", - "jiosaavn_source_description", - "highest_quality", - "select_audio_source", - "endless_playback_description", - "choose_your_region", - "choose_your_region_description", - "choose_your_language", - "help_project_grow", - "help_project_grow_description", - "contribute_on_github", - "donate_on_open_collective", - "browse_anonymously" - ], - - "ko": [ - "sort_duration", - "start_a_radio", - "how_to_start_radio", - "replace_queue_question", - "endless_playback", - "delete_playlist", - "delete_playlist_confirmation", - "local_tracks", - "song_link", - "skip_this_nonsense", - "freedom_of_music", - "freedom_of_music_palm", - "get_started", - "youtube_source_description", - "piped_source_description", - "jiosaavn_source_description", - "highest_quality", - "select_audio_source", - "endless_playback_description", - "choose_your_region", - "choose_your_region_description", - "choose_your_language", - "help_project_grow", - "help_project_grow_description", - "contribute_on_github", - "donate_on_open_collective", - "browse_anonymously" - ], - - "ne": [ - "sort_duration", - "start_a_radio", - "how_to_start_radio", - "replace_queue_question", - "endless_playback", - "delete_playlist", - "delete_playlist_confirmation", - "local_tracks", - "song_link", - "skip_this_nonsense", - "freedom_of_music", - "freedom_of_music_palm", - "get_started", - "youtube_source_description", - "piped_source_description", - "jiosaavn_source_description", - "highest_quality", - "select_audio_source", - "endless_playback_description", - "choose_your_region", - "choose_your_region_description", - "choose_your_language", - "help_project_grow", - "help_project_grow_description", - "contribute_on_github", - "donate_on_open_collective", - "browse_anonymously" - ], - - "nl": [ - "sort_duration", - "audio_source", - "start_a_radio", - "how_to_start_radio", - "replace_queue_question", - "endless_playback", - "delete_playlist", - "delete_playlist_confirmation", - "local_tracks", - "song_link", - "skip_this_nonsense", - "freedom_of_music", - "freedom_of_music_palm", - "get_started", - "youtube_source_description", - "piped_source_description", - "jiosaavn_source_description", - "highest_quality", - "select_audio_source", - "endless_playback_description", - "choose_your_region", - "choose_your_region_description", - "choose_your_language", - "help_project_grow", - "help_project_grow_description", - "contribute_on_github", - "donate_on_open_collective", - "browse_anonymously" - ], - - "pl": [ - "sort_duration", - "start_a_radio", - "how_to_start_radio", - "replace_queue_question", - "endless_playback", - "delete_playlist", - "delete_playlist_confirmation", - "local_tracks", - "song_link", - "skip_this_nonsense", - "freedom_of_music", - "freedom_of_music_palm", - "get_started", - "youtube_source_description", - "piped_source_description", - "jiosaavn_source_description", - "highest_quality", - "select_audio_source", - "endless_playback_description", - "choose_your_region", - "choose_your_region_description", - "choose_your_language", - "help_project_grow", - "help_project_grow_description", - "contribute_on_github", - "donate_on_open_collective", - "browse_anonymously" - ], - - "pt": [ - "sort_duration", - "start_a_radio", - "how_to_start_radio", - "replace_queue_question", - "endless_playback", - "delete_playlist", - "delete_playlist_confirmation", - "local_tracks", - "song_link", - "skip_this_nonsense", - "freedom_of_music", - "freedom_of_music_palm", - "get_started", - "youtube_source_description", - "piped_source_description", - "jiosaavn_source_description", - "highest_quality", - "select_audio_source", - "endless_playback_description", - "choose_your_region", - "choose_your_region_description", - "choose_your_language", - "help_project_grow", - "help_project_grow_description", - "contribute_on_github", - "donate_on_open_collective", - "browse_anonymously" - ], - - "ru": [ - "sort_duration", - "start_a_radio", - "how_to_start_radio", - "replace_queue_question", - "endless_playback", - "delete_playlist", - "delete_playlist_confirmation", - "local_tracks", - "song_link", - "skip_this_nonsense", - "freedom_of_music", - "freedom_of_music_palm", - "get_started", - "youtube_source_description", - "piped_source_description", - "jiosaavn_source_description", - "highest_quality", - "select_audio_source", - "endless_playback_description", - "choose_your_region", - "choose_your_region_description", - "choose_your_language", - "help_project_grow", - "help_project_grow_description", - "contribute_on_github", - "donate_on_open_collective", - "browse_anonymously" - ], - - "tr": [ - "sort_duration", - "start_a_radio", - "how_to_start_radio", - "replace_queue_question", - "endless_playback", - "delete_playlist", - "delete_playlist_confirmation", - "local_tracks", - "song_link", - "skip_this_nonsense", - "freedom_of_music", - "freedom_of_music_palm", - "get_started", - "youtube_source_description", - "piped_source_description", - "jiosaavn_source_description", - "highest_quality", - "select_audio_source", - "endless_playback_description", - "choose_your_region", - "choose_your_region_description", - "choose_your_language", - "help_project_grow", - "help_project_grow_description", - "contribute_on_github", - "donate_on_open_collective", - "browse_anonymously" - ], - - "uk": [ - "sort_duration", - "start_a_radio", - "how_to_start_radio", - "replace_queue_question", - "endless_playback", - "delete_playlist", - "delete_playlist_confirmation", - "local_tracks", - "song_link", - "skip_this_nonsense", - "freedom_of_music", - "freedom_of_music_palm", - "get_started", - "youtube_source_description", - "piped_source_description", - "jiosaavn_source_description", - "highest_quality", - "select_audio_source", - "endless_playback_description", - "choose_your_region", - "choose_your_region_description", - "choose_your_language", - "help_project_grow", - "help_project_grow_description", - "contribute_on_github", - "donate_on_open_collective", - "browse_anonymously" - ], - "vi": [ - "sort_duration", "friends", - "no_lyrics_available", - "start_a_radio", - "how_to_start_radio", - "replace_queue_question", - "endless_playback", - "delete_playlist", - "delete_playlist_confirmation", - "local_tracks", - "song_link", - "skip_this_nonsense", - "freedom_of_music", - "freedom_of_music_palm", - "get_started", - "youtube_source_description", - "piped_source_description", - "jiosaavn_source_description", - "highest_quality", - "select_audio_source", - "endless_playback_description", - "choose_your_region", - "choose_your_region_description", - "choose_your_language", - "help_project_grow", - "help_project_grow_description", - "contribute_on_github", - "donate_on_open_collective", - "browse_anonymously" - ], - - "zh": [ - "sort_duration", - "start_a_radio", - "how_to_start_radio", - "replace_queue_question", - "endless_playback", - "delete_playlist", - "delete_playlist_confirmation", - "local_tracks", - "song_link", - "skip_this_nonsense", - "freedom_of_music", - "freedom_of_music_palm", - "get_started", - "youtube_source_description", - "piped_source_description", - "jiosaavn_source_description", - "highest_quality", - "select_audio_source", - "endless_playback_description", - "choose_your_region", - "choose_your_region_description", - "choose_your_language", - "help_project_grow", - "help_project_grow_description", - "contribute_on_github", - "donate_on_open_collective", - "browse_anonymously" + "no_lyrics_available" ] } From a248a4b48c1fd5d46e2f3dedb9330efa25de571f Mon Sep 17 00:00:00 2001 From: Kingkor Roy Tirtho Date: Fri, 8 Mar 2024 23:07:55 +0600 Subject: [PATCH 190/195] chore: fix getting started showing up everytime --- lib/main.dart | 1 - lib/pages/getting_started/sections/support.dart | 16 ++++++++++------ lib/services/kv_store/kv_store.dart | 4 ++-- 3 files changed, 12 insertions(+), 9 deletions(-) diff --git a/lib/main.dart b/lib/main.dart index 31c1da57..01e418dd 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -70,7 +70,6 @@ Future main(List rawArgs) async { } await KVStoreService.initialize(); - KVStoreService.doneGettingStarted = false; final hiveCacheDir = kIsWeb ? null : (await getApplicationSupportDirectory()).path; diff --git a/lib/pages/getting_started/sections/support.dart b/lib/pages/getting_started/sections/support.dart index 1be7ca34..46823425 100644 --- a/lib/pages/getting_started/sections/support.dart +++ b/lib/pages/getting_started/sections/support.dart @@ -101,9 +101,11 @@ class GettingStartedScreenSupportSection extends HookConsumerWidget { style: TextButton.styleFrom( foregroundColor: Colors.white, ), - onPressed: () { - KVStoreService.doneGettingStarted = true; - context.go("/"); + onPressed: () async { + await KVStoreService.setDoneGettingStarted(true); + if (context.mounted) { + context.go("/"); + } }, ), ), @@ -115,9 +117,11 @@ class GettingStartedScreenSupportSection extends HookConsumerWidget { backgroundColor: const Color(0xff1db954), foregroundColor: Colors.white, ), - onPressed: () { - KVStoreService.doneGettingStarted = true; - context.push("/login"); + onPressed: () async { + await KVStoreService.setDoneGettingStarted(true); + if (context.mounted) { + context.push("/login"); + } }, ), ], diff --git a/lib/services/kv_store/kv_store.dart b/lib/services/kv_store/kv_store.dart index 6f6807e0..c1275612 100644 --- a/lib/services/kv_store/kv_store.dart +++ b/lib/services/kv_store/kv_store.dart @@ -10,6 +10,6 @@ abstract class KVStoreService { static bool get doneGettingStarted => sharedPreferences.getBool('doneGettingStarted') ?? false; - static set doneGettingStarted(bool value) => - sharedPreferences.setBool('doneGettingStarted', value); + static Future setDoneGettingStarted(bool value) async => + await sharedPreferences.setBool('doneGettingStarted', value); } From e516afb185f616471822ea745495a3d1d1281bd3 Mon Sep 17 00:00:00 2001 From: Kingkor Roy Tirtho Date: Sat, 9 Mar 2024 00:00:36 +0600 Subject: [PATCH 191/195] fix(android): only ask battery optimization once #1252 --- .../use_disable_battery_optimizations.dart | 46 ++++--------------- lib/services/kv_store/kv_store.dart | 5 ++ 2 files changed, 15 insertions(+), 36 deletions(-) diff --git a/lib/hooks/configurators/use_disable_battery_optimizations.dart b/lib/hooks/configurators/use_disable_battery_optimizations.dart index c1155d19..a9afef45 100644 --- a/lib/hooks/configurators/use_disable_battery_optimizations.dart +++ b/lib/hooks/configurators/use_disable_battery_optimizations.dart @@ -1,47 +1,21 @@ import 'package:disable_battery_optimization/disable_battery_optimization.dart'; import 'package:flutter_desktop_tools/flutter_desktop_tools.dart'; -import 'package:shared_preferences/shared_preferences.dart'; import 'package:spotube/hooks/utils/use_async_effect.dart'; +import 'package:spotube/services/kv_store/kv_store.dart'; -bool _asked = false; void useDisableBatteryOptimizations() { useAsyncEffect(() async { - if (!DesktopTools.platform.isAndroid || _asked) return; - final localStorage = await SharedPreferences.getInstance(); + if (!DesktopTools.platform.isAndroid || + KVStoreService.askedForBatteryOptimization) return; - final rawIsBatteryOptimizationDisabled = - localStorage.getBool("isBatteryOptimizationDisabled"); - final isBatteryOptimizationDisabled = - await DisableBatteryOptimization.isBatteryOptimizationDisabled; - if (rawIsBatteryOptimizationDisabled != false && - isBatteryOptimizationDisabled == false) { - final hasDisabled = await DisableBatteryOptimization - .showDisableBatteryOptimizationSettings(); + await DisableBatteryOptimization.showDisableBatteryOptimizationSettings(); - localStorage.setBool( - "isBatteryOptimizationDisabled", - hasDisabled == true, - ); - } + await DisableBatteryOptimization + .showDisableManufacturerBatteryOptimizationSettings( + "Your device has additional battery optimization", + "Follow the steps and disable the optimizations to allow smooth functioning of this app", + ); - final rawIsManBatteryOptimizationDisabled = - localStorage.getBool("isManufacturerBatteryOptimizationDisabled"); - final isManBatteryOptimizationDisabled = await DisableBatteryOptimization - .isManufacturerBatteryOptimizationDisabled; - - if (rawIsManBatteryOptimizationDisabled != false && - isManBatteryOptimizationDisabled == false) { - final hasDisabled = await DisableBatteryOptimization - .showDisableManufacturerBatteryOptimizationSettings( - "Your device has additional battery optimization", - "Follow the steps and disable the optimizations to allow smooth functioning of this app", - ); - - localStorage.setBool( - "isManufacturerBatteryOptimizationDisabled", - hasDisabled == true, - ); - } - _asked = true; + await KVStoreService.setAskedForBatteryOptimization(true); }, null, []); } diff --git a/lib/services/kv_store/kv_store.dart b/lib/services/kv_store/kv_store.dart index c1275612..5845b120 100644 --- a/lib/services/kv_store/kv_store.dart +++ b/lib/services/kv_store/kv_store.dart @@ -12,4 +12,9 @@ abstract class KVStoreService { sharedPreferences.getBool('doneGettingStarted') ?? false; static Future setDoneGettingStarted(bool value) async => await sharedPreferences.setBool('doneGettingStarted', value); + + static bool get askedForBatteryOptimization => + sharedPreferences.getBool('askedForBatteryOptimization') ?? false; + static Future setAskedForBatteryOptimization(bool value) async => + await sharedPreferences.setBool('askedForBatteryOptimization', value); } From eec7a9dbc41ab673b392690d3fbda335b097f7f9 Mon Sep 17 00:00:00 2001 From: Kingkor Roy Tirtho Date: Sat, 9 Mar 2024 00:05:47 +0600 Subject: [PATCH 192/195] chore: update changelogs and update credits --- CHANGELOG.md | 1 + README.md | 12 ++++++++---- 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 02624a7f..ddbd4fe1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -24,6 +24,7 @@ All notable changes to this project will be documented in this file. See [standa * album images are small in certain places ([ca76a39](https://github.com/krtirtho/spotube/commit/ca76a39910b1a5af91aa7882a0d33c9d71db58a2)) * album, artist page not loading [#1282](https://github.com/krtirtho/spotube/issues/1282) ([a9a1d4c](https://github.com/krtirtho/spotube/commit/a9a1d4c9dc24aaf3181dc4090d1822ebfe755991)) * **android:** audio issue when screen is off and broadcast audio session id ([#1221](https://github.com/krtirtho/spotube/issues/1221) & [#1247](https://github.com/krtirtho/spotube/issues/1247)) ([17105a6](https://github.com/krtirtho/spotube/commit/17105a640bf5107bd5d333b9b4d097c14a3949a2)), closes [KRTirtho/spotube#571](https://github.com/KRTirtho/spotube/issues/571) +* **android:** only ask battery optimization once [#1252](https://github.com/krtirtho/spotube/issues/1252) ([e516afb](https://github.com/krtirtho/spotube/commit/e516afb185f616471822ea745495a3d1d1281bd3)) * **android:** pressing back button in any other tab other than home exits the app ([c3289a0](https://github.com/krtirtho/spotube/commit/c3289a0ba4e7de094a15246677ffcb940504ebde)) * **android:** system back button in player page exits the app ([3294f65](https://github.com/krtirtho/spotube/commit/3294f657fe8a03b18d9be8974968b6508465963d)) * cleanTitle removing feat and ft from words instead of whole words ([8612345](https://github.com/krtirtho/spotube/commit/86123456f2ff577921cf62cffca180427dfe1dd5)) diff --git a/README.md b/README.md index 469d03ac..de00054f 100644 --- a/README.md +++ b/README.md @@ -204,6 +204,7 @@ If you are concerned, you can [read the reason of choosing this license](https:/ 1. [Piped](https://piped-docs.kavin.rocks/) - Piped is a privacy friendly alternative YouTube frontend, which is efficient and scalable by design. 1. [YouTube](https://youtube.com/) - YouTube is an American online video-sharing platform headquartered in San Bruno, California. Three former PayPal employees—Chad Hurley, Steve Chen, and Jawed Karim—created the service in February 2005 1. [JioSaavn](https://www.jiosaavn.com) - JioSaavn is an Indian online music streaming service and a digital distributor of Bollywood, English and other regional Indian music across the world. Since it was founded in 2007 as Saavn, the company has acquired rights to over 5 crore (50 million) music tracks in 15 languages +1. [SongLink](https://song.link) - SongLink is a free smart link service that helps you share music with your audience. It's a one-stop-shop for creating smart links for music, podcasts, and other audio content 1. [Linux](https://www.linux.org) - Linux is a family of open-source Unix-like operating systems based on the Linux kernel, an operating system kernel first released on September 17, 1991, by Linus Torvalds. Linux is typically packaged in a Linux distribution 1. [AUR](https://aur.archlinux.org) - AUR stands for Arch User Repository. It is a community-driven repository for Arch-based Linux distributions users 1. [Flatpak](https://flatpak.org) - Flatpak is a utility for software deployment and package management for Linux @@ -242,7 +243,7 @@ If you are concerned, you can [read the reason of choosing this license](https:/ 1. [flutter_hooks](https://github.com/rrousselGit/flutter_hooks) - A flutter implementation of React hooks. It adds a new kind of widget with enhanced code reuse. 1. [flutter_inappwebview](https://inappwebview.dev/) - A Flutter plugin that allows you to add an inline webview, to use an headless webview, and to open an in-app browser window. 1. [flutter_native_splash](https://pub.dev/packages/flutter_native_splash) - Customize Flutter's default white native splash screen with background color and splash image. Supports dark mode, full screen, and more. -1. [flutter_riverpod](https://riverpod.dev) - A simple way to access state from anywhere in your application while robust and testable. +1. [flutter_riverpod](https://riverpod.dev) - A reactive caching and data-binding framework. Riverpod makes working with asynchronous code a breeze. 1. [flutter_secure_storage](https://pub.dev/packages/flutter_secure_storage) - Flutter Secure Storage provides API to store data in secure storage. Keychain is used in iOS, KeyStore based solution is used in Android. 1. [flutter_svg](https://pub.dev/packages/flutter_svg) - An SVG rendering and widget library for Flutter, which allows painting and displaying Scalable Vector Graphics 1.1 files. 1. [form_validator](https://github.com/TheMisir/form-validator) - Simplest form validation library for flutter's form field widgets @@ -251,7 +252,7 @@ If you are concerned, you can [read the reason of choosing this license](https:/ 1. [google_fonts](https://pub.dev/packages/google_fonts) - A Flutter package to use fonts from fonts.google.com. Supports HTTP fetching, caching, and asset bundling. 1. [hive](https://github.com/hivedb/hive/tree/master/hive) - Lightweight and blazing fast key-value database written in pure Dart. Strongly encrypted using AES-256. 1. [hive_flutter](https://github.com/hivedb/hive/tree/master/hive_flutter) - Extension for Hive. Makes it easier to use Hive in Flutter apps. -1. [hooks_riverpod](https://riverpod.dev) - A simple way to access state from anywhere in your application while robust and testable. +1. [hooks_riverpod](https://riverpod.dev) - A reactive caching and data-binding framework. Riverpod makes working with asynchronous code a breeze. 1. [html](https://pub.dev/packages/html) - APIs for parsing and manipulating HTML content outside the browser. 1. [http](https://pub.dev/packages/http) - A composable, multi-platform, Future-based API for HTTP requests. 1. [image_picker](https://pub.dev/packages/image_picker) - Flutter plugin for selecting images from the Android and iOS image library, and taking new pictures with the camera. @@ -268,14 +269,12 @@ If you are concerned, you can [read the reason of choosing this license](https:/ 1. [path](https://pub.dev/packages/path) - A string-based path manipulation library. All of the path operations you know and love, with solid support for Windows, POSIX (Linux and Mac OS X), and the web. 1. [path_provider](https://pub.dev/packages/path_provider) - Flutter plugin for getting commonly used locations on host platform file systems, such as the temp and app data directories. 1. [permission_handler](https://pub.dev/packages/permission_handler) - Permission plugin for Flutter. This plugin provides a cross-platform (iOS, Android) API to request and check permissions. -1. [piped_client](https://github.com/KRTirtho/piped_client) - API Client for piped.video 1. [popover](https://github.com/minikin/popover) - A popover is a transient view that appears above other content onscreen when you tap a control or in an area. 1. [scroll_to_index](https://github.com/quire-io/scroll-to-index) - Scroll to a specific child of any scrollable widget in Flutter 1. [sidebarx](https://github.com/Frezyx/sidebarx) - flutter multiplatform navigation sidebar / side navigationbar / drawer widget 1. [shared_preferences](https://pub.dev/packages/shared_preferences) - Flutter plugin for reading and writing simple key-value pairs. Wraps NSUserDefaults on iOS and SharedPreferences on Android. 1. [skeleton_text](https://github.com/101Loop/Skeleton-Text) - A package that provides an easy way to add skeleton text loading animation in Flutter project. This project is a part of 101Loop community. 1. [smtc_windows](https://github.com/KRTirtho/smtc_windows) - Windows `SystemMediaTransportControls` implementation for Flutter giving access to Windows OS Media Control applet. -1. [spotify](https://github.com/rinukkusu/spotify-dart) - An incomplete dart library for interfacing with the Spotify Web API. 1. [stroke_text](https://github.com/MohamedAbd0/stroke_text) - A Simple Flutter plugin for applying stroke (border) style to a text widget 1. [system_theme](https://pub.dev/packages/system_theme) - A plugin to get the current system theme info. Supports Android, Web, Windows, Linux and macOS 1. [titlebar_buttons](https://github.com/gtk-flutter/titlebar_buttons) - A package which provides most of the titlebar buttons from windows, linux and macos. @@ -298,6 +297,9 @@ If you are concerned, you can [read the reason of choosing this license](https:/ 1. [app_links](https://github.com/llfbandit/app_links) - Android App Links, Deep Links, iOs Universal Links and Custom URL schemes handler for Flutter (desktop included). 1. [win32_registry](https://win32.pub) - A package that provides a friendly Dart API for accessing the Windows Registry. 1. [flutter_sharing_intent](https://github.com/bhagat-techind/flutter_sharing_intent.git) - A flutter plugin that allow flutter apps to receive photos, videos, text, urls or any other file types from another app. +1. [flutter_broadcasts](https://pub.dev/packages/flutter_broadcasts) - A plugin for sending and receiving broadcasts with Android intents and iOS notifications. +1. [freezed_annotation](https://pub.dev/packages/freezed_annotation) - Annotations for the freezed code-generator. This package does nothing without freezed too. +1. [spotify](https://github.com/rinukkusu/spotify-dart) - An incomplete dart library for interfacing with the Spotify Web API. 1. [build_runner](https://pub.dev/packages/build_runner) - A build system for Dart code generation and modular compilation. 1. [envied_generator](https://github.com/petercinibulk/envied) - Generator for the Envied package. See https://pub.dev/packages/envied. 1. [flutter_distributor](https://distributor.leanflutter.org) - A complete tool for packaging and publishing your Flutter apps. @@ -308,7 +310,9 @@ If you are concerned, you can [read the reason of choosing this license](https:/ 1. [json_serializable](https://pub.dev/packages/json_serializable) - Automatically generate code for converting to and from JSON by annotating Dart classes. 1. [pub_api_client](https://github.com/leoafarias/pub_api_client) - An API Client for Pub to interact with public package information. 1. [pubspec_parse](https://pub.dev/packages/pubspec_parse) - Simple package for parsing pubspec.yaml files with a type-safe API and rich error reporting. +1. [freezed](https://pub.dev/packages/freezed) - Code generation for immutable classes that has a simple syntax/API without compromising on the features. 1. [flutter_desktop_tools](https://github.com/KRTirtho/flutter_desktop_tools) - Essential collection of tools for flutter desktop app development +1. [piped_client](https://github.com/KRTirtho/piped_client) - API Client for piped.video 1. [scrobblenaut](https://github.com/Nebulino/Scrobblenaut) - A deadly simple LastFM API Wrapper for Dart. So deadly simple that it's gonna hit the mark. 1. [window_size](https://github.com/google/flutter-desktop-embedding.git) - Allows resizing and repositioning the window containing Flutter. 1. [draggable_scrollbar](https://github.com/fluttercommunity/flutter-draggable-scrollbar) - A scrollbar that can be dragged for quickly navigation through a vertical list. Additional option is showing label next to scrollthumb with information about current item. From 653900962937da58d00c6cbec8a6157e7a6964fe Mon Sep 17 00:00:00 2001 From: Kingkor Roy Tirtho Date: Sat, 9 Mar 2024 00:38:08 +0600 Subject: [PATCH 193/195] cd: fix linux tar --- .github/workflows/spotube-release-binary.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/spotube-release-binary.yml b/.github/workflows/spotube-release-binary.yml index 14aeafa4..68ea2d67 100644 --- a/.github/workflows/spotube-release-binary.yml +++ b/.github/workflows/spotube-release-binary.yml @@ -181,7 +181,7 @@ jobs: - uses: actions/upload-artifact@v3 - if: ${{ inputs.channel == 'release' }} + if: ${{ inputs.channel == 'stable' }} with: if-no-files-found: error name: Spotube-Release-Binaries From ca2b81d5720c79fcaaa545c990f8770243f0bf6a Mon Sep 17 00:00:00 2001 From: Kingkor Roy Tirtho Date: Sat, 9 Mar 2024 22:28:40 +0600 Subject: [PATCH 194/195] chore: fix linux appdata formatting --- linux/com.github.KRTirtho.Spotube.appdata.xml | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/linux/com.github.KRTirtho.Spotube.appdata.xml b/linux/com.github.KRTirtho.Spotube.appdata.xml index 7b6c92c2..ebe2fb7d 100644 --- a/linux/com.github.KRTirtho.Spotube.appdata.xml +++ b/linux/com.github.KRTirtho.Spotube.appdata.xml @@ -3,7 +3,7 @@ com.github.KRTirtho.Spotube Spotube - 🎧 Open source Spotify client that doesn't require Premium nor uses Electron! Available for both desktop & mobile! + Freedom of music CC0-1.0 BSD-4-Clause @@ -13,9 +13,11 @@ touch Kingkor Roy Tirtho - https://github.com/krtirtho/spotube + https://github.com/krtirtho/spotube/issues + https://spotube.krtirtho.dev + https://opencollective.com/spotube -

    🎧 Open source Spotify client that doesn't require Premium nor uses Electron! Available for +

    Open source Spotify client that doesn't require Premium nor uses Electron! Available for both desktop & mobile!

    Following are the features that currently spotube offers:

      @@ -30,12 +32,13 @@
    • 📖 Open source/libre software
    • 🔉 Playback control is done locally, not on the server
    -
    - + - https://rawcdn.githack.com/KRTirtho/spotube/62055018feade0b895663a0bfc5f85f265ae2154/assets/spotube-screenshot.png + https://rawcdn.githack.com/KRTirtho/spotube/62055018feade0b895663a0bfc5f85f265ae2154/assets/spotube-screenshot.png + +
    Spotube screenshot