Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: improve radio search and update yaru #1101

Merged
merged 1 commit into from
Dec 19, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 12 additions & 3 deletions lib/app/view/desktop_musicpod_app.dart
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,9 @@ import 'dart:ui';
import 'package:flutter/material.dart';
import 'package:phoenix_theme/phoenix_theme.dart';
import 'package:watch_it/watch_it.dart';
import 'package:yaru/yaru.dart';

import '../../app_config.dart';
import '../../constants.dart';
import '../../external_path/external_path_service.dart';
import '../../l10n/l10n.dart';
Expand Down Expand Up @@ -56,15 +58,22 @@ class _DesktopMusicPodAppState extends State<DesktopMusicPodApp> {
@override
Widget build(BuildContext context) {
final themeIndex = watchPropertyValue((SettingsModel m) => m.themeIndex);
final phoenix = phoenixTheme(color: widget.accent ?? Colors.greenAccent);
final color = widget.accent ?? const Color(0xFFed3c63);
final phoenix = phoenixTheme(color: color);

return MaterialApp(
debugShowCheckedModeBanner: false,
themeMode: ThemeMode.values[themeIndex],
highContrastTheme: widget.highContrastTheme,
highContrastDarkTheme: widget.highContrastDarkTheme,
theme: widget.lightTheme ?? phoenix.lightTheme,
darkTheme: widget.darkTheme ?? phoenix.darkTheme,
theme: widget.lightTheme ??
(yaruStyled
? createYaruLightTheme(primaryColor: color)
: phoenix.lightTheme),
darkTheme: widget.darkTheme ??
(yaruStyled
? createYaruDarkTheme(primaryColor: color)
: phoenix.darkTheme),
localizationsDelegates: AppLocalizations.localizationsDelegates,
supportedLocales: supportedLocales,
onGenerateTitle: (context) => kAppTitle,
Expand Down
6 changes: 5 additions & 1 deletion lib/app/view/main_page_icon.dart
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,11 @@ class MainPageIcon extends StatelessWidget with WatchItMixin {

return Padding(
padding: mainPageIconPadding,
child: Icon(selected ? audioType.selectedIconData : audioType.iconData),
child: Icon(
selected
? audioType.selectedIconDataMainPage
: audioType.iconDataMainPage,
),
);
}
}
2 changes: 2 additions & 0 deletions lib/app_config.dart
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ bool allowDiscordRPC = (kDebugMode && !Platform.isAndroid) ||
Platform.isWindows ||
bool.tryParse(const String.fromEnvironment('ALLOW_DISCORD_RPC')) == true;

bool get useSystemTheme => !Platform.isLinux;

bool get yaruStyled => Platform.isLinux;

bool get appleStyled => Platform.isMacOS || Platform.isIOS;
Expand Down
14 changes: 13 additions & 1 deletion lib/common/data/audio_type.dart
Original file line number Diff line number Diff line change
Expand Up @@ -15,12 +15,24 @@ enum AudioType {
};

IconData get iconData => switch (this) {
local => Iconz.localAudio,
local => Iconz.musicNote,
radio => Iconz.radio,
podcast => Iconz.podcast,
};

IconData get selectedIconData => switch (this) {
local => Iconz.musicNote,
radio => Iconz.radioFilled,
podcast => Iconz.podcastFilled,
};

IconData get iconDataMainPage => switch (this) {
local => Iconz.localAudio,
radio => Iconz.radio,
podcast => Iconz.podcast,
};

IconData get selectedIconDataMainPage => switch (this) {
local => Iconz.localAudioFilled,
radio => Iconz.radioFilled,
podcast => Iconz.podcastFilled,
Expand Down
57 changes: 57 additions & 0 deletions lib/common/view/audio_fall_back_icon.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
import 'package:flutter/material.dart';
import 'package:yaru/yaru.dart';

import '../data/audio.dart';
import 'icons.dart';
import 'theme.dart';
import '../../extensions/build_context_x.dart';
import '../../extensions/theme_data_x.dart';

class AudioFallBackIcon extends StatelessWidget {
const AudioFallBackIcon({
super.key,
required this.audio,
this.iconSize,
this.dimension,
this.color,
});

final double? iconSize;
final Audio? audio;
final double? dimension;
final Color? color;

@override
Widget build(BuildContext context) {
final theme = context.theme;
final light = theme.isLight;
final fallBackColor = theme.primaryColor;
final gradientColor = color ??
getAlphabetColor(
audio?.title ?? audio?.album ?? '',
fallBackColor,
);
return Container(
height: dimension ?? double.infinity,
width: dimension ?? double.infinity,
decoration: BoxDecoration(
gradient: LinearGradient(
begin: Alignment.bottomLeft,
end: Alignment.topRight,
colors: [
gradientColor.scale(lightness: light ? 0 : -0.4, saturation: -0.5),
gradientColor.scale(
lightness: light ? -0.1 : -0.2,
saturation: -0.5,
),
],
),
),
child: Icon(
audio?.audioType?.iconData ?? Iconz.musicNote,
size: iconSize,
color: contrastColor(gradientColor).withOpacity(0.7),
),
);
}
}
1 change: 1 addition & 0 deletions lib/common/view/audio_tile.dart
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,7 @@ class _AudioTileState extends State<AudioTile> {
},
title: Padding(
padding: const EdgeInsets.only(right: kLargestSpace),
// TODO: make playlists audiotype agnostic and stop forwarding callbacks once and for all
child: widget.onTitleTap == null
? Text(
widget.audio.title ?? l10n.unknown,
Expand Down
27 changes: 10 additions & 17 deletions lib/common/view/audio_tile_image.dart
Original file line number Diff line number Diff line change
@@ -1,50 +1,43 @@
import 'package:flutter/material.dart';

import 'ui_constants.dart';
import '../../local_audio/view/local_cover.dart';
import '../data/audio.dart';
import '../data/audio_type.dart';
import 'icons.dart';
import 'audio_fall_back_icon.dart';
import 'safe_network_image.dart';
import 'ui_constants.dart';

class AudioTileImage extends StatelessWidget {
const AudioTileImage({
super.key,
this.audio,
required this.size,
this.fallback,
});
final Audio? audio;
final double size;
final Widget? fallback;

@override
Widget build(BuildContext context) {
final icon = Icon(
switch (audio?.audioType) {
AudioType.radio => Iconz.radio,
AudioType.podcast => Iconz.podcast,
_ => Iconz.musicNote,
},
size: size / (1.65),
);
final fallbackIcon =
AudioFallBackIcon(audio: audio, iconSize: size / (1.65));
Widget image;
if (audio?.hasPathAndId == true) {
image = LocalCover(
albumId: audio!.albumId!,
path: audio!.path!,
fit: BoxFit.cover,
dimension: size,
fallback: icon,
fallback: fallbackIcon,
);
} else if (audio?.imageUrl != null || audio?.albumArtUrl != null) {
} else {
image = SafeNetworkImage(
url: audio?.imageUrl ?? audio?.albumArtUrl,
height: size,
fit: BoxFit.cover,
fallBackIcon: icon,
errorIcon: icon,
fallBackIcon: fallbackIcon,
errorIcon: fallbackIcon,
);
} else {
image = icon;
}

return SizedBox.square(
Expand Down
1 change: 0 additions & 1 deletion lib/common/view/progress.dart
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,6 @@ class LinearProgress extends StatelessWidget {
return yaruStyled
? YaruLinearProgressIndicator(
value: value,
minHeight: trackHeight,
strokeWidth: trackHeight,
color: color,
)
Expand Down
2 changes: 1 addition & 1 deletion lib/main.dart
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ Future<void> main(List<String> args) async {
..setMinimumSize(const Size(500, 700))
..setSize(const Size(950, 820));
}
if (!yaruStyled) {
if (useSystemTheme) {
SystemTheme.fallbackColor = const Color(0xFFed3c63);
await SystemTheme.accentColor.load();
}
Expand Down
27 changes: 5 additions & 22 deletions lib/player/view/player_fall_back_image.dart
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,7 @@ import 'package:flutter/material.dart';
import 'package:yaru/yaru.dart';

import '../../common/data/audio.dart';
import '../../common/data/audio_type.dart';
import '../../common/view/icons.dart';
import '../../common/view/theme.dart';
import '../../extensions/build_context_x.dart';
import '../../extensions/theme_data_x.dart';

Expand All @@ -26,30 +24,19 @@ class PlayerFallBackImage extends StatelessWidget {
Widget build(BuildContext context) {
final iconSize = width * 0.7;
final theme = context.theme;
IconData iconData;
if (audio?.audioType == AudioType.radio) {
iconData = Iconz.radio;
} else if (audio?.audioType == AudioType.podcast) {
iconData = Iconz.podcast;
} else {
iconData = Iconz.musicNote;
}
final color = theme.primaryColor;
return Center(
child: Container(
decoration: BoxDecoration(
gradient: LinearGradient(
begin: Alignment.bottomLeft,
end: Alignment.topRight,
colors: [
getAlphabetColor(
audio?.title ?? audio?.album ?? 'a',
).scale(
color.scale(
lightness: theme.isLight ? 0 : -0.4,
saturation: -0.5,
),
getAlphabetColor(
audio?.title ?? audio?.album ?? 'a',
).scale(
color.scale(
lightness: theme.isLight ? -0.1 : -0.2,
saturation: -0.5,
),
Expand All @@ -61,13 +48,9 @@ class PlayerFallBackImage extends StatelessWidget {
child: noIcon
? null
: Icon(
iconData,
audio?.audioType?.iconData ?? Iconz.musicNote,
size: iconSize,
color: contrastColor(
getAlphabetColor(
audio?.title ?? audio?.album ?? 'a',
),
),
color: contrastColor(color),
),
),
);
Expand Down
45 changes: 36 additions & 9 deletions lib/radio/radio_service.dart
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,14 @@ class RadioService {
return hosts;
}

RadioBrowserListResponse<Station>? _response;
String? _uuid;
String? _country;
String? _name;
String? _state;
String? _tag;
String? _language;
int? _limit;
Future<List<Station>?> search({
String? uuid,
String? country,
Expand All @@ -72,36 +80,55 @@ class RadioService {
}
}

RadioBrowserListResponse<Station>? response;
if (_response?.items != null &&
_uuid == uuid &&
_country == country &&
_name == name &&
_state == state &&
_tag == tag &&
_language == language &&
_limit == limit) {
return _response?.items;
}

final parameters = InputParameters(
hidebroken: true,
order: 'stationcount',
limit: limit,
limit: limit > 300 ? 300 : limit,
);
try {
if (uuid != null) {
response = await _radioBrowserApi!.getStationsByUUID(uuids: [uuid]);
_response = await _radioBrowserApi!.getStationsByUUID(uuids: [uuid]);
}
if (name?.isEmpty == false) {
response = await _radioBrowserApi!
_response = await _radioBrowserApi!
.getStationsByName(name: name!, parameters: parameters);
} else if (country?.isEmpty == false) {
response = await _radioBrowserApi!
_response = await _radioBrowserApi!
.getStationsByCountry(country: country!, parameters: parameters);
} else if (tag?.isEmpty == false) {
response = await _radioBrowserApi!
_response = await _radioBrowserApi!
.getStationsByTag(tag: tag!, parameters: parameters);
} else if (state?.isEmpty == false) {
response = await _radioBrowserApi!
_response = await _radioBrowserApi!
.getStationsByState(state: state!, parameters: parameters);
} else if (language?.isEmpty == false) {
response = await _radioBrowserApi!
_response = await _radioBrowserApi!
.getStationsByLanguage(language: language!, parameters: parameters);
}
} on Exception catch (e) {
printMessageInDebugMode(e);
}
return response?.items ?? [];

_uuid = uuid;
_country = country;
_name = name;
_state = state;
_tag = tag;
_language = language;
_limit = limit;

return _response?.items ?? [];
}

List<Tag>? _tags;
Expand Down
Loading
Loading