canal -> brook

This commit is contained in:
Henry Hiles 2025-01-04 12:14:46 -05:00
parent a2ef7da707
commit a6f2291309
25 changed files with 169 additions and 129 deletions

View file

@ -1 +1 @@
# Canal
# Brook

View file

@ -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

View file

@ -1,6 +1,6 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
<application
android:label="canal"
android:label="brook"
android:name="${applicationName}"
android:icon="@mipmap/ic_launcher">
<activity

View file

@ -1,4 +1,4 @@
package com.example.canal
package com.example.brook
import io.flutter.embedding.android.FlutterActivity

View file

@ -1,4 +1,4 @@
import 'package:canal/widgets/loading.dart';
import 'package:brook/widgets/loading.dart';
import 'package:flutter/material.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart';

View file

@ -1,6 +1,6 @@
import 'package:flutter/widgets.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:canal/widgets/app.dart';
import 'package:brook/widgets/app.dart';
import 'package:window_size/window_size.dart';
import 'package:yaru/yaru.dart';

View file

@ -1,7 +1,7 @@
import 'package:hooks_riverpod/hooks_riverpod.dart';
import "package:riverpod_annotation/riverpod_annotation.dart";
import 'package:canal/models/decorations.dart';
import 'package:canal/providers/button_layout_provider.dart';
import 'package:brook/models/decorations.dart';
import 'package:brook/providers/button_layout_provider.dart';
import 'package:yaru/yaru.dart';
import "package:collection/collection.dart";
part 'decorations_provider.g.dart';

View file

@ -1,4 +1,4 @@
import 'package:canal/providers/ytmusic_provider.dart';
import 'package:brook/providers/ytmusic_provider.dart';
import 'package:dart_ytmusic_api/dart_ytmusic_api.dart';
import 'package:fast_immutable_collections/fast_immutable_collections.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart';

View file

@ -1,23 +1,27 @@
import 'package:canal/models/search_type.dart';
import 'package:brook/models/search_type.dart';
import 'package:dart_ytmusic_api/types.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:canal/providers/ytmusic_provider.dart';
import 'package:brook/providers/ytmusic_provider.dart';
import 'package:riverpod_annotation/riverpod_annotation.dart';
import 'package:fast_immutable_collections/fast_immutable_collections.dart';
part "search_provider.g.dart";
@riverpod
Future<IList<dynamic>> searchProvider(
Future<IList<SearchResult>> 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<SearchResult>()),
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),
},
);
}

View file

@ -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 {

View file

@ -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 {

View file

@ -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});

View file

@ -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';

View file

@ -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(),
),
),
],
);
}

View file

@ -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<TabPage> 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

View file

@ -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 {

View file

@ -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;

View file

@ -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';

View file

@ -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(

View file

@ -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.

View file

@ -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);

View file

@ -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:

View file

@ -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

View file

@ -1,7 +1,7 @@
<!DOCTYPE html>
<html>
<head>
<!--
<head>
<!--
If you are serving your web app in a path other than the root, change the
href value below to reflect the base path you are serving from.
@ -14,25 +14,25 @@
This is a placeholder for base href that will be replaced by the value of
the `--base-href` argument provided to `flutter build`.
-->
<base href="$FLUTTER_BASE_HREF">
<base href="$FLUTTER_BASE_HREF" />
<meta charset="UTF-8">
<meta content="IE=Edge" http-equiv="X-UA-Compatible">
<meta name="description" content="A new Flutter project.">
<meta charset="UTF-8" />
<meta content="IE=Edge" http-equiv="X-UA-Compatible" />
<meta name="description" content="A new Flutter project." />
<!-- iOS meta tags & icons -->
<meta name="apple-mobile-web-app-capable" content="yes">
<meta name="apple-mobile-web-app-status-bar-style" content="black">
<meta name="apple-mobile-web-app-title" content="canal">
<link rel="apple-touch-icon" href="icons/Icon-192.png">
<!-- iOS meta tags & icons -->
<meta name="apple-mobile-web-app-capable" content="yes" />
<meta name="apple-mobile-web-app-status-bar-style" content="black" />
<meta name="apple-mobile-web-app-title" content="brook" />
<link rel="apple-touch-icon" href="icons/Icon-192.png" />
<!-- Favicon -->
<link rel="icon" type="image/png" href="favicon.png"/>
<!-- Favicon -->
<link rel="icon" type="image/png" href="favicon.png" />
<title>canal</title>
<link rel="manifest" href="manifest.json">
</head>
<body>
<script src="flutter_bootstrap.js" async></script>
</body>
<title>brook</title>
<link rel="manifest" href="manifest.json" />
</head>
<body>
<script src="flutter_bootstrap.js" async></script>
</body>
</html>

View file

@ -1,6 +1,6 @@
{
"name": "canal",
"short_name": "canal",
"name": "brook",
"short_name": "brook",
"start_url": ".",
"display": "standalone",
"background_color": "#0175C2",