From 6e07fec1a50281f0cbd2def10357eeea4414a627 Mon Sep 17 00:00:00 2001 From: Kingkor Roy Tirtho Date: Mon, 15 Apr 2024 18:01:35 +0600 Subject: [PATCH 01/13] chore: fix no window button and feed section page bottom overflow --- lib/pages/home/feed/feed_section.dart | 5 +++++ lib/pages/home/home.dart | 1 + 2 files changed, 6 insertions(+) diff --git a/lib/pages/home/feed/feed_section.dart b/lib/pages/home/feed/feed_section.dart index 40ac2482..c945251c 100644 --- a/lib/pages/home/feed/feed_section.dart +++ b/lib/pages/home/feed/feed_section.dart @@ -54,6 +54,11 @@ class HomeFeedSectionPage extends HookConsumerWidget { ); }, ), + const SliverToBoxAdapter( + child: SafeArea( + child: SizedBox(), + ), + ), ], ), ), diff --git a/lib/pages/home/home.dart b/lib/pages/home/home.dart index e37898a8..d5639274 100644 --- a/lib/pages/home/home.dart +++ b/lib/pages/home/home.dart @@ -29,6 +29,7 @@ class HomePage extends HookConsumerWidget { return SafeArea( bottom: false, child: Scaffold( + appBar: kIsMobile || kIsMacOS ? null : const PageWindowTitleBar(), body: CustomScrollView( controller: controller, slivers: [ From 6f4c30845783f436c447229f9886cdddfbf63717 Mon Sep 17 00:00:00 2001 From: Kingkor Roy Tirtho Date: Mon, 15 Apr 2024 19:11:59 +0600 Subject: [PATCH 02/13] chore: fix shuffle doesn't move active track to top and library gridview with floating filter field --- lib/components/connect/connect_device.dart | 86 +++++------ lib/components/library/user_albums.dart | 120 ++++++++-------- lib/components/library/user_artists.dart | 136 +++++++++--------- lib/components/library/user_local_tracks.dart | 4 +- lib/components/library/user_playlists.dart | 60 ++++---- lib/pages/connect/connect.dart | 1 + lib/pages/home/genres/genres.dart | 1 + lib/pages/home/home.dart | 7 +- lib/services/audio_player/custom_player.dart | 4 + 9 files changed, 212 insertions(+), 207 deletions(-) diff --git a/lib/components/connect/connect_device.dart b/lib/components/connect/connect_device.dart index 14243fa8..3ac585df 100644 --- a/lib/components/connect/connect_device.dart +++ b/lib/components/connect/connect_device.dart @@ -52,52 +52,58 @@ class ConnectDeviceButton extends HookConsumerWidget { alignment: Alignment.centerRight, fit: StackFit.loose, children: [ - Center( - child: InkWell( - onTap: () { - ServiceUtils.push(context, "/connect"); - }, - borderRadius: BorderRadius.circular(50), - child: Ink( - decoration: BoxDecoration( + Material( + type: MaterialType.transparency, + child: Center( + child: ClipRect( + clipBehavior: Clip.hardEdge, + child: InkWell( + onTap: () { + ServiceUtils.push(context, "/connect"); + }, borderRadius: BorderRadius.circular(50), - color: colorScheme.primaryContainer, - ), - padding: - const EdgeInsets.symmetric(horizontal: 10, vertical: 5), - child: Row( - mainAxisSize: MainAxisSize.min, - children: [ - if (connectClients.asData?.value.resolvedService != - null) ...[ - Container( - width: 7, - height: 7, - decoration: BoxDecoration( - color: Colors.greenAccent, - borderRadius: BorderRadius.circular(50), - ), - ), - const Gap(5), - ], - Text(context.l10n.devices), - if (connectClients.asData?.value.services.isNotEmpty == - true) - Text( - " (${connectClients.asData?.value.services.length})", - style: TextStyle( - color: - colorScheme.onPrimaryContainer.withOpacity(0.5), - ), - ), - const Gap(35), - ], + child: Ink( + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(50), + color: colorScheme.primaryContainer, + ), + padding: + const EdgeInsets.symmetric(horizontal: 10, vertical: 5), + child: Row( + mainAxisSize: MainAxisSize.min, + children: [ + if (connectClients.asData?.value.resolvedService != + null) ...[ + Container( + width: 7, + height: 7, + decoration: BoxDecoration( + color: Colors.greenAccent, + borderRadius: BorderRadius.circular(50), + ), + ), + const Gap(5), + ], + Text(context.l10n.devices), + if (connectClients.asData?.value.services.isNotEmpty == + true) + Text( + " (${connectClients.asData?.value.services.length})", + style: TextStyle( + color: colorScheme.onPrimaryContainer + .withOpacity(0.5), + ), + ), + const Gap(35), + ], + ), + ), ), ), ), ), Positioned( - right: 0, + right: -3, child: IconButton.filled( icon: const Icon(SpotubeIcons.speaker), style: IconButton.styleFrom( diff --git a/lib/components/library/user_albums.dart b/lib/components/library/user_albums.dart index 43fa0165..e1b82113 100644 --- a/lib/components/library/user_albums.dart +++ b/lib/components/library/user_albums.dart @@ -2,17 +2,17 @@ import 'package:flutter/material.dart' hide Image; import 'package:flutter_hooks/flutter_hooks.dart'; import 'package:collection/collection.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: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'; -import 'package:spotube/extensions/album_simple.dart'; +import 'package:spotube/extensions/constrains.dart'; import 'package:spotube/extensions/context.dart'; import 'package:spotube/provider/authentication_provider.dart'; import 'package:spotube/provider/spotify/spotify.dart'; @@ -50,71 +50,65 @@ class UserAlbums extends HookConsumerWidget { return const AnonymousFallback(); } - final theme = Theme.of(context); - - return RefreshIndicator( - onRefresh: () async { - ref.invalidate(favoriteAlbumsProvider); - }, - child: SafeArea( - child: Scaffold( - appBar: PreferredSize( - preferredSize: const Size.fromHeight(50), - child: Padding( - padding: const EdgeInsets.symmetric(horizontal: 8.0), - child: ColoredBox( - color: theme.scaffoldBackgroundColor, - child: SearchBar( - onChanged: (value) => searchText.value = value, - leading: const Icon(SpotubeIcons.filter), - hintText: context.l10n.filter_albums, - ), - ), - ), - ), - body: SizedBox.expand( - child: InterScrollbar( + return SafeArea( + child: Scaffold( + body: RefreshIndicator( + onRefresh: () async { + ref.invalidate(favoriteAlbumsProvider); + }, + child: InterScrollbar( + controller: controller, + child: CustomScrollView( controller: controller, - child: SingleChildScrollView( - padding: const EdgeInsets.all(8.0), - controller: controller, - child: Skeletonizer( - enabled: albumsQuery.isLoading, - child: Center( - child: Wrap( - runSpacing: 20, - alignment: WrapAlignment.center, - runAlignment: WrapAlignment.center, - crossAxisAlignment: WrapCrossAlignment.center, - children: [ - if (albumsQuery.asData?.value == null || - albumsQuery.asData!.value.items.isEmpty) - ...List.generate( - 10, - (index) => AlbumCard(FakeData.album), - ) - else if (albums.isEmpty) - const Row( - mainAxisAlignment: MainAxisAlignment.center, - children: [NotFound()], - ), - for (final album in albums) AlbumCard(album.toAlbum()), - if (albums.isNotEmpty && - albumsQuery.asData?.value.hasMore == true) - Skeletonizer( - enabled: true, - child: Waypoint( - controller: controller, - isGrid: true, - onTouchEdge: albumsQueryNotifier.fetchMore, - child: AlbumCard(FakeData.album), - ), - ) - ], + slivers: [ + SliverAppBar( + floating: true, + flexibleSpace: Padding( + padding: const EdgeInsets.symmetric(horizontal: 8.0), + child: SearchBar( + onChanged: (value) => searchText.value = value, + leading: const Icon(SpotubeIcons.filter), + hintText: context.l10n.filter_albums, ), ), ), - ), + const SliverGap(10), + Skeletonizer.sliver( + enabled: albumsQuery.isLoading, + child: SliverLayoutBuilder(builder: (context, constrains) { + return SliverGrid.builder( + itemCount: albums.isEmpty ? 6 : albums.length + 1, + gridDelegate: SliverGridDelegateWithMaxCrossAxisExtent( + maxCrossAxisExtent: 200, + mainAxisExtent: constrains.smAndDown ? 225 : 250, + crossAxisSpacing: 8, + mainAxisSpacing: 8, + ), + itemBuilder: (context, index) { + if (albums.isNotEmpty && index == albums.length) { + if (albumsQuery.asData?.value.hasMore != true) { + return const SizedBox.shrink(); + } + + return Waypoint( + controller: controller, + isGrid: true, + onTouchEdge: albumsQueryNotifier.fetchMore, + child: Skeletonizer( + enabled: true, + child: AlbumCard(FakeData.albumSimple), + ), + ); + } + + return AlbumCard( + albums.elementAtOrNull(index) ?? FakeData.albumSimple, + ); + }, + ); + }), + ), + ], ), ), ), diff --git a/lib/components/library/user_artists.dart b/lib/components/library/user_artists.dart index 83db35c6..0ef0ff39 100644 --- a/lib/components/library/user_artists.dart +++ b/lib/components/library/user_artists.dart @@ -2,6 +2,7 @@ import 'package:flutter/material.dart'; import 'package:flutter_hooks/flutter_hooks.dart'; import 'package:collection/collection.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:spotube/collections/fake.dart'; @@ -9,8 +10,9 @@ 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/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/provider/spotify/spotify.dart'; @@ -20,10 +22,10 @@ class UserArtists extends HookConsumerWidget { @override Widget build(BuildContext context, ref) { - final theme = Theme.of(context); final auth = ref.watch(authenticationProvider); final artistQuery = ref.watch(followedArtistsProvider); + final artistQueryNotifier = ref.watch(followedArtistsProvider.notifier); final searchText = useState(''); @@ -50,77 +52,73 @@ class UserArtists extends HookConsumerWidget { return const AnonymousFallback(); } - return Scaffold( - appBar: PreferredSize( - preferredSize: const Size.fromHeight(50), - child: Padding( - padding: const EdgeInsets.symmetric(horizontal: 8.0), - child: ColoredBox( - color: theme.scaffoldBackgroundColor, - child: SearchBar( - onChanged: (value) => searchText.value = value, - leading: const Icon(SpotubeIcons.filter), - hintText: context.l10n.filter_artist, + return SafeArea( + child: Scaffold( + body: RefreshIndicator( + onRefresh: () async { + ref.invalidate(followedArtistsProvider); + }, + child: InterScrollbar( + controller: controller, + child: Padding( + padding: const EdgeInsets.symmetric(horizontal: 8.0), + child: CustomScrollView( + controller: controller, + slivers: [ + SliverAppBar( + floating: true, + flexibleSpace: SearchBar( + onChanged: (value) => searchText.value = value, + leading: const Icon(SpotubeIcons.filter), + hintText: context.l10n.filter_artist, + ), + ), + const SliverGap(10), + Skeletonizer.sliver( + enabled: artistQuery.isLoading, + child: SliverLayoutBuilder(builder: (context, constrains) { + return SliverGrid.builder( + itemCount: filteredArtists.isEmpty + ? 6 + : filteredArtists.length + 1, + gridDelegate: SliverGridDelegateWithMaxCrossAxisExtent( + maxCrossAxisExtent: 200, + mainAxisExtent: constrains.smAndDown ? 225 : 250, + crossAxisSpacing: 8, + mainAxisSpacing: 8, + ), + itemBuilder: (context, index) { + if (filteredArtists.isNotEmpty && + index == filteredArtists.length) { + if (artistQuery.asData?.value.hasMore != true) { + return const SizedBox.shrink(); + } + + return Waypoint( + controller: controller, + isGrid: true, + onTouchEdge: artistQueryNotifier.fetchMore, + child: Skeletonizer( + enabled: true, + child: ArtistCard(FakeData.artist), + ), + ); + } + + return ArtistCard( + filteredArtists.elementAtOrNull(index) ?? + FakeData.artist, + ); + }, + ); + }), + ), + ], + ), ), ), ), ), - backgroundColor: theme.scaffoldBackgroundColor, - body: artistQuery.asData?.value.items.isEmpty == true - ? Padding( - padding: const EdgeInsets.all(20), - child: Row( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - const CircularProgressIndicator(), - const SizedBox(width: 10), - Text(context.l10n.loading), - ], - ), - ) - : RefreshIndicator( - onRefresh: () async { - ref.invalidate(followedArtistsProvider); - }, - child: InterScrollbar( - controller: controller, - child: SingleChildScrollView( - controller: controller, - child: SizedBox( - width: double.infinity, - child: SafeArea( - child: Center( - child: Skeletonizer( - enabled: artistQuery.isLoading, - child: Wrap( - spacing: 15, - runSpacing: 5, - children: artistQuery.isLoading - ? List.generate( - 10, (index) => ArtistCard(FakeData.artist)) - : 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 f8bd1326..a7b2102b 100644 --- a/lib/components/library/user_local_tracks.dart +++ b/lib/components/library/user_local_tracks.dart @@ -176,7 +176,7 @@ class UserLocalTracks extends HookConsumerWidget { padding: const EdgeInsets.all(8.0), child: Row( children: [ - const SizedBox(width: 10), + const SizedBox(width: 5), FilledButton( onPressed: trackSnapshot.asData?.value != null ? () async { @@ -212,7 +212,7 @@ class UserLocalTracks extends HookConsumerWidget { sortBy.value = value; }, ), - const SizedBox(width: 10), + const SizedBox(width: 5), FilledButton( child: const Icon(SpotubeIcons.refresh), onPressed: () { diff --git a/lib/components/library/user_playlists.dart b/lib/components/library/user_playlists.dart index 563541de..069dfad9 100644 --- a/lib/components/library/user_playlists.dart +++ b/lib/components/library/user_playlists.dart @@ -2,6 +2,7 @@ import 'package:flutter/material.dart' hide Image; import 'package:flutter_hooks/flutter_hooks.dart'; import 'package:fuzzywuzzy/fuzzywuzzy.dart'; import 'package:collection/collection.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'; @@ -18,6 +19,7 @@ import 'package:spotube/extensions/constrains.dart'; import 'package:spotube/extensions/context.dart'; import 'package:spotube/provider/authentication_provider.dart'; import 'package:spotube/provider/spotify/spotify.dart'; +import 'package:spotube/utils/platform.dart'; class UserPlaylists extends HookConsumerWidget { const UserPlaylists({super.key}); @@ -86,39 +88,37 @@ class UserPlaylists extends HookConsumerWidget { 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), + SliverAppBar( + floating: true, + flexibleSpace: Padding( + padding: const EdgeInsets.symmetric(horizontal: 8), + child: SearchBar( + onChanged: (value) => searchText.value = value, + hintText: context.l10n.filter_playlists, + leading: const Icon(SpotubeIcons.filter), + ), + ), + bottom: PreferredSize( + preferredSize: + Size.fromHeight(kIsDesktop ? 35 : kToolbarHeight), + child: Row( + children: [ + const Gap(10), + const PlaylistCreateDialogButton(), + const Gap(10), + ElevatedButton.icon( + icon: const Icon(SpotubeIcons.magic), + label: Text(context.l10n.generate_playlist), + onPressed: () { + GoRouter.of(context).push("/library/generate"); + }, ), - ), - 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 Gap(10), + ], + ), ), ), - const SliverToBoxAdapter( - child: SizedBox(height: 10), - ), + const SliverGap(10), SliverLayoutBuilder(builder: (context, constrains) { return SliverGrid.builder( itemCount: playlists.isEmpty ? 6 : playlists.length + 1, diff --git a/lib/pages/connect/connect.dart b/lib/pages/connect/connect.dart index 170a0c72..cbdb446e 100644 --- a/lib/pages/connect/connect.dart +++ b/lib/pages/connect/connect.dart @@ -23,6 +23,7 @@ class ConnectPage extends HookConsumerWidget { appBar: PageWindowTitleBar( automaticallyImplyLeading: true, title: Text(context.l10n.devices), + titleSpacing: 0, ), body: ListTileTheme( shape: RoundedRectangleBorder( diff --git a/lib/pages/home/genres/genres.dart b/lib/pages/home/genres/genres.dart index a981cbe7..291ce737 100644 --- a/lib/pages/home/genres/genres.dart +++ b/lib/pages/home/genres/genres.dart @@ -26,6 +26,7 @@ class GenrePage extends HookConsumerWidget { appBar: PageWindowTitleBar( title: Text(context.l10n.explore_genres), automaticallyImplyLeading: true, + titleSpacing: 0, ), body: SafeArea( top: false, diff --git a/lib/pages/home/home.dart b/lib/pages/home/home.dart index d5639274..31f26bee 100644 --- a/lib/pages/home/home.dart +++ b/lib/pages/home/home.dart @@ -1,8 +1,8 @@ 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/collections/assets.gen.dart'; import 'package:spotube/components/connect/connect_device.dart'; import 'package:spotube/components/home/sections/featured.dart'; import 'package:spotube/components/home/sections/feed.dart'; @@ -34,8 +34,9 @@ class HomePage extends HookConsumerWidget { controller: controller, slivers: [ if (mediaQuery.mdAndDown) - PageWindowTitleBar.sliver( - pinned: DesktopTools.platform.isDesktop, + SliverAppBar( + floating: true, + title: Assets.spotubeLogoPng.image(height: 45), actions: [ const ConnectDeviceButton(), const Gap(10), diff --git a/lib/services/audio_player/custom_player.dart b/lib/services/audio_player/custom_player.dart index d273519e..916a983f 100644 --- a/lib/services/audio_player/custom_player.dart +++ b/lib/services/audio_player/custom_player.dart @@ -106,6 +106,10 @@ class CustomPlayer extends Player { _shuffled = shuffle; await super.setShuffle(shuffle); _shuffleStream.add(shuffle); + await Future.delayed(const Duration(milliseconds: 100)); + if (shuffle) { + await move(state.playlist.index, 0); + } } @override From 5a6b80091259359bc38c4b91cd8cb496c4270fa4 Mon Sep 17 00:00:00 2001 From: Tutislav Date: Mon, 15 Apr 2024 15:26:19 +0200 Subject: [PATCH 03/13] feat(translations): Add Czech translation (#1401) --- lib/collections/language_codes.dart | 8 +- lib/l10n/app_cs.arb | 324 ++++++++++++++++++++++++++++ lib/l10n/l10n.dart | 2 + 3 files changed, 330 insertions(+), 4 deletions(-) create mode 100644 lib/l10n/app_cs.arb diff --git a/lib/collections/language_codes.dart b/lib/collections/language_codes.dart index bd3f8740..45456d69 100644 --- a/lib/collections/language_codes.dart +++ b/lib/collections/language_codes.dart @@ -157,10 +157,10 @@ abstract class LanguageLocals { // name: "Croatian", // nativeName: "hrvatski", // ), - // "cs": const ISOLanguageName( - // name: "Czech", - // nativeName: "česky, čeština", - // ), + "cs": const ISOLanguageName( + name: "Czech", + nativeName: "česky, čeština", + ), // "da": const ISOLanguageName( // name: "Danish", // nativeName: "dansk", diff --git a/lib/l10n/app_cs.arb b/lib/l10n/app_cs.arb new file mode 100644 index 00000000..52f5bcf8 --- /dev/null +++ b/lib/l10n/app_cs.arb @@ -0,0 +1,324 @@ +{ + "guest": "Host", + "browse": "Procházet", + "search": "Hledat", + "library": "Knihovna", + "lyrics": "Texty", + "settings": "Nastavení", + "genre_categories_filter": "Filtrovat kategorie nebo žánry...", + "genre": "Žánr", + "personalized": "Personalizované", + "featured": "Doporučené", + "new_releases": "Nově vydané", + "songs": "Skladby", + "playing_track": "Hraje {track}", + "queue_clear_alert": "Toto vymaže aktuální frontu. {track_length} skladeb bude odstraněno\nChcete pokračovat?", + "load_more": "Načíst více", + "playlists": "Playlisty", + "artists": "Umělci", + "albums": "Alba", + "tracks": "Skladby", + "downloads": "Stahování", + "filter_playlists": "Filtrovat playlisty...", + "liked_tracks": "Oblíbené skladby", + "liked_tracks_description": "Všechny vaše oblíbené skladby", + "create_playlist": "Vytvořit playlist", + "create_a_playlist": "Vytvořit playlist", + "update_playlist": "Aktualizovat playlist", + "create": "Vytvořit", + "cancel": "Zrušit", + "update": "Aktualizovat", + "playlist_name": "Název playlistu", + "name_of_playlist": "Název playlistu", + "description": "Popis", + "public": "Veřejné", + "collaborative": "Společný", + "search_local_tracks": "Hledat místní skladby...", + "play": "Přehrát", + "delete": "Smazat", + "none": "Žádné", + "sort_a_z": "Seřadit od A-Z", + "sort_z_a": "Seřadit od Z-A", + "sort_artist": "Seřadit podle umělce", + "sort_album": "Seřadit podle alba", + "sort_duration": "Seřadit podle délky", + "sort_tracks": "Seřadit skladby", + "currently_downloading": "Právě se stahuje ({tracks_length})", + "cancel_all": "Zrušit vše", + "filter_artist": "Filtrovat umělce...", + "followers": "{followers} Sledující", + "add_artist_to_blacklist": "Přidat umělce na černou listinu", + "top_tracks": "Top skladby", + "fans_also_like": "Fanoušci mají také rádi", + "loading": "Načítání...", + "artist": "Umělec", + "blacklisted": "Na černé listině", + "following": "Sleduje", + "follow": "Sledovat", + "artist_url_copied": "URL umělce zkopírována do schránky", + "added_to_queue": "Přidáno {tracks} skladeb do fronty", + "filter_albums": "Filtrovat alba...", + "synced": "Synchronizováno", + "plain": "Jednoduché", + "shuffle": "Zamíchat", + "search_tracks": "Hledat skladby...", + "released": "Vydáno", + "error": "Chyba {error}", + "title": "Název", + "time": "Čas", + "more_actions": "Více akcí", + "download_count": "Stáhnout ({count})", + "add_count_to_playlist": "Přidat ({count}) do playlistu", + "add_count_to_queue": "Přidat ({count}) do fronty", + "play_count_next": "Přehrát ({count}) dalších", + "album": "Album", + "copied_to_clipboard": "Zkopírováno {data} do schránky", + "add_to_following_playlists": "Přidat {track} do následujících playlistů", + "add": "Přidat", + "added_track_to_queue": "Přidána skladba {track} do fronty", + "add_to_queue": "Přidat do fronty", + "track_will_play_next": "{track} se přehraje jako další", + "play_next": "Přehrát další", + "removed_track_from_queue": "Odstraněna skladba {track} z fronty", + "remove_from_queue": "Odstranit z fronty", + "remove_from_favorites": "Odstranit z oblíbených", + "save_as_favorite": "Uložit jako oblíbené", + "add_to_playlist": "Přidat do playlistu", + "remove_from_playlist": "Odstranit z playlistu", + "add_to_blacklist": "Přidat na černou listinu", + "remove_from_blacklist": "Odstranit z černé listiny", + "share": "Sdílet", + "mini_player": "Mini přehrávač", + "slide_to_seek": "Táhněte pro posunutí vpřed nebo vzad", + "shuffle_playlist": "Zamíchat playlist", + "unshuffle_playlist": "Zrušit zamíchání playlistu", + "previous_track": "Předchozí skladba", + "next_track": "Další skladba", + "pause_playback": "Pozastavit přehrávání", + "resume_playback": "Pokračovat v přehrávání", + "loop_track": "Opakovat skladbu", + "repeat_playlist": "Opakovat playlist", + "queue": "Fronta", + "alternative_track_sources": "Alternativní zdroje skladeb", + "download_track": "Stáhnout skladbu", + "tracks_in_queue": "{tracks} skladeb ve frontě", + "clear_all": "Vymazat vše", + "show_hide_ui_on_hover": "Zobrazit/Skrýt UI při najetí", + "always_on_top": "Vždy nahoře", + "exit_mini_player": "Zavřít mini přehrávač", + "download_location": "Umístění stahování", + "account": "Účet", + "login_with_spotify": "Přihlásit se pomocí Spotify účtu", + "connect_with_spotify": "Připojit k Spotify", + "logout": "Odhlásit se", + "logout_of_this_account": "Odhlásit se z tohoto účtu", + "language_region": "Jazyk a region", + "language": "Jazyk", + "system_default": "Systém", + "market_place_region": "Region", + "recommendation_country": "Země pro doporučení", + "appearance": "Vzhled", + "layout_mode": "Režim rozložení", + "override_layout_settings": "Přepsat režim rozložení", + "adaptive": "Adaptivní", + "compact": "Kompaktní", + "extended": "Rozšířený", + "theme": "Téma", + "dark": "Tmavé", + "light": "Světlé", + "system": "Systém", + "accent_color": "Barva akcentu", + "sync_album_color": "Synchronizovat barvu alba", + "sync_album_color_description": "Používá dominantní barvu obalu alba jako barvu akcentu", + "playback": "Přehrávání", + "audio_quality": "Kvalita zvuku", + "high": "Vysoká", + "low": "Nízká", + "pre_download_play": "Předstáhnout a přehrát", + "pre_download_play_description": "Místo streamování audia stáhnout skladbu a přehrát (doporučeno pro uživatele s rychlejším internetem)", + "skip_non_music": "Přeskočit nehudební segmenty (SponsorBlock)", + "blacklist_description": "Zakázané skladby a umělci", + "wait_for_download_to_finish": "Počkejte, až se dokončí stahování", + "desktop": "Desktop", + "close_behavior": "Chování při zavření", + "close": "Zavřít", + "minimize_to_tray": "Minimalizovat do lišty", + "show_tray_icon": "Zobrazit ikonu v systémové liště", + "about": "O aplikaci", + "u_love_spotube": "Víme, že milujete Spotube", + "check_for_updates": "Zkontrolovat aktualizace", + "about_spotube": "O Spotube", + "blacklist": "Černá listina", + "please_sponsor": "Sponzorovat/darovat", + "spotube_description": "Spotube, rychlý, multiplatformní, bezplatný Spotify klient", + "version": "Verze", + "build_number": "Číslo sestavení", + "founder": "Zakladatel", + "repository": "Repozitář", + "bug_issues": "Chyby+Problémy", + "made_with": "Vytvořeno s ❤️ v Bangladéši🇧🇩", + "kingkor_roy_tirtho": "Kingkor Roy Tirtho", + "copyright": "© 2021-{current_year} Kingkor Roy Tirtho", + "license": "Licence", + "add_spotify_credentials": "Přidejte své přihlašovací údaje Spotify a začněte", + "credentials_will_not_be_shared_disclaimer": "Nebojte, žádné z vašich údajů nebudou shromažďovány ani s nikým sdíleny", + "know_how_to_login": "Nevíte, jak na to?", + "follow_step_by_step_guide": "Postupujte podle návodu", + "spotify_cookie": "Cookie Spotify {name}", + "cookie_name_cookie": "Cookie {name}", + "fill_in_all_fields": "Vyplňte prosím všechna pole", + "submit": "Odeslat", + "exit": "Ukončit", + "previous": "Předchozí", + "next": "Další", + "done": "Hotovo", + "step_1": "Krok 1", + "first_go_to": "Nejprve jděte na", + "login_if_not_logged_in": "a přihlašte se nebo se zaregistrujte, pokud nejste přihlášeni", + "step_2": "Krok 2", + "step_2_steps": "1. Jakmile jste přihlášeni, stiskněte F12 nebo pravé tlačítko myši > Prozkoumat, abyste otevřeli nástroje pro vývojáře prohlížeče.\n2. Poté přejděte na kartu \"Aplikace\" (Chrome, Edge, Brave atd.) nebo kartu \"Úložiště\" (Firefox, Palemoon atd.)\n3. Přejděte do sekce \"Cookies\" a pak do podsekce \"https://accounts.spotify.com\"", + "step_3": "Krok 3", + "step_3_steps": "Zkopírujte hodnotu cookie \"sp_dc\"", + "success_emoji": "Úspěch🥳", + "success_message": "Nyní jste úspěšně přihlášeni pomocí svého Spotify účtu. Dobrá práce, kamaráde!", + "step_4": "Krok 4", + "step_4_steps": "Vložte zkopírovanou hodnotu \"sp_dc\"", + "something_went_wrong": "Něco se pokazilo", + "piped_instance": "Instance serveru Piped", + "piped_description": "Instance serveru Piped, kterou použít pro hledání skladeb", + "piped_warning": "Některé z nich nemusí dobře fungovat. Používejte na vlastní riziko", + "generate_playlist": "Vygenerovat playlist", + "track_exists": "Skladba {track} již existuje", + "replace_downloaded_tracks": "Nahradit všechny stažené skladby", + "skip_download_tracks": "Přeskočit stahování všech stažených skladeb", + "do_you_want_to_replace": "Chcete nahradit existující skladbu??", + "replace": "Nahradit", + "skip": "Přeskočit", + "select_up_to_count_type": "Vyberte až {count} {type}", + "select_genres": "Vyberte žánry", + "add_genres": "Přidat žánry", + "country": "Země", + "number_of_tracks_generate": "Počet skladeb k vygenerování", + "acousticness": "Akustičnost", + "danceability": "Tanečnost", + "energy": "Energie", + "instrumentalness": "Instrumentálnost", + "liveness": "Živost", + "loudness": "Hlasitost", + "speechiness": "Mluvnost", + "valence": "Valence", + "popularity": "Popularita", + "key": "Klíč", + "duration": "Délka (s)", + "tempo": "Tempo (BPM)", + "mode": "Režim", + "time_signature": "Udání taktu", + "short": "Krátký", + "medium": "Střední", + "long": "Dlouhý", + "min": "Min", + "max": "Max", + "target": "Cíl", + "moderate": "Mírný", + "deselect_all": "Zrušit výběr", + "select_all": "Vybrat vše", + "are_you_sure": "Jste si jisti?", + "generating_playlist": "Generování vašeho vlastního playlistu...", + "selected_count_tracks": "Vybráno {count} skladeb", + "download_warning": "Pokud stáhnete všechny skladby najednou, pirátíte tím hudbu a škodíte kreativní společnosti hudby. Doufám, že jste si toho vědomi. Vždy se snažte respektovat a podporovat tvrdou práci umělců", + "download_ip_ban_warning": "Mimochodem, vaše IP může být na YouTube zablokována kvůli nadměrným požadavkům na stahování. Blokování IP znamená, že nemůžete používat YouTube (i když jste přihlášeni) alespoň 2-3 měsíce ze zařízení s touto IP. A Spotube nenese žádnou odpovědnost, pokud se to někdy stane", + "by_clicking_accept_terms": "Kliknutím na 'přijmout' souhlasíte s následujícími podmínkami:", + "download_agreement_1": "Vím, že pirátím hudbu. Jsem špatný", + "download_agreement_2": "Budu podporovat umělce, kdekoliv to bude možné, a dělám to jen proto, že nemám peníze na koupi jejich umění", + "download_agreement_3": "Jsem si naprosto vědom toho, že moje IP může být na YouTube zablokována a nenesu žádnou odpovědnost za nehody způsobené mým současným jednáním", + "decline": "Odmítnout", + "accept": "Přijmout", + "details": "Podrobnosti", + "youtube": "YouTube", + "channel": "Kanál", + "likes": "Líbí se", + "dislikes": "Nelíbí se", + "views": "Zobrazení", + "streamUrl": "URL streamu", + "stop": "Zastavit", + "sort_newest": "Seřadit od nejnovějších", + "sort_oldest": "Seřadit od nejstarších", + "sleep_timer": "Časovač spánku", + "mins": "{minutes} Minut", + "hours": "{hours} Hodin", + "hour": "{hours} Hodina", + "custom_hours": "Vlastní hodiny", + "logs": "Protokoly", + "developers": "Vývojáři", + "not_logged_in": "Nejste přihlášeni", + "search_mode": "Režim hledání", + "audio_source": "Zdroj zvuku", + "ok": "Ok", + "failed_to_encrypt": "Šifrování selhalo", + "encryption_failed_warning": "Spotube používá šifrování k bezpečnému ukládání vašich dat. Ale selhalo. Takže se vrátí k nezabezpečenému úložišti\nPokud používáte linux, ujistěte se, že máte nainstalovanou jakoukoli službu k ukládání bezpečnostních pověření (gnome-keyring, kde-wallet, keepassxc atd.)", + "querying_info": "Získávání informací...", + "piped_api_down": "Piped API je mimo provoz", + "piped_down_error_instructions": "Instance Piped {pipedInstance} je momentálně mimo provoz\n\nBuď změňte instanci nebo změňte 'Typ API' na oficiální YouTube API\n\nPo změně se ujistěte, že aplikaci restartujete", + "you_are_offline": "Momentálně jste offline", + "connection_restored": "Vaše internetové připojení bylo obnoveno", + "use_system_title_bar": "Použít systémové záhlaví okna", + "crunching_results": "Zpracovávání výsledků...", + "search_to_get_results": "Hledejte pro získání výsledků", + "use_amoled_mode": "Úplně černé téma", + "pitch_dark_theme": "AMOLED režim", + "normalize_audio": "Normalizovat audio", + "change_cover": "Změnit obal", + "add_cover": "Přidat obal", + "restore_defaults": "Obnovit výchozí", + "download_music_codec": "Kodek pro stahování", + "streaming_music_codec": "Kodek pro streamování", + "login_with_lastfm": "Přihlásit se pomocí Last.fm", + "connect": "Připojit", + "disconnect_lastfm": "Odpojit Last.fm", + "disconnect": "Odpojit", + "username": "Uživatelské jméno", + "password": "Heslo", + "login": "Přihlásit se", + "login_with_your_lastfm": "Přihlásit se pomocí vašeho Last.fm účtu", + "scrobble_to_lastfm": "Scrobble na Last.fm", + "go_to_album": "Přejít na album", + "discord_rich_presence": "Discord Rich Presence", + "browse_all": "Procházet vše", + "genres": "Žánry", + "explore_genres": "Prozkoumat žánry", + "friends": "Přátelé", + "no_lyrics_available": "Omlouváme se, není možné najít texty pro tuto skladbu", + "start_a_radio": "Vytvořit rádio", + "how_to_start_radio": "Jak chcete vytvořit rádio?", + "replace_queue_question": "Chcete nahradit aktuální frontu nebo k ní přidat?", + "endless_playback": "Nekonečné přehrávání", + "delete_playlist": "Smazat playlist", + "delete_playlist_confirmation": "Jste si jisti, že chcete smazat tento playlist?", + "local_tracks": "Místní skladby", + "song_link": "Odkaz na skladbu", + "skip_this_nonsense": "Přeskočit tenhle nesmysl", + "freedom_of_music": "“Svobodná hudba”", + "freedom_of_music_palm": "“Svobodná hudba ve vaší dlani”", + "get_started": "Začít", + "youtube_source_description": "Doporučeno a funguje nejlépe.", + "piped_source_description": "Nechcete být sledováni? Stejné jako YouTube, ale respektuje soukromí.", + "jiosaavn_source_description": "Nejlepší pro jihoasijský region.", + "highest_quality": "Nejvyšší kvalita: {quality}", + "select_audio_source": "Vyberte zdroj zvuku", + "endless_playback_description": "Automaticky přidávat nové skladby\nna konec fronty", + "choose_your_region": "Vyberte svůj region", + "choose_your_region_description": "To pomůže Spotube ukázat vám správný obsah\npro vaši lokalitu.", + "choose_your_language": "Vyberte svůj jazyk", + "help_project_grow": "Pomozte tomuto projektu růst", + "help_project_grow_description": "Spotube je open-source projekt. Můžete pomoci tomuto projektu růst tím, že přispějete do projektu, nahlásíte chyby nebo navrhnete nové funkce.", + "contribute_on_github": "Přispějte na GitHub", + "donate_on_open_collective": "Darujte na Open Collective", + "browse_anonymously": "Procházet anonymně", + "enable_connect": "Povolit ovládání", + "enable_connect_description": "Ovládejte Spotube z jiného zařízení", + "devices": "Zařízení", + "select": "Vybrat", + "connect_client_alert": "Zařízení je ovládáno z {client}", + "this_device": "Toto zařízení", + "remote": "Ovladač" +} \ No newline at end of file diff --git a/lib/l10n/l10n.dart b/lib/l10n/l10n.dart index e584d2be..ef3685fa 100644 --- a/lib/l10n/l10n.dart +++ b/lib/l10n/l10n.dart @@ -12,6 +12,7 @@ /// doannc2212@github => Vietnamese /// sappho192@github => Korean /// watchakorn-18k@github => Thai +/// Microsoft Copilot, Tutislav@github => Czech library l10n; @@ -23,6 +24,7 @@ class L10n { const Locale('ar', 'SA'), const Locale('bn', 'BD'), const Locale('ca', 'AD'), + const Locale('cs', 'CZ'), const Locale('de', 'GE'), const Locale('es', 'ES'), const Locale('fa', 'IR'), From 7ae9f56482240b2946c42d4382cbedee330ed5fb Mon Sep 17 00:00:00 2001 From: Kingkor Roy Tirtho Date: Mon, 15 Apr 2024 19:28:01 +0600 Subject: [PATCH 04/13] chore: bump version and generate changelogs --- .github/workflows/spotube-release-binary.yml | 2 +- CHANGELOG.md | 21 ++++++++++++++++++++ pubspec.yaml | 2 +- 3 files changed, 23 insertions(+), 2 deletions(-) diff --git a/.github/workflows/spotube-release-binary.yml b/.github/workflows/spotube-release-binary.yml index 5d918a03..d9fbd0c7 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.1 + default: 3.6.0 required: true channel: type: choice diff --git a/CHANGELOG.md b/CHANGELOG.md index ddbd4fe1..21ca4b69 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,27 @@ 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.6.0-0](https://github.com/krtirtho/spotube/compare/v3.5.0...v3.6.0-0) (2024-04-15) + + +### Features + +* add Spotify homepage personalized recommendations ([#1402](https://github.com/krtirtho/spotube/issues/1402)) ([9e25c74](https://github.com/krtirtho/spotube/commit/9e25c742d4e43e4e10d2b48afb8e6d90288ffa11)) +* add user profile page ([39e97ee](https://github.com/krtirtho/spotube/commit/39e97eef34d87348a264843e145f31f82832d12e)) +* **android:** Filter Device To Force High Frame Rate ([#880](https://github.com/krtirtho/spotube/issues/880)) ([6e41b10](https://github.com/krtirtho/spotube/commit/6e41b106fa989adee393d3ce2535e75446ad3eea)) +* improved caching based on riverpod ([#1343](https://github.com/krtirtho/spotube/issues/1343)) ([6673e5a](https://github.com/krtirtho/spotube/commit/6673e5a8a86b9667cf9dbff9bb7c40ea6b7de771)) +* LAN connect a.k.a control remote Spotube playback and local output device selection ([#1355](https://github.com/krtirtho/spotube/issues/1355)) ([68374ef](https://github.com/krtirtho/spotube/commit/68374efd3ec556f31b937e5b96920787b54eec78)) +* **lyrics:** add LRCLIB lyrics provider as fallback ([5afe823](https://github.com/krtirtho/spotube/commit/5afe823abdb198340b55d138d8173d886a811632)) +* search history support [#1236](https://github.com/krtirtho/spotube/issues/1236) ([82b1cfa](https://github.com/krtirtho/spotube/commit/82b1cfa0d775e3958c666280943a893c9113d468)) +* **translations:** Add Czech translation ([#1401](https://github.com/krtirtho/spotube/issues/1401)) ([5a6b800](https://github.com/krtirtho/spotube/commit/5a6b80091259359bc38c4b91cd8cb496c4270fa4)) +* **translations:** add Thai Language ([#1319](https://github.com/krtirtho/spotube/issues/1319)) ([b70f250](https://github.com/krtirtho/spotube/commit/b70f250e8d5137fd990787ec9e3d058126cf14f3)), closes [#1310](https://github.com/krtirtho/spotube/issues/1310) [#1311](https://github.com/krtirtho/spotube/issues/1311) + + +### Bug Fixes + +* instance of Artist bug [#1362](https://github.com/krtirtho/spotube/issues/1362) ([c8dd802](https://github.com/krtirtho/spotube/commit/c8dd8025ec96bd78ed77cae35f1429aa48c16fde)) +* **playback:** sponsor block skips and stutters in same position ([0d080b7](https://github.com/krtirtho/spotube/commit/0d080b77b72529c0be5ebc27ace1c52307511f73)) + ## [3.5.0](https://github.com/krtirtho/spotube/compare/v3.4.1...v3.5.0) (2024-03-08) diff --git a/pubspec.yaml b/pubspec.yaml index 16f51981..3f4c22af 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+29 +version: 3.6.0+30 homepage: https://spotube.krtirtho.dev repository: https://github.com/KRTirtho/spotube From 883783b769673c1ade30c2f17a3cae4b68f4c7da Mon Sep 17 00:00:00 2001 From: Kingkor Roy Tirtho Date: Mon, 15 Apr 2024 19:40:38 +0600 Subject: [PATCH 05/13] chore: add untranslated messages --- README.md | 24 +++-- lib/l10n/app_ar.arb | 9 +- lib/l10n/app_bn.arb | 9 +- lib/l10n/app_ca.arb | 9 +- lib/l10n/app_de.arb | 9 +- lib/l10n/app_es.arb | 9 +- lib/l10n/app_fa.arb | 9 +- lib/l10n/app_fr.arb | 9 +- lib/l10n/app_hi.arb | 9 +- lib/l10n/app_it.arb | 9 +- lib/l10n/app_ja.arb | 9 +- lib/l10n/app_ko.arb | 9 +- lib/l10n/app_ne.arb | 9 +- lib/l10n/app_nl.arb | 9 +- lib/l10n/app_pl.arb | 9 +- lib/l10n/app_pt.arb | 9 +- lib/l10n/app_ru.arb | 9 +- lib/l10n/app_th.arb | 10 +- lib/l10n/app_uk.arb | 9 +- lib/l10n/app_vi.arb | 11 +- lib/l10n/app_zh.arb | 9 +- untranslated_messages.json | 205 +------------------------------------ 22 files changed, 180 insertions(+), 232 deletions(-) diff --git a/README.md b/README.md index 4ad4e1be..8b8a6214 100644 --- a/README.md +++ b/README.md @@ -205,6 +205,7 @@ If you are concerned, you can [read the reason of choosing this license](https:/ 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. [LRCLib](https://lrclib.net/) - A public synced lyric API 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 @@ -233,9 +234,6 @@ 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. [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. @@ -257,7 +255,7 @@ If you are concerned, you can [read the reason of choosing this license](https:/ 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. 1. [intl](https://pub.dev/packages/intl) - Contains code to deal with internationalized/localized messages, date and number formatting and parsing, bi-directional text, and other internationalization issues. -1. [introduction_screen](https://github.com/pyozer/introduction_screen) - Introduction/Onboarding package for flutter app with some customizations possibilities +1. [introduction_screen](https://pub.dev/packages/introduction_screen) - Introduction/Onboarding package for flutter app with some customizations possibilities 1. [json_annotation](https://pub.dev/packages/json_annotation) - Classes and helper functions that support JSON code generation via the `json_serializable` package. 1. [logger](https://pub.dev/packages/logger) - Small, easy to use and extensible logger which prints beautiful logs. 1. [media_kit](https://github.com/media-kit/media-kit) - A cross-platform video player & audio player for Flutter & Dart. Performant, stable, feature-proof & modular. @@ -295,22 +293,32 @@ If you are concerned, you can [read the reason of choosing this license](https:/ 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. [win32_registry](https://pub.dev/packages/win32_registry) - 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. [bonsoir](https://bonsoir.skyost.eu) - A Zeroconf library that allows you to discover network services and to broadcast your own. Based on Apple Bonjour and Android NSD. +1. [shelf](https://pub.dev/packages/shelf) - A model for web server middleware that encourages composition and easy reuse. +1. [shelf_router](https://pub.dev/packages/shelf_router) - A convenient request router for the shelf web-framework, with support for URL-parameters, nested routers and routers generated from source annotations. +1. [shelf_web_socket](https://pub.dev/packages/shelf_web_socket) - A shelf handler that wires up a listener for every connection. +1. [web_socket_channel](https://pub.dev/packages/web_socket_channel) - StreamChannel wrappers for WebSockets. Provides a cross-platform WebSocketChannel API, a cross-platform implementation of that API that communicates over an underlying StreamChannel. +1. [lrc](https://pub.dev/packages/lrc) - A Dart-only package that creates, parses, and handles LRC, which is a format that stores song lyrics. +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. [timezone](https://pub.dev/packages/timezone) - Time zone database and time zone aware DateTime. +1. [crypto](https://pub.dev/packages/crypto) - Implementations of SHA, MD5, and HMAC cryptographic functions. 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. +1. [flutter_distributor](https://distributor.leanflutter.dev) - A complete tool for packaging and publishing your Flutter apps. 1. [flutter_gen_runner](https://github.com/FlutterGen/flutter_gen) - The Flutter code generator for your assets, fonts, colors, … — Get rid of all String-based APIs. 1. [flutter_launcher_icons](https://github.com/fluttercommunity/flutter_launcher_icons) - A package which simplifies the task of updating your Flutter app's launcher icon. 1. [flutter_lints](https://pub.dev/packages/flutter_lints) - Recommended lints for Flutter apps, packages, and plugins to encourage good coding practices. 1. [hive_generator](https://github.com/hivedb/hive/tree/master/hive_generator) - Extension for Hive. Automatically generates TypeAdapters to store any class. 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. [custom_lint](https://pub.dev/packages/custom_lint) - Lint rules are a powerful way to improve the maintainability of a project. Custom Lint allows package authors and developers to easily write custom lint rules. +1. [riverpod_lint](https://riverpod.dev) - Riverpod_lint is a developer tool for users of Riverpod, designed to help stop common issues and simplify repetitive tasks. 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. diff --git a/lib/l10n/app_ar.arb b/lib/l10n/app_ar.arb index 41fab083..68308ba1 100644 --- a/lib/l10n/app_ar.arb +++ b/lib/l10n/app_ar.arb @@ -313,5 +313,12 @@ "help_project_grow_description": "Spotube هو مشروع مفتوح المصدر. يمكنك مساعدة هذا المشروع في النمو عن طريق المساهمة في المشروع، أو الإبلاغ عن الأخطاء، أو اقتراح ميزات جديدة.", "contribute_on_github": "المساهمة على GitHub", "donate_on_open_collective": "التبرع على Open Collective", - "browse_anonymously": "تصفح بشكل مجهول" + "browse_anonymously": "تصفح بشكل مجهول", + "enable_connect": "تمكين الاتصال", + "enable_connect_description": "التحكم في Spotube من الأجهزة الأخرى", + "devices": "الأجهزة", + "select": "اختر", + "connect_client_alert": "أنت تتم التحكم بواسطة {client}", + "this_device": "هذا الجهاز", + "remote": "بعيد" } \ No newline at end of file diff --git a/lib/l10n/app_bn.arb b/lib/l10n/app_bn.arb index 353ca617..506e78bc 100644 --- a/lib/l10n/app_bn.arb +++ b/lib/l10n/app_bn.arb @@ -313,5 +313,12 @@ "help_project_grow_description": "স্পটুব একটি ওপেন সোর্স প্রকল্প। আপনি প্রকল্পে অবদান রাখেন, বাগ রিপোর্ট করেন, বা নতুন বৈশিষ্ট্যগুলি সুপারিশ করেন।", "contribute_on_github": "গিটহাবে অবদান রাখুন", "donate_on_open_collective": "ওপেন কলেক্টিভে অনুদান করুন", - "browse_anonymously": "অজানে ব্রাউজ করুন" + "browse_anonymously": "অজানে ব্রাউজ করুন", + "enable_connect": "সংযোগ সক্রিয় করুন", + "enable_connect_description": "অন্যান্য ডিভাইস থেকে Spotube নিয়ন্ত্রণ করুন", + "devices": "ডিভাইস", + "select": "নির্বাচন করুন", + "connect_client_alert": "আপনি {client} দ্বারা নিয়ন্ত্রিত হচ্ছেন", + "this_device": "এই ডিভাইস", + "remote": "রিমোট" } \ No newline at end of file diff --git a/lib/l10n/app_ca.arb b/lib/l10n/app_ca.arb index 9848954a..8faa0d09 100644 --- a/lib/l10n/app_ca.arb +++ b/lib/l10n/app_ca.arb @@ -313,5 +313,12 @@ "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" + "browse_anonymously": "Navega de manera anònima", + "enable_connect": "Habilita la connexió", + "enable_connect_description": "Controla Spotube des d'altres dispositius", + "devices": "Dispositius", + "select": "Selecciona", + "connect_client_alert": "Estàs sent controlat per {client}", + "this_device": "Aquest dispositiu", + "remote": "Remot" } \ No newline at end of file diff --git a/lib/l10n/app_de.arb b/lib/l10n/app_de.arb index b058d41a..77435d67 100644 --- a/lib/l10n/app_de.arb +++ b/lib/l10n/app_de.arb @@ -313,5 +313,12 @@ "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" + "browse_anonymously": "Anonym durchsuchen", + "enable_connect": "Verbindung aktivieren", + "enable_connect_description": "Spotube von anderen Geräten steuern", + "devices": "Geräte", + "select": "Auswählen", + "connect_client_alert": "Du wirst von {client} gesteuert", + "this_device": "Dieses Gerät", + "remote": "Fernbedienung" } \ No newline at end of file diff --git a/lib/l10n/app_es.arb b/lib/l10n/app_es.arb index 0b4cbb2a..11617b42 100644 --- a/lib/l10n/app_es.arb +++ b/lib/l10n/app_es.arb @@ -313,5 +313,12 @@ "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" + "browse_anonymously": "Navegar Anónimamente", + "enable_connect": "Habilitar conexión", + "enable_connect_description": "Controla Spotube desde otros dispositivos", + "devices": "Dispositivos", + "select": "Seleccionar", + "connect_client_alert": "Estás siendo controlado por {client}", + "this_device": "Este dispositivo", + "remote": "Remoto" } \ No newline at end of file diff --git a/lib/l10n/app_fa.arb b/lib/l10n/app_fa.arb index 629238cc..8a0bee3a 100644 --- a/lib/l10n/app_fa.arb +++ b/lib/l10n/app_fa.arb @@ -313,5 +313,12 @@ "help_project_grow_description": "Spotube یک پروژه متن باز است. شما می‌توانید با به پروژه کمک کردن، گزارش دادن اشکالات یا پیشنهاد ویژگی‌های جدید، به این پروژه کمک کنید.", "contribute_on_github": "مشارکت در GitHub", "donate_on_open_collective": "کمک مالی در Open Collective", - "browse_anonymously": "مرور به صورت ناشناس" + "browse_anonymously": "مرور به صورت ناشناس", + "enable_connect": "فعال‌سازی اتصال", + "enable_connect_description": "کنترل Spotube از دیگر دستگاه‌ها", + "devices": "دستگاه‌ها", + "select": "انتخاب", + "connect_client_alert": "شما توسط {client} کنترل می‌شوید", + "this_device": "این دستگاه", + "remote": "راه‌دور" } \ No newline at end of file diff --git a/lib/l10n/app_fr.arb b/lib/l10n/app_fr.arb index 69b2bb69..cabcb8e1 100644 --- a/lib/l10n/app_fr.arb +++ b/lib/l10n/app_fr.arb @@ -313,5 +313,12 @@ "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" + "browse_anonymously": "Naviguer anonymement", + "enable_connect": "Activer la connexion", + "enable_connect_description": "Contrôlez Spotube depuis d'autres appareils", + "devices": "Appareils", + "select": "Sélectionner", + "connect_client_alert": "Vous êtes contrôlé par {client}", + "this_device": "Cet appareil", + "remote": "À distance" } \ No newline at end of file diff --git a/lib/l10n/app_hi.arb b/lib/l10n/app_hi.arb index b442da37..a72e136e 100644 --- a/lib/l10n/app_hi.arb +++ b/lib/l10n/app_hi.arb @@ -313,5 +313,12 @@ "help_project_grow_description": "Spotube एक ओपन सोर्स परियोजना है। आप इस परियोजना को योगदान देकर, बग रिपोर्ट करके या नई विशेषताओं का सुझाव देकर इस परियोजना को बढ़ा सकते हैं।", "contribute_on_github": "GitHub पर योगदान करें", "donate_on_open_collective": "ओपन कलेक्टिव पर दान करें", - "browse_anonymously": "बिना नाम के ब्राउज़ करें" + "browse_anonymously": "बिना नाम के ब्राउज़ करें", + "enable_connect": "कनेक्ट सक्षम करें", + "enable_connect_description": "अन्य उपकरणों से Spotube को नियंत्रित करें", + "devices": "उपकरण", + "select": "चयन करें", + "connect_client_alert": "आप {client} द्वारा नियंत्रित हो रहे हैं", + "this_device": "यह उपकरण", + "remote": "रिमोट" } \ No newline at end of file diff --git a/lib/l10n/app_it.arb b/lib/l10n/app_it.arb index f8440cd0..bb1881d6 100644 --- a/lib/l10n/app_it.arb +++ b/lib/l10n/app_it.arb @@ -314,5 +314,12 @@ "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" + "browse_anonymously": "Naviga in modo anonimo", + "enable_connect": "Abilita connessione", + "enable_connect_description": "Controlla Spotube da altri dispositivi", + "devices": "Dispositivi", + "select": "Seleziona", + "connect_client_alert": "Stai venendo controllato da {client}", + "this_device": "Questo dispositivo", + "remote": "Remoto" } \ No newline at end of file diff --git a/lib/l10n/app_ja.arb b/lib/l10n/app_ja.arb index ecdc77a2..ab759404 100644 --- a/lib/l10n/app_ja.arb +++ b/lib/l10n/app_ja.arb @@ -313,5 +313,12 @@ "help_project_grow_description": "Spotubeはオープンソースプロジェクトです。プロジェクトに貢献したり、バグを報告したり、新しい機能を提案することで、このプロジェクトの成長に貢献できます。", "contribute_on_github": "GitHubで貢献する", "donate_on_open_collective": "Open Collectiveで寄付する", - "browse_anonymously": "匿名で閲覧する" + "browse_anonymously": "匿名で閲覧する", + "enable_connect": "接続を有効にする", + "enable_connect_description": "他のデバイスからSpotubeを制御する", + "devices": "デバイス", + "select": "選択する", + "connect_client_alert": "{client} によって操作されています", + "this_device": "このデバイス", + "remote": "リモート" } \ No newline at end of file diff --git a/lib/l10n/app_ko.arb b/lib/l10n/app_ko.arb index 5a3ee8bc..c94f8142 100644 --- a/lib/l10n/app_ko.arb +++ b/lib/l10n/app_ko.arb @@ -314,5 +314,12 @@ "help_project_grow_description": "Spotube는 오픈 소스 프로젝트입니다. 프로젝트에 기여하거나 버그를 보고하거나 새로운 기능을 제안하여이 프로젝트의 성장에 도움을 줄 수 있습니다.", "contribute_on_github": "GitHub에서 기여하기", "donate_on_open_collective": "Open Collective에 기부하기", - "browse_anonymously": "익명으로 둘러보기" + "browse_anonymously": "익명으로 둘러보기", + "enable_connect": "연결 활성화", + "enable_connect_description": "다른 장치에서 Spotube 제어", + "devices": "장치", + "select": "선택", + "connect_client_alert": "{client}님에 의해 제어되고 있습니다", + "this_device": "이 장치", + "remote": "원격" } \ No newline at end of file diff --git a/lib/l10n/app_ne.arb b/lib/l10n/app_ne.arb index d921f3ba..4085b00e 100644 --- a/lib/l10n/app_ne.arb +++ b/lib/l10n/app_ne.arb @@ -313,5 +313,12 @@ "help_project_grow_description": "Spotube एक खुला स्रोतको परियोजना हो। तपाईं परियोजनामा योगदान गरेर, त्रुटिहरू सूचिकै, वा नयाँ सुविधाहरू सुझाव दिएर यस परियोजनामा वृद्धि गर्न सक्नुहुन्छ।", "contribute_on_github": "GitHubमा योगदान गर्नुहोस्", "donate_on_open_collective": "खुला संगठनमा दान गर्नुहोस्", - "browse_anonymously": "अनामित रूपमा ब्राउज़ गर्नुहोस्" + "browse_anonymously": "अनामित रूपमा ब्राउज़ गर्नुहोस्", + "enable_connect": "कनेक्ट सक्रिय गर्नुहोस्", + "enable_connect_description": "अन्य उपकरणहरूबाट Spotube कन्ट्रोल गर्नुहोस्", + "devices": "उपकरणहरू", + "select": "चयन गर्नुहोस्", + "connect_client_alert": "तपाईंलाई {client} द्वारा नियन्त्रित गरिएको छ", + "this_device": "यो उपकरण", + "remote": "दूरसंचार" } \ No newline at end of file diff --git a/lib/l10n/app_nl.arb b/lib/l10n/app_nl.arb index 33e94a2e..0a04c40b 100644 --- a/lib/l10n/app_nl.arb +++ b/lib/l10n/app_nl.arb @@ -314,5 +314,12 @@ "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" + "browse_anonymously": "Anoniem Bladeren", + "enable_connect": "Verbinding inschakelen", + "enable_connect_description": "Spotube bedienen vanaf andere apparaten", + "devices": "Apparaten", + "select": "Selecteren", + "connect_client_alert": "Je wordt gecontroleerd door {client}", + "this_device": "Dit apparaat", + "remote": "Afstandsbediening" } \ No newline at end of file diff --git a/lib/l10n/app_pl.arb b/lib/l10n/app_pl.arb index a1bc5de6..9ce31187 100644 --- a/lib/l10n/app_pl.arb +++ b/lib/l10n/app_pl.arb @@ -313,5 +313,12 @@ "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" + "browse_anonymously": "Przeglądaj Anonimowo", + "enable_connect": "Włącz połączenie", + "enable_connect_description": "Kontroluj Spotube z innych urządzeń", + "devices": "Urządzenia", + "select": "Wybierz", + "connect_client_alert": "Jesteś sterowany przez {client}", + "this_device": "To urządzenie", + "remote": "Zdalny" } \ No newline at end of file diff --git a/lib/l10n/app_pt.arb b/lib/l10n/app_pt.arb index 7f290a1d..53732589 100644 --- a/lib/l10n/app_pt.arb +++ b/lib/l10n/app_pt.arb @@ -313,5 +313,12 @@ "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" + "browse_anonymously": "Navegar Anonimamente", + "enable_connect": "Ativar conexão", + "enable_connect_description": "Controle o Spotube a partir de outros dispositivos", + "devices": "Dispositivos", + "select": "Selecionar", + "connect_client_alert": "Você está sendo controlado por {client}", + "this_device": "Este dispositivo", + "remote": "Remoto" } \ No newline at end of file diff --git a/lib/l10n/app_ru.arb b/lib/l10n/app_ru.arb index c9139a90..a18e02e7 100644 --- a/lib/l10n/app_ru.arb +++ b/lib/l10n/app_ru.arb @@ -313,5 +313,12 @@ "help_project_grow_description": "Spotube - это проект с открытым исходным кодом. Вы можете помочь этому проекту развиваться, внося вклад в проект, сообщая ошибках или предлагая новые функции.", "contribute_on_github": "Внести вклад на GitHub", "donate_on_open_collective": "Пожертвовать на Open Collective", - "browse_anonymously": "Анонимно просматривать" + "browse_anonymously": "Анонимно просматривать", + "enable_connect": "Включить подключение", + "enable_connect_description": "Управление Spotube с других устройств", + "devices": "Устройства", + "select": "Выбрать", + "connect_client_alert": "Вас контролирует {client}", + "this_device": "Это устройство", + "remote": "Дистанционное управление" } \ No newline at end of file diff --git a/lib/l10n/app_th.arb b/lib/l10n/app_th.arb index cd58a20d..866929fa 100644 --- a/lib/l10n/app_th.arb +++ b/lib/l10n/app_th.arb @@ -313,5 +313,13 @@ "help_project_grow_description": "Spotube เป็นโครงการโอเพนซอร์ส คุณสามารถช่วยให้โครงการนี้เติบโตได้โดยการมีส่วนร่วมในโครงการ รายงานข้อบกพร่อง หรือเสนอคุณสมบัติใหม่", "contribute_on_github": "มีส่วนร่วมบน GitHub", "donate_on_open_collective": "บริจาคบน Open Collective", - "browse_anonymously": "เรียกดูแบบไม่ระบุตัวตน" + "browse_anonymously": "เรียกดูแบบไม่ระบุตัวตน", + "choose_your_language": "เลือกภาษาของคุณ", + "enable_connect": "เปิดใช้งานการเชื่อมต่อ", + "enable_connect_description": "ควบคุม Spotube จากอุปกรณ์อื่น", + "devices": "อุปกรณ์", + "select": "เลือก", + "connect_client_alert": "คุณกำลังถูกควบคุมโดย {client}", + "this_device": "อุปกรณ์นี้", + "remote": "ระยะไกล" } \ No newline at end of file diff --git a/lib/l10n/app_uk.arb b/lib/l10n/app_uk.arb index fe57e617..4208a3d2 100644 --- a/lib/l10n/app_uk.arb +++ b/lib/l10n/app_uk.arb @@ -313,5 +313,12 @@ "help_project_grow_description": "Spotube - це проект з відкритим кодом. Ви можете допомогти цьому проекту зростати, вносячи свій внесок у проект, повідомляючи про помилки або пропонуючи нові функції.", "contribute_on_github": "Долучайтесь на GitHub", "donate_on_open_collective": "Пожертвуйте на Open Collective", - "browse_anonymously": "Анонімно переглядати" + "browse_anonymously": "Анонімно переглядати", + "enable_connect": "Увімкнути підключення", + "enable_connect_description": "Керуйте Spotube з інших пристроїв", + "devices": "Пристрої", + "select": "Вибрати", + "connect_client_alert": "Вас керує {client}", + "this_device": "Цей пристрій", + "remote": "Віддалений" } \ No newline at end of file diff --git a/lib/l10n/app_vi.arb b/lib/l10n/app_vi.arb index 0e9b0b7c..6115fc0c 100644 --- a/lib/l10n/app_vi.arb +++ b/lib/l10n/app_vi.arb @@ -311,5 +311,14 @@ "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" + "browse_anonymously": "Duyệt Anonymously", + "friends": "Bạn bè", + "no_lyrics_available": "Xin lỗi, không tìm thấy lời cho bài hát này", + "enable_connect": "Kích hoạt kết nối", + "enable_connect_description": "Điều khiển Spotube từ các thiết bị khác", + "devices": "Thiết bị", + "select": "Chọn", + "connect_client_alert": "Bạn đang được điều khiển bởi {client}", + "this_device": "Thiết bị này", + "remote": "Từ xa" } \ No newline at end of file diff --git a/lib/l10n/app_zh.arb b/lib/l10n/app_zh.arb index 506661f0..da5254a3 100644 --- a/lib/l10n/app_zh.arb +++ b/lib/l10n/app_zh.arb @@ -313,5 +313,12 @@ "help_project_grow_description": "Spotube是一个开源项目。您可以通过为项目做出贡献、报告错误或建议新功能来帮助该项目成长。", "contribute_on_github": "在GitHub上做出贡献", "donate_on_open_collective": "在Open Collective上捐款", - "browse_anonymously": "匿名浏览" + "browse_anonymously": "匿名浏览", + "enable_connect": "启用连接", + "enable_connect_description": "从其他设备控制Spotube", + "devices": "设备", + "select": "选择", + "connect_client_alert": "您正在被 {client} 控制", + "this_device": "此设备", + "remote": "远程" } \ No newline at end of file diff --git a/untranslated_messages.json b/untranslated_messages.json index 3696d52e..9e26dfee 100644 --- a/untranslated_messages.json +++ b/untranslated_messages.json @@ -1,204 +1 @@ -{ - "ar": [ - "enable_connect", - "enable_connect_description", - "devices", - "select", - "connect_client_alert", - "this_device", - "remote" - ], - - "bn": [ - "enable_connect", - "enable_connect_description", - "devices", - "select", - "connect_client_alert", - "this_device", - "remote" - ], - - "ca": [ - "enable_connect", - "enable_connect_description", - "devices", - "select", - "connect_client_alert", - "this_device", - "remote" - ], - - "de": [ - "enable_connect", - "enable_connect_description", - "devices", - "select", - "connect_client_alert", - "this_device", - "remote" - ], - - "es": [ - "enable_connect", - "enable_connect_description", - "devices", - "select", - "connect_client_alert", - "this_device", - "remote" - ], - - "fa": [ - "enable_connect", - "enable_connect_description", - "devices", - "select", - "connect_client_alert", - "this_device", - "remote" - ], - - "fr": [ - "enable_connect", - "enable_connect_description", - "devices", - "select", - "connect_client_alert", - "this_device", - "remote" - ], - - "hi": [ - "enable_connect", - "enable_connect_description", - "devices", - "select", - "connect_client_alert", - "this_device", - "remote" - ], - - "it": [ - "enable_connect", - "enable_connect_description", - "devices", - "select", - "connect_client_alert", - "this_device", - "remote" - ], - - "ja": [ - "enable_connect", - "enable_connect_description", - "devices", - "select", - "connect_client_alert", - "this_device", - "remote" - ], - - "ko": [ - "enable_connect", - "enable_connect_description", - "devices", - "select", - "connect_client_alert", - "this_device", - "remote" - ], - - "ne": [ - "enable_connect", - "enable_connect_description", - "devices", - "select", - "connect_client_alert", - "this_device", - "remote" - ], - - "nl": [ - "enable_connect", - "enable_connect_description", - "devices", - "select", - "connect_client_alert", - "this_device", - "remote" - ], - - "pl": [ - "enable_connect", - "enable_connect_description", - "devices", - "select", - "connect_client_alert", - "this_device", - "remote" - ], - - "pt": [ - "enable_connect", - "enable_connect_description", - "devices", - "select", - "connect_client_alert", - "this_device", - "remote" - ], - - "ru": [ - "enable_connect", - "enable_connect_description", - "devices", - "select", - "connect_client_alert", - "this_device", - "remote" - ], - - "th": [ - "choose_your_language", - "enable_connect", - "enable_connect_description", - "devices", - "select", - "connect_client_alert", - "this_device", - "remote" - ], - - "uk": [ - "enable_connect", - "enable_connect_description", - "devices", - "select", - "connect_client_alert", - "this_device", - "remote" - ], - - "vi": [ - "friends", - "no_lyrics_available", - "enable_connect", - "enable_connect_description", - "devices", - "select", - "connect_client_alert", - "this_device", - "remote" - ], - - "zh": [ - "enable_connect", - "enable_connect_description", - "devices", - "select", - "connect_client_alert", - "this_device", - "remote" - ] -} +{} \ No newline at end of file From 930539ca483a9fbedd40a241ee133e28a9076a94 Mon Sep 17 00:00:00 2001 From: Kingkor Roy Tirtho Date: Mon, 15 Apr 2024 19:47:15 +0600 Subject: [PATCH 06/13] chore: fix analyzer issues --- lib/components/desktop_login/login_form.dart | 3 +-- lib/components/shared/waypoint.dart | 8 +++----- lib/hooks/configurators/use_get_storage_perms.dart | 6 +++--- lib/hooks/utils/use_palette_color.dart | 7 +++---- lib/pages/root/root_app.dart | 3 +-- 5 files changed, 11 insertions(+), 16 deletions(-) diff --git a/lib/components/desktop_login/login_form.dart b/lib/components/desktop_login/login_form.dart index 2949fbae..6091829c 100644 --- a/lib/components/desktop_login/login_form.dart +++ b/lib/components/desktop_login/login_form.dart @@ -16,7 +16,6 @@ class TokenLoginForm extends HookConsumerWidget { Widget build(BuildContext context, ref) { final authenticationNotifier = ref.watch(authenticationProvider.notifier); final directCodeController = useTextEditingController(); - final mounted = useIsMounted(); final isLoading = useState(false); @@ -57,7 +56,7 @@ class TokenLoginForm extends HookConsumerWidget { await AuthenticationCredentials.fromCookie( cookieHeader), ); - if (mounted()) { + if (context.mounted) { onDone?.call(); } } finally { diff --git a/lib/components/shared/waypoint.dart b/lib/components/shared/waypoint.dart index 08e9088a..cf00e29b 100644 --- a/lib/components/shared/waypoint.dart +++ b/lib/components/shared/waypoint.dart @@ -20,8 +20,6 @@ class Waypoint extends HookWidget { @override Widget build(BuildContext context) { - final isMounted = useIsMounted(); - useEffect(() { if (isGrid) { return null; @@ -32,19 +30,19 @@ class Waypoint extends HookWidget { // scrollController fetches the next paginated data when the current // position of the user on the screen has surpassed - if (controller.position.pixels >= nextPageTrigger && isMounted()) { + if (controller.position.pixels >= nextPageTrigger && context.mounted) { await onTouchEdge?.call(); } } WidgetsBinding.instance.addPostFrameCallback((_) { - if (controller.hasClients && isMounted()) { + if (controller.hasClients && context.mounted) { listener(); controller.addListener(listener); } }); return () => controller.removeListener(listener); - }, [controller, onTouchEdge, isMounted]); + }, [controller, onTouchEdge]); if (isGrid) { return VisibilityDetector( diff --git a/lib/hooks/configurators/use_get_storage_perms.dart b/lib/hooks/configurators/use_get_storage_perms.dart index 86b495c4..db51af14 100644 --- a/lib/hooks/configurators/use_get_storage_perms.dart +++ b/lib/hooks/configurators/use_get_storage_perms.dart @@ -7,7 +7,7 @@ import 'package:spotube/components/library/user_local_tracks.dart'; import 'package:spotube/hooks/utils/use_async_effect.dart'; void useGetStoragePermissions(WidgetRef ref) { - final isMounted = useIsMounted(); + final context = useContext(); useAsyncEffect( () async { @@ -25,11 +25,11 @@ void useGetStoragePermissions(WidgetRef ref) { if (hasNoStoragePerm) { await Permission.storage.request(); - if (isMounted()) ref.invalidate(localTracksProvider); + if (context.mounted) ref.invalidate(localTracksProvider); } if (hasNoAudioPerm) { await Permission.audio.request(); - if (isMounted()) ref.invalidate(localTracksProvider); + if (context.mounted) ref.invalidate(localTracksProvider); } }, null, diff --git a/lib/hooks/utils/use_palette_color.dart b/lib/hooks/utils/use_palette_color.dart index 9269edd7..e6d8b398 100644 --- a/lib/hooks/utils/use_palette_color.dart +++ b/lib/hooks/utils/use_palette_color.dart @@ -14,7 +14,6 @@ PaletteColor usePaletteColor(String imageUrl, WidgetRef ref) { final context = useContext(); final theme = Theme.of(context); final paletteColor = ref.watch(_paletteColorState); - final mounted = useIsMounted(); useEffect(() { WidgetsBinding.instance.addPostFrameCallback((timeStamp) async { @@ -25,7 +24,7 @@ PaletteColor usePaletteColor(String imageUrl, WidgetRef ref) { width: 50, ), ); - if (!mounted()) return; + if (!context.mounted) return; final color = theme.brightness == Brightness.light ? palette.lightMutedColor ?? palette.lightVibrantColor : palette.darkMutedColor ?? palette.darkVibrantColor; @@ -41,7 +40,7 @@ PaletteColor usePaletteColor(String imageUrl, WidgetRef ref) { PaletteGenerator usePaletteGenerator(String imageUrl) { final palette = useState(PaletteGenerator.fromColors([])); - final mounted = useIsMounted(); + final context = useContext(); useEffect(() { WidgetsBinding.instance.addPostFrameCallback((timeStamp) async { @@ -52,7 +51,7 @@ PaletteGenerator usePaletteGenerator(String imageUrl) { width: 50, ), ); - if (!mounted()) return; + if (!context.mounted) return; palette.value = newPalette; }); diff --git a/lib/pages/root/root_app.dart b/lib/pages/root/root_app.dart index 56ea43a6..5ac0689a 100644 --- a/lib/pages/root/root_app.dart +++ b/lib/pages/root/root_app.dart @@ -38,7 +38,6 @@ class RootApp extends HookConsumerWidget { @override Widget build(BuildContext context, ref) { - final isMounted = useIsMounted(); final showingDialogCompleter = useRef(Completer()..complete()); final downloader = ref.watch(downloadManagerProvider); final scaffoldMessenger = ScaffoldMessenger.of(context); @@ -129,7 +128,7 @@ class RootApp extends HookConsumerWidget { useEffect(() { downloader.onFileExists = (track) async { - if (!isMounted()) return false; + if (!context.mounted) return false; if (!showingDialogCompleter.value.isCompleted) { await showingDialogCompleter.value.future; From 6907f9c756d8f49aadb1b23a2a1dc8bf7d658dc0 Mon Sep 17 00:00:00 2001 From: Kshamendra Date: Wed, 17 Apr 2024 18:25:06 +0530 Subject: [PATCH 07/13] fix(updater): dead link (#1408) * docs: broken link in README.md (fixes #1310) (#1311) * docs: remove appimage link in readme #1082 (#1171) * Updating Readme according to #1082 Updating Readme according to #1082 * Added explanation The explanation is now given and the expression is more formal and explanatory, instead of just linking the issue. * Update use_update_checker.dart --------- Co-authored-by: MerkomassDev <70111455+MerkomassDev@users.noreply.github.com> Co-authored-by: Karim <37943746+ksaadDE@users.noreply.github.com> Co-authored-by: Kingkor Roy Tirtho --- README.md | 7 +------ lib/hooks/configurators/use_update_checker.dart | 2 +- 2 files changed, 2 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index 8b8a6214..f2666fbc 100644 --- a/README.md +++ b/README.md @@ -97,12 +97,7 @@ This handy table lists all the methods you can use to install Spotube: AppImage - - - Download AppImage - -

Note: AppimageLauncher is required!

- + AppImage's lacking stability led to it's temporal removal. More information at https://github.com/KRTirtho/spotube/issues/1082 Debian/Ubuntu diff --git a/lib/hooks/configurators/use_update_checker.dart b/lib/hooks/configurators/use_update_checker.dart index 1a6a5be5..7b937efb 100644 --- a/lib/hooks/configurators/use_update_checker.dart +++ b/lib/hooks/configurators/use_update_checker.dart @@ -62,7 +62,7 @@ void useUpdateChecker(WidgetRef ref) { barrierColor: Colors.black26, builder: (context) { const url = - "https://spotube.krtirtho.dev/other-downloads/stable-downloads"; + "https://spotube.krtirtho.dev/downloads"; return AlertDialog( title: const Text("Spotube has an update"), actions: [ From 7ac791757abb30f40374c169c4211916287bb3f3 Mon Sep 17 00:00:00 2001 From: Kingkor Roy Tirtho Date: Wed, 17 Apr 2024 22:20:13 +0600 Subject: [PATCH 08/13] fix(linux): tray icon not showing #541 upgrade old packages --- .fvm/fvm_config.json | 2 +- .github/workflows/spotube-publish-binary.yml | 2 +- .github/workflows/spotube-release-binary.yml | 2 +- lib/collections/env.dart | 4 +- lib/collections/initializers.dart | 5 +- lib/components/root/bottom_player.dart | 18 +- .../inter_scrollbar/inter_scrollbar.dart | 4 +- .../shared/page_window_title_bar.dart | 35 +- .../sections/header/flexible_header.dart | 5 +- .../shared/tracks_view/track_view.dart | 5 +- .../configurators/use_close_behavior.dart | 26 +- lib/hooks/configurators/use_deep_linking.dart | 4 +- .../use_disable_battery_optimizations.dart | 6 +- .../configurators/use_get_storage_perms.dart | 5 +- .../configurators/use_init_sys_tray.dart | 128 ---- .../configurators/use_window_listener.dart | 10 +- lib/main.dart | 33 +- lib/models/connect/connect.freezed.dart | 2 +- lib/models/spotify/home_feed.freezed.dart | 2 +- .../spotify/recommendation_seeds.freezed.dart | 2 +- lib/pages/home/genres/genre_playlists.dart | 8 +- lib/pages/lyrics/mini_lyrics.dart | 92 +-- lib/pages/root/root_app.dart | 4 +- lib/pages/settings/sections/desktop.dart | 4 +- lib/pages/settings/sections/downloads.dart | 4 +- lib/pages/settings/settings.dart | 5 +- lib/provider/discord_provider.dart | 6 +- lib/provider/tray_manager/tray_manager.dart | 79 +++ lib/provider/tray_manager/tray_menu.dart | 108 +++ .../user_preferences_provider.dart | 10 +- .../user_preferences_state.dart | 4 +- .../user_preferences_state.freezed.dart | 6 +- .../user_preferences_state.g.dart | 4 +- lib/services/audio_player/audio_player.dart | 2 +- lib/services/audio_player/custom_player.dart | 6 +- .../audio_services/audio_services.dart | 10 +- lib/services/kv_store/kv_store.dart | 20 + lib/services/song_link/song_link.freezed.dart | 2 +- lib/services/sourced_track/sources/piped.dart | 2 +- lib/services/wm_tools/wm_tools.dart | 88 +++ linux/flutter/generated_plugin_registrant.cc | 8 +- linux/flutter/generated_plugins.cmake | 2 +- macos/Flutter/GeneratedPluginRegistrant.swift | 6 +- macos/Podfile.lock | 20 +- pubspec.lock | 658 ++++++++---------- pubspec.yaml | 96 ++- .../flutter/generated_plugin_registrant.cc | 6 +- windows/flutter/generated_plugins.cmake | 2 +- 48 files changed, 840 insertions(+), 722 deletions(-) delete mode 100644 lib/hooks/configurators/use_init_sys_tray.dart create mode 100644 lib/provider/tray_manager/tray_manager.dart create mode 100644 lib/provider/tray_manager/tray_menu.dart create mode 100644 lib/services/wm_tools/wm_tools.dart diff --git a/.fvm/fvm_config.json b/.fvm/fvm_config.json index 7ca74200..d42a42fa 100644 --- a/.fvm/fvm_config.json +++ b/.fvm/fvm_config.json @@ -1,4 +1,4 @@ { - "flutterSdkVersion": "3.19.1", + "flutterSdkVersion": "3.19.5", "flavors": {} } \ No newline at end of file diff --git a/.github/workflows/spotube-publish-binary.yml b/.github/workflows/spotube-publish-binary.yml index 805a89ac..960507f9 100644 --- a/.github/workflows/spotube-publish-binary.yml +++ b/.github/workflows/spotube-publish-binary.yml @@ -4,7 +4,7 @@ on: inputs: version: description: Version to publish (x.x.x) - default: 3.1.0 + default: 3.6.0 required: true dry_run: description: Dry run diff --git a/.github/workflows/spotube-release-binary.yml b/.github/workflows/spotube-release-binary.yml index d9fbd0c7..969e1b77 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.19.1' + FLUTTER_VERSION: '3.19.5' jobs: windows: diff --git a/lib/collections/env.dart b/lib/collections/env.dart index 50fe1e6a..14f33b80 100644 --- a/lib/collections/env.dart +++ b/lib/collections/env.dart @@ -1,5 +1,5 @@ import 'package:envied/envied.dart'; -import 'package:flutter_desktop_tools/flutter_desktop_tools.dart'; +import 'package:spotube/utils/platform.dart'; part 'env.g.dart'; @@ -26,7 +26,7 @@ abstract class Env { static final String _enableUpdateChecker = _Env._enableUpdateChecker; static bool get enableUpdateChecker => - DesktopTools.platform.isFlatpak || _enableUpdateChecker == "1"; + kIsFlatpak || _enableUpdateChecker == "1"; static String discordAppId = "1176718791388975124"; } diff --git a/lib/collections/initializers.dart b/lib/collections/initializers.dart index 9627de1c..976661fc 100644 --- a/lib/collections/initializers.dart +++ b/lib/collections/initializers.dart @@ -1,9 +1,10 @@ import 'dart:io'; -import 'package:flutter_desktop_tools/flutter_desktop_tools.dart'; + +import 'package:spotube/utils/platform.dart'; import 'package:win32_registry/win32_registry.dart'; Future registerWindowsScheme(String scheme) async { - if (!DesktopTools.platform.isWindows) return; + if (!kIsWindows) return; String appPath = Platform.resolvedExecutable; String protocolRegKey = 'Software\\Classes\\$scheme'; diff --git a/lib/components/root/bottom_player.dart b/lib/components/root/bottom_player.dart index 06250131..5429e172 100644 --- a/lib/components/root/bottom_player.dart +++ b/lib/components/root/bottom_player.dart @@ -1,6 +1,5 @@ import 'dart:ui'; -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'; @@ -24,6 +23,7 @@ import 'package:spotube/provider/user_preferences/user_preferences_provider.dart import 'package:spotube/provider/user_preferences/user_preferences_state.dart'; import 'package:spotube/provider/volume_provider.dart'; import 'package:spotube/utils/platform.dart'; +import 'package:window_manager/window_manager.dart'; class BottomPlayer extends HookConsumerWidget { BottomPlayer({super.key}); @@ -95,19 +95,19 @@ class BottomPlayer extends HookConsumerWidget { tooltip: context.l10n.mini_player, icon: const Icon(SpotubeIcons.miniPlayer), onPressed: () async { - final prevSize = - await DesktopTools.window.getSize(); - await DesktopTools.window.setMinimumSize( + if (!kIsDesktop) return; + + final prevSize = await windowManager.getSize(); + await windowManager.setMinimumSize( const Size(300, 300), ); - await DesktopTools.window.setAlwaysOnTop(true); + await windowManager.setAlwaysOnTop(true); if (!kIsLinux) { - await DesktopTools.window.setHasShadow(false); + await windowManager.setHasShadow(false); } - await DesktopTools.window + await windowManager .setAlignment(Alignment.topRight); - await DesktopTools.window - .setSize(const Size(400, 500)); + await windowManager.setSize(const Size(400, 500)); await Future.delayed( const Duration(milliseconds: 100), () async { diff --git a/lib/components/shared/inter_scrollbar/inter_scrollbar.dart b/lib/components/shared/inter_scrollbar/inter_scrollbar.dart index 2b3ce319..8a86b643 100644 --- a/lib/components/shared/inter_scrollbar/inter_scrollbar.dart +++ b/lib/components/shared/inter_scrollbar/inter_scrollbar.dart @@ -1,7 +1,7 @@ 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'; +import 'package:spotube/utils/platform.dart'; class InterScrollbar extends HookWidget { final Widget child; @@ -15,7 +15,7 @@ class InterScrollbar extends HookWidget { @override Widget build(BuildContext context) { - if (DesktopTools.platform.isDesktop) return child; + if (kIsDesktop) return child; return DraggableScrollbar.semicircle( controller: controller, diff --git a/lib/components/shared/page_window_title_bar.dart b/lib/components/shared/page_window_title_bar.dart index 37daefa9..f19757f3 100644 --- a/lib/components/shared/page_window_title_bar.dart +++ b/lib/components/shared/page_window_title_bar.dart @@ -7,7 +7,8 @@ import 'package:titlebar_buttons/titlebar_buttons.dart'; import 'dart:math'; import 'package:flutter/foundation.dart' show kIsWeb; import 'dart:io' show Platform; -import 'package:flutter_desktop_tools/flutter_desktop_tools.dart'; + +import 'package:window_manager/window_manager.dart'; class PageWindowTitleBar extends StatefulHookConsumerWidget implements PreferredSizeWidget { @@ -89,7 +90,7 @@ class _PageWindowTitleBarState extends ConsumerState { final systemTitleBar = ref.read(userPreferencesProvider.select((s) => s.systemTitleBar)); if (kIsDesktop && !systemTitleBar) { - DesktopTools.window.startDragging(); + windowManager.startDragging(); } } @@ -107,11 +108,7 @@ class _PageWindowTitleBarState extends ConsumerState { return SliverPadding( padding: EdgeInsets.only( - left: DesktopTools.platform.isMacOS && - hasFullscreen && - hasLeadingOrCanPop - ? 65 - : 0, + left: kIsMacOS && hasFullscreen && hasLeadingOrCanPop ? 65 : 0, ), sliver: SliverAppBar( leading: widget.leading, @@ -149,11 +146,7 @@ class _PageWindowTitleBarState extends ConsumerState { onVerticalDragStart: onDrag, child: Padding( padding: EdgeInsets.only( - left: DesktopTools.platform.isMacOS && - hasFullscreen && - hasLeadingOrCanPop - ? 65 - : 0, + left: kIsMacOS && hasFullscreen && hasLeadingOrCanPop ? 65 : 0, ), child: AppBar( leading: widget.leading, @@ -193,12 +186,12 @@ class WindowTitleBarButtons extends HookConsumerWidget { const type = ThemeType.auto; Future onClose() async { - await DesktopTools.window.close(); + await windowManager.close(); } useEffect(() { if (kIsDesktop) { - DesktopTools.window.isMaximized().then((value) { + windowManager.isMaximized().then((value) { isMaximized.value = value; }); } @@ -235,14 +228,14 @@ class WindowTitleBarButtons extends HookConsumerWidget { crossAxisAlignment: CrossAxisAlignment.start, children: [ MinimizeWindowButton( - onPressed: DesktopTools.window.minimize, + onPressed: windowManager.minimize, colors: colors, ), if (isMaximized.value != true) MaximizeWindowButton( colors: colors, onPressed: () { - DesktopTools.window.maximize(); + windowManager.maximize(); isMaximized.value = true; }, ) @@ -250,7 +243,7 @@ class WindowTitleBarButtons extends HookConsumerWidget { RestoreWindowButton( colors: colors, onPressed: () { - DesktopTools.window.unmaximize(); + windowManager.unmaximize(); isMaximized.value = false; }, ), @@ -270,16 +263,16 @@ class WindowTitleBarButtons extends HookConsumerWidget { children: [ DecoratedMinimizeButton( type: type, - onPressed: DesktopTools.window.minimize, + onPressed: windowManager.minimize, ), DecoratedMaximizeButton( type: type, onPressed: () async { - if (await DesktopTools.window.isMaximized()) { - await DesktopTools.window.unmaximize(); + if (await windowManager.isMaximized()) { + await windowManager.unmaximize(); isMaximized.value = false; } else { - await DesktopTools.window.maximize(); + await windowManager.maximize(); isMaximized.value = true; } }, 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 4a704302..d6e71e8f 100644 --- a/lib/components/shared/tracks_view/sections/header/flexible_header.dart +++ b/lib/components/shared/tracks_view/sections/header/flexible_header.dart @@ -1,7 +1,7 @@ import 'dart:ui'; 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'; @@ -12,6 +12,7 @@ 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'; +import 'package:spotube/utils/platform.dart'; class TrackViewFlexHeader extends HookConsumerWidget { const TrackViewFlexHeader({super.key}); @@ -53,7 +54,7 @@ class TrackViewFlexHeader extends HookConsumerWidget { floating: false, pinned: true, expandedHeight: 450, - automaticallyImplyLeading: DesktopTools.platform.isMobile, + automaticallyImplyLeading: kIsMobile, backgroundColor: palette.color, title: isExpanded ? null : Text(props.title, style: headingStyle), flexibleSpace: FlexibleSpaceBar( diff --git a/lib/components/shared/tracks_view/track_view.dart b/lib/components/shared/tracks_view/track_view.dart index eb8f6871..03d628a8 100644 --- a/lib/components/shared/tracks_view/track_view.dart +++ b/lib/components/shared/tracks_view/track_view.dart @@ -1,5 +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:sliver_tools/sliver_tools.dart'; @@ -8,6 +8,7 @@ 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'; import 'package:spotube/components/shared/tracks_view/track_view_props.dart'; +import 'package:spotube/utils/platform.dart'; class TrackView extends HookConsumerWidget { const TrackView({super.key}); @@ -18,7 +19,7 @@ class TrackView extends HookConsumerWidget { final controller = useScrollController(); return Scaffold( - appBar: DesktopTools.platform.isDesktop + appBar: kIsDesktop ? const PageWindowTitleBar( backgroundColor: Colors.transparent, foregroundColor: Colors.white, diff --git a/lib/hooks/configurators/use_close_behavior.dart b/lib/hooks/configurators/use_close_behavior.dart index 79b14fa9..3df6a528 100644 --- a/lib/hooks/configurators/use_close_behavior.dart +++ b/lib/hooks/configurators/use_close_behavior.dart @@ -1,29 +1,31 @@ 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'; -// ignore: depend_on_referenced_packages import 'package:local_notifier/local_notifier.dart'; +import 'package:spotube/utils/platform.dart'; +import 'package:window_manager/window_manager.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); - }; +final closeNotification = !kIsDesktop + ? null + : (LocalNotification( + title: 'Spotube', + body: '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(); + await windowManager.hide(); closeNotification?.show(); } else { exit(0); diff --git a/lib/hooks/configurators/use_deep_linking.dart b/lib/hooks/configurators/use_deep_linking.dart index 2650b05c..90d062dc 100644 --- a/lib/hooks/configurators/use_deep_linking.dart +++ b/lib/hooks/configurators/use_deep_linking.dart @@ -7,7 +7,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'; +import 'package:spotube/utils/platform.dart'; final appLinks = AppLinks(); final linkStream = appLinks.allStringLinkStream.asBroadcastStream(); @@ -53,7 +53,7 @@ void useDeepLinking(WidgetRef ref) { StreamSubscription? mediaStream; - if (DesktopTools.platform.isMobile) { + if (kIsMobile) { FlutterSharingIntent.instance.getInitialSharing().then(uriListener); mediaStream = diff --git a/lib/hooks/configurators/use_disable_battery_optimizations.dart b/lib/hooks/configurators/use_disable_battery_optimizations.dart index a9afef45..4aa51b74 100644 --- a/lib/hooks/configurators/use_disable_battery_optimizations.dart +++ b/lib/hooks/configurators/use_disable_battery_optimizations.dart @@ -1,12 +1,12 @@ import 'package:disable_battery_optimization/disable_battery_optimization.dart'; -import 'package:flutter_desktop_tools/flutter_desktop_tools.dart'; + import 'package:spotube/hooks/utils/use_async_effect.dart'; import 'package:spotube/services/kv_store/kv_store.dart'; +import 'package:spotube/utils/platform.dart'; void useDisableBatteryOptimizations() { useAsyncEffect(() async { - if (!DesktopTools.platform.isAndroid || - KVStoreService.askedForBatteryOptimization) return; + if (!kIsAndroid || KVStoreService.askedForBatteryOptimization) return; await DisableBatteryOptimization.showDisableBatteryOptimizationSettings(); diff --git a/lib/hooks/configurators/use_get_storage_perms.dart b/lib/hooks/configurators/use_get_storage_perms.dart index db51af14..bcc34042 100644 --- a/lib/hooks/configurators/use_get_storage_perms.dart +++ b/lib/hooks/configurators/use_get_storage_perms.dart @@ -1,17 +1,18 @@ import 'package:device_info_plus/device_info_plus.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:permission_handler/permission_handler.dart'; import 'package:spotube/components/library/user_local_tracks.dart'; import 'package:spotube/hooks/utils/use_async_effect.dart'; +import 'package:spotube/utils/platform.dart'; void useGetStoragePermissions(WidgetRef ref) { final context = useContext(); useAsyncEffect( () async { - if (!DesktopTools.platform.isMobile) return; + if (!kIsMobile) return; final androidInfo = await DeviceInfoPlugin().androidInfo; diff --git a/lib/hooks/configurators/use_init_sys_tray.dart b/lib/hooks/configurators/use_init_sys_tray.dart deleted file mode 100644 index 0bce6727..00000000 --- a/lib/hooks/configurators/use_init_sys_tray.dart +++ /dev/null @@ -1,128 +0,0 @@ -import 'dart:io'; - -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/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/user_preferences_provider.dart'; - -void useInitSysTray(WidgetRef ref) { - final context = useContext(); - final systemTray = useRef(null); - - final initializeMenu = useCallback(() async { - systemTray.value?.destroy(); - final playlist = ref.read(proxyPlaylistProvider); - final playlistQueue = ref.read(proxyPlaylistProvider.notifier); - final preferences = ref.read(userPreferencesProvider); - if (!preferences.showSystemTrayIcon) { - await systemTray.value?.destroy(); - systemTray.value = null; - return; - } - final enabled = !playlist.isFetching; - systemTray.value = await DesktopTools.createSystemTrayMenu( - title: DesktopTools.platform.isWindows ? "Spotube" : "", - iconPath: "assets/spotube-logo.png", - windowsIconPath: "assets/spotube-logo.ico", - items: [ - MenuItemLabel( - label: "Show/Hide", - name: "show-hide", - onClicked: (item) async { - if (await DesktopTools.window.isVisible()) { - await DesktopTools.window.hide(); - } else { - await DesktopTools.window.show(); - } - }, - ), - MenuSeparator(), - MenuItemLabel( - label: "Play/Pause", - name: "play-pause", - enabled: enabled, - onClicked: (_) async { - Actions.maybeInvoke( - context, PlayPauseIntent(ref)) ?? - PlayPauseAction().invoke(PlayPauseIntent(ref)); - }, - ), - MenuItemLabel( - label: "Next", - name: "next", - enabled: enabled && (playlist.tracks.length) > 1, - onClicked: (p0) async { - await playlistQueue.next(); - }, - ), - MenuItemLabel( - label: "Previous", - name: "previous", - enabled: enabled && (playlist.tracks.length) > 1, - onClicked: (p0) async { - await playlistQueue.previous(); - }, - ), - MenuSeparator(), - MenuItemLabel( - label: "Quit", - name: "quit", - onClicked: (item) async { - exit(0); - }, - ), - ], - onEvent: (event, tray) async { - if (DesktopTools.platform.isWindows) { - switch (event) { - case SystemTrayEvent.click: - await DesktopTools.window.show(); - break; - case SystemTrayEvent.rightClick: - await tray.popUpContextMenu(); - break; - default: - } - } else { - switch (event) { - case SystemTrayEvent.rightClick: - await DesktopTools.window.show(); - break; - case SystemTrayEvent.click: - await tray.popUpContextMenu(); - break; - default: - } - } - }, - ); - }, [ref]); - - useReassemble(initializeMenu); - - ref.listen( - proxyPlaylistProvider, - (previous, next) { - initializeMenu(); - }, - ); - ref.listen( - userPreferencesProvider.select((s) => s.showSystemTrayIcon), - (previous, next) { - initializeMenu(); - }, - ); - - useEffect(() { - WidgetsBinding.instance.addPostFrameCallback((_) { - initializeMenu(); - }); - return () async { - await systemTray.value?.destroy(); - }; - }, [initializeMenu]); -} diff --git a/lib/hooks/configurators/use_window_listener.dart b/lib/hooks/configurators/use_window_listener.dart index b91ad413..5977ea8e 100644 --- a/lib/hooks/configurators/use_window_listener.dart +++ b/lib/hooks/configurators/use_window_listener.dart @@ -1,6 +1,8 @@ import 'package:flutter/widgets.dart'; -import 'package:flutter_desktop_tools/flutter_desktop_tools.dart'; + import 'package:flutter_hooks/flutter_hooks.dart'; +import 'package:spotube/utils/platform.dart'; +import 'package:window_manager/window_manager.dart'; class CallbackWindowListener implements WindowListener { final VoidCallback? _onWindowClose; @@ -154,6 +156,8 @@ void useWindowListener({ VoidCallback? onWindowEvent, }) { useEffect(() { + if (!kIsDesktop) return null; + final listener = CallbackWindowListener( onWindowClose: onWindowClose, onWindowFocus: onWindowFocus, @@ -172,9 +176,9 @@ void useWindowListener({ onWindowUndocked: onWindowUndocked, onWindowEvent: onWindowEvent, ); - DesktopTools.window.addListener(listener); + windowManager.addListener(listener); return () { - DesktopTools.window.removeListener(listener); + windowManager.removeListener(listener); }; }, [ onWindowClose, diff --git a/lib/main.dart b/lib/main.dart index 0bb72932..7123b0d0 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -4,11 +4,11 @@ import 'package:device_preview/device_preview.dart'; import 'package:flutter/foundation.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:flutter_localizations/flutter_localizations.dart'; import 'package:hive/hive.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; +import 'package:local_notifier/local_notifier.dart'; import 'package:media_kit/media_kit.dart'; import 'package:metadata_god/metadata_god.dart'; import 'package:shared_preferences/shared_preferences.dart'; @@ -19,6 +19,7 @@ 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/provider/tray_manager/tray_manager.dart'; import 'package:spotube/l10n/l10n.dart'; import 'package:spotube/models/logger.dart'; import 'package:spotube/models/skip_segment.dart'; @@ -31,15 +32,17 @@ 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/kv_store/kv_store.dart'; +import 'package:spotube/services/wm_tools/wm_tools.dart'; import 'package:spotube/themes/theme.dart'; import 'package:spotube/utils/persisted_state_notifier.dart'; +import 'package:spotube/utils/platform.dart'; import 'package:system_theme/system_theme.dart'; import 'package:path_provider/path_provider.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'; import 'package:timezone/data/latest.dart' as tz; +import 'package:window_manager/window_manager.dart'; Future main(List rawArgs) async { final arguments = await startCLI(rawArgs); @@ -55,12 +58,12 @@ Future main(List rawArgs) async { MediaKit.ensureInitialized(); // force High Refresh Rate on some Android devices (like One Plus) - if (DesktopTools.platform.isAndroid) { + if (kIsAndroid) { await FlutterDisplayMode.setHighRefreshRate(); } - if (DesktopTools.platform.isDesktop) { - await DesktopTools.window.setPreventClose(true); + if (kIsDesktop) { + await windowManager.setPreventClose(true); } await SystemTheme.accentColor.load(); @@ -69,7 +72,7 @@ Future main(List rawArgs) async { MetadataGod.initialize(); } - if (DesktopTools.platform.isWindows || DesktopTools.platform.isLinux) { + if (kIsWindows || kIsLinux) { DiscordRPC.initialize(); } @@ -101,14 +104,10 @@ Future main(List rawArgs) async { path: hiveCacheDir, ); - await DesktopTools.ensureInitialized( - DesktopWindowOptions( - hideTitleBar: true, - title: "Spotube", - backgroundColor: Colors.transparent, - minimumSize: const Size(300, 700), - ), - ); + if (kIsDesktop) { + await localNotifier.setup(appName: "Spotube"); + await WindowManagerTools.initialize(); + } Catcher2( enableLogger: arguments["verbose"], @@ -189,9 +188,9 @@ class SpotubeState extends ConsumerState { ref.listen(playbackServerProvider, (_, __) {}); ref.listen(connectServerProvider, (_, __) {}); ref.listen(connectClientsProvider, (_, __) {}); + ref.listen(trayManagerProvider, (_, __) {}); useDisableBatteryOptimizations(); - useInitSysTray(ref); useDeepLinking(ref); useCloseBehavior(ref); useGetStoragePermissions(ref); @@ -233,9 +232,7 @@ class SpotubeState extends ConsumerState { builder: (context, child) { return DevicePreview.appBuilder( context, - DesktopTools.platform.isDesktop && !DesktopTools.platform.isMacOS - ? DragToResizeArea(child: child!) - : child, + kIsDesktop && !kIsMacOS ? DragToResizeArea(child: child!) : child, ); }, themeMode: themeMode, diff --git a/lib/models/connect/connect.freezed.dart b/lib/models/connect/connect.freezed.dart index dcbd783d..face800e 100644 --- a/lib/models/connect/connect.freezed.dart +++ b/lib/models/connect/connect.freezed.dart @@ -12,7 +12,7 @@ part of 'connect.dart'; 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'); + '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#adding-getters-and-methods-to-our-models'); WebSocketLoadEventData _$WebSocketLoadEventDataFromJson( Map json) { diff --git a/lib/models/spotify/home_feed.freezed.dart b/lib/models/spotify/home_feed.freezed.dart index 97c4ffc7..c2bb2aba 100644 --- a/lib/models/spotify/home_feed.freezed.dart +++ b/lib/models/spotify/home_feed.freezed.dart @@ -12,7 +12,7 @@ part of 'home_feed.dart'; 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'); + '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#adding-getters-and-methods-to-our-models'); SpotifySectionPlaylist _$SpotifySectionPlaylistFromJson( Map json) { diff --git a/lib/models/spotify/recommendation_seeds.freezed.dart b/lib/models/spotify/recommendation_seeds.freezed.dart index 4cfcce12..adf4aab8 100644 --- a/lib/models/spotify/recommendation_seeds.freezed.dart +++ b/lib/models/spotify/recommendation_seeds.freezed.dart @@ -12,7 +12,7 @@ part of 'recommendation_seeds.dart'; 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'); + '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#adding-getters-and-methods-to-our-models'); /// @nodoc mixin _$GeneratePlaylistProviderInput { diff --git a/lib/pages/home/genres/genre_playlists.dart b/lib/pages/home/genres/genre_playlists.dart index d80b4513..ca4e7238 100644 --- a/lib/pages/home/genres/genre_playlists.dart +++ b/lib/pages/home/genres/genre_playlists.dart @@ -12,7 +12,7 @@ import 'package:spotube/components/shared/waypoint.dart'; import 'package:spotube/extensions/constrains.dart'; import 'package:spotube/provider/spotify/spotify.dart'; import 'package:collection/collection.dart'; -import 'package:flutter_desktop_tools/flutter_desktop_tools.dart'; +import 'package:spotube/utils/platform.dart'; class GenrePlaylistsPage extends HookConsumerWidget { final Category category; @@ -27,7 +27,7 @@ class GenrePlaylistsPage extends HookConsumerWidget { final scrollController = useScrollController(); return Scaffold( - appBar: DesktopTools.platform.isDesktop + appBar: kIsDesktop ? const PageWindowTitleBar( leading: BackButton(color: Colors.white), backgroundColor: Colors.transparent, @@ -53,12 +53,12 @@ class GenrePlaylistsPage extends HookConsumerWidget { controller: scrollController, slivers: [ SliverAppBar( - automaticallyImplyLeading: DesktopTools.platform.isMobile, + automaticallyImplyLeading: kIsMobile, expandedHeight: mediaQuery.mdAndDown ? 200 : 150, title: const Text(""), backgroundColor: Colors.transparent, flexibleSpace: FlexibleSpaceBar( - centerTitle: DesktopTools.platform.isDesktop, + centerTitle: kIsDesktop, title: Text( category.name!, style: Theme.of(context).textTheme.headlineMedium?.copyWith( diff --git a/lib/pages/lyrics/mini_lyrics.dart b/lib/pages/lyrics/mini_lyrics.dart index 1e4d4641..6d6f75a9 100644 --- a/lib/pages/lyrics/mini_lyrics.dart +++ b/lib/pages/lyrics/mini_lyrics.dart @@ -1,5 +1,4 @@ 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'; @@ -18,6 +17,7 @@ import 'package:spotube/pages/lyrics/synced_lyrics.dart'; import 'package:spotube/provider/authentication_provider.dart'; import 'package:spotube/provider/proxy_playlist/proxy_playlist_provider.dart'; import 'package:spotube/utils/platform.dart'; +import 'package:window_manager/window_manager.dart'; class MiniLyricsPage extends HookConsumerWidget { final Size prevSize; @@ -36,9 +36,11 @@ class MiniLyricsPage extends HookConsumerWidget { final showLyrics = useState(true); useEffect(() { - WidgetsBinding.instance.addPostFrameCallback((_) async { - wasMaximized.value = await DesktopTools.window.isMaximized(); - }); + if (kIsDesktop) { + WidgetsBinding.instance.addPostFrameCallback((_) async { + wasMaximized.value = await windowManager.isMaximized(); + }); + } return null; }, []); @@ -112,11 +114,13 @@ class MiniLyricsPage extends HookConsumerWidget { areaActive.value = true; hoverMode.value = false; - await DesktopTools.window.setSize( - showLyrics.value - ? const Size(400, 500) - : const Size(400, 150), - ); + if (kIsDesktop) { + await windowManager.setSize( + showLyrics.value + ? const Size(400, 500) + : const Size(400, 150), + ); + } }, ), IconButton( @@ -135,33 +139,34 @@ class MiniLyricsPage extends HookConsumerWidget { hoverMode.value = !hoverMode.value; }, ), - FutureBuilder( - future: DesktopTools.window.isAlwaysOnTop(), - builder: (context, snapshot) { - return IconButton( - tooltip: context.l10n.always_on_top, - icon: Icon( - snapshot.data == true - ? SpotubeIcons.pinOn - : SpotubeIcons.pinOff, - ), - style: ButtonStyle( - foregroundColor: snapshot.data == true - ? MaterialStateProperty.all( - theme.colorScheme.primary) - : null, - ), - onPressed: snapshot.data == null - ? null - : () async { - await DesktopTools.window.setAlwaysOnTop( - snapshot.data == true ? false : true, - ); - update(); - }, - ); - }, - ), + if (kIsDesktop) + FutureBuilder( + future: windowManager.isAlwaysOnTop(), + builder: (context, snapshot) { + return IconButton( + tooltip: context.l10n.always_on_top, + icon: Icon( + snapshot.data == true + ? SpotubeIcons.pinOn + : SpotubeIcons.pinOff, + ), + style: ButtonStyle( + foregroundColor: snapshot.data == true + ? MaterialStateProperty.all( + theme.colorScheme.primary) + : null, + ), + onPressed: snapshot.data == null + ? null + : () async { + await windowManager.setAlwaysOnTop( + snapshot.data == true ? false : true, + ); + update(); + }, + ); + }, + ), ], ), ), @@ -243,19 +248,20 @@ class MiniLyricsPage extends HookConsumerWidget { tooltip: context.l10n.exit_mini_player, icon: const Icon(SpotubeIcons.maximize), onPressed: () async { + if (!kIsDesktop) return; + try { - await DesktopTools.window + await windowManager .setMinimumSize(const Size(300, 700)); - await DesktopTools.window.setAlwaysOnTop(false); + await windowManager.setAlwaysOnTop(false); if (wasMaximized.value) { - await DesktopTools.window.maximize(); + await windowManager.maximize(); } else { - await DesktopTools.window.setSize(prevSize); + await windowManager.setSize(prevSize); } - await DesktopTools.window - .setAlignment(Alignment.center); + await windowManager.setAlignment(Alignment.center); if (!kIsLinux) { - await DesktopTools.window.setHasShadow(true); + await windowManager.setHasShadow(true); } await Future.delayed( const Duration(milliseconds: 200)); diff --git a/lib/pages/root/root_app.dart b/lib/pages/root/root_app.dart index 5ac0689a..f3ed6571 100644 --- a/lib/pages/root/root_app.dart +++ b/lib/pages/root/root_app.dart @@ -2,7 +2,6 @@ import 'dart:async'; 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'; @@ -21,6 +20,7 @@ import 'package:spotube/provider/download_manager_provider.dart'; import 'package:spotube/provider/proxy_playlist/proxy_playlist_provider.dart'; import 'package:spotube/services/connectivity_adapter.dart'; import 'package:spotube/utils/persisted_state_notifier.dart'; +import 'package:spotube/utils/platform.dart'; const rootPaths = { "/": 0, @@ -206,7 +206,7 @@ class RootApp extends HookConsumerWidget { ), extendBody: true, drawerScrimColor: Colors.transparent, - endDrawer: DesktopTools.platform.isDesktop + endDrawer: kIsDesktop ? Container( constraints: const BoxConstraints(maxWidth: 800), decoration: BoxDecoration( diff --git a/lib/pages/settings/sections/desktop.dart b/lib/pages/settings/sections/desktop.dart index 4e4408d9..56306868 100644 --- a/lib/pages/settings/sections/desktop.dart +++ b/lib/pages/settings/sections/desktop.dart @@ -1,5 +1,4 @@ import 'package:flutter/material.dart'; -import 'package:flutter_desktop_tools/flutter_desktop_tools.dart'; import 'package:gap/gap.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:spotube/collections/spotube_icons.dart'; @@ -8,6 +7,7 @@ import 'package:spotube/components/shared/adaptive/adaptive_select_tile.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'; +import 'package:spotube/utils/platform.dart'; class SettingsDesktopSection extends HookConsumerWidget { const SettingsDesktopSection({super.key}); @@ -53,7 +53,7 @@ class SettingsDesktopSection extends HookConsumerWidget { value: preferences.systemTitleBar, onChanged: preferencesNotifier.setSystemTitleBar, ), - if (!DesktopTools.platform.isMacOS) + if (!kIsMacOS) SwitchListTile( secondary: const Icon(SpotubeIcons.discord), title: Text(context.l10n.discord_rich_presence), diff --git a/lib/pages/settings/sections/downloads.dart b/lib/pages/settings/sections/downloads.dart index 1f25028e..76ef8e3e 100644 --- a/lib/pages/settings/sections/downloads.dart +++ b/lib/pages/settings/sections/downloads.dart @@ -1,13 +1,13 @@ 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/user_preferences_provider.dart'; +import 'package:spotube/utils/platform.dart'; class SettingsDownloadsSection extends HookConsumerWidget { const SettingsDownloadsSection({super.key}); @@ -18,7 +18,7 @@ class SettingsDownloadsSection extends HookConsumerWidget { final preferences = ref.watch(userPreferencesProvider); final pickDownloadLocation = useCallback(() async { - if (DesktopTools.platform.isMobile || DesktopTools.platform.isMacOS) { + if (kIsMobile || kIsMacOS) { final dirStr = await FilePicker.platform.getDirectoryPath( initialDirectory: preferences.downloadLocation, ); diff --git a/lib/pages/settings/settings.dart b/lib/pages/settings/settings.dart index d2a75057..d293518d 100644 --- a/lib/pages/settings/settings.dart +++ b/lib/pages/settings/settings.dart @@ -1,6 +1,5 @@ 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/page_window_title_bar.dart'; @@ -14,6 +13,7 @@ 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/user_preferences_provider.dart'; +import 'package:spotube/utils/platform.dart'; class SettingsPage extends HookConsumerWidget { const SettingsPage({super.key}); @@ -45,8 +45,7 @@ class SettingsPage extends HookConsumerWidget { const SettingsAppearanceSection(), const SettingsPlaybackSection(), const SettingsDownloadsSection(), - if (DesktopTools.platform.isDesktop) - const SettingsDesktopSection(), + if (kIsDesktop) const SettingsDesktopSection(), if (!kIsWeb) const SettingsDevelopersSection(), const SettingsAboutSection(), Center( diff --git a/lib/provider/discord_provider.dart b/lib/provider/discord_provider.dart index ca8eecfa..f90db54a 100644 --- a/lib/provider/discord_provider.dart +++ b/lib/provider/discord_provider.dart @@ -1,21 +1,19 @@ 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/extensions/artist_simple.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/platform.dart'; class Discord extends ChangeNotifier { final DiscordRPC? discordRPC; final bool isEnabled; Discord(this.isEnabled) - : discordRPC = (DesktopTools.platform.isWindows || - DesktopTools.platform.isLinux) && - isEnabled + : discordRPC = (kIsWindows || kIsLinux) && isEnabled ? DiscordRPC(applicationId: Env.discordAppId) : null { discordRPC?.start(autoRegister: true); diff --git a/lib/provider/tray_manager/tray_manager.dart b/lib/provider/tray_manager/tray_manager.dart new file mode 100644 index 00000000..2145cbef --- /dev/null +++ b/lib/provider/tray_manager/tray_manager.dart @@ -0,0 +1,79 @@ +import 'package:hooks_riverpod/hooks_riverpod.dart'; +import 'package:spotube/provider/tray_manager/tray_menu.dart'; +import 'package:spotube/provider/user_preferences/user_preferences_provider.dart'; +import 'package:spotube/utils/platform.dart'; +import 'package:tray_manager/tray_manager.dart'; +import 'package:window_manager/window_manager.dart'; + +class SystemTrayManager with TrayListener { + final Ref ref; + final bool enabled; + + SystemTrayManager( + this.ref, { + required this.enabled, + }) { + initialize(); + } + + Future initialize() async { + if (!kIsDesktop) return; + + if (enabled) { + await trayManager.setIcon( + kIsWindows + ? 'assets/spotube-logo.ico' + : kIsFlatpak + ? 'com.github.KRTirtho.Spotube.png' + : 'assets/spotube-logo.png', + ); + trayManager.addListener(this); + } else { + await trayManager.destroy(); + } + } + + void dispose() { + trayManager.removeListener(this); + } + + @override + onTrayIconMouseDown() { + if (kIsWindows) { + windowManager.show(); + } else { + trayManager.popUpContextMenu(); + } + } + + @override + onTrayIconRightMouseDown() { + if (!kIsWindows) { + windowManager.show(); + } else { + trayManager.popUpContextMenu(); + } + } +} + +final trayManagerProvider = Provider( + (ref) { + final enabled = ref.watch( + userPreferencesProvider.select((s) => s.showSystemTrayIcon), + ); + + ref.listen(trayMenuProvider, (_, menu) { + if (!enabled || !kIsDesktop) return; + trayManager.setContextMenu(menu); + }); + + final manager = SystemTrayManager( + ref, + enabled: enabled, + ); + + ref.onDispose(manager.dispose); + + return manager; + }, +); diff --git a/lib/provider/tray_manager/tray_menu.dart b/lib/provider/tray_manager/tray_menu.dart new file mode 100644 index 00000000..cb793707 --- /dev/null +++ b/lib/provider/tray_manager/tray_menu.dart @@ -0,0 +1,108 @@ +import 'dart:io'; + +import 'package:hooks_riverpod/hooks_riverpod.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:tray_manager/tray_manager.dart'; +import 'package:window_manager/window_manager.dart'; + +final audioPlayerLoopMode = StreamProvider((ref) { + return audioPlayer.loopModeStream; +}); + +final audioPlayerShuffleMode = StreamProvider((ref) { + return audioPlayer.shuffledStream; +}); +final audioPlayerPlaying = StreamProvider((ref) { + return audioPlayer.playingStream; +}); + +final trayMenuProvider = Provider((ref) { + final playlistNotifier = ref.watch(proxyPlaylistProvider.notifier); + final isPlaybackPlaying = + ref.watch(proxyPlaylistProvider.select((s) => s.activeTrack != null)); + final isLoopOne = + ref.watch(audioPlayerLoopMode).asData?.value == PlaybackLoopMode.one; + final isShuffled = ref.watch(audioPlayerShuffleMode).asData?.value ?? false; + final isPlaying = ref.watch(audioPlayerPlaying).asData?.value ?? false; + + return Menu( + items: [ + MenuItem( + label: "Show/Hide Window", + onClick: (menuItem) async { + if (await windowManager.isVisible()) { + await windowManager.hide(); + } else { + await windowManager.focus(); + await windowManager.show(); + } + }, + ), + MenuItem.separator(), + MenuItem( + label: isPlaying ? "Pause" : "Play", + disabled: !isPlaybackPlaying, + onClick: (menuItem) async { + if (audioPlayer.isPlaying) { + await audioPlayer.pause(); + } else { + await audioPlayer.resume(); + } + }, + ), + MenuItem( + label: "Next", + disabled: !isPlaybackPlaying, + onClick: (menuItem) { + playlistNotifier.next(); + }, + ), + MenuItem( + label: "Previous", + disabled: !isPlaybackPlaying, + onClick: (menuItem) { + playlistNotifier.previous(); + }, + ), + MenuItem.submenu( + label: "Playback", + submenu: Menu( + items: [ + MenuItem( + label: "Repeat", + checked: isLoopOne, + onClick: (menuItem) { + audioPlayer.setLoopMode( + isLoopOne ? PlaybackLoopMode.none : PlaybackLoopMode.one, + ); + }, + ), + MenuItem( + label: "Shuffle", + checked: isShuffled, + onClick: (menuItem) { + audioPlayer.setShuffle(!isShuffled); + }, + ), + MenuItem.separator(), + MenuItem( + label: "Stop", + onClick: (menuItem) { + playlistNotifier.stop(); + }, + ), + ], + ), + ), + MenuItem.separator(), + MenuItem( + label: "Quit", + onClick: (menuItem) { + exit(0); + }, + ), + ], + ); +}); diff --git a/lib/provider/user_preferences/user_preferences_provider.dart b/lib/provider/user_preferences/user_preferences_provider.dart index a1e247b2..a537038e 100644 --- a/lib/provider/user_preferences/user_preferences_provider.dart +++ b/lib/provider/user_preferences/user_preferences_provider.dart @@ -1,7 +1,6 @@ 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'; @@ -15,6 +14,7 @@ import 'package:spotube/services/sourced_track/enums.dart'; import 'package:spotube/utils/persisted_state_notifier.dart'; import 'package:spotube/utils/platform.dart'; import 'package:path/path.dart' as path; +import 'package:window_manager/window_manager.dart'; class UserPreferencesNotifier extends PersistedStateNotifier { final Ref ref; @@ -103,8 +103,8 @@ class UserPreferencesNotifier extends PersistedStateNotifier { void setSystemTitleBar(bool isSystemTitleBar) { state = state.copyWith(systemTitleBar: isSystemTitleBar); - if (DesktopTools.platform.isDesktop) { - DesktopTools.window.setTitleBarStyle( + if (kIsDesktop) { + windowManager.setTitleBarStyle( isSystemTitleBar ? TitleBarStyle.normal : TitleBarStyle.hidden, ); } @@ -151,8 +151,8 @@ class UserPreferencesNotifier extends PersistedStateNotifier { ); } - if (DesktopTools.platform.isDesktop) { - await DesktopTools.window.setTitleBarStyle( + if (kIsDesktop) { + await windowManager.setTitleBarStyle( state.systemTitleBar ? TitleBarStyle.normal : TitleBarStyle.hidden, ); } diff --git a/lib/provider/user_preferences/user_preferences_state.dart b/lib/provider/user_preferences/user_preferences_state.dart index e35c73b5..67eb18a2 100644 --- a/lib/provider/user_preferences/user_preferences_state.dart +++ b/lib/provider/user_preferences/user_preferences_state.dart @@ -62,10 +62,10 @@ class UserPreferences with _$UserPreferences { @Default(false) bool amoledDarkTheme, @Default(true) bool checkUpdate, @Default(false) bool normalizeAudio, - @Default(true) bool showSystemTrayIcon, + @Default(false) bool showSystemTrayIcon, @Default(false) bool skipNonMusic, @Default(false) bool systemTitleBar, - @Default(CloseBehavior.minimizeToTray) CloseBehavior closeBehavior, + @Default(CloseBehavior.close) CloseBehavior closeBehavior, @Default(SpotubeColor(0xFF2196F3, name: "Blue")) @JsonKey( fromJson: UserPreferences._accentColorSchemeFromJson, diff --git a/lib/provider/user_preferences/user_preferences_state.freezed.dart b/lib/provider/user_preferences/user_preferences_state.freezed.dart index a5b076bb..94015d37 100644 --- a/lib/provider/user_preferences/user_preferences_state.freezed.dart +++ b/lib/provider/user_preferences/user_preferences_state.freezed.dart @@ -12,7 +12,7 @@ part of 'user_preferences_state.dart'; 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'); + '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#adding-getters-and-methods-to-our-models'); UserPreferences _$UserPreferencesFromJson(Map json) { return _UserPreferences.fromJson(json); @@ -415,10 +415,10 @@ class _$UserPreferencesImpl implements _UserPreferences { this.amoledDarkTheme = false, this.checkUpdate = true, this.normalizeAudio = false, - this.showSystemTrayIcon = true, + this.showSystemTrayIcon = false, this.skipNonMusic = false, this.systemTitleBar = false, - this.closeBehavior = CloseBehavior.minimizeToTray, + this.closeBehavior = CloseBehavior.close, @JsonKey( fromJson: UserPreferences._accentColorSchemeFromJson, toJson: UserPreferences._accentColorSchemeToJson, diff --git a/lib/provider/user_preferences/user_preferences_state.g.dart b/lib/provider/user_preferences/user_preferences_state.g.dart index 8bdd12cc..930b1dd1 100644 --- a/lib/provider/user_preferences/user_preferences_state.g.dart +++ b/lib/provider/user_preferences/user_preferences_state.g.dart @@ -16,12 +16,12 @@ _$UserPreferencesImpl _$$UserPreferencesImplFromJson( amoledDarkTheme: json['amoledDarkTheme'] as bool? ?? false, checkUpdate: json['checkUpdate'] as bool? ?? true, normalizeAudio: json['normalizeAudio'] as bool? ?? false, - showSystemTrayIcon: json['showSystemTrayIcon'] as bool? ?? true, + showSystemTrayIcon: json['showSystemTrayIcon'] as bool? ?? false, skipNonMusic: json['skipNonMusic'] as bool? ?? false, systemTitleBar: json['systemTitleBar'] as bool? ?? false, closeBehavior: $enumDecodeNullable(_$CloseBehaviorEnumMap, json['closeBehavior']) ?? - CloseBehavior.minimizeToTray, + CloseBehavior.close, accentColorScheme: UserPreferences._accentColorSchemeReadValue( json, 'accentColorScheme') == null diff --git a/lib/services/audio_player/audio_player.dart b/lib/services/audio_player/audio_player.dart index a81c6c95..92de192b 100644 --- a/lib/services/audio_player/audio_player.dart +++ b/lib/services/audio_player/audio_player.dart @@ -101,7 +101,7 @@ abstract class AudioPlayerInterface { return _mkPlayer.state.completed; } - Future get isShuffled async { + bool get isShuffled { return _mkPlayer.shuffled; } diff --git a/lib/services/audio_player/custom_player.dart b/lib/services/audio_player/custom_player.dart index 916a983f..e32a0d14 100644 --- a/lib/services/audio_player/custom_player.dart +++ b/lib/services/audio_player/custom_player.dart @@ -1,5 +1,4 @@ import 'dart:async'; -import 'package:flutter_desktop_tools/flutter_desktop_tools.dart'; import 'package:catcher_2/catcher_2.dart'; import 'package:media_kit/media_kit.dart'; import 'package:flutter_broadcasts/flutter_broadcasts.dart'; @@ -7,6 +6,7 @@ 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'; +import 'package:spotube/utils/platform.dart'; /// MediaKit [Player] by default doesn't have a state stream. /// This class adds a state stream to the [Player] class. @@ -54,7 +54,7 @@ class CustomPlayer extends Player { PackageInfo.fromPlatform().then((packageInfo) { _packageName = packageInfo.packageName; }); - if (DesktopTools.platform.isAndroid) { + if (kIsAndroid) { _androidAudioManager = AndroidAudioManager(); AudioSession.instance.then((s) async { _androidAudioSessionId = @@ -71,7 +71,7 @@ class CustomPlayer extends Player { } Future notifyAudioSessionUpdate(bool active) async { - if (DesktopTools.platform.isAndroid) { + if (kIsAndroid) { sendBroadcast( BroadcastMessage( name: active diff --git a/lib/services/audio_services/audio_services.dart b/lib/services/audio_services/audio_services.dart index 338427aa..f42d6c4b 100644 --- a/lib/services/audio_services/audio_services.dart +++ b/lib/services/audio_services/audio_services.dart @@ -1,5 +1,4 @@ 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/extensions/artist_simple.dart'; @@ -8,6 +7,7 @@ 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/platform.dart'; class AudioServices { final MobileAudioService? mobile; @@ -19,9 +19,7 @@ class AudioServices { Ref ref, ProxyPlaylistNotifier playback, ) async { - final mobile = DesktopTools.platform.isMobile || - DesktopTools.platform.isMacOS || - DesktopTools.platform.isLinux + final mobile = kIsMobile || kIsMacOS || kIsLinux ? await AudioService.init( builder: () => MobileAudioService(playback), config: const AudioServiceConfig( @@ -31,9 +29,7 @@ class AudioServices { ), ) : null; - final smtc = DesktopTools.platform.isWindows - ? WindowsAudioService(ref, playback) - : null; + final smtc = kIsWindows ? WindowsAudioService(ref, playback) : null; return AudioServices( mobile, diff --git a/lib/services/kv_store/kv_store.dart b/lib/services/kv_store/kv_store.dart index f94ec4ee..ae62a055 100644 --- a/lib/services/kv_store/kv_store.dart +++ b/lib/services/kv_store/kv_store.dart @@ -1,4 +1,7 @@ +import 'dart:convert'; + import 'package:shared_preferences/shared_preferences.dart'; +import 'package:spotube/services/wm_tools/wm_tools.dart'; abstract class KVStoreService { static SharedPreferences? _sharedPreferences; @@ -23,4 +26,21 @@ abstract class KVStoreService { static Future setRecentSearches(List value) async => await sharedPreferences.setStringList('recentSearches', value); + + static WindowSize? get windowSize { + final raw = sharedPreferences.getString('windowSize'); + + if (raw == null) { + return null; + } + return WindowSize.fromJson(jsonDecode(raw)); + } + + static Future setWindowSize(WindowSize value) async => + await sharedPreferences.setString( + 'windowSize', + jsonEncode( + value.toJson(), + ), + ); } diff --git a/lib/services/song_link/song_link.freezed.dart b/lib/services/song_link/song_link.freezed.dart index a8230eeb..0a1af8a9 100644 --- a/lib/services/song_link/song_link.freezed.dart +++ b/lib/services/song_link/song_link.freezed.dart @@ -12,7 +12,7 @@ part of 'song_link.dart'; 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'); + '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#adding-getters-and-methods-to-our-models'); SongLink _$SongLinkFromJson(Map json) { return _SongLink.fromJson(json); diff --git a/lib/services/sourced_track/sources/piped.dart b/lib/services/sourced_track/sources/piped.dart index 75f83125..8444db53 100644 --- a/lib/services/sourced_track/sources/piped.dart +++ b/lib/services/sourced_track/sources/piped.dart @@ -163,7 +163,7 @@ class PipedSourcedTrack extends SourcedTrack { final PipedSearchResult(items: searchResults) = await pipedClient.search( query, preference.searchMode == SearchMode.youtube - ? PipedFilter.videos + ? PipedFilter.video : PipedFilter.musicSongs, ); diff --git a/lib/services/wm_tools/wm_tools.dart b/lib/services/wm_tools/wm_tools.dart new file mode 100644 index 00000000..4572a8b4 --- /dev/null +++ b/lib/services/wm_tools/wm_tools.dart @@ -0,0 +1,88 @@ +import 'package:flutter/material.dart'; +import 'package:spotube/services/kv_store/kv_store.dart'; +import 'package:spotube/utils/platform.dart'; +import 'package:window_manager/window_manager.dart'; + +class WindowSize { + final double height; + final double width; + final bool maximized; + + WindowSize({ + required this.height, + required this.width, + required this.maximized, + }); + + factory WindowSize.fromJson(Map json) => WindowSize( + height: json["height"], + width: json["width"], + maximized: json["maximized"], + ); + + Map toJson() => { + "height": height, + "width": width, + "maximized": maximized, + }; +} + +class WindowManagerTools with WidgetsBindingObserver { + static WindowManagerTools? _instance; + static WindowManagerTools get instance => _instance!; + + WindowManagerTools._(); + + static Future initialize() async { + await windowManager.ensureInitialized(); + _instance = WindowManagerTools._(); + WidgetsBinding.instance.addObserver(instance); + + await windowManager.waitUntilReadyToShow( + const WindowOptions( + title: "Spotube", + backgroundColor: Colors.transparent, + minimumSize: Size(300, 700), + titleBarStyle: TitleBarStyle.hidden, + ), + () async { + final savedSize = KVStoreService.windowSize; + await windowManager.setResizable(true); + if (savedSize?.maximized == true && + !(await windowManager.isMaximized())) { + await windowManager.maximize(); + } else if (savedSize != null) { + await windowManager.setSize(Size(savedSize.width, savedSize.height)); + } + + await windowManager.focus(); + await windowManager.show(); + }, + ); + } + + Size? _prevSize; + + @override + void didChangeMetrics() async { + super.didChangeMetrics(); + if (kIsMobile) return; + final size = await windowManager.getSize(); + final windowSameDimension = + _prevSize?.width == size.width && _prevSize?.height == size.height; + + if (windowSameDimension || _prevSize == null) { + _prevSize = size; + return; + } + final isMaximized = await windowManager.isMaximized(); + await KVStoreService.setWindowSize( + WindowSize( + height: size.height, + width: size.width, + maximized: isMaximized, + ), + ); + _prevSize = size; + } +} diff --git a/linux/flutter/generated_plugin_registrant.cc b/linux/flutter/generated_plugin_registrant.cc index c69c17c0..6dfdd740 100644 --- a/linux/flutter/generated_plugin_registrant.cc +++ b/linux/flutter/generated_plugin_registrant.cc @@ -14,7 +14,7 @@ #include #include #include -#include +#include #include #include #include @@ -44,9 +44,9 @@ void fl_register_plugins(FlPluginRegistry* registry) { g_autoptr(FlPluginRegistrar) system_theme_registrar = fl_plugin_registry_get_registrar_for_plugin(registry, "SystemThemePlugin"); system_theme_plugin_register_with_registrar(system_theme_registrar); - g_autoptr(FlPluginRegistrar) system_tray_registrar = - fl_plugin_registry_get_registrar_for_plugin(registry, "SystemTrayPlugin"); - system_tray_plugin_register_with_registrar(system_tray_registrar); + g_autoptr(FlPluginRegistrar) tray_manager_registrar = + fl_plugin_registry_get_registrar_for_plugin(registry, "TrayManagerPlugin"); + tray_manager_plugin_register_with_registrar(tray_manager_registrar); g_autoptr(FlPluginRegistrar) url_launcher_linux_registrar = fl_plugin_registry_get_registrar_for_plugin(registry, "UrlLauncherPlugin"); url_launcher_plugin_register_with_registrar(url_launcher_linux_registrar); diff --git a/linux/flutter/generated_plugins.cmake b/linux/flutter/generated_plugins.cmake index a4487f4d..93ffd3e9 100644 --- a/linux/flutter/generated_plugins.cmake +++ b/linux/flutter/generated_plugins.cmake @@ -11,7 +11,7 @@ list(APPEND FLUTTER_PLUGIN_LIST media_kit_libs_linux screen_retriever system_theme - system_tray + tray_manager url_launcher_linux window_manager window_size diff --git a/macos/Flutter/GeneratedPluginRegistrant.swift b/macos/Flutter/GeneratedPluginRegistrant.swift index a9f6650f..84f39341 100644 --- a/macos/Flutter/GeneratedPluginRegistrant.swift +++ b/macos/Flutter/GeneratedPluginRegistrant.swift @@ -21,7 +21,7 @@ import screen_retriever import shared_preferences_foundation import sqflite import system_theme -import system_tray +import tray_manager import url_launcher_macos import window_manager import window_size @@ -37,13 +37,13 @@ func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) { FlutterSecureStoragePlugin.register(with: registry.registrar(forPlugin: "FlutterSecureStoragePlugin")) LocalNotifierPlugin.register(with: registry.registrar(forPlugin: "LocalNotifierPlugin")) MediaKitLibsMacosAudioPlugin.register(with: registry.registrar(forPlugin: "MediaKitLibsMacosAudioPlugin")) - FLTPackageInfoPlusPlugin.register(with: registry.registrar(forPlugin: "FLTPackageInfoPlusPlugin")) + FPPPackageInfoPlusPlugin.register(with: registry.registrar(forPlugin: "FPPPackageInfoPlusPlugin")) PathProviderPlugin.register(with: registry.registrar(forPlugin: "PathProviderPlugin")) ScreenRetrieverPlugin.register(with: registry.registrar(forPlugin: "ScreenRetrieverPlugin")) SharedPreferencesPlugin.register(with: registry.registrar(forPlugin: "SharedPreferencesPlugin")) SqflitePlugin.register(with: registry.registrar(forPlugin: "SqflitePlugin")) SystemThemePlugin.register(with: registry.registrar(forPlugin: "SystemThemePlugin")) - SystemTrayPlugin.register(with: registry.registrar(forPlugin: "SystemTrayPlugin")) + TrayManagerPlugin.register(with: registry.registrar(forPlugin: "TrayManagerPlugin")) UrlLauncherPlugin.register(with: registry.registrar(forPlugin: "UrlLauncherPlugin")) WindowManagerPlugin.register(with: registry.registrar(forPlugin: "WindowManagerPlugin")) WindowSizePlugin.register(with: registry.registrar(forPlugin: "WindowSizePlugin")) diff --git a/macos/Podfile.lock b/macos/Podfile.lock index 317de385..c1cf630c 100644 --- a/macos/Podfile.lock +++ b/macos/Podfile.lock @@ -44,7 +44,7 @@ PODS: - FMDB (>= 2.7.5) - system_theme (0.0.1): - FlutterMacOS - - system_tray (0.0.1): + - tray_manager (0.0.1): - FlutterMacOS - url_launcher_macos (0.0.1): - FlutterMacOS @@ -73,7 +73,7 @@ DEPENDENCIES: - 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`) + - tray_manager (from `Flutter/ephemeral/.symlinks/plugins/tray_manager/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`) @@ -122,8 +122,8 @@ EXTERNAL SOURCES: :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 + tray_manager: + :path: Flutter/ephemeral/.symlinks/plugins/tray_manager/macos url_launcher_macos: :path: Flutter/ephemeral/.symlinks/plugins/url_launcher_macos/macos window_manager: @@ -132,11 +132,11 @@ EXTERNAL SOURCES: :path: Flutter/ephemeral/.symlinks/plugins/window_size/macos SPEC CHECKSUMS: - app_links: 4481ed4d71f384b0c3ae5016f4633aa73d32ff67 + app_links: 10e0a0ab602ffaf34d142cd4862f29d34b303b2a audio_service: b88ff778e0e3915efd4cd1a5ad6f0beef0c950a9 audio_session: dea1f41890dbf1718f04a56f1d6150fd50039b72 bonsoir_darwin: e3b8526c42ca46a885142df84229131dfabea842 - device_info_plus: 5401765fde0b8d062a2f8eb65510fb17e77cf07f + device_info_plus: ce1b7762849d3ec103d0e0517299f2db7ad60720 file_selector_macos: 468fb6b81fac7c0e88d71317f3eec34c3b008ff9 flutter_inappwebview_macos: 9600c9df9fdb346aaa8933812009f8d94304203d flutter_secure_storage_macos: d56e2d218c1130b262bef8b4a7d64f88d7f9c9ea @@ -147,13 +147,13 @@ SPEC CHECKSUMS: media_kit_native_event_loop: 7321675377cb9ae8596a29bddf3a3d2b5e8792c5 metadata_god: eceae399d0020475069a5cebc35943ce8562b5d7 OrderedSet: aaeb196f7fef5a9edf55d89760da9176ad40b93c - package_info_plus: 02d7a575e80f194102bef286361c6c326e4c29ce - path_provider_foundation: 29f094ae23ebbca9d3d0cec13889cd9060c0e943 + package_info_plus: fa739dd842b393193c5ca93c26798dff6e3d0e0c + path_provider_foundation: 3784922295ac71e43754bd15e0653ccfd36a147c screen_retriever: 59634572a57080243dd1bf715e55b6c54f241a38 - shared_preferences_foundation: 5b919d13b803cadd15ed2dc053125c68730e5126 + shared_preferences_foundation: b4c3b4cddf1c21f02770737f147a3f5da9d39695 sqflite: a5789cceda41d54d23f31d6de539d65bb14100ea system_theme: c7b9f6659a5caa26c9bc2284da096781e9a6fcbc - system_tray: e53c972838c69589ff2e77d6d3abfd71332f9e5d + tray_manager: 9064e219c56d75c476e46b9a21182087930baf90 url_launcher_macos: d2691c7dd33ed713bf3544850a623080ec693d95 window_manager: 3a1844359a6295ab1e47659b1a777e36773cd6e8 window_size: 339dafa0b27a95a62a843042038fa6c3c48de195 diff --git a/pubspec.lock b/pubspec.lock index 8d19f604..1532bcf7 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -5,26 +5,26 @@ packages: dependency: transitive description: name: _fe_analyzer_shared - sha256: ae92f5d747aee634b87f89d9946000c2de774be1d6ac3e58268224348cd0101a + sha256: "0b2f2bd91ba804e53a61d757b986f89f1f9eaed5b11e4b2f5a2468d86d6c9fc7" url: "https://pub.dev" source: hosted - version: "61.0.0" + version: "67.0.0" analyzer: dependency: transitive description: name: analyzer - sha256: ea3d8652bda62982addfd92fdc2d0214e5f82e43325104990d4f4c4a2a313562 + sha256: "37577842a27e4338429a1cbc32679d508836510b056f1eedf0c8d20e39c1383d" url: "https://pub.dev" source: hosted - version: "5.13.0" + version: "6.4.1" analyzer_plugin: dependency: transitive description: name: analyzer_plugin - sha256: c1d5f167683de03d5ab6c3b53fc9aeefc5d59476e7810ba7bbddff50c6f4392d + sha256: "9661b30b13a685efaee9f02e5d01ed9f2b423bd889d28a304d02d704aee69161" url: "https://pub.dev" source: hosted - version: "0.11.2" + version: "0.11.3" ansicolor: dependency: transitive description: @@ -37,90 +37,26 @@ packages: dependency: "direct main" description: name: app_links - sha256: "4e392b5eba997df356ca6021f28431ce1cfeb16758699553a94b13add874a3bb" + sha256: "42dc15aecf2618ace4ffb74a2e58a50e45cd1b9f2c17c8f0cafe4c297f08c815" url: "https://pub.dev" source: hosted - version: "3.5.0" - app_package_maker: - dependency: transitive - description: - name: app_package_maker - sha256: "0dc1949e09a60ec2d0b79b43c5237734e6d03f7a022919bdfe1b4789f4c3bfb0" - url: "https://pub.dev" - source: hosted - version: "0.0.9" - app_package_maker_aab: - dependency: transitive - description: - name: app_package_maker_aab - sha256: "44810e77dff3b3b54011270b01a42876e838766d6e85c98f9a33bfe61db51651" - url: "https://pub.dev" - source: hosted - version: "0.0.9" - app_package_maker_apk: - dependency: transitive - description: - name: app_package_maker_apk - sha256: "974e639cda26c2e18fffaba18f88797523731f5b5457056b25e92243c9191f61" - url: "https://pub.dev" - source: hosted - version: "0.0.9" - app_package_maker_deb: - dependency: transitive - description: - name: app_package_maker_deb - sha256: dcd4047cb67648e53afd61079a8baa3c8ea383668f068e3ce8da841f3728eb29 - url: "https://pub.dev" - source: hosted - version: "0.0.9" - app_package_maker_dmg: - dependency: transitive - description: - name: app_package_maker_dmg - sha256: e0410a51304f3fff3e3850696c8e56f53f71c990e097f1c325126ebe90d242c4 - url: "https://pub.dev" - source: hosted - version: "0.0.9" - app_package_maker_exe: - dependency: transitive - description: - name: app_package_maker_exe - sha256: "07e3899a3ae12e8b6cd80efc7281ccca6c9050d2810e0fdc0e7e614cf4bd8a02" - url: "https://pub.dev" - source: hosted - version: "0.0.9" - app_package_maker_ipa: - dependency: transitive - description: - name: app_package_maker_ipa - sha256: "1a11498506ba975d02a4715650701981a382a2161c81481911517b50b378cd65" - url: "https://pub.dev" - source: hosted - version: "0.0.9" - app_package_maker_zip: - dependency: transitive - description: - name: app_package_maker_zip - sha256: cef07a47c589036a4762fdc9e61b9022f0a2a2a9f69538109a0a952a7e668306 - url: "https://pub.dev" - source: hosted - version: "0.0.9" + version: "4.0.1" archive: dependency: transitive description: name: archive - sha256: ca12e6c9ac022f33fd89128e7007fb5e97ab6e814d4fa05dd8d4f2db1e3c69cb + sha256: "22600aa1e926be775fa5fe7e6894e7fb3df9efda8891c73f70fb3262399a432d" url: "https://pub.dev" source: hosted - version: "3.4.5" + version: "3.4.10" args: dependency: "direct main" description: name: args - sha256: eef6c46b622e0494a36c5a12d10d77fb4e855501a91c1b9ef9339326e58f0596 + sha256: "7cf60b9f0cc88203c5a190b4cd62a99feea42759a7fa695010eb5de1c0b2252a" url: "https://pub.dev" source: hosted - version: "2.4.2" + version: "2.5.0" async: dependency: "direct main" description: @@ -133,18 +69,18 @@ packages: dependency: "direct main" description: name: audio_service - sha256: a4d989f1225ea9621898d60f23236dcbfc04876fa316086c23c5c4af075dbac4 + sha256: "4547c312a94f9cb2c48b60823fb190767cbd63454a83c73049384d5d3cba4650" url: "https://pub.dev" source: hosted - version: "0.18.12" + version: "0.18.13" audio_service_mpris: dependency: "direct main" description: name: audio_service_mpris - sha256: "31be5de2db0c71b217157afce1974ac6d0ad329bd91deb1f19ad094d29340d8e" + sha256: a8d1583f9143d17b2facc994a99bd1ea257cec43adcb8d7349458555c62b570f url: "https://pub.dev" source: hosted - version: "0.1.0" + version: "0.1.3" audio_service_platform_interface: dependency: transitive description: @@ -157,18 +93,18 @@ packages: dependency: transitive description: name: audio_service_web - sha256: "523e64ddc914c714d53eec2da85bba1074f08cf26c786d4efb322de510815ea7" + sha256: "9d7d5ae5f98a5727f2580fad73062f2484f400eef6cef42919413268e62a363e" url: "https://pub.dev" source: hosted - version: "0.1.1" + version: "0.1.2" audio_session: dependency: "direct main" description: name: audio_session - sha256: "6fdf255ed3af86535c96452c33ecff1245990bb25a605bfb1958661ccc3d467f" + sha256: a49af9981eec5d7cd73b37bacb6ee73f8143a6a9f9bd5b6021e6c346b9b6cf4e url: "https://pub.dev" source: hosted - version: "0.1.18" + version: "0.1.19" auto_size_text: dependency: "direct main" description: @@ -261,18 +197,18 @@ packages: dependency: transitive description: name: build_daemon - sha256: "5f02d73eb2ba16483e693f80bee4f088563a820e47d1027d4cdfe62b5bb43e65" + sha256: "0343061a33da9c5810b2d6cee51945127d8f4c060b7fbdd9d54917f0a3feaaa1" url: "https://pub.dev" source: hosted - version: "4.0.0" + version: "4.0.1" build_resolvers: dependency: transitive description: name: build_resolvers - sha256: d912852cce27c9e80a93603db721c267716894462e7033165178b91138587972 + sha256: "339086358431fa15d7eca8b6a36e5d783728cf025e559b834f4609a1fcfb7b0a" url: "https://pub.dev" source: hosted - version: "2.3.2" + version: "2.4.2" build_runner: dependency: "direct dev" description: @@ -285,10 +221,10 @@ packages: dependency: transitive description: name: build_runner_core - sha256: "6d6ee4276b1c5f34f21fdf39425202712d2be82019983d52f351c94aafbc2c41" + sha256: "4ae8ffe5ac758da294ecf1802f2aff01558d8b1b00616aa7538ea9a8a5d50799" url: "https://pub.dev" source: hosted - version: "7.2.10" + version: "7.3.0" built_collection: dependency: transitive description: @@ -301,18 +237,18 @@ packages: dependency: transitive description: name: built_value - sha256: ff627b645b28fb8bdb69e645f910c2458fd6b65f6585c3a53e0626024897dedf + sha256: c7913a9737ee4007efedaffc968c049fd0f3d0e49109e778edc10de9426005cb url: "https://pub.dev" source: hosted - version: "8.6.2" + version: "8.9.2" buttons_tabbar: dependency: "direct main" description: name: buttons_tabbar - sha256: "781128180f3e76cf93c093183f10395c664983dbee20bc4da2025be70085c2da" + sha256: "3f0969c26574ef15c0c9ff1dee42c3c4b0d3563d2c8607804372490fb8b76896" url: "https://pub.dev" source: hosted - version: "1.3.7+1" + version: "1.3.8" cached_network_image: dependency: "direct main" description: @@ -341,10 +277,10 @@ packages: dependency: "direct main" description: name: catcher_2 - sha256: "73e251057b1b59442d58b5109d26401cfed850df21da44b028338d4f85f69105" + sha256: "3c8f6cedc8c5eab61192830096d4f303900a5d0bddbf96a07ff9f7a8d5ff8fcd" url: "https://pub.dev" source: hosted - version: "1.0.0" + version: "1.2.4" change_case: dependency: transitive description: @@ -381,10 +317,10 @@ packages: dependency: transitive description: name: cli_util - sha256: b8db3080e59b2503ca9e7922c3df2072cf13992354d5e944074ffa836fba43b7 + sha256: c05b7406fdabc7a49a3929d4af76bcaccbbffcbcdcf185b082e1ae07da323d19 url: "https://pub.dev" source: hosted - version: "0.4.0" + version: "0.4.1" clock: dependency: transitive description: @@ -397,10 +333,10 @@ packages: dependency: transitive description: name: code_builder - sha256: "315a598c7fbe77f22de1c9da7cfd6fd21816312f16ffa124453b4fc679e540f1" + sha256: f692079e25e7869c14132d39f223f8eec9830eb76131925143b2129c4bb01b37 url: "https://pub.dev" source: hosted - version: "4.6.0" + version: "4.10.0" collection: dependency: "direct main" description: @@ -429,10 +365,10 @@ packages: dependency: transitive description: name: cross_file - sha256: fd832b5384d0d6da4f6df60b854d33accaaeb63aa9e10e736a87381f08dee2cb + sha256: "55d7b444feb71301ef6b8838dbc1ae02e63dd48c8773f3810ff53bb1e2945b32" url: "https://pub.dev" source: hosted - version: "0.3.3+5" + version: "0.3.4+1" crypto: dependency: "direct main" description: @@ -449,14 +385,6 @@ packages: url: "https://pub.dev" source: hosted version: "1.0.0" - cupertino_icons: - dependency: "direct main" - description: - name: cupertino_icons - sha256: d57953e10f9f8327ce64a508a355f0b1ec902193f66288e8cb5070e7c47eeb2d - url: "https://pub.dev" - source: hosted - version: "1.0.6" curved_navigation_bar: dependency: "direct main" description: @@ -469,26 +397,26 @@ packages: dependency: "direct dev" description: name: custom_lint - sha256: "22bd87a362f433ba6aae127a7bac2838645270737f3721b180916d7c5946cb5d" + sha256: "7c0aec12df22f9082146c354692056677f1e70bc43471644d1fdb36c6fdda799" url: "https://pub.dev" source: hosted - version: "0.5.11" + version: "0.6.4" custom_lint_builder: dependency: transitive description: name: custom_lint_builder - sha256: "0d48e002438950f9582e574ef806b2bea5719d8d14c0f9f754fbad729bcf3b19" + sha256: d7dc41e709dde223806660268678be7993559e523eb3164e2a1425fd6f7615a9 url: "https://pub.dev" source: hosted - version: "0.5.14" + version: "0.6.4" custom_lint_core: dependency: transitive description: name: custom_lint_core - sha256: "2952837953022de610dacb464f045594854ced6506ac7f76af28d4a6490e189b" + sha256: a85e8f78f4c52f6c63cdaf8c872eb573db0231dcdf3c3a5906d493c1f8bc20e6 url: "https://pub.dev" source: hosted - version: "0.5.14" + version: "0.6.3" dart_des: dependency: transitive description: @@ -506,14 +434,22 @@ packages: url: "https://github.com/Tommypop2/dart_discord_rpc.git" source: git version: "0.0.3" + dart_mappable: + dependency: transitive + description: + name: dart_mappable + sha256: "47269caf2060533c29b823ff7fa9706502355ffcb61e7f2a374e3a0fb2f2c3f0" + url: "https://pub.dev" + source: hosted + version: "4.2.2" dart_style: dependency: transitive description: name: dart_style - sha256: "1efa911ca7086affd35f463ca2fc1799584fb6aa89883cf0af8e3664d6a02d55" + sha256: "99e066ce75c89d6b29903d788a7bb9369cf754f7b24bf70bf4b6d6d6b26853b9" url: "https://pub.dev" source: hosted - version: "2.3.2" + version: "2.3.6" dartx: dependency: transitive description: @@ -542,10 +478,10 @@ packages: dependency: "direct main" description: name: device_info_plus - sha256: "77f757b789ff68e4eaf9c56d1752309bd9f7ad557cb105b938a7f8eb89e59110" + sha256: eead12d1a1ed83d8283ab4c2f3fca23ac4082f29f25f29dff0f758f57d06ec91 url: "https://pub.dev" source: hosted - version: "9.1.2" + version: "10.1.0" device_info_plus_platform_interface: dependency: transitive description: @@ -566,18 +502,18 @@ packages: dependency: "direct main" description: name: dio - sha256: "49af28382aefc53562459104f64d16b9dfd1e8ef68c862d5af436cc8356ce5a8" + sha256: "11e40df547d418cc0c4900a9318b26304e665da6fa4755399a9ff9efd09034b5" url: "https://pub.dev" source: hosted - version: "5.4.1" + version: "5.4.3+1" disable_battery_optimization: dependency: "direct main" description: name: disable_battery_optimization - sha256: b3441975ab2a3ab0c19ed78e909a88d245ce689d43d17f9b23582b1ed41c047b + sha256: "6b2ba802f984af141faf1b6b5fb956d5ef01f9cd555597c35b9cc335a03185ba" url: "https://pub.dev" source: hosted - version: "1.1.0+1" + version: "1.1.1" dots_indicator: dependency: transitive description: @@ -607,18 +543,26 @@ packages: dependency: "direct main" description: name: envied - sha256: "60d3f5606c7b35bc6ef493e650d916b34351d8af2e58b7ac45881ba59dfcf039" + sha256: bbff9c76120e4dc5e2e36a46690cf0a26feb65e7765633f4e8d916bcd173a450 url: "https://pub.dev" source: hosted - version: "0.3.0+3" + version: "0.5.4+1" envied_generator: dependency: "direct dev" description: name: envied_generator - sha256: dfdbe5dc52863e54c036a4c4042afbdf1bd528cb4c1e638ecba26228ba72e9e5 + sha256: "517b70de08d13dcd40e97b4e5347e216a0b1c75c99e704f3c85c0474a392d14a" url: "https://pub.dev" source: hosted - version: "0.3.0+3" + version: "0.5.4+1" + equatable: + dependency: transitive + description: + name: equatable + sha256: c2b87cb7756efdf69892005af546c56c0b5037f54d2a88269b4f347a505e3ca2 + url: "https://pub.dev" + source: hosted + version: "2.0.5" fake_async: dependency: transitive description: @@ -631,10 +575,10 @@ packages: dependency: transitive description: name: ffi - sha256: "7bf0adc28a23d395f19f3f1eb21dd7cfd1dd9f8e1c50051c069122e6853bc878" + sha256: "493f37e7df1804778ff3a53bd691d8692ddf69702cf4c1c1096a2e41b4779e21" url: "https://pub.dev" source: hosted - version: "2.1.0" + version: "2.1.2" file: dependency: transitive description: @@ -647,34 +591,34 @@ packages: dependency: "direct main" description: name: file_picker - sha256: "4e42aacde3b993c5947467ab640882c56947d9d27342a5b6f2895b23956954a6" + sha256: d1d0ac3966b36dc3e66eeefb40280c17feb87fa2099c6e22e6a1fc959327bd03 url: "https://pub.dev" source: hosted - version: "6.1.1" + version: "8.0.0+1" file_selector: dependency: "direct main" description: name: file_selector - sha256: "84eaf3e034d647859167d1f01cfe7b6352488f34c1b4932635012b202014c25b" + sha256: "5019692b593455127794d5718304ff1ae15447dea286cdda9f0db2a796a1b828" url: "https://pub.dev" source: hosted - version: "1.0.1" + version: "1.0.3" file_selector_android: dependency: transitive description: name: file_selector_android - sha256: d41e165d6f798ca941d536e5dc93494d50e78c571c28ad60cfe0b0fefeb9f1e7 + sha256: "1cd66575f063b689e041aec836905ba7be18d76c9f0634d0d75daec825f67095" url: "https://pub.dev" source: hosted - version: "0.5.0+3" + version: "0.5.0+7" file_selector_ios: dependency: transitive description: name: file_selector_ios - sha256: b3fbdda64aa2e335df6e111f6b0f1bb968402ed81d2dd1fa4274267999aa32c2 + sha256: "0a1196a9c5795858aa315332da2fb5c4bcfdcb312d8a4e27651f765b87904431" url: "https://pub.dev" source: hosted - version: "0.5.1+6" + version: "0.5.1+9" file_selector_linux: dependency: transitive description: @@ -687,26 +631,26 @@ packages: dependency: transitive description: name: file_selector_macos - sha256: "182c3f8350cee659f7b115e956047ee3dc672a96665883a545e81581b9a82c72" + sha256: b15c3da8bd4908b9918111fa486903f5808e388b8d1c559949f584725a6594d6 url: "https://pub.dev" source: hosted - version: "0.9.3+2" + version: "0.9.3+3" file_selector_platform_interface: dependency: transitive description: name: file_selector_platform_interface - sha256: "0aa47a725c346825a2bd396343ce63ac00bda6eff2fbc43eabe99737dede8262" + sha256: a3994c26f10378a039faa11de174d7b78eb8f79e4dd0af2a451410c1a5c3f66b url: "https://pub.dev" source: hosted - version: "2.6.1" + version: "2.6.2" file_selector_web: dependency: transitive description: name: file_selector_web - sha256: dc6622c4d66cb1bee623ddcc029036603c6cc45c85e4a775bb06008d61c809c1 + sha256: "619e431b224711a3869e30dbd7d516f5f5a4f04b265013a50912f39e1abc88c8" url: "https://pub.dev" source: hosted - version: "0.9.2+1" + version: "0.9.4+1" file_selector_windows: dependency: transitive description: @@ -727,31 +671,15 @@ packages: dependency: "direct main" description: name: fluentui_system_icons - sha256: "7637cab80bd8d1ba762144cd85df79a7318c12ed5a66d166a9e4acbf24a4c412" + sha256: "1c860f10a0e74c5788ff8a650ae6074d9a544463ae269714f1044b32df52b978" url: "https://pub.dev" source: hosted - version: "1.1.214" + version: "1.1.234" flutter: dependency: "direct main" description: flutter source: sdk version: "0.0.0" - flutter_app_builder: - dependency: transitive - description: - name: flutter_app_builder - sha256: "9e5527919f62424f0fafaa3e8dfda8469caf63e465862e9866a0d60a37c00fcf" - url: "https://pub.dev" - source: hosted - version: "0.0.9" - flutter_app_packager: - dependency: transitive - description: - name: flutter_app_packager - sha256: b5bfb7113b49710c004c5f1ab6f08ac121418540d49e14825dd75e99810fa695 - url: "https://pub.dev" - source: hosted - version: "0.0.9" flutter_broadcasts: dependency: "direct main" description: @@ -768,15 +696,6 @@ packages: url: "https://pub.dev" source: hosted version: "3.3.1" - flutter_desktop_tools: - dependency: "direct main" - description: - path: "." - ref: "1f0bec3283626dcbd8ee2f54e238d096d8dea50e" - resolved-ref: "1f0bec3283626dcbd8ee2f54e238d096d8dea50e" - url: "https://github.com/KRTirtho/flutter_desktop_tools.git" - source: git - version: "0.0.1" flutter_displaymode: dependency: "direct main" description: @@ -785,14 +704,6 @@ packages: url: "https://pub.dev" source: hosted version: "0.6.0" - flutter_distributor: - dependency: "direct dev" - description: - name: flutter_distributor - sha256: "50d56df265e97396427ec42cc02374b72d08c71b3442d662b97fc089bd1705ea" - url: "https://pub.dev" - source: hosted - version: "0.0.2" flutter_driver: dependency: transitive description: flutter @@ -890,10 +801,10 @@ packages: dependency: transitive description: name: flutter_keyboard_visibility - sha256: "4983655c26ab5b959252ee204c2fffa4afeb4413cd030455194ec0caa3b8e7cb" + sha256: "98664be7be0e3ffca00de50f7f6a287ab62c763fc8c762e0a21584584a3ff4f8" url: "https://pub.dev" source: hosted - version: "5.4.1" + version: "6.0.0" flutter_keyboard_visibility_linux: dependency: transitive description: @@ -946,10 +857,10 @@ packages: dependency: "direct dev" description: name: flutter_lints - sha256: e2a421b7e59244faef694ba7b30562e489c2b489866e505074eb005cd7060db7 + sha256: "9e8c3858111da373efc5aa341de011d9bd23e2c5c5e0c62bccf32438e192d7b1" url: "https://pub.dev" source: hosted - version: "3.0.1" + version: "3.0.2" flutter_localizations: dependency: "direct main" description: flutter @@ -959,42 +870,42 @@ packages: dependency: transitive description: name: flutter_mailer - sha256: a935e9caa842877e8ed56109afb75b86e6488edbcd4696a5ac02b327a48fcd8a + sha256: "4fffaa35e911ff5ec2e5a4ebbca62c372e99a154eb3bb2c0bf79f09adf6ecf4c" url: "https://pub.dev" source: hosted - version: "2.1.1" + version: "2.1.2" flutter_native_splash: dependency: "direct main" description: name: flutter_native_splash - sha256: "558f10070f03ee71f850a78f7136ab239a67636a294a44a06b6b7345178edb1e" + sha256: edf39bcf4d74aca1eb2c1e43c3e445fd9f494013df7f0da752fefe72020eedc0 url: "https://pub.dev" source: hosted - version: "2.3.10" + version: "2.4.0" flutter_plugin_android_lifecycle: dependency: transitive description: name: flutter_plugin_android_lifecycle - sha256: f185ac890306b5779ecbd611f52502d8d4d63d27703ef73161ca0407e815f02c + sha256: "8cf40eebf5dec866a6d1956ad7b4f7016e6c0cc69847ab946833b7d43743809f" url: "https://pub.dev" source: hosted - version: "2.0.16" + version: "2.0.19" flutter_riverpod: dependency: "direct main" description: name: flutter_riverpod - sha256: "4bce556b7ecbfea26109638d5237684538d4abc509d253e6c5c4c5733b360098" + sha256: "0f1974eff5bbe774bf1d870e406fc6f29e3d6f1c46bd9c58e7172ff68a785d7d" url: "https://pub.dev" source: hosted - version: "2.4.10" + version: "2.5.1" flutter_rust_bridge: dependency: transitive description: name: flutter_rust_bridge - sha256: e12415c3bce49bcbc3fed383f0ea41ad7d828f6cf0eccba0588ffa5a812fe522 + sha256: "02720226035257ad0b571c1256f43df3e1556a499f6bcb004849a0faaa0e87f0" url: "https://pub.dev" source: hosted - version: "1.82.1" + version: "1.82.6" flutter_secure_storage: dependency: "direct main" description: @@ -1047,10 +958,10 @@ packages: dependency: "direct main" description: name: flutter_sharing_intent - sha256: "6eb896e6523b735e8230eeb206fd3b9f220f11ce879c2400a90b443147036ff9" + sha256: "785ffc391822641457f930eb477c91c2f598a888f50b8fbb40d481ee01c7e719" url: "https://pub.dev" source: hosted - version: "1.1.0" + version: "1.1.1" flutter_svg: dependency: "direct main" description: @@ -1073,10 +984,10 @@ packages: dependency: transitive description: name: fluttertoast - sha256: "474f7d506230897a3cd28c965ec21c5328ae5605fc9c400cd330e9e9d6ac175c" + sha256: "81b68579e23fcbcada2db3d50302813d2371664afe6165bc78148050ab94bf66" url: "https://pub.dev" source: hosted - version: "8.2.2" + version: "8.2.5" form_validator: dependency: "direct main" description: @@ -1089,10 +1000,10 @@ packages: dependency: "direct dev" description: name: freezed - sha256: "6c5031daae12c7072b3a87eff98983076434b4889ef2a44384d0cae3f82372ba" + sha256: a434911f643466d78462625df76fd9eb13e57348ff43fe1f77bbe909522c67a1 url: "https://pub.dev" source: hosted - version: "2.4.6" + version: "2.5.2" freezed_annotation: dependency: "direct main" description: @@ -1105,10 +1016,10 @@ packages: dependency: transitive description: name: frontend_server_client - sha256: "408e3ca148b31c20282ad6f37ebfa6f4bdc8fede5b74bc2f08d9d92b55db3612" + sha256: f64a0333a82f30b0cca061bc3d143813a486dc086b574bfb233b7c1372427694 url: "https://pub.dev" source: hosted - version: "3.2.0" + version: "4.0.0" fuchsia_remote_debug_protocol: dependency: transitive description: flutter @@ -1150,10 +1061,10 @@ packages: dependency: "direct main" description: name: google_fonts - sha256: f0b8d115a13ecf827013ec9fc883390ccc0e87a96ed5347a3114cac177ef18e8 + sha256: b1ac0fe2832c9cc95e5e88b57d627c5e68c223b9657f4b96e1487aa9098c7b82 url: "https://pub.dev" source: hosted - version: "6.1.0" + version: "6.2.1" graphs: dependency: transitive description: @@ -1206,10 +1117,10 @@ packages: dependency: "direct main" description: name: hooks_riverpod - sha256: "758b07eba336e3cbacbd81dba481f2228a14102083fdde07045e8514e8054c49" + sha256: "45b2030a18bcd6dbd680c2c91bc3b33e3fe7c323e3acb5ecec93a613e2fbaa8a" url: "https://pub.dev" source: hosted - version: "2.4.10" + version: "2.5.1" hotreloader: dependency: transitive description: @@ -1270,42 +1181,42 @@ packages: dependency: transitive description: name: image - sha256: "028f61960d56f26414eb616b48b04eb37d700cbe477b7fb09bf1d7ce57fd9271" + sha256: "4c68bfd5ae83e700b5204c1e74451e7bf3cf750e6843c6e158289cf56bda018e" url: "https://pub.dev" source: hosted - version: "4.1.3" + version: "4.1.7" image_picker: dependency: "direct main" description: name: image_picker - sha256: "7d7f2768df2a8b0a3cefa5ef4f84636121987d403130e70b17ef7e2cf650ba84" + sha256: fe9ee64ccb8d599a5dfb0e21cc6652232c610bcf667af4e79b9eb175cc30a7a5 url: "https://pub.dev" source: hosted - version: "1.0.4" + version: "1.1.0" image_picker_android: dependency: transitive description: name: image_picker_android - sha256: "47da2161c2e9f8f8a9cbbd89d466d174333fbdd769aeed848912e0b16d9cb369" + sha256: "8e75431a62b7feb4fd55cb4a5c6f0ac4564460ec5dc09f9c4a0d50a5ce7c4cb9" url: "https://pub.dev" source: hosted - version: "0.8.8" + version: "0.8.10" image_picker_for_web: dependency: transitive description: name: image_picker_for_web - sha256: "50bc9ae6a77eea3a8b11af5eb6c661eeb858fdd2f734c2a4fd17086922347ef7" + sha256: "5d6eb13048cd47b60dbf1a5495424dea226c5faf3950e20bf8120a58efb5b5f3" url: "https://pub.dev" source: hosted - version: "3.0.1" + version: "3.0.4" image_picker_ios: dependency: transitive description: name: image_picker_ios - sha256: c5538cacefacac733c724be7484377923b476216ad1ead35a0d2eadcdc0fc497 + sha256: f4a6f62be96d6fd268f32a6bf8ef444cd8e3fff64d16923c6e6fe55e0c84a761 url: "https://pub.dev" source: hosted - version: "0.8.8+2" + version: "0.8.10" image_picker_linux: dependency: transitive description: @@ -1326,10 +1237,10 @@ packages: dependency: transitive description: name: image_picker_platform_interface - sha256: ed9b00e63977c93b0d2d2b343685bed9c324534ba5abafbb3dfbd6a780b1b514 + sha256: "9ec26d410ff46f483c5519c29c02ef0e02e13a543f882b152d4bfd2f06802f80" url: "https://pub.dev" source: hosted - version: "2.9.1" + version: "2.10.0" image_picker_windows: dependency: transitive description: @@ -1355,10 +1266,10 @@ packages: dependency: "direct main" description: name: introduction_screen - sha256: ef5a5479a8e06a84b9a7eff16c698b9b82f70cd1b6203b264bc3686f9bfb77e2 + sha256: "325f26e86fa3c3e86e6ab2bbc1fda860c9e6eae5ff29166fc2a3cab8f710d5b5" url: "https://pub.dev" source: hosted - version: "3.1.11" + version: "3.1.14" io: dependency: transitive description: @@ -1432,21 +1343,21 @@ packages: source: hosted version: "3.0.0" local_notifier: - dependency: transitive + dependency: "direct main" description: name: local_notifier - sha256: cc855aa6362c8840e3d3b35b1c3b058a3a8becdb2b03d5a9aa3f3a1e861f0a03 + sha256: f6cfc933c6fbc961f4e52b5c880f68e41b2d3cd29aad557cc654fd211093a025 url: "https://pub.dev" source: hosted - version: "0.1.5" + version: "0.1.6" logger: dependency: "direct main" description: name: logger - sha256: ba3bc83117b2b49bdd723c0ea7848e8285a0fbc597ba09203b20d329d020c24a + sha256: "8c94b8c219e7e50194efc8771cd0e9f10807d8d3e219af473d89b06cc2ee4e04" url: "https://pub.dev" source: hosted - version: "2.0.2" + version: "2.2.0" logging: dependency: transitive description: @@ -1467,10 +1378,10 @@ packages: dependency: transitive description: name: mailer - sha256: "57f6dd1496699999a7bfd0aa6be0645384f477f4823e16d4321c40a434346382" + sha256: d25d89555c1031abacb448f07b801d7c01b4c21d4558e944b12b64394c84a3cb url: "https://pub.dev" source: hosted - version: "6.0.1" + version: "6.1.0" matcher: dependency: transitive description: @@ -1491,26 +1402,26 @@ packages: dependency: "direct main" description: name: media_kit - sha256: "92c7f59e075d74471b31e703f81ccc1d7102739ebcce945b30a6417fa2f751d5" + sha256: "3289062540e3b8b9746e5c50d95bd78a9289826b7227e253dff806d002b9e67a" url: "https://pub.dev" source: hosted - version: "1.1.7" + version: "1.1.10+1" media_kit_libs_android_audio: dependency: transitive description: name: media_kit_libs_android_audio - sha256: "1d9ba8814e58a12ae69014884abf96893d38e444abfb806ff38896dfe089dd15" + sha256: "3d2df5c09d3f3ff7c55b53bf955e46712f76483e77562a5a017439a3ea85ce88" url: "https://pub.dev" source: hosted - version: "1.3.5" + version: "1.3.6" media_kit_libs_audio: dependency: "direct main" description: name: media_kit_libs_audio - sha256: "9ccf9019edc220b8d0bfa1f53a91aa2cf2506ac860b4d5774c9d6bbdd49796ca" + sha256: f3f91df69848005363b3ae0ef7971a90edbd80a9365195684ef26c9a6ac8833f url: "https://pub.dev" source: hosted - version: "1.0.3" + version: "1.0.4" media_kit_libs_ios_audio: dependency: transitive description: @@ -1551,6 +1462,14 @@ packages: url: "https://pub.dev" source: hosted version: "1.0.8" + menu_base: + dependency: transitive + description: + name: menu_base + sha256: "820368014a171bd1241030278e6c2617354f492f5c703d7b7d4570a6b8b84405" + url: "https://pub.dev" + source: hosted + version: "0.1.1" meta: dependency: transitive description: @@ -1571,10 +1490,10 @@ packages: dependency: "direct main" description: name: mime - sha256: e4ff8e8564c03f255408decd16e7899da1733852a9110a58fe6d1b817684a63e + sha256: "2e123074287cc9fd6c09de8336dae606d1ddb88d9ac47358826db698c176a1f2" url: "https://pub.dev" source: hosted - version: "1.0.4" + version: "1.0.5" nested: dependency: transitive description: @@ -1611,10 +1530,10 @@ packages: dependency: "direct main" description: name: package_info_plus - sha256: "6ff267fcd9d48cb61c8df74a82680e8b82e940231bb5f68356672fde0397334a" + sha256: cb44f49b6e690fa766f023d5b22cac6b9affe741dd792b6ac7ad4fabe0d7b097 url: "https://pub.dev" source: hosted - version: "4.1.0" + version: "6.0.0" package_info_plus_platform_interface: dependency: transitive description: @@ -1659,26 +1578,26 @@ packages: dependency: "direct main" description: name: path_provider - sha256: a1aa8aaa2542a6bc57e381f132af822420216c80d4781f7aa085ca3229208aaa + sha256: c9e7d3a4cd1410877472158bee69963a4579f78b68c65a2b7d40d1a7a88bb161 url: "https://pub.dev" source: hosted - version: "2.1.1" + version: "2.1.3" path_provider_android: dependency: transitive description: name: path_provider_android - sha256: "6b8b19bd80da4f11ce91b2d1fb931f3006911477cec227cce23d3253d80df3f1" + sha256: a248d8146ee5983446bf03ed5ea8f6533129a12b11f12057ad1b4a67a2b3b41d url: "https://pub.dev" source: hosted - version: "2.2.0" + version: "2.2.4" path_provider_foundation: dependency: transitive description: name: path_provider_foundation - sha256: "19314d595120f82aca0ba62787d58dde2cc6b5df7d2f0daf72489e38d1b57f2d" + sha256: "5a7999be66e000916500be4f15a3633ebceb8302719b47b9cc49ce924125350f" url: "https://pub.dev" source: hosted - version: "2.3.1" + version: "2.3.2" path_provider_linux: dependency: transitive description: @@ -1691,10 +1610,10 @@ packages: dependency: transitive description: name: path_provider_platform_interface - sha256: "94b1e0dd80970c1ce43d5d4e050a9918fce4f4a775e6142424c30a29a363265c" + sha256: "88f5779f72ba699763fa3a3b06aa4bf6de76c8e5de842cf6f29e2e06476c2334" url: "https://pub.dev" source: hosted - version: "2.1.1" + version: "2.1.2" path_provider_windows: dependency: transitive description: @@ -1707,42 +1626,50 @@ packages: dependency: "direct main" description: name: permission_handler - sha256: "284a66179cabdf942f838543e10413246f06424d960c92ba95c84439154fcac8" + sha256: "18bf33f7fefbd812f37e72091a15575e72d5318854877e0e4035a24ac1113ecb" url: "https://pub.dev" source: hosted - version: "11.0.1" + version: "11.3.1" permission_handler_android: dependency: transitive description: name: permission_handler_android - sha256: ace7d15a3d1a4a0b91c041d01e5405df221edb9de9116525efc773c74e6fc790 + sha256: "1acac6bae58144b442f11e66621c062aead9c99841093c38f5bcdcc24c1c3474" url: "https://pub.dev" source: hosted - version: "11.0.5" + version: "12.0.5" permission_handler_apple: dependency: transitive description: name: permission_handler_apple - sha256: "99e220bce3f8877c78e4ace901082fb29fa1b4ebde529ad0932d8d664b34f3f5" + sha256: e9ad66020b89ff1b63908f247c2c6f931c6e62699b756ef8b3c4569350cd8662 url: "https://pub.dev" source: hosted - version: "9.1.4" + version: "9.4.4" + permission_handler_html: + dependency: transitive + description: + name: permission_handler_html + sha256: "54bf176b90f6eddd4ece307e2c06cf977fb3973719c35a93b85cc7093eb6070d" + url: "https://pub.dev" + source: hosted + version: "0.1.1" permission_handler_platform_interface: dependency: transitive description: name: permission_handler_platform_interface - sha256: f2343e9fa9c22ae4fd92d4732755bfe452214e7189afcc097380950cf567b4b2 + sha256: "48d4fcf201a1dad93ee869ab0d4101d084f49136ec82a8a06ed9cfeacab9fd20" url: "https://pub.dev" source: hosted - version: "3.11.5" + version: "4.2.1" permission_handler_windows: dependency: transitive description: name: permission_handler_windows - sha256: cc074aace208760f1eee6aa4fae766b45d947df85bc831cde77009cdb4720098 + sha256: "1a790728016f79a41216d88672dbc5df30e686e811ad4e698bfc51f76ad91f1e" url: "https://pub.dev" source: hosted - version: "0.1.3" + version: "0.2.1" petitparser: dependency: transitive description: @@ -1754,11 +1681,10 @@ packages: piped_client: dependency: "direct main" description: - path: "." - ref: HEAD - resolved-ref: "64631732eefe3d93889756dc2e4ff5c8523ed763" - url: "https://github.com/KRTirtho/piped_client.git" - source: git + name: piped_client + sha256: "87b04b2ebf4e008cfbb0ac85e9920ab3741f5aa697be2dd44919658a3297a4bc" + url: "https://pub.dev" + source: hosted version: "0.1.1" platform: dependency: transitive @@ -1772,18 +1698,18 @@ packages: dependency: transitive description: name: plugin_platform_interface - sha256: da3fdfeccc4d4ff2da8f8c556704c08f912542c5fb3cf2233ed75372384a034d + sha256: "4820fbfdb9478b1ebae27888254d445073732dae3d6ea81f0b7e06d5dedc3f02" url: "https://pub.dev" source: hosted - version: "2.1.6" + version: "2.1.8" pointycastle: dependency: transitive description: name: pointycastle - sha256: "7c1e5f0d23c9016c5bbd8b1473d0d3fb3fc851b876046039509e18e0c7485f2c" + sha256: "70fe966348fe08c34bf929582f1d8247d9d9408130723206472b4687227e4333" url: "https://pub.dev" source: hosted - version: "3.7.3" + version: "3.8.0" pool: dependency: transitive description: @@ -1812,18 +1738,18 @@ packages: dependency: transitive description: name: provider - sha256: cdbe7530b12ecd9eb455bdaa2fcb8d4dad22e80b8afb4798b41479d5ce26847f + sha256: c8a055ee5ce3fd98d6fc872478b03823ffdb448699c6ebdbbc71d59b596fd48c url: "https://pub.dev" source: hosted - version: "6.0.5" + version: "6.1.2" pub_api_client: dependency: "direct main" description: name: pub_api_client - sha256: d456816ef5142906a22dc56e37be6bef6cb0276f0a26c11d1f7d277868202e71 + sha256: cc3d2c93df3823553de6a3e7d3ac09a3f43f8c271af4f43c2795266090ac9625 url: "https://pub.dev" source: hosted - version: "2.6.0" + version: "2.7.0" pub_semver: dependency: transitive description: @@ -1852,10 +1778,10 @@ packages: dependency: transitive description: name: puppeteer - sha256: eedeaae6ec5d2e54f9ae22ab4d6b3dda2e8791c356cc783046d06c287ffe11d8 + sha256: "6833edca01b1e9dcdd9a6e41bad84b706dfba4366d095c4edff64b00c02ac472" url: "https://pub.dev" source: hosted - version: "3.6.0" + version: "3.8.0" quiver: dependency: transitive description: @@ -1864,30 +1790,38 @@ packages: url: "https://pub.dev" source: hosted version: "3.2.1" + recase: + dependency: transitive + description: + name: recase + sha256: e4eb4ec2dcdee52dcf99cb4ceabaffc631d7424ee55e56f280bc039737f89213 + url: "https://pub.dev" + source: hosted + version: "4.1.0" riverpod: dependency: transitive description: name: riverpod - sha256: "548e2192eb7aeb826eb89387f814edb76594f3363e2c0bb99dd733d795ba3589" + sha256: f21b32ffd26a36555e501b04f4a5dca43ed59e16343f1a30c13632b2351dfa4d url: "https://pub.dev" source: hosted - version: "2.5.0" + version: "2.5.1" riverpod_analyzer_utils: dependency: transitive description: name: riverpod_analyzer_utils - sha256: d72d7096964baf288b55619fe48100001fc4564ab7923ed0a7f5c7650e03c0d6 + sha256: "8b71f03fc47ae27d13769496a1746332df4cec43918aeba9aff1e232783a780f" url: "https://pub.dev" source: hosted - version: "0.3.4" + version: "0.5.1" riverpod_lint: dependency: "direct dev" description: name: riverpod_lint - sha256: "70198738c3047ae4f6517ef1a2011a8514a980a52576c7f629a3a08810319a02" + sha256: "3c67c14ccd16f0c9d53e35ef70d06cd9d072e2fb14557326886bbde903b230a5" url: "https://pub.dev" source: hosted - version: "2.1.1" + version: "2.3.10" rxdart: dependency: transitive description: @@ -1933,34 +1867,34 @@ packages: dependency: transitive description: name: sentry - sha256: "39c23342fc96105da449914f7774139a17a0ca8a4e70d9ad5200171f7e47d6ba" + sha256: "19a267774906ca3a3c4677fc7e9582ea9da79ae9a28f84bbe4885dac2c269b70" url: "https://pub.dev" source: hosted - version: "7.9.0" + version: "7.20.0" shared_preferences: dependency: "direct main" description: name: shared_preferences - sha256: "81429e4481e1ccfb51ede496e916348668fd0921627779233bd24cc3ff6abd02" + sha256: d3bbe5553a986e83980916ded2f0b435ef2e1893dfaa29d5a7a790d0eca12180 url: "https://pub.dev" source: hosted - version: "2.2.2" + version: "2.2.3" shared_preferences_android: dependency: transitive description: name: shared_preferences_android - sha256: "8568a389334b6e83415b6aae55378e158fbc2314e074983362d20c562780fb06" + sha256: "1ee8bf911094a1b592de7ab29add6f826a7331fb854273d55918693d5364a1f2" url: "https://pub.dev" source: hosted - version: "2.2.1" + version: "2.2.2" shared_preferences_foundation: dependency: transitive description: name: shared_preferences_foundation - sha256: "7bf53a9f2d007329ee6f3df7268fd498f8373602f943c975598bbb34649b62a7" + sha256: "7708d83064f38060c7b39db12aefe449cb8cdc031d6062280087bc4cdb988f5c" url: "https://pub.dev" source: hosted - version: "2.3.4" + version: "2.3.5" shared_preferences_linux: dependency: transitive description: @@ -1973,18 +1907,18 @@ packages: dependency: transitive description: name: shared_preferences_platform_interface - sha256: d4ec5fc9ebb2f2e056c617112aa75dcf92fc2e4faaf2ae999caa297473f75d8a + sha256: "22e2ecac9419b4246d7c22bfbbda589e3acf5c0351137d87dd2939d984d37c3b" url: "https://pub.dev" source: hosted - version: "2.3.1" + version: "2.3.2" shared_preferences_web: dependency: transitive description: name: shared_preferences_web - sha256: d762709c2bbe80626ecc819143013cc820fa49ca5e363620ee20a8b15a3e3daf + sha256: "9aee1089b36bd2aafe06582b7d7817fd317ef05fc30e6ba14bff247d0933042a" url: "https://pub.dev" source: hosted - version: "2.2.1" + version: "2.3.0" shared_preferences_windows: dependency: transitive description: @@ -2025,22 +1959,30 @@ packages: url: "https://pub.dev" source: hosted version: "1.0.4" + shortid: + dependency: transitive + description: + name: shortid + sha256: d0b40e3dbb50497dad107e19c54ca7de0d1a274eb9b4404991e443dadb9ebedb + url: "https://pub.dev" + source: hosted + version: "0.1.2" sidebarx: dependency: "direct main" description: name: sidebarx - sha256: "7042d64844b8e64ca5c17e70d89b49df35b54a26c015b90000da9741eab70bc0" + sha256: abe39d6db237fb8e25c600e8039ffab80fa7fe71acab03e9c378c31f912d2766 url: "https://pub.dev" source: hosted - version: "0.16.3" + version: "0.17.1" simple_icons: dependency: "direct main" description: name: simple_icons - sha256: "8aa6832dc7a263a3213e40ecbf1328a392308c809d534a3b860693625890483b" + sha256: "30067d70a9d72923fbc80e142e17fa46085dfa970e66bc4bede3be4819d05901" url: "https://pub.dev" source: hosted - version: "7.10.0" + version: "10.1.3" skeleton_text: dependency: "direct main" description: @@ -2053,10 +1995,10 @@ packages: dependency: "direct main" description: name: skeletonizer - sha256: ff4c36e826efd5288d7a84e7619a6e9be8185d3064cecf101a9133762f3b401b + sha256: "9a3ae2f4ee4349bdbed3292d04586a1315a44745d2c454684f82f0c46dbeabf9" url: "https://pub.dev" source: hosted - version: "0.8.0" + version: "1.1.1" sky_engine: dependency: transitive description: flutter @@ -2074,18 +2016,18 @@ packages: dependency: "direct main" description: name: smtc_windows - sha256: aba2bad5ddfaf595496db04df3d9fdb54fb128fc1f39c8f024945a67455388fe + sha256: "799bbe0f8e4436da852c5dcc0be482c97b8ae0f504f65c6b750cd239b4835aa0" url: "https://pub.dev" source: hosted - version: "0.1.1" + version: "0.1.2" source_gen: dependency: transitive description: name: source_gen - sha256: fc0da689e5302edb6177fdd964efcb7f58912f43c28c2047a808f5bfff643d16 + sha256: "14658ba5f669685cd3d63701d01b31ea748310f7ab854e471962670abcf57832" url: "https://pub.dev" source: hosted - version: "1.4.0" + version: "1.5.0" source_helper: dependency: transitive description: @@ -2106,26 +2048,34 @@ packages: dependency: "direct main" description: name: spotify - sha256: "2308a84511c18ec1e72515a57e28abb1467389549d571c460732b4538c2e34de" + sha256: "50bd5a07b580ee441d0b4d81227185ada768332c353671aa7555ea47cc68eb9e" url: "https://pub.dev" source: hosted - version: "0.13.3" + version: "0.13.5" + sprintf: + dependency: transitive + description: + name: sprintf + sha256: "1fc9ffe69d4df602376b52949af107d8f5703b77cda567c4d7d86a0693120f23" + url: "https://pub.dev" + source: hosted + version: "7.0.0" sqflite: dependency: transitive description: name: sqflite - sha256: "591f1602816e9c31377d5f008c2d9ef7b8aca8941c3f89cc5fd9d84da0c38a9a" + sha256: "5ce2e1a15e822c3b4bfb5400455775e421da7098eed8adc8f26298ada7c9308c" url: "https://pub.dev" source: hosted - version: "2.3.0" + version: "2.3.3" sqflite_common: dependency: transitive description: name: sqflite_common - sha256: "1b92f368f44b0dee2425bb861cfa17b6f6cf3961f762ff6f941d20b33355660a" + sha256: "3da423ce7baf868be70e2c0976c28a1bb2f73644268b7ffa7d2e08eab71f16a4" url: "https://pub.dev" source: hosted - version: "2.5.0" + version: "2.5.4" stack_trace: dependency: transitive description: @@ -2138,10 +2088,10 @@ packages: dependency: transitive description: name: state_notifier - sha256: "8fe42610f179b843b12371e40db58c9444f8757f8b69d181c97e50787caed289" + sha256: b8677376aa54f2d7c58280d5a007f9e8774f1968d1fb1c096adcb4792fba29bb url: "https://pub.dev" source: hosted - version: "0.7.2+1" + version: "1.0.0" stream_channel: dependency: transitive description: @@ -2186,10 +2136,10 @@ packages: dependency: transitive description: name: synchronized - sha256: "5fcbd27688af6082f5abd611af56ee575342c30e87541d0245f7ff99faa02c60" + sha256: "539ef412b170d65ecdafd780f924e5be3f60032a1128df156adad6c5b373d558" url: "https://pub.dev" source: hosted - version: "3.1.0" + version: "3.1.0+1" system_theme: dependency: "direct main" description: @@ -2206,14 +2156,6 @@ packages: url: "https://pub.dev" source: hosted version: "0.0.2" - system_tray: - dependency: "direct overridden" - description: - name: system_tray - sha256: "087edb877f22f286d82d42f330fa640138c192e98aa9d20c2b83aa4e406bb432" - url: "https://pub.dev" - source: hosted - version: "2.0.2" term_glyph: dependency: transitive description: @@ -2234,10 +2176,10 @@ packages: dependency: transitive description: name: time - sha256: "83427e11d9072e038364a5e4da559e85869b227cf699a541be0da74f14140124" + sha256: ad8e018a6c9db36cb917a031853a1aae49467a93e0d464683e029537d848c221 url: "https://pub.dev" source: hosted - version: "2.1.3" + version: "2.1.4" timezone: dependency: "direct main" description: @@ -2262,6 +2204,14 @@ packages: url: "https://pub.dev" source: hosted version: "1.0.0" + tray_manager: + dependency: "direct main" + description: + name: tray_manager + sha256: e0ac9a88b2700f366b8629b97e8663b6ef450a2f169560a685dc167bfe9c9c29 + url: "https://pub.dev" + source: hosted + version: "0.2.2" tuple: dependency: transitive description: @@ -2270,6 +2220,14 @@ packages: url: "https://pub.dev" source: hosted version: "2.0.2" + type_plus: + dependency: transitive + description: + name: type_plus + sha256: d5d1019471f0d38b91603adb9b5fd4ce7ab903c879d2fbf1a3f80a630a03fcc9 + url: "https://pub.dev" + source: hosted + version: "2.1.1" typed_data: dependency: transitive description: @@ -2314,74 +2272,74 @@ packages: dependency: "direct main" description: name: url_launcher - sha256: "47e208a6711459d813ba18af120d9663c20bdf6985d6ad39fe165d2538378d27" + sha256: "6ce1e04375be4eed30548f10a315826fd933c1e493206eab82eed01f438c8d2e" url: "https://pub.dev" source: hosted - version: "6.1.14" + version: "6.2.6" url_launcher_android: dependency: transitive description: name: url_launcher_android - sha256: b04af59516ab45762b2ca6da40fa830d72d0f6045cd97744450b73493fa76330 + sha256: "360a6ed2027f18b73c8d98e159dda67a61b7f2e0f6ec26e86c3ada33b0621775" url: "https://pub.dev" source: hosted - version: "6.1.0" + version: "6.3.1" url_launcher_ios: dependency: transitive description: name: url_launcher_ios - sha256: "7c65021d5dee51813d652357bc65b8dd4a6177082a9966bc8ba6ee477baa795f" + sha256: "9149d493b075ed740901f3ee844a38a00b33116c7c5c10d7fb27df8987fb51d5" url: "https://pub.dev" source: hosted - version: "6.1.5" + version: "6.2.5" url_launcher_linux: dependency: transitive description: name: url_launcher_linux - sha256: b651aad005e0cb06a01dbd84b428a301916dc75f0e7ea6165f80057fee2d8e8e + sha256: ab360eb661f8879369acac07b6bb3ff09d9471155357da8443fd5d3cf7363811 url: "https://pub.dev" source: hosted - version: "3.0.6" + version: "3.1.1" url_launcher_macos: dependency: transitive description: name: url_launcher_macos - sha256: b55486791f666e62e0e8ff825e58a023fd6b1f71c49926483f1128d3bbd8fe88 + sha256: b7244901ea3cf489c5335bdacda07264a6e960b1c1b1a9f91e4bc371d9e68234 url: "https://pub.dev" source: hosted - version: "3.0.7" + version: "3.1.0" url_launcher_platform_interface: dependency: transitive description: name: url_launcher_platform_interface - sha256: "95465b39f83bfe95fcb9d174829d6476216f2d548b79c38ab2506e0458787618" + sha256: "552f8a1e663569be95a8190206a38187b531910283c3e982193e4f2733f01029" url: "https://pub.dev" source: hosted - version: "2.1.5" + version: "2.3.2" url_launcher_web: dependency: transitive description: name: url_launcher_web - sha256: "2942294a500b4fa0b918685aff406773ba0a4cd34b7f42198742a94083020ce5" + sha256: "8d9e750d8c9338601e709cd0885f95825086bd8b642547f26bda435aade95d8a" url: "https://pub.dev" source: hosted - version: "2.0.20" + version: "2.3.1" url_launcher_windows: dependency: transitive description: name: url_launcher_windows - sha256: "95fef3129dc7cfaba2bc3d5ba2e16063bb561fc6d78e63eee16162bc70029069" + sha256: ecf9725510600aa2bb6d7ddabe16357691b6d2805f66216a97d1b881e21beff7 url: "https://pub.dev" source: hosted - version: "3.0.8" + version: "3.1.1" uuid: dependency: "direct main" description: name: uuid - sha256: "648e103079f7c64a36dc7d39369cabb358d377078a051d6ae2ad3aa539519313" + sha256: "814e9e88f21a176ae1359149021870e87f7cddaf633ab678a5d2b0bff7fd1ba8" url: "https://pub.dev" source: hosted - version: "3.0.7" + version: "4.4.0" vector_math: dependency: transitive description: @@ -2434,18 +2392,18 @@ packages: dependency: transitive description: name: web - sha256: "1d9158c616048c38f712a6646e317a3426da10e884447626167240d45209cbad" + sha256: "97da13628db363c635202ad97068d47c5b8aa555808e7a9411963c533b449b27" url: "https://pub.dev" source: hosted - version: "0.5.0" + version: "0.5.1" web_socket_channel: dependency: "direct main" description: name: web_socket_channel - sha256: "1d8e795e2a8b3730c41b8a98a2dff2e0fb57ae6f0764a1c46ec5915387d257b2" + sha256: "58c6666b342a38816b2e7e50ed0f1e261959630becd4c879c4f26bfa14aa5a42" url: "https://pub.dev" source: hosted - version: "2.4.4" + version: "2.4.5" webdriver: dependency: transitive description: @@ -2466,26 +2424,26 @@ packages: dependency: transitive description: name: win32 - sha256: "9e82a402b7f3d518fb9c02d0e9ae45952df31b9bf34d77baf19da2de03fc2aaa" + sha256: "0a989dc7ca2bb51eac91e8fd00851297cfffd641aa7538b165c62637ca0eaa4a" url: "https://pub.dev" source: hosted - version: "5.0.7" + version: "5.4.0" win32_registry: dependency: "direct main" description: name: win32_registry - sha256: "41fd8a189940d8696b1b810efb9abcf60827b6cbfab90b0c43e8439e3a39d85a" + sha256: "10589e0d7f4e053f2c61023a31c9ce01146656a70b7b7f0828c0b46d7da2a9bb" url: "https://pub.dev" source: hosted - version: "1.1.2" + version: "1.1.3" window_manager: dependency: "direct main" description: name: window_manager - sha256: "6ee795be9124f90660ea9d05e581a466de19e1c89ee74fc4bf528f60c8600edd" + sha256: b3c895bdf936c77b83c5254bec2e6b3f066710c1f89c38b20b8acc382b525494 url: "https://pub.dev" source: hosted - version: "0.3.6" + version: "0.3.8" window_size: dependency: "direct main" description: @@ -2499,10 +2457,10 @@ packages: dependency: transitive description: name: xdg_directories - sha256: "589ada45ba9e39405c198fe34eb0f607cddb2108527e658136120892beac46d2" + sha256: faea9dee56b520b55a566385b84f2e8de55e7496104adada9962e0bd11bcff1d url: "https://pub.dev" source: hosted - version: "1.0.3" + version: "1.0.4" xml: dependency: transitive description: @@ -2523,10 +2481,10 @@ packages: dependency: "direct main" description: name: youtube_explode_dart - sha256: "98fd11b51adbbca76cbdb17f560168f1d7a9835cecceea965f49eb1e5eed155c" + sha256: "12d32dffd8c85927eb46f7cf7a9dfce690edfe82134c08a90529c51eba58a85c" url: "https://pub.dev" source: hosted - version: "2.0.2" + version: "2.2.0" sdks: dart: ">=3.3.0 <4.0.0" - flutter: ">=3.16.0" + flutter: ">=3.19.2" diff --git a/pubspec.yaml b/pubspec.yaml index 3f4c22af..62c20c35 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -13,96 +13,89 @@ environment: flutter: ">=3.10.0" dependencies: - args: ^2.3.2 + args: ^2.5.0 async: ^2.9.0 - audio_service: ^0.18.9 - audio_session: ^0.1.18 + audio_service: ^0.18.13 + audio_service_mpris: ^0.1.3 + audio_session: ^0.1.19 auto_size_text: ^3.0.0 - buttons_tabbar: ^1.3.6 + buttons_tabbar: ^1.3.8 cached_network_image: ^3.3.1 - catcher_2: 1.0.0 + catcher_2: ^1.2.4 collection: ^1.15.0 - cupertino_icons: ^1.0.5 curved_navigation_bar: ^1.0.3 dbus: ^0.7.8 - device_info_plus: ^9.1.2 + device_info_plus: ^10.1.0 device_preview: ^1.1.0 - dio: ^5.4.1 - disable_battery_optimization: ^1.1.0+1 + dio: ^5.4.3+1 + disable_battery_optimization: ^1.1.1 duration: ^3.0.12 - envied: ^0.3.0 - file_selector: ^1.0.1 - fluentui_system_icons: ^1.1.189 + envied: ^0.5.4+1 + file_picker: ^8.0.0+1 + file_selector: ^1.0.3 + fluentui_system_icons: ^1.1.234 flutter: sdk: flutter flutter_cache_manager: ^3.3.0 - flutter_desktop_tools: - git: - url: https://github.com/KRTirtho/flutter_desktop_tools.git - ref: 1f0bec3283626dcbd8ee2f54e238d096d8dea50e flutter_displaymode: ^0.6.0 flutter_feather_icons: ^2.0.0+1 flutter_hooks: ^0.20.5 flutter_inappwebview: ^6.0.0 flutter_localizations: sdk: flutter - flutter_native_splash: ^2.3.10 - flutter_riverpod: ^2.4.10 + flutter_native_splash: ^2.4.0 + flutter_riverpod: ^2.5.1 flutter_secure_storage: ^9.0.0 flutter_svg: ^1.1.6 form_validator: ^2.1.1 fuzzywuzzy: ^1.1.6 go_router: 12.1.3 # Stuck on this https://github.com/flutter/flutter/issues/140869 - google_fonts: ^6.1.0 + google_fonts: ^6.2.1 hive: ^2.2.3 hive_flutter: ^1.1.0 - hooks_riverpod: ^2.4.3 + hooks_riverpod: ^2.5.1 html: ^0.15.1 http: ^1.2.0 - image_picker: ^1.0.4 + image_picker: ^1.1.0 intl: ^0.18.0 - introduction_screen: ^3.0.2 + introduction_screen: ^3.1.14 json_annotation: ^4.8.1 logger: ^2.0.2 - media_kit: ^1.1.3 - media_kit_libs_audio: ^1.0.3 + media_kit: ^1.1.10+1 + media_kit_libs_audio: ^1.0.4 metadata_god: ^0.5.2+1 mime: ^1.0.2 - package_info_plus: ^4.1.0 + package_info_plus: ^6.0.0 palette_generator: ^0.3.3 path: ^1.8.0 - path_provider: ^2.0.8 - permission_handler: ^11.0.1 - piped_client: - git: - url: https://github.com/KRTirtho/piped_client.git + path_provider: ^2.1.3 + permission_handler: ^11.3.1 + piped_client: ^0.1.1 popover: ^0.3.0 scrobblenaut: git: 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.17.1 + shared_preferences: ^2.2.3 skeleton_text: ^3.0.1 - smtc_windows: ^0.1.1 + smtc_windows: ^0.1.2 stroke_text: ^0.0.2 system_theme: ^2.1.0 titlebar_buttons: ^1.0.0 - url_launcher: ^6.1.7 - uuid: ^3.0.7 + url_launcher: ^6.2.6 + uuid: ^4.4.0 version: ^3.0.2 visibility_detector: ^0.4.0+2 - window_manager: ^0.3.1 + window_manager: ^0.3.8 window_size: git: url: https://github.com/google/flutter-desktop-embedding.git ref: a738913c8ce2c9f47515382d40827e794a334274 path: plugins/window_size - youtube_explode_dart: ^2.0.1 - simple_icons: ^7.10.0 - audio_service_mpris: ^0.1.0 - file_picker: ^6.0.0 + youtube_explode_dart: ^2.2.0 + simple_icons: ^10.1.3 jiosaavn: ^0.1.0 draggable_scrollbar: git: @@ -116,28 +109,29 @@ dependencies: url: https://github.com/Tommypop2/dart_discord_rpc.git html_unescape: ^2.0.0 wikipedia_api: ^0.1.0 - skeletonizer: ^0.8.0 - app_links: ^3.5.0 - win32_registry: ^1.1.2 + skeletonizer: ^1.1.1 + app_links: ^4.0.1 + win32_registry: ^1.1.3 flutter_sharing_intent: ^1.1.0 flutter_broadcasts: ^0.4.0 freezed_annotation: ^2.4.1 - spotify: ^0.13.3 + spotify: ^0.13.5 bonsoir: ^5.1.9 shelf: ^1.4.1 shelf_router: ^1.1.4 shelf_web_socket: ^1.0.4 - web_socket_channel: ^2.4.4 + web_socket_channel: ^2.4.5 lrc: ^1.0.2 pub_api_client: ^2.4.0 pubspec_parse: ^1.2.2 timezone: ^0.9.2 crypto: ^3.0.3 + local_notifier: ^0.1.6 + tray_manager: ^0.2.2 dev_dependencies: build_runner: ^2.4.9 - envied_generator: ^0.3.0+3 - flutter_distributor: ^0.0.2 + envied_generator: ^0.5.4+1 flutter_gen_runner: ^5.4.0 flutter_launcher_icons: ^0.13.1 flutter_lints: ^3.0.1 @@ -147,12 +141,12 @@ dev_dependencies: sdk: flutter hive_generator: ^2.0.0 json_serializable: ^6.6.2 - freezed: ^2.4.6 - custom_lint: ^0.5.11 - riverpod_lint: ^2.1.1 + freezed: ^2.5.2 + custom_lint: ^0.6.4 + riverpod_lint: ^2.3.10 dependency_overrides: - system_tray: 2.0.2 + uuid: ^4.4.0 flutter: generate: true diff --git a/windows/flutter/generated_plugin_registrant.cc b/windows/flutter/generated_plugin_registrant.cc index d8a9db29..57542dec 100644 --- a/windows/flutter/generated_plugin_registrant.cc +++ b/windows/flutter/generated_plugin_registrant.cc @@ -16,7 +16,7 @@ #include #include #include -#include +#include #include #include #include @@ -42,8 +42,8 @@ void RegisterPlugins(flutter::PluginRegistry* registry) { registry->GetRegistrarForPlugin("ScreenRetrieverPlugin")); SystemThemePluginRegisterWithRegistrar( registry->GetRegistrarForPlugin("SystemThemePlugin")); - SystemTrayPluginRegisterWithRegistrar( - registry->GetRegistrarForPlugin("SystemTrayPlugin")); + TrayManagerPluginRegisterWithRegistrar( + registry->GetRegistrarForPlugin("TrayManagerPlugin")); UrlLauncherWindowsRegisterWithRegistrar( registry->GetRegistrarForPlugin("UrlLauncherWindows")); WindowManagerPluginRegisterWithRegistrar( diff --git a/windows/flutter/generated_plugins.cmake b/windows/flutter/generated_plugins.cmake index 90292744..6a0c7723 100644 --- a/windows/flutter/generated_plugins.cmake +++ b/windows/flutter/generated_plugins.cmake @@ -13,7 +13,7 @@ list(APPEND FLUTTER_PLUGIN_LIST permission_handler_windows screen_retriever system_theme - system_tray + tray_manager url_launcher_windows window_manager window_size From 7e07c2e1985da7ccb96b1fac2ecd703720068d26 Mon Sep 17 00:00:00 2001 From: Kingkor Roy Tirtho Date: Thu, 18 Apr 2024 00:05:47 +0600 Subject: [PATCH 09/13] fix(search): load more button not working #1417 --- lib/pages/search/sections/tracks.dart | 2 +- macos/Podfile.lock | 15 +++++---------- 2 files changed, 6 insertions(+), 11 deletions(-) diff --git a/lib/pages/search/sections/tracks.dart b/lib/pages/search/sections/tracks.dart index 48dabc13..7fb58759 100644 --- a/lib/pages/search/sections/tracks.dart +++ b/lib/pages/search/sections/tracks.dart @@ -113,7 +113,7 @@ class SearchTracksSection extends HookConsumerWidget { child: TextButton( onPressed: searchTrack.isLoadingNextPage ? null - : () => searchTrackNotifier.fetchMore, + : searchTrackNotifier.fetchMore, child: searchTrack.isLoadingNextPage ? const CircularProgressIndicator() : Text(context.l10n.load_more), diff --git a/macos/Podfile.lock b/macos/Podfile.lock index c1cf630c..ce2ef233 100644 --- a/macos/Podfile.lock +++ b/macos/Podfile.lock @@ -18,9 +18,6 @@ PODS: - flutter_secure_storage_macos (6.1.1): - FlutterMacOS - FlutterMacOS (1.0.0) - - FMDB (2.7.5): - - FMDB/standard (= 2.7.5) - - FMDB/standard (2.7.5) - local_notifier (0.1.0): - FlutterMacOS - media_kit_libs_macos_audio (1.0.4): @@ -39,9 +36,9 @@ PODS: - shared_preferences_foundation (0.0.1): - Flutter - FlutterMacOS - - sqflite (0.0.2): + - sqflite (0.0.3): + - Flutter - FlutterMacOS - - FMDB (>= 2.7.5) - system_theme (0.0.1): - FlutterMacOS - tray_manager (0.0.1): @@ -71,7 +68,7 @@ DEPENDENCIES: - 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`) + - sqflite (from `Flutter/ephemeral/.symlinks/plugins/sqflite/darwin`) - system_theme (from `Flutter/ephemeral/.symlinks/plugins/system_theme/macos`) - tray_manager (from `Flutter/ephemeral/.symlinks/plugins/tray_manager/macos`) - url_launcher_macos (from `Flutter/ephemeral/.symlinks/plugins/url_launcher_macos/macos`) @@ -80,7 +77,6 @@ DEPENDENCIES: SPEC REPOS: trunk: - - FMDB - OrderedSet EXTERNAL SOURCES: @@ -119,7 +115,7 @@ EXTERNAL SOURCES: shared_preferences_foundation: :path: Flutter/ephemeral/.symlinks/plugins/shared_preferences_foundation/darwin sqflite: - :path: Flutter/ephemeral/.symlinks/plugins/sqflite/macos + :path: Flutter/ephemeral/.symlinks/plugins/sqflite/darwin system_theme: :path: Flutter/ephemeral/.symlinks/plugins/system_theme/macos tray_manager: @@ -141,7 +137,6 @@ SPEC CHECKSUMS: flutter_inappwebview_macos: 9600c9df9fdb346aaa8933812009f8d94304203d flutter_secure_storage_macos: d56e2d218c1130b262bef8b4a7d64f88d7f9c9ea FlutterMacOS: 8f6f14fa908a6fb3fba0cd85dbd81ec4b251fb24 - FMDB: 2ce00b547f966261cd18927a3ddb07cb6f3db82a local_notifier: e9506bc66fc70311e8bc7291fb70f743c081e4ff media_kit_libs_macos_audio: 3871782a4f3f84c77f04d7666c87800a781c24da media_kit_native_event_loop: 7321675377cb9ae8596a29bddf3a3d2b5e8792c5 @@ -151,7 +146,7 @@ SPEC CHECKSUMS: path_provider_foundation: 3784922295ac71e43754bd15e0653ccfd36a147c screen_retriever: 59634572a57080243dd1bf715e55b6c54f241a38 shared_preferences_foundation: b4c3b4cddf1c21f02770737f147a3f5da9d39695 - sqflite: a5789cceda41d54d23f31d6de539d65bb14100ea + sqflite: 673a0e54cc04b7d6dba8d24fb8095b31c3a99eec system_theme: c7b9f6659a5caa26c9bc2284da096781e9a6fcbc tray_manager: 9064e219c56d75c476e46b9a21182087930baf90 url_launcher_macos: d2691c7dd33ed713bf3544850a623080ec693d95 From 9bccbc93c63dd34f6e15ff68c276976ecd1d9a33 Mon Sep 17 00:00:00 2001 From: Kingkor Roy Tirtho Date: Thu, 18 Apr 2024 00:19:47 +0600 Subject: [PATCH 10/13] fix: spotify friends and user profile icon (mobile) showing when not authenticated #1410 --- .vscode/settings.json | 1 + lib/components/home/sections/friends.dart | 47 +++++++++++++---------- lib/pages/home/home.dart | 6 +++ 3 files changed, 34 insertions(+), 20 deletions(-) diff --git a/.vscode/settings.json b/.vscode/settings.json index 29c5ba4e..de5fbd69 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -24,5 +24,6 @@ "explorer.fileNesting.patterns": { "pubspec.yaml": "pubspec.lock,analysis_options.yaml,.packages,.flutter-plugins,.flutter-plugins-dependencies,flutter_launcher_icons*.yaml,flutter_native_splash*.yaml", "README.md": "LICENSE,CODE_OF_CONDUCT.md,CONTRIBUTING.md,SECURITY.md,CONTRIBUTION.md,CHANGELOG.md,PRIVACY_POLICY.md", + "*.dart": "${capture}.g.dart,${capture}.freezed.dart", } } \ No newline at end of file diff --git a/lib/components/home/sections/friends.dart b/lib/components/home/sections/friends.dart index 35ec09b0..4ae802e6 100644 --- a/lib/components/home/sections/friends.dart +++ b/lib/components/home/sections/friends.dart @@ -1,12 +1,14 @@ import 'dart:ui'; 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: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/provider/authentication_provider.dart'; import 'package:spotube/provider/spotify/spotify.dart'; class HomePageFriendsSection extends HookConsumerWidget { @@ -14,6 +16,7 @@ class HomePageFriendsSection extends HookConsumerWidget { @override Widget build(BuildContext context, ref) { + final auth = ref.watch(authenticationProvider); final friendsQuery = ref.watch(friendsProvider); final friends = friendsQuery.asData?.value.friends ?? FakeData.friends.friends; @@ -27,32 +30,36 @@ class HomePageFriendsSection extends HookConsumerWidget { xxl: 7, ); - final friendGroup = friends.fold>>( - [], - (previousValue, element) { - if (previousValue.isEmpty) { + final friendGroup = useMemoized( + () => 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] ]; - } - - final lastGroup = previousValue.last; - if (lastGroup.length < groupCount) { - return [ - ...previousValue.sublist(0, previousValue.length - 1), - [...lastGroup, element] - ]; - } - - return [ - ...previousValue, - [element] - ]; - }, + }, + ), + [friends, groupCount], ); if (friendsQuery.isLoading || - friendsQuery.asData?.value.friends.isEmpty == true) { + friendsQuery.asData?.value.friends.isEmpty == true || + auth == null) { return const SliverToBoxAdapter( child: SizedBox.shrink(), ); diff --git a/lib/pages/home/home.dart b/lib/pages/home/home.dart index 31f26bee..a4a71146 100644 --- a/lib/pages/home/home.dart +++ b/lib/pages/home/home.dart @@ -14,6 +14,7 @@ import 'package:spotube/components/shared/image/universal_image.dart'; import 'package:spotube/components/shared/page_window_title_bar.dart'; import 'package:spotube/extensions/constrains.dart'; import 'package:spotube/extensions/image.dart'; +import 'package:spotube/provider/authentication_provider.dart'; import 'package:spotube/provider/spotify/spotify.dart'; import 'package:spotube/utils/platform.dart'; import 'package:spotube/utils/service_utils.dart'; @@ -41,9 +42,14 @@ class HomePage extends HookConsumerWidget { const ConnectDeviceButton(), const Gap(10), Consumer(builder: (context, ref, _) { + final auth = ref.watch(authenticationProvider); final me = ref.watch(meProvider); final meData = me.asData?.value; + if (auth == null) { + return const SizedBox(); + } + return IconButton( icon: CircleAvatar( backgroundImage: UniversalImage.imageProvider( From 2da5d786d277ee8ba05685c4f98ae22e9c27d023 Mon Sep 17 00:00:00 2001 From: Kingkor Roy Tirtho Date: Fri, 19 Apr 2024 16:05:01 +0600 Subject: [PATCH 11/13] chore: add docker and m1 based linux arm build --- .dockerignore | 4 ++ .github/Dockerfile | 32 +++++++++ .github/workflows/spotube-release-binary.yml | 74 ++++++++++++++++++-- 3 files changed, 103 insertions(+), 7 deletions(-) create mode 100644 .dockerignore create mode 100644 .github/Dockerfile diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 00000000..55fee41a --- /dev/null +++ b/.dockerignore @@ -0,0 +1,4 @@ +build +dist +.dart_tool +.idea diff --git a/.github/Dockerfile b/.github/Dockerfile new file mode 100644 index 00000000..e4dacb0e --- /dev/null +++ b/.github/Dockerfile @@ -0,0 +1,32 @@ +ARG FLUTTER_VERSION +ARG BUILD_VERSION + +FROM --platform=arm64 fischerscode/flutter-sudo:${FLUTTER_VERSION} + +WORKDIR /app + +# Install dependencies +RUN sudo apt-get update &&\ + sudo apt-get install -y tar clang cmake ninja-build pkg-config libgtk-3-dev make python3-pip python3-setuptools desktop-file-utils libgdk-pixbuf2.0-dev fakeroot strace fuse libunwind-dev locate patchelf gir1.2-appindicator3-0.1 libappindicator3-1 libappindicator3-dev libsecret-1-0 libjsoncpp25 libsecret-1-dev libjsoncpp-dev libnotify-bin libnotify-dev mpv libmpv-dev rpm &&\ + sudo rm -rf /var/lib/apt/lists/* + +COPY . . + +RUN sudo chown -R $(whoami) /app + +RUN flutter pub get &&\ + flutter config --enable-linux-desktop &&\ + flutter pub get &&\ + dart run build_runner build --delete-conflicting-outputs + +RUN 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=rpm + + +RUN make tar VERSION=${BUILD_VERSION} ARCH=arm64 PKG_ARCH=aarch64 + +RUN mv build/spotube-linux-*-aarch64.tar.xz dist/ &&\ + mv dist/**/spotube-*-linux.deb dist/Spotube-linux-aarch64.deb &&\ + mv dist/**/spotube-*-linux.rpm dist/Spotube-linux-aarch64.rpm \ No newline at end of file diff --git a/.github/workflows/spotube-release-binary.yml b/.github/workflows/spotube-release-binary.yml index 969e1b77..044738c9 100644 --- a/.github/workflows/spotube-release-binary.yml +++ b/.github/workflows/spotube-release-binary.yml @@ -70,7 +70,7 @@ jobs: run: | flutter config --enable-windows-desktop flutter pub get - dart run build_runner build --delete-conflicting-outputs --enable-experiment=records,patterns + dart run build_runner build --delete-conflicting-outputs - name: Build Windows Executable run: | @@ -156,7 +156,7 @@ jobs: run: | flutter config --enable-linux-desktop flutter pub get - dart run build_runner build --delete-conflicting-outputs --enable-experiment=records,patterns + dart run build_runner build --delete-conflicting-outputs - name: Build Linux Packages run: | @@ -206,6 +206,66 @@ jobs: with: limit-access-to-actor: true + linux_arm: + runs-on: macos-14 + steps: + - uses: actions/checkout@v4 + + - name: Install Docker + run: brew install docker + + - 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: Get current date + id: date + run: echo "::set-output name=date::$(date +'%Y-%m-%d')" + + - name: Replace Version in files + run: | + sed -i 's|%{{APPDATA_RELEASE}}%||' linux/com.github.KRTirtho.Spotube.appdata.xml + + - 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: Build Linux Arm + run: | + docker build -t spotube-linux-arm -f .github/Dockerfile . --build-arg BUILD_VERSION=${{ env.BUILD_VERSION }} --build-arg FLUTTER_VERSION=${{ env.FLUTTER_VERSION }} + docker create --name spotube-linux-arm spotube-linux-arm + docker cp spotube-linux-arm:/app/dist . + docker rm -f spotube-linux-arm + + - uses: actions/upload-artifact@v3 + with: + if-no-files-found: error + name: Spotube-Release-Binaries + path: | + dist/Spotube-linux-aarch64.deb + dist/Spotube-linux-aarch64.rpm + dist/spotube-linux-nightly-aarch64.tar.xz + + - name: Debug With SSH When fails + if: ${{ failure() && inputs.debug && inputs.channel == 'nightly' }} + uses: mxschmitt/action-tmate@v3 + with: + limit-access-to-actor: true + android: runs-on: ubuntu-latest @@ -245,7 +305,7 @@ jobs: - name: Generate Secrets run: | flutter pub get - dart run build_runner build --delete-conflicting-outputs --enable-experiment=records,patterns + dart run build_runner build --delete-conflicting-outputs - name: Sign Apk run: | @@ -260,7 +320,7 @@ jobs: - name: Build Playstore AppBundle run: | echo 'ENABLE_UPDATE_CHECK=0' >> .env - dart run build_runner build --delete-conflicting-outputs --enable-experiment=records,patterns + dart run build_runner build --delete-conflicting-outputs export MANIFEST=android/app/src/main/AndroidManifest.xml xmlstarlet ed -d '//meta-data[@android:name="com.google.android.gms.car.application"]' $MANIFEST > $MANIFEST.tmp mv $MANIFEST.tmp $MANIFEST @@ -283,7 +343,6 @@ jobs: limit-access-to-actor: true macos: - runs-on: macos-14 steps: - uses: actions/checkout@v4 @@ -317,7 +376,7 @@ jobs: run: | dart pub global activate flutter_distributor flutter pub get - dart run build_runner build --delete-conflicting-outputs --enable-experiment=records,patterns + dart run build_runner build --delete-conflicting-outputs - name: Build Macos App run: | @@ -381,7 +440,7 @@ jobs: - name: Generate Secrets run: | flutter pub get - dart run build_runner build --delete-conflicting-outputs --enable-experiment=records,patterns + dart run build_runner build --delete-conflicting-outputs - name: Build iOS iPA run: | @@ -408,6 +467,7 @@ jobs: needs: - windows - linux + - linux_arm - android - macos - iOS From ef7833eb672feb591b424ece900e0b3b199fe036 Mon Sep 17 00:00:00 2001 From: Kingkor Roy Tirtho Date: Fri, 19 Apr 2024 16:10:28 +0600 Subject: [PATCH 12/13] cd: fix sed failing us --- .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 044738c9..4979c21a 100644 --- a/.github/workflows/spotube-release-binary.yml +++ b/.github/workflows/spotube-release-binary.yml @@ -234,7 +234,7 @@ jobs: - name: Replace Version in files run: | - sed -i 's|%{{APPDATA_RELEASE}}%||' linux/com.github.KRTirtho.Spotube.appdata.xml + sed -i '' 's|%{{APPDATA_RELEASE}}%||' linux/com.github.KRTirtho.Spotube.appdata.xml - name: Create Stable .env if: ${{ inputs.channel == 'stable' }} From 88fea7ecf9ea426d26b6c8ad44e9b872136e8eb5 Mon Sep 17 00:00:00 2001 From: Kingkor Roy Tirtho Date: Fri, 19 Apr 2024 16:14:17 +0600 Subject: [PATCH 13/13] cd: use docker cask --- .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 4979c21a..c7753155 100644 --- a/.github/workflows/spotube-release-binary.yml +++ b/.github/workflows/spotube-release-binary.yml @@ -212,7 +212,7 @@ jobs: - uses: actions/checkout@v4 - name: Install Docker - run: brew install docker + run: brew install --cask docker - name: Replace pubspec version and BUILD_VERSION Env (nightly) if: ${{ inputs.channel == 'nightly' }}