diff --git a/README.md b/README.md index a6ace5d..c27dab9 100644 --- a/README.md +++ b/README.md @@ -1 +1 @@ -# Canal +# Brook diff --git a/android/app/build.gradle b/android/app/build.gradle index 33a096e..f653a28 100644 --- a/android/app/build.gradle +++ b/android/app/build.gradle @@ -6,7 +6,7 @@ plugins { } android { - namespace = "com.example.canal" + namespace = "com.example.brook" compileSdk = flutter.compileSdkVersion ndkVersion = flutter.ndkVersion @@ -21,7 +21,7 @@ android { defaultConfig { // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). - applicationId = "com.example.canal" + applicationId = "com.example.brook" // You can update the following values to match your application needs. // For more information, see: https://docs.flutter.dev/deployment/android#reviewing-the-gradle-build-configuration. minSdk = flutter.minSdkVersion diff --git a/android/app/src/main/AndroidManifest.xml b/android/app/src/main/AndroidManifest.xml index 8ee2f39..61b82f4 100644 --- a/android/app/src/main/AndroidManifest.xml +++ b/android/app/src/main/AndroidManifest.xml @@ -1,6 +1,6 @@ > searchProvider( +Future> searchProvider( Ref ref, { required String search, required SearchType searchType, }) async { final yt = await ytmusic(ref); - return IList(switch (searchType) { - SearchType.any => await yt.search(search), - SearchType.songs => await yt.searchSongs(search), - SearchType.albums => await yt.searchAlbums(search), - SearchType.videos => await yt.searchVideos(search), - SearchType.artists => await yt.searchAlbums(search), - SearchType.playlists => await yt.searchPlaylists(search), - }); + return IList( + switch (searchType) { + SearchType.any => + await yt.search(search).then((search) => search.cast()), + SearchType.songs => await yt.searchSongs(search), + SearchType.albums => await yt.searchAlbums(search), + SearchType.videos => await yt.searchVideos(search), + SearchType.artists => await yt.searchAlbums(search), + SearchType.playlists => await yt.searchPlaylists(search), + }, + ); } diff --git a/lib/screens/album_page.dart b/lib/screens/album_page.dart index 88bc647..c05f51f 100644 --- a/lib/screens/album_page.dart +++ b/lib/screens/album_page.dart @@ -1,4 +1,4 @@ -import 'package:canal/widgets/appbar.dart'; +import 'package:brook/widgets/appbar.dart'; import 'package:flutter/material.dart'; class AlbumPage extends StatelessWidget { diff --git a/lib/screens/playlist_page.dart b/lib/screens/playlist_page.dart index 03c0f19..78dd937 100644 --- a/lib/screens/playlist_page.dart +++ b/lib/screens/playlist_page.dart @@ -1,4 +1,4 @@ -import 'package:canal/widgets/appbar.dart'; +import 'package:brook/widgets/appbar.dart'; import 'package:flutter/material.dart'; class PlaylistPage extends StatelessWidget { diff --git a/lib/screens/tabs/account.dart b/lib/screens/tabs/account.dart index 48e271b..07cd066 100644 --- a/lib/screens/tabs/account.dart +++ b/lib/screens/tabs/account.dart @@ -1,5 +1,5 @@ import 'package:flutter/material.dart'; -import 'package:canal/models/tab.dart'; +import 'package:brook/models/tab.dart'; class AccountTab extends StatelessWidget implements TabPage { const AccountTab({super.key}); diff --git a/lib/screens/tabs/home.dart b/lib/screens/tabs/home.dart index c857192..c18f6d6 100644 --- a/lib/screens/tabs/home.dart +++ b/lib/screens/tabs/home.dart @@ -1,11 +1,11 @@ -import 'package:canal/helpers/extension_helper.dart'; -import 'package:canal/providers/home_sections_provider.dart'; -import 'package:canal/screens/album_page.dart'; -import 'package:canal/screens/playlist_page.dart'; -import 'package:canal/widgets/thumbnail.dart'; +import 'package:brook/helpers/extension_helper.dart'; +import 'package:brook/providers/home_sections_provider.dart'; +import 'package:brook/screens/album_page.dart'; +import 'package:brook/screens/playlist_page.dart'; +import 'package:brook/widgets/thumbnail.dart'; import 'package:dart_ytmusic_api/dart_ytmusic_api.dart'; import 'package:flutter/material.dart'; -import 'package:canal/models/tab.dart'; +import 'package:brook/models/tab.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:yaru/yaru.dart'; diff --git a/lib/screens/tabs/search.dart b/lib/screens/tabs/search.dart index 2f6cc7a..44de994 100644 --- a/lib/screens/tabs/search.dart +++ b/lib/screens/tabs/search.dart @@ -1,11 +1,12 @@ -import 'package:canal/helpers/extension_helper.dart'; -import 'package:canal/providers/search_provider.dart'; -import 'package:canal/widgets/thumbnail.dart'; +import 'package:brook/helpers/extension_helper.dart'; +import 'package:collection/collection.dart'; +import 'package:brook/providers/search_provider.dart'; +import 'package:brook/widgets/thumbnail.dart'; import 'package:dart_ytmusic_api/types.dart'; import 'package:flutter_hooks/flutter_hooks.dart'; -import 'package:canal/widgets/select_button.dart'; -import 'package:canal/models/search_type.dart'; -import 'package:canal/models/tab.dart'; +import 'package:brook/widgets/select_button.dart'; +import 'package:brook/models/search_type.dart'; +import 'package:brook/models/tab.dart'; import 'package:flutter/material.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:yaru/yaru.dart'; @@ -23,7 +24,6 @@ class SearchTab extends HookConsumerWidget implements TabPage { Widget build(BuildContext context, WidgetRef ref) { final type = useState(SearchType.any); final search = useState(""); - final debouncedSearch = useDebounced(search, Duration(milliseconds: 250)); return ListView( padding: EdgeInsets.symmetric(horizontal: 16, vertical: 4), @@ -45,39 +45,65 @@ class SearchTab extends HookConsumerWidget implements TabPage { SizedBox(height: 8), ref .watch(searchProviderProvider( - search: search.value, searchType: type.value)) + search: search.value, + searchType: type.value, + )) .betterWhen( - data: (results) => Wrap( - children: results - .map((result) => SizedBox( - height: 64, - width: 64, - child: switch (result) { - SongDetailed _ => Thumbnail( - url: result.thumbnails.first.url, - onClick: () {}, - ), - AlbumDetailed _ => Thumbnail( - url: result.thumbnails.first.url, - onClick: () {}, - ), - VideoDetailed _ => Thumbnail( - url: result.thumbnails.first.url, - onClick: () {}, - ), - ArtistDetailed _ => Thumbnail( - url: result.thumbnails.first.url, - onClick: () {}, - ), - PlaylistDetailed _ => Thumbnail( - url: result.thumbnails.first.url, - onClick: () {}, - ), - _ => throw Exception( - "Unknown Detailed Result: ${result.runtimeType}", - ), - })) - .toList())), + data: (results) => Column( + children: results + .mapIndexed((index, result) => switch (result) { + SongDetailed _ => Builder(builder: (_) { + final padding = + EdgeInsets.symmetric(horizontal: 16); + final leading = Thumbnail( + url: result.thumbnails.first.url, + onClick: () {}, + ); + return index == 0 + ? SizedBox( + height: 128, + child: YaruBanner.tile( + padding: padding, + icon: leading, + title: Text(result.name), + subtitle: Text(result.artist.name), + ), + ) + : YaruTile( + padding: padding, + leading: leading, + title: Text(result.name), + subtitle: Text(result.artist.name), + ); + }), + AlbumDetailed _ => Thumbnail( + url: result.thumbnails.first.url, + onClick: () {}, + ), + VideoDetailed _ => Thumbnail( + url: result.thumbnails.first.url, + onClick: () {}, + radius: 0, + ), + ArtistDetailed _ => Thumbnail( + url: result.thumbnails.first.url, + onClick: () {}, + ), + PlaylistDetailed _ => Thumbnail( + url: result.thumbnails.first.url, + onClick: () {}, + ), + _ => throw Exception( + "Unknown Detailed Result: ${result.runtimeType}", + ), + }) + .map((element) => Padding( + padding: EdgeInsets.only(bottom: 16), + child: element, + )) + .toList(), + ), + ), ], ); } diff --git a/lib/widgets/app.dart b/lib/widgets/app.dart index d10103c..18ebc73 100644 --- a/lib/widgets/app.dart +++ b/lib/widgets/app.dart @@ -1,18 +1,18 @@ import 'package:adwaita/adwaita.dart'; -import 'package:canal/helpers/extension_helper.dart'; -import 'package:canal/models/tab.dart'; -import 'package:canal/providers/ytmusic_provider.dart'; -import 'package:canal/screens/tabs/account.dart'; -import 'package:canal/screens/tabs/home.dart'; -import 'package:canal/screens/tabs/search.dart'; -import 'package:canal/widgets/appbar.dart'; +import 'package:brook/helpers/extension_helper.dart'; +import 'package:brook/models/tab.dart'; +import 'package:brook/providers/ytmusic_provider.dart'; +import 'package:brook/screens/tabs/account.dart'; +import 'package:brook/screens/tabs/home.dart'; +import 'package:brook/screens/tabs/search.dart'; +import 'package:brook/widgets/appbar.dart'; import "package:flutter/material.dart"; import 'package:fast_immutable_collections/fast_immutable_collections.dart'; import 'package:flutter_hooks/flutter_hooks.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:yaru/yaru.dart'; -import 'package:canal/providers/button_layout_provider.dart'; -import 'package:canal/providers/warmup_provider.dart'; +import 'package:brook/providers/button_layout_provider.dart'; +import 'package:brook/providers/warmup_provider.dart'; const List tabs = [HomeTab(), SearchTab(), AccountTab()]; @@ -31,7 +31,7 @@ class App extends HookConsumerWidget { ]))) .betterWhen( data: (_) => YaruDetailPage( - appBar: const Appbar(title: "Canal"), + appBar: const Appbar(title: "Brook"), body: tabs[selected.value], bottomNavigationBar: NavigationBar( destinations: tabs diff --git a/lib/widgets/appbar.dart b/lib/widgets/appbar.dart index b79535b..ef33132 100644 --- a/lib/widgets/appbar.dart +++ b/lib/widgets/appbar.dart @@ -1,6 +1,6 @@ import 'package:flutter/material.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; -import 'package:canal/providers/decorations_provider.dart'; +import 'package:brook/providers/decorations_provider.dart'; import 'package:yaru/yaru.dart'; class Appbar extends ConsumerWidget implements PreferredSizeWidget { diff --git a/lib/widgets/package_card.dart b/lib/widgets/package_card.dart index 3206589..ed05d41 100644 --- a/lib/widgets/package_card.dart +++ b/lib/widgets/package_card.dart @@ -1,5 +1,5 @@ import 'package:flutter/material.dart'; -import 'package:canal/models/package.dart'; +import 'package:brook/models/package.dart'; class PackageCard extends StatelessWidget { final Package package; diff --git a/lib/widgets/select_button.dart b/lib/widgets/select_button.dart index e84591a..dfbec07 100644 --- a/lib/widgets/select_button.dart +++ b/lib/widgets/select_button.dart @@ -1,4 +1,4 @@ -import 'package:canal/helpers/extension_helper.dart'; +import 'package:brook/helpers/extension_helper.dart'; import 'package:flutter/material.dart'; import 'package:flutter_hooks/flutter_hooks.dart'; diff --git a/lib/widgets/thumbnail.dart b/lib/widgets/thumbnail.dart index be7bfeb..a14bd57 100644 --- a/lib/widgets/thumbnail.dart +++ b/lib/widgets/thumbnail.dart @@ -3,11 +3,17 @@ import 'package:flutter/material.dart'; class Thumbnail extends StatelessWidget { final String url; final VoidCallback onClick; - const Thumbnail({required this.url, required this.onClick, super.key}); + final double radius; + const Thumbnail({ + super.key, + required this.url, + required this.onClick, + this.radius = 16, + }); @override Widget build(BuildContext context) => ClipRRect( - borderRadius: BorderRadius.all(Radius.circular(16)), + borderRadius: BorderRadius.all(Radius.circular(radius)), child: InkWell( onTap: onClick, child: Image.network( diff --git a/linux/CMakeLists.txt b/linux/CMakeLists.txt index ff2447f..9cec270 100644 --- a/linux/CMakeLists.txt +++ b/linux/CMakeLists.txt @@ -4,10 +4,10 @@ project(runner LANGUAGES CXX) # The name of the executable created for the application. Change this to change # the on-disk name of your application. -set(BINARY_NAME "canal") +set(BINARY_NAME "brook") # The unique GTK application identifier for this application. See: # https://wiki.gnome.org/HowDoI/ChooseApplicationID -set(APPLICATION_ID "com.example.canal") +set(APPLICATION_ID "com.example.brook") # Explicitly opt in to modern CMake behaviors to avoid warnings with recent # versions of CMake. diff --git a/linux/my_application.cc b/linux/my_application.cc index 602646a..4ab1d22 100644 --- a/linux/my_application.cc +++ b/linux/my_application.cc @@ -40,11 +40,11 @@ static void my_application_activate(GApplication* application) { if (use_header_bar) { GtkHeaderBar* header_bar = GTK_HEADER_BAR(gtk_header_bar_new()); gtk_widget_show(GTK_WIDGET(header_bar)); - gtk_header_bar_set_title(header_bar, "canal"); + gtk_header_bar_set_title(header_bar, "brook"); gtk_header_bar_set_show_close_button(header_bar, TRUE); gtk_window_set_titlebar(window, GTK_WIDGET(header_bar)); } else { - gtk_window_set_title(window, "canal"); + gtk_window_set_title(window, "brook"); } gtk_window_set_default_size(window, 1280, 720); diff --git a/pubspec.lock b/pubspec.lock index 954f8da..c35b73f 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -202,10 +202,10 @@ packages: dependency: "direct main" description: name: collection - sha256: ee67cb0715911d28db6bf4af1026078bd6f0128b07a5f66fb2ed94ec6783c09a + sha256: "2f5709ae4d3d59dd8f7cd309b4e023046b57d8a6c82130785d2b0e5868084e76" url: "https://pub.dev" source: hosted - version: "1.18.0" + version: "1.19.1" convert: dependency: transitive description: @@ -281,10 +281,11 @@ packages: dart_ytmusic_api: dependency: "direct main" description: - name: dart_ytmusic_api - sha256: "1e35f07c69a36eab672f37815bc0f644328c06cda51404e30fa90a0412023135" - url: "https://pub.dev" - source: hosted + path: "." + ref: HEAD + resolved-ref: "2f3c6f7d385cf10827780e03bfaf133f3b8221a3" + url: "https://github.com/Henry-Hiles/dart_ytmusic_api" + source: git version: "1.0.8" dbus: dependency: transitive @@ -477,10 +478,10 @@ packages: dependency: transitive description: name: http_parser - sha256: "2aa08ce0341cc9b354a498388e30986515406668dbcc4f7c950c3e715496693b" + sha256: "178d74305e7866013777bab2c3d8726205dc5a4dd935297175b19a23a2e66571" url: "https://pub.dev" source: hosted - version: "4.0.2" + version: "4.1.2" image: dependency: transitive description: @@ -490,13 +491,13 @@ packages: source: hosted version: "4.5.2" intl: - dependency: transitive + dependency: "direct overridden" description: name: intl - sha256: d6f56758b7d3014a48af9701c085700aac781a92a87a62b1333b46d8879661cf + sha256: "00f33b908655e606b86d2ade4710a231b802eec6f11e87e4ea3783fd72077a50" url: "https://pub.dev" source: hosted - version: "0.19.0" + version: "0.20.1" io: dependency: transitive description: @@ -570,13 +571,13 @@ packages: source: hosted version: "0.11.1" meta: - dependency: "direct overridden" + dependency: transitive description: name: meta - sha256: e3641ec5d63ebf0d9b41bd43201a66e3fc79a65db5f61fc181f04cd27aab950c + sha256: bdb68674043280c3428e9ec998512fb681678676b3c54e773629ffe74419f8c7 url: "https://pub.dev" source: hosted - version: "1.16.0" + version: "1.15.0" mime: dependency: transitive description: @@ -765,10 +766,10 @@ packages: dependency: transitive description: name: shelf - sha256: ad29c505aee705f41a4d8963641f91ac4cee3c8fad5947e033390a7bd8180fa4 + sha256: e7dd780a7ffb623c57850b33f43309312fc863fb6aa3d276a754bb299839ef12 url: "https://pub.dev" source: hosted - version: "1.4.1" + version: "1.4.2" shelf_web_socket: dependency: transitive description: diff --git a/pubspec.yaml b/pubspec.yaml index 6aaab06..147aea1 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,4 +1,4 @@ -name: canal +name: brook description: "A music player" publish_to: "none" version: 1.0.0+1 @@ -7,8 +7,8 @@ environment: sdk: "^3.5.4" dependencies: + collection: ^1.19.1 adwaita: ^1.1.0 - collection: ^1.18.0 fast_immutable_collections: ^11.0.2 flutter: sdk: flutter @@ -25,10 +25,13 @@ dependencies: git: url: https://github.com/google/flutter-desktop-embedding path: plugins/window_size - dart_ytmusic_api: ^1.0.8 + dart_ytmusic_api: + git: + url: https://github.com/Henry-Hiles/dart_ytmusic_api dependency_overrides: - meta: ^1.15.0 + collection: ^1.19.1 + intl: ^0.20.1 dev_dependencies: build_runner: ^2.4.11 diff --git a/web/index.html b/web/index.html index 5a4ccd7..556871a 100644 --- a/web/index.html +++ b/web/index.html @@ -1,7 +1,7 @@ - - - + - - - + + + - - - - - + + + + + - - + + - canal - - - - - + brook + + + + + diff --git a/web/manifest.json b/web/manifest.json index b6d7819..ed7976e 100644 --- a/web/manifest.json +++ b/web/manifest.json @@ -1,6 +1,6 @@ { - "name": "canal", - "short_name": "canal", + "name": "brook", + "short_name": "brook", "start_url": ".", "display": "standalone", "background_color": "#0175C2",