Skip to content

Commit

Permalink
feat: make use of pinned albums in the mobile view, persist local aud…
Browse files Browse the repository at this point in the history
…io index (again) (#1044)
  • Loading branch information
Feichtmeier authored Nov 23, 2024
1 parent 699eb9b commit 195f57f
Show file tree
Hide file tree
Showing 11 changed files with 145 additions and 56 deletions.
44 changes: 44 additions & 0 deletions lib/common/view/audio_card_vignette.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
import '../../extensions/build_context_x.dart';
import '../../l10n/l10n.dart';
import 'package:flutter/material.dart';
import 'package:yaru/yaru.dart';
import 'theme.dart';

class AudioCardVignette extends StatelessWidget {
const AudioCardVignette({
super.key,
this.onTap,
required this.iconData,
});

final void Function()? onTap;
final IconData iconData;

@override
Widget build(BuildContext context) {
final colorScheme = context.colorScheme;
const borderRadius = BorderRadius.only(
bottomLeft: Radius.circular(kYaruContainerRadius),
topRight: Radius.circular(kYaruContainerRadius),
);
return Tooltip(
message: context.l10n.unPinAlbum,
child: InkWell(
borderRadius: borderRadius,
onTap: onTap,
child: Container(
decoration: BoxDecoration(
color: colorScheme.inverseSurface,
borderRadius: borderRadius,
),
width: audioCardDimension / (isMobile ? 3 : 4),
height: audioCardDimension / (isMobile ? 3 : 4),
child: Icon(
iconData,
color: colorScheme.onInverseSurface,
),
),
),
);
}
}
48 changes: 29 additions & 19 deletions lib/local_audio/local_audio_model.dart
Original file line number Diff line number Diff line change
Expand Up @@ -5,21 +5,30 @@ import 'package:safe_change_notifier/safe_change_notifier.dart';

import '../common/data/audio.dart';
import '../common/view/audio_filter.dart';
import '../settings/settings_service.dart';
import 'local_audio_service.dart';
import 'local_audio_view.dart';

class LocalAudioModel extends SafeChangeNotifier {
LocalAudioModel({
required LocalAudioService localAudioService,
}) : _service = localAudioService;
required SettingsService settingsService,
}) : _localAudioService = localAudioService,
_settingsService = settingsService;

final LocalAudioService _service;
final LocalAudioService _localAudioService;
final SettingsService _settingsService;
StreamSubscription<bool>? _audiosChangedSub;

int _localAudioIndex = 2;
int get localAudioindex => _localAudioIndex;
int? _localAudioIndex;
int get localAudioindex =>
_localAudioIndex ?? LocalAudioView.values.indexOf(LocalAudioView.albums);
set localAudioindex(int value) {
if (value == _localAudioIndex) return;
_localAudioIndex = value;
// Note: we do not listen to the local audio index change on purpose, we just pump it into the sink
// and load it fresh in init
_settingsService.setLocalAudioIndex(value);
notifyListeners();
}

Expand All @@ -39,60 +48,61 @@ class LocalAudioModel extends SafeChangeNotifier {
notifyListeners();
}

List<Audio>? get audios => _service.audios;
List<String>? get allArtists => _service.allArtists;
List<String>? get allAlbumArtists => _service.allAlbumArtists;
List<String>? get allGenres => _service.allGenres;
List<String>? get allAlbums => _service.allAlbums;
List<Audio>? get audios => _localAudioService.audios;
List<String>? get allArtists => _localAudioService.allArtists;
List<String>? get allAlbumArtists => _localAudioService.allAlbumArtists;
List<String>? get allGenres => _localAudioService.allGenres;
List<String>? get allAlbums => _localAudioService.allAlbums;

List<Audio>? findAlbum(
String albumName, [
AudioFilter audioFilter = AudioFilter.trackNumber,
]) =>
_service.findAlbum(albumName, audioFilter);
_localAudioService.findAlbum(albumName, audioFilter);

List<Audio>? findTitlesOfArtist(
String artist, [
AudioFilter audioFilter = AudioFilter.album,
]) =>
_service.findTitlesOfArtist(artist, audioFilter);
_localAudioService.findTitlesOfArtist(artist, audioFilter);

List<Audio>? findTitlesOfAlbumArtists(
String artist, [
AudioFilter audioFilter = AudioFilter.album,
]) =>
_service.findTitlesOfAlbumArtists(artist, audioFilter);
_localAudioService.findTitlesOfAlbumArtists(artist, audioFilter);

List<String>? findArtistsOfGenre(String genre) =>
_service.findArtistsOfGenre(genre);
_localAudioService.findArtistsOfGenre(genre);

Set<Uint8List>? findLocalCovers({
required List<Audio> audios,
int limit = 4,
}) =>
_service.findLocalCovers(audios: audios, limit: limit);
_localAudioService.findLocalCovers(audios: audios, limit: limit);

List<Audio> findUniqueAlbumAudios(List<Audio> audios) =>
_service.findUniqueAlbumAudios(audios);
_localAudioService.findUniqueAlbumAudios(audios);

List<String>? get failedImports => _service.failedImports;
List<String>? get failedImports => _localAudioService.failedImports;

List<String>? findAllAlbums({
Iterable<Audio>? newAudios,
bool clean = true,
}) =>
_service.findAllAlbums(newAudios: newAudios, clean: clean);
_localAudioService.findAllAlbums(newAudios: newAudios, clean: clean);

Future<void> init({
bool forceInit = false,
String? directory,
}) async {
await _service.init(
_localAudioIndex = _settingsService.localAudioIndex;
await _localAudioService.init(
forceInit: forceInit,
directory: directory,
);
_audiosChangedSub ??=
_service.audiosChanged.listen((_) => notifyListeners());
_localAudioService.audiosChanged.listen((_) => notifyListeners());

notifyListeners();
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import '../../l10n/l10n.dart';
import '../l10n/l10n.dart';

enum LocalAudioView {
titles,
Expand Down
87 changes: 57 additions & 30 deletions lib/local_audio/view/album_view.dart
Original file line number Diff line number Diff line change
@@ -1,13 +1,17 @@
import 'package:collection/collection.dart';
import 'package:flutter/material.dart';
import 'package:watch_it/watch_it.dart';
import 'package:yaru/yaru.dart';

import '../../common/view/audio_card.dart';
import '../../common/view/audio_card_bottom.dart';
import '../../common/view/audio_card_vignette.dart';
import '../../common/view/cover_background.dart';
import '../../common/view/icons.dart';
import '../../common/view/no_search_result_page.dart';
import '../../common/view/sliver_fill_remaining_progress.dart';
import '../../common/view/theme.dart';
import '../../constants.dart';
import '../../library/library_model.dart';
import '../../player/player_model.dart';
import '../local_audio_model.dart';
Expand Down Expand Up @@ -39,13 +43,14 @@ class AlbumsView extends StatelessWidget with WatchItMixin {
}

watchPropertyValue((LibraryModel m) => m.pinnedAlbums.hashCode);
final pinnedAlbums = di<LibraryModel>()
.pinnedAlbums
.entries
.map((e) => e.value.firstOrNull?.album);
final pinnedAlbums = di<LibraryModel>().pinnedAlbums;
final pinnedAlbumsAlbumNames =
pinnedAlbums.entries.map((e) => e.value.firstOrNull?.album);
final pinned = albums!.where((e) => pinnedAlbumsAlbumNames.contains(e));
final notPinned = albums!.where((e) => !pinnedAlbumsAlbumNames.contains(e));
final sortedAlbums = [
...albums!.where((e) => pinnedAlbums.contains(e)),
...albums!.where((e) => !pinnedAlbums.contains(e)),
...pinned,
...notPinned,
];

return SliverGrid.builder(
Expand All @@ -56,16 +61,22 @@ class AlbumsView extends StatelessWidget with WatchItMixin {
return AlbumCard(
key: ValueKey(album),
album: album,
pinned: pinned.contains(album),
);
},
);
}
}

class AlbumCard extends StatelessWidget {
const AlbumCard({super.key, required this.album});
const AlbumCard({
super.key,
required this.album,
required this.pinned,
});

final String album;
final bool pinned;

@override
Widget build(BuildContext context) {
Expand All @@ -76,29 +87,45 @@ class AlbumCard extends StatelessWidget {
final id = albumAudios?.firstWhereOrNull((e) => e.albumId != null)?.albumId;
final path = albumAudios?.firstWhereOrNull((e) => e.path != null)?.path;

return AudioCard(
bottom: AudioCardBottom(text: album),
image: id != null && path != null
? LocalCover(
dimension: audioCardDimension,
albumId: id,
path: path,
fallback: fallback,
)
: const CoverBackground(),
background: fallback,
onTap: id == null || albumAudios == null
? null
: () => di<LibraryModel>().push(
builder: (context) => AlbumPage(id: id, album: albumAudios),
pageId: id,
),
onPlay: albumAudios == null || albumAudios.isEmpty || id == null
? null
: () => playerModel.startPlaylist(
audios: albumAudios,
listName: id,
),
return Stack(
alignment: Alignment.center,
children: [
AudioCard(
bottom: AudioCardBottom(text: album),
image: id != null && path != null
? LocalCover(
dimension: audioCardDimension,
albumId: id,
path: path,
fallback: fallback,
)
: const CoverBackground(),
background: fallback,
onTap: id == null || albumAudios == null
? null
: () => di<LibraryModel>().push(
builder: (context) => AlbumPage(id: id, album: albumAudios),
pageId: id,
),
onPlay: albumAudios == null || albumAudios.isEmpty || id == null
? null
: () => playerModel.startPlaylist(
audios: albumAudios,
listName: id,
),
),
if (pinned)
Positioned(
left: isMobile ? 6 : 5,
bottom: kAudioCardBottomHeight + (isMobile ? 25 : 13),
child: AudioCardVignette(
iconData: Iconz.pinFilled,
onTap: id == null
? null
: () => di<LibraryModel>().removePinnedAlbum(id),
),
),
],
);
}
}
2 changes: 1 addition & 1 deletion lib/local_audio/view/local_audio_body.dart
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import '../../common/data/audio.dart';
import 'album_view.dart';
import 'artists_view.dart';
import 'genres_view.dart';
import 'local_audio_view.dart';
import '../local_audio_view.dart';
import 'playlists_view.dart';
import 'titles_view.dart';

Expand Down
2 changes: 1 addition & 1 deletion lib/local_audio/view/local_audio_control_panel.dart
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import 'package:yaru/yaru.dart';
import '../../common/view/icons.dart';
import '../../l10n/l10n.dart';
import '../local_audio_model.dart';
import 'local_audio_view.dart';
import '../local_audio_view.dart';

class LocalAudioControlPanel extends StatelessWidget with WatchItMixin {
const LocalAudioControlPanel({super.key});
Expand Down
2 changes: 1 addition & 1 deletion lib/local_audio/view/local_audio_page.dart
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ import '../local_audio_model.dart';
import 'failed_imports_content.dart';
import 'local_audio_body.dart';
import 'local_audio_control_panel.dart';
import 'local_audio_view.dart';
import '../local_audio_view.dart';

class LocalAudioPage extends StatefulWidget with WatchItStatefulWidgetMixin {
const LocalAudioPage({super.key});
Expand Down
2 changes: 1 addition & 1 deletion lib/playlists/view/manual_add_dialog.dart
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import '../../external_path/external_path_service.dart';
import '../../l10n/l10n.dart';
import '../../library/library_model.dart';
import '../../local_audio/local_audio_model.dart';
import '../../local_audio/view/local_audio_view.dart';
import '../../local_audio/local_audio_view.dart';
import '../../podcasts/podcast_model.dart';

class ManualAddDialog extends StatelessWidget {
Expand Down
5 changes: 4 additions & 1 deletion lib/register.dart
Original file line number Diff line number Diff line change
Expand Up @@ -187,7 +187,10 @@ Future<void> registerDependencies({
dispose: (s) => s.dispose(),
)
..registerLazySingleton<LocalAudioModel>(
() => LocalAudioModel(localAudioService: di<LocalAudioService>()),
() => LocalAudioModel(
localAudioService: di<LocalAudioService>(),
settingsService: di<SettingsService>(),
),
dispose: (s) => s.dispose(),
)
..registerLazySingleton<PodcastModel>(
Expand Down
2 changes: 1 addition & 1 deletion lib/search/view/sliver_local_search_results.dart
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import '../../l10n/l10n.dart';
import '../../local_audio/local_audio_model.dart';
import '../../local_audio/view/failed_imports_content.dart';
import '../../local_audio/view/local_audio_body.dart';
import '../../local_audio/view/local_audio_view.dart';
import '../../local_audio/local_audio_view.dart';
import '../search_model.dart';
import '../search_type.dart';

Expand Down
5 changes: 5 additions & 0 deletions lib/settings/settings_service.dart
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,11 @@ class SettingsService {
_preferences.setInt(kThemeIndex, value).then(notify);
}

int get localAudioIndex => _preferences.getInt(kLocalAudioIndex) ?? 0;
void setLocalAudioIndex(int value) {
_preferences.setInt(kLocalAudioIndex, value).then(notify);
}

bool get neverShowFailedImports =>
_preferences.getBool(kNeverShowImportFails) ?? false;
void setNeverShowFailedImports(bool value) {
Expand Down

0 comments on commit 195f57f

Please sign in to comment.