This commit is contained in:
Moritz Weber 2023-03-11 21:18:36 +01:00
parent fce520abc7
commit 5a64e50423
12 changed files with 161 additions and 5 deletions

View file

@ -6,3 +6,4 @@
- Fix bug with smart lists in history entries
- Added logging to files
- Implement natural sorting for album songs (#59)
- Add option for counting songs as played (#38)

View file

@ -10,3 +10,5 @@ const String SETTING_PLAY_ALBUMS_IN_ORDER = 'SETTING_PLAY_ALBUMS_IN_ORDER';
const String ALBUM_OF_DAY = 'ALBUM_OF_DAY';
const String ARTIST_OF_DAY = 'ARTIST_OF_DAY';
const String LISTENED_PERCENTAGE = 'LISTENED_PERCENTAGE';

View file

@ -2,26 +2,33 @@ import '../entities/song.dart';
import '../repositories/audio_player_repository.dart';
import '../repositories/music_data_repository.dart';
import '../repositories/platform_integration_repository.dart';
import '../repositories/settings_repository.dart';
class AudioPlayerActor {
AudioPlayerActor(
this._audioPlayerRepository,
this._musicDataRepository,
this._platformIntegrationRepository,
this._settingsInfoRepository,
) {
_audioPlayerRepository.currentSongStream.listen(_handleCurrentSong);
_audioPlayerRepository.playbackEventStream
.listen(_platformIntegrationRepository.handlePlaybackEvent);
_audioPlayerRepository.positionStream
.listen((duration) => _handlePosition(duration, _currentSong));
_listenedPercentage = _settingsInfoRepository.listenedPercentageStream.valueOrNull ?? 50;
_settingsInfoRepository.listenedPercentageStream.listen((event) => _listenedPercentage = event);
}
final AudioPlayerRepository _audioPlayerRepository;
final MusicDataRepository _musicDataRepository;
final PlatformIntegrationRepository _platformIntegrationRepository;
final SettingsInfoRepository _settingsInfoRepository;
Song? _currentSong;
bool _countSongPlayback = false;
late int _listenedPercentage;
Future<void> _handleCurrentSong(Song? song) async {
_currentSong = song;
@ -33,9 +40,9 @@ class AudioPlayerActor {
return;
}
if (position < song.duration * 0.05) {
if (position < song.duration * 0.01) {
_countSongPlayback = true;
} else if (position > song.duration * 0.95 && _countSongPlayback) {
} else if (position > song.duration * (_listenedPercentage / 100) && _countSongPlayback) {
_countSongPlayback = false;
await _musicDataRepository.incrementPlayCount(song);
}

View file

@ -4,6 +4,7 @@ abstract class SettingsInfoRepository {
Stream<List<String>> get libraryFoldersStream;
ValueStream<String> get fileExtensionsStream;
ValueStream<bool> get playAlbumsInOrderStream;
ValueStream<int> get listenedPercentageStream;
}
abstract class SettingsRepository extends SettingsInfoRepository {
@ -11,4 +12,5 @@ abstract class SettingsRepository extends SettingsInfoRepository {
Future<void> removeLibraryFolder(String? path);
Future<void> setFileExtension(String extensions);
Future<void> setPlayAlbumsInOrder(bool playInOrder);
Future<void> setListenedPercentage(int percentage);
}

View file

@ -294,6 +294,9 @@ Future<void> setupGetIt() async {
getIt(),
),
);
getIt.registerLazySingleton<SettingsInfoRepository>(
() => getIt<SettingsRepository>(),
);
getIt.registerLazySingleton<PlatformIntegrationRepository>(
() => PlatformIntegrationRepositoryImpl(
getIt(),
@ -369,6 +372,7 @@ Future<void> setupGetIt() async {
getIt(),
getIt(),
getIt(),
getIt(),
),
);

View file

@ -1,3 +1,5 @@
import 'dart:async';
import 'package:flutter/material.dart';
import 'package:flutter_mobx/flutter_mobx.dart';
import 'package:get_it/get_it.dart';
@ -158,6 +160,10 @@ class SettingsPage extends StatelessWidget {
isThreeLine: true,
),
),
const Divider(
height: 4.0,
),
PercentageSlider(settingsStore),
],
),
),
@ -191,3 +197,69 @@ class SettingsSection extends StatelessWidget {
);
}
}
class PercentageSlider extends StatefulWidget {
const PercentageSlider(this.settingsStore, {super.key});
final SettingsStore settingsStore;
@override
State<PercentageSlider> createState() => _PercentageSliderState();
}
class _PercentageSliderState extends State<PercentageSlider> {
late double _value;
late StreamSubscription _streamSubscription;
@override
void initState() {
_value = (widget.settingsStore.listenedPercentageStream.value ?? 50).toDouble();
_streamSubscription = widget.settingsStore.listenedPercentageStream.listen(
(value) => setState(() => _value = value.toDouble()),
);
super.initState();
}
@override
void dispose() {
_streamSubscription.cancel();
super.dispose();
}
@override
Widget build(BuildContext context) {
return Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Padding(
padding: const EdgeInsets.only(
left: HORIZONTAL_PADDING,
right: HORIZONTAL_PADDING,
top: 16.0,
),
child: Text(
'Count songs as played after: ${_value.round()}%',
style: Theme.of(context).textTheme.titleMedium,
),
),
Padding(
padding: const EdgeInsets.symmetric(vertical: 4.0),
child: Slider(
value: _value,
onChanged: (value) {
setState(() {
_value = value;
});
},
onChangeEnd: (value) {
widget.settingsStore.setListenedPercentage(value.round());
},
min: 1,
max: 99,
),
),
],
);
}
}

View file

@ -33,6 +33,10 @@ abstract class _SettingsStore with Store {
late ObservableStream<Set<String>> blockedFilesStream =
_musicDataRepository.blockedFilesStream.asObservable(initialValue: {});
@observable
late ObservableStream<int> listenedPercentageStream =
_settingsRepository.listenedPercentageStream.asObservable();
@computed
int get numBlockedFiles => blockedFilesStream.value!.length;
@ -66,5 +70,9 @@ abstract class _SettingsStore with Store {
await _settingsRepository.setPlayAlbumsInOrder(playInOrder);
}
Future<void> setListenedPercentage(int percentage) async {
await _settingsRepository.setListenedPercentage(percentage);
}
void dispose() {}
}

View file

@ -67,6 +67,23 @@ mixin _$SettingsStore on _SettingsStore, Store {
});
}
late final _$listenedPercentageStreamAtom =
Atom(name: '_SettingsStore.listenedPercentageStream', context: context);
@override
ObservableStream<int> get listenedPercentageStream {
_$listenedPercentageStreamAtom.reportRead();
return super.listenedPercentageStream;
}
@override
set listenedPercentageStream(ObservableStream<int> value) {
_$listenedPercentageStreamAtom
.reportWrite(value, super.listenedPercentageStream, () {
super.listenedPercentageStream = value;
});
}
late final _$playAlbumsInOrderStreamAtom =
Atom(name: '_SettingsStore.playAlbumsInOrderStream', context: context);
@ -90,6 +107,7 @@ mixin _$SettingsStore on _SettingsStore, Store {
libraryFoldersStream: ${libraryFoldersStream},
fileExtensionsStream: ${fileExtensionsStream},
blockedFilesStream: ${blockedFilesStream},
listenedPercentageStream: ${listenedPercentageStream},
playAlbumsInOrderStream: ${playAlbumsInOrderStream},
numBlockedFiles: ${numBlockedFiles}
''';

View file

@ -47,8 +47,19 @@ class SettingsDao extends DatabaseAccessor<MainDatabase>
@override
Future<void> setPlayAlbumsInOrder(bool playInOrder) async {
print(playInOrder);
await (update(keyValueEntries)..where((tbl) => tbl.key.equals(SETTING_PLAY_ALBUMS_IN_ORDER)))
.write(KeyValueEntriesCompanion(value: Value(playInOrder ? 'true' : 'false')));
}
@override
Stream<int> get listenedPercentageStream =>
(select(keyValueEntries)..where((tbl) => tbl.key.equals(LISTENED_PERCENTAGE)))
.watchSingle()
.map((event) => int.parse(event.value));
@override
Future<void> setListenedPercentage(int percentage) async {
await (update(keyValueEntries)..where((tbl) => tbl.key.equals(LISTENED_PERCENTAGE)))
.write(KeyValueEntriesCompanion(value: Value(percentage.toString())));
}
}

View file

@ -221,7 +221,7 @@ class MainDatabase extends _$MainDatabase {
MainDatabase.withQueryExecutor(QueryExecutor e) : super(e);
@override
int get schemaVersion => 16;
int get schemaVersion => 17;
@override
MigrationStrategy get migration => MigrationStrategy(
@ -238,7 +238,9 @@ class MainDatabase extends _$MainDatabase {
);
await into(keyValueEntries).insert(
const KeyValueEntriesCompanion(
key: Value(SETTING_ALLOWED_EXTENSIONS), value: Value(ALLOWED_FILE_EXTENSIONS)),
key: Value(SETTING_ALLOWED_EXTENSIONS),
value: Value(ALLOWED_FILE_EXTENSIONS),
),
);
await into(keyValueEntries).insert(
const KeyValueEntriesCompanion(
@ -301,6 +303,12 @@ class MainDatabase extends _$MainDatabase {
),
),
);
await into(keyValueEntries).insert(
const KeyValueEntriesCompanion(
key: Value(LISTENED_PERCENTAGE),
value: Value('95'),
),
);
}
},
onUpgrade: (Migrator m, int from, int to) async {
@ -409,6 +417,14 @@ class MainDatabase extends _$MainDatabase {
await m.addColumn(songs, songs.color);
await m.addColumn(albums, albums.color);
}
if (from < 17) {
await into(keyValueEntries).insert(
const KeyValueEntriesCompanion(
key: Value(LISTENED_PERCENTAGE),
value: Value('95'),
),
);
}
},
);
}

View file

@ -8,4 +8,7 @@ abstract class SettingsDataSource {
Stream<bool> get playAlbumsInOrderStream;
Future<void> setPlayAlbumsInOrder(bool playInOrder);
Stream<int> get listenedPercentageStream;
Future<void> setListenedPercentage(int percentage);
}

View file

@ -7,12 +7,16 @@ class SettingsRepositoryImpl implements SettingsRepository {
SettingsRepositoryImpl(this._settingsDataSource) {
_settingsDataSource.fileExtensionsStream.listen(_fileExtensionsSubject.add);
_settingsDataSource.playAlbumsInOrderStream.listen(_playAlbumsInOrderSubject.add);
_settingsDataSource.listenedPercentageStream.listen(
(value) => _listenedPercentageSubject.add(value),
);
}
final SettingsDataSource _settingsDataSource;
final BehaviorSubject<String> _fileExtensionsSubject = BehaviorSubject();
final BehaviorSubject<bool> _playAlbumsInOrderSubject = BehaviorSubject();
final BehaviorSubject<int> _listenedPercentageSubject = BehaviorSubject();
@override
Stream<List<String>> get libraryFoldersStream => _settingsDataSource.libraryFoldersStream;
@ -44,4 +48,12 @@ class SettingsRepositoryImpl implements SettingsRepository {
Future<void> setPlayAlbumsInOrder(bool playInOrder) async {
await _settingsDataSource.setPlayAlbumsInOrder(playInOrder);
}
@override
ValueStream<int> get listenedPercentageStream => _listenedPercentageSubject.stream;
@override
Future<void> setListenedPercentage(int percentage) async {
await _settingsDataSource.setListenedPercentage(percentage);
}
}