Skip to content

Commit

Permalink
fix: radio history tile images after new station uuid mapping (#998)
Browse files Browse the repository at this point in the history
  • Loading branch information
Feichtmeier authored Nov 5, 2024
1 parent ce9cf1b commit e305900
Show file tree
Hide file tree
Showing 11 changed files with 134 additions and 108 deletions.
8 changes: 7 additions & 1 deletion lib/main.dart
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ import 'player/player_service.dart';
import 'podcasts/download_model.dart';
import 'podcasts/podcast_model.dart';
import 'podcasts/podcast_service.dart';
import 'radio/online_art_model.dart';
import 'radio/online_art_service.dart';
import 'radio/radio_model.dart';
import 'radio/radio_service.dart';
Expand Down Expand Up @@ -182,6 +183,12 @@ void registerServicesAndViewModels({
)..init(),
dispose: (s) => s.dispose(),
)
..registerLazySingleton<OnlineArtModel>(
() => OnlineArtModel(
onlineArtService: di<OnlineArtService>(),
)..init(),
dispose: (s) => s.dispose(),
)
..registerLazySingleton<AppModel>(
() => AppModel(
appVersion: version,
Expand All @@ -207,7 +214,6 @@ void registerServicesAndViewModels({
..registerLazySingleton<RadioModel>(
() => RadioModel(
radioService: di<RadioService>(),
onlineArtService: di<OnlineArtService>(),
),
dispose: (s) => s.dispose(),
)
Expand Down
3 changes: 3 additions & 0 deletions lib/player/player_model.dart
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,9 @@ class PlayerModel extends SafeChangeNotifier {

int getRadioHistoryLength({String? filter}) =>
filteredRadioHistory(filter: filter).length;
MpvMetaData? getMetadata(String? icyTitle) =>
icyTitle == null ? null : _playerService.radioHistory[icyTitle];

Iterable<MapEntry<String, MpvMetaData>> filteredRadioHistory({
required String? filter,
}) {
Expand Down
4 changes: 2 additions & 2 deletions lib/player/player_service.dart
Original file line number Diff line number Diff line change
Expand Up @@ -81,13 +81,13 @@ class PlayerService {
}
if (validHistoryElement) {
_addRadioHistoryElement(
icyTitle: mpvMetaData!.icyTitle.everyWordCapitalized,
icyTitle: mpvMetaData!.icyTitle,
mpvMetaData: mpvMetaData!.copyWith(
icyName: audio?.title?.trim() ?? _mpvMetaData?.icyName ?? '',
),
);

await _processParsedIcyTitle(mpvMetaData!.icyTitle.everyWordCapitalized);
await _processParsedIcyTitle(mpvMetaData!.icyTitle);
}
_propertiesChangedController.add(true);
}
Expand Down
26 changes: 26 additions & 0 deletions lib/radio/online_art_model.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import 'dart:async';

import 'package:safe_change_notifier/safe_change_notifier.dart';

import 'online_art_service.dart';

class OnlineArtModel extends SafeChangeNotifier {
OnlineArtModel({
required OnlineArtService onlineArtService,
}) : _onlineArtService = onlineArtService;

final OnlineArtService _onlineArtService;
StreamSubscription<bool>? _propertiesChangedSub;
String? getCover(String icyTitle) => _onlineArtService.get(icyTitle);

void init() {
_propertiesChangedSub ??=
_onlineArtService.propertiesChanged.listen((_) => notifyListeners());
}

@override
Future<void> dispose() async {
await _propertiesChangedSub?.cancel();
super.dispose();
}
}
23 changes: 14 additions & 9 deletions lib/radio/online_art_service.dart
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,14 @@ const _kCoverArtArchiveAddress = 'https://coverartarchive.org/release/';
class OnlineArtService {
OnlineArtService({required Dio dio}) : _dio = dio;
final Dio _dio;
final _propertiesChangedController = StreamController<bool>.broadcast();
Stream<bool> get propertiesChanged => _propertiesChangedController.stream;
final _errorController = StreamController<String?>.broadcast();
Stream<String?> get error => _errorController.stream;

Future<String?> fetchAlbumArt(String icyTitle) async {
_errorController.add(null);
return get(icyTitle) ??
final albumArtUrl = get(icyTitle) ??
put(
key: icyTitle,
url: await compute(
Expand All @@ -29,23 +33,24 @@ class OnlineArtService {
return null;
}),
);
_propertiesChangedController.add(true);

return albumArtUrl;
}

final _value = <String, String?>{};
final _store = <String, String?>{};

String? put({required String key, String? url}) {
return _value.containsKey(key)
? _value.update(key, (value) => url)
: _value.putIfAbsent(key, () => url);
return _store.containsKey(key)
? _store.update(key, (value) => url)
: _store.putIfAbsent(key, () => url);
}

String? get(String? icyTitle) => icyTitle == null ? null : _value[icyTitle];

final _errorController = StreamController<String?>.broadcast();
Stream<String?> get error => _errorController.stream;
String? get(String? icyTitle) => icyTitle == null ? null : _store[icyTitle];

Future<void> dispose() async {
await _errorController.close();
await _propertiesChangedController.close();
}
}

Expand Down
11 changes: 2 additions & 9 deletions lib/radio/radio_model.dart
Original file line number Diff line number Diff line change
Expand Up @@ -4,20 +4,13 @@ import 'package:safe_change_notifier/safe_change_notifier.dart';

import '../common/data/audio.dart';
import '../l10n/l10n.dart';
import 'online_art_service.dart';
import 'radio_service.dart';

class RadioModel extends SafeChangeNotifier {
final RadioService _radioService;
final OnlineArtService _onlineArtService;

RadioModel({
required RadioService radioService,
required OnlineArtService onlineArtService,
}) : _radioService = radioService,
_onlineArtService = onlineArtService;

String? getCover(String icyTitle) => _onlineArtService.get(icyTitle);
RadioModel({required RadioService radioService})
: _radioService = radioService;

Future<void> clickStation(Audio? station) async {
if (station?.description != null) {
Expand Down
9 changes: 6 additions & 3 deletions lib/radio/view/radio_history_list.dart
Original file line number Diff line number Diff line change
Expand Up @@ -53,12 +53,12 @@ class RadioHistoryList extends StatelessWidget with WatchItMixin {
.elementAt(reversedIndex);
return simpleList
? RadioHistoryTile.simple(
entry: e,
icyTitle: e.key,
selected: current?.icyTitle != null &&
current?.icyTitle == e.value.icyTitle,
)
: RadioHistoryTile(
entry: e,
icyTitle: e.key,
selected: current?.icyTitle != null &&
current?.icyTitle == e.value.icyTitle,
);
Expand All @@ -77,12 +77,14 @@ class SliverRadioHistoryList extends StatelessWidget with WatchItMixin {
this.emptyMessage,
this.padding,
this.emptyIcon,
required this.allowNavigation,
});

final String? filter;
final Widget? emptyMessage;
final Widget? emptyIcon;
final EdgeInsetsGeometry? padding;
final bool allowNavigation;

@override
Widget build(BuildContext context) {
Expand All @@ -109,9 +111,10 @@ class SliverRadioHistoryList extends StatelessWidget with WatchItMixin {
.filteredRadioHistory(filter: filter)
.elementAt(reversedIndex);
return RadioHistoryTile(
entry: e,
icyTitle: e.key,
selected: current?.icyTitle != null &&
current?.icyTitle == e.value.icyTitle,
allowNavigation: allowNavigation,
);
},
childCount: length,
Expand Down
99 changes: 52 additions & 47 deletions lib/radio/view/radio_history_tile.dart
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ import 'package:yaru/constants.dart';
import 'package:yaru/yaru.dart';

import '../../common/data/audio.dart';
import '../../common/data/mpv_meta_data.dart';
import '../../common/view/copy_clipboard_content.dart';
import '../../common/view/icons.dart';
import '../../common/view/mpv_metadata_dialog.dart';
Expand All @@ -15,92 +14,98 @@ import '../../extensions/build_context_x.dart';
import '../../extensions/theme_data_x.dart';
import '../../l10n/l10n.dart';
import '../../library/library_model.dart';
import '../../player/player_model.dart';
import '../../search/search_model.dart';
import '../online_art_model.dart';
import '../radio_model.dart';
import 'icy_image.dart';
import 'radio_history_tile_image.dart';
import 'station_page.dart';

enum _RadioHistoryTileVariant { regular, simple }

class RadioHistoryTile extends StatelessWidget {
const RadioHistoryTile({
super.key,
required this.entry,
required this.icyTitle,
required this.selected,
this.allowNavigation = true,
}) : _variant = _RadioHistoryTileVariant.regular;

const RadioHistoryTile.simple({
super.key,
required this.entry,
required this.icyTitle,
required this.selected,
this.allowNavigation = false,
}) : _variant = _RadioHistoryTileVariant.simple;

final _RadioHistoryTileVariant _variant;
final MapEntry<String, MpvMetaData> entry;
final String icyTitle;
final bool selected;
final bool allowNavigation;

@override
Widget build(BuildContext context) {
final icyName = di<PlayerModel>().getMetadata(icyTitle)?.icyName;
return switch (_variant) {
_RadioHistoryTileVariant.simple => _SimpleRadioHistoryTile(
key: ValueKey(entry.value.icyTitle),
entry: entry,
key: ValueKey(icyTitle),
icyTitle: icyTitle,
selected: selected,
),
_RadioHistoryTileVariant.regular => ListTile(
key: ValueKey(entry.value.icyTitle),
key: ValueKey(icyTitle),
selected: selected,
selectedColor: context.theme.contrastyPrimary,
contentPadding:
const EdgeInsets.symmetric(horizontal: kYaruPagePadding),
leading: IcyImage(
key: ValueKey(entry.value.icyTitle),
leading: RadioHistoryTileImage(
key: ValueKey(icyTitle),
height: yaruStyled ? 34 : 40,
width: yaruStyled ? 34 : 40,
mpvMetaData: entry.value,
icyTitle: icyTitle,
),
trailing: IconButton(
tooltip: context.l10n.metadata,
onPressed: () => showDialog(
context: context,
builder: (context) {
final image = di<RadioModel>().getCover(entry.value.icyTitle);
return MpvMetadataDialog(
mpvMetaData: entry.value,
onPressed: () {
final image = di<OnlineArtModel>().getCover(icyTitle);
final metadata = di<PlayerModel>().getMetadata(icyTitle);
if (metadata == null) return;
showDialog(
context: context,
builder: (context) => MpvMetadataDialog(
mpvMetaData: metadata,
image: image,
);
},
),
icon: Icon(
Iconz.info,
),
),
);
},
icon: Icon(Iconz.info),
),
title: TapAbleText(
overflow: TextOverflow.visible,
maxLines: 10,
text: entry.value.icyTitle,
text: icyTitle,
onTap: () => showSnackBar(
context: context,
content: CopyClipboardContent(text: entry.value.icyTitle),
content: CopyClipboardContent(text: icyTitle),
),
),
subtitle: TapAbleText(
text: entry.value.icyName,
onTap: () async {
final libraryModel = di<LibraryModel>();
if (libraryModel.selectedPageId == entry.value.icyUrl) return;

await di<RadioModel>().init();
di<SearchModel>().radioNameSearch(entry.value.icyName).then((v) {
if (v?.firstOrNull?.stationUUID != null) {
libraryModel.push(
builder: (_) =>
StationPage(station: Audio.fromStation(v.first)),
pageId: v!.first.stationUUID,
);
}
});
},
text: icyName ?? context.l10n.station,
onTap: !allowNavigation || icyName == null
? null
: () async {
await di<RadioModel>().init();
di<SearchModel>().radioNameSearch(icyName).then((v) {
if (v?.firstOrNull?.stationUUID != null) {
di<LibraryModel>().push(
builder: (_) => StationPage(
station: Audio.fromStation(v.first),
),
pageId: v!.first.stationUUID,
);
}
});
},
),
)
};
Expand All @@ -110,17 +115,16 @@ class RadioHistoryTile extends StatelessWidget {
class _SimpleRadioHistoryTile extends StatelessWidget {
const _SimpleRadioHistoryTile({
super.key,
required this.entry,
required this.icyTitle,
required this.selected,
});

final MapEntry<String, MpvMetaData> entry;
final String icyTitle;
final bool selected;

@override
Widget build(BuildContext context) {
return ListTile(
key: ValueKey(entry.value.icyTitle),
selected: selected,
selectedColor: context.theme.colorScheme.onSurface,
contentPadding: const EdgeInsets.symmetric(horizontal: kYaruPagePadding),
Expand All @@ -135,14 +139,15 @@ class _SimpleRadioHistoryTile extends StatelessWidget {
title: TapAbleText(
overflow: TextOverflow.visible,
maxLines: 10,
text: entry.value.icyTitle,
text: icyTitle,
onTap: () => showSnackBar(
context: context,
content: CopyClipboardContent(text: entry.value.icyTitle),
content: CopyClipboardContent(text: icyTitle),
),
),
subtitle: Text(
entry.value.icyName,
di<PlayerModel>().getMetadata(icyTitle)?.icyName ??
context.l10n.station,
),
);
}
Expand Down
Loading

0 comments on commit e305900

Please sign in to comment.