From eb979c7d0f48b12f7997d538683f4be671cec083 Mon Sep 17 00:00:00 2001 From: Chaphasilor Date: Wed, 9 Oct 2024 13:40:42 +0200 Subject: [PATCH 01/15] avoid some null checks --- lib/components/PlayerScreen/progress_slider.dart | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/lib/components/PlayerScreen/progress_slider.dart b/lib/components/PlayerScreen/progress_slider.dart index 1f697dec..29ba2644 100644 --- a/lib/components/PlayerScreen/progress_slider.dart +++ b/lib/components/PlayerScreen/progress_slider.dart @@ -226,9 +226,10 @@ class __PlaybackProgressSliderState min: 0.0, max: widget.mediaItem?.duration == null ? widget.playbackState.bufferedPosition.inMicroseconds.toDouble() - : widget.mediaItem!.duration!.inMicroseconds.toDouble(), + : widget.mediaItem?.duration?.inMicroseconds.toDouble() ?? 0, value: (_dragValue ?? widget.position.inMicroseconds) - .clamp(0, widget.mediaItem!.duration!.inMicroseconds.toDouble()) + .clamp( + 0, widget.mediaItem?.duration?.inMicroseconds.toDouble() ?? 0) .toDouble(), semanticFormatterCallback: (double value) { final positionFullMinutes = @@ -254,9 +255,9 @@ class __PlaybackProgressSliderState ? widget.playbackState.bufferedPosition.inMicroseconds .clamp( 0.0, - widget.mediaItem!.duration == null + widget.mediaItem?.duration == null ? widget.playbackState.bufferedPosition.inMicroseconds - : widget.mediaItem!.duration!.inMicroseconds, + : widget.mediaItem?.duration?.inMicroseconds ?? 0, ) .toDouble() : 0, From 2c72061a2c074ca796f5195c85755859ba145bf4 Mon Sep 17 00:00:00 2001 From: Chaphasilor Date: Wed, 9 Oct 2024 14:25:07 +0200 Subject: [PATCH 02/15] disable autocorrect for search field, label as search field --- lib/screens/music_screen.dart | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/lib/screens/music_screen.dart b/lib/screens/music_screen.dart index b97bb6e2..53e5d860 100644 --- a/lib/screens/music_screen.dart +++ b/lib/screens/music_screen.dart @@ -218,8 +218,11 @@ class _MusicScreenState extends ConsumerState title: isSearching ? TextField( controller: textEditingController, + autocorrect: false, // avoid autocorrect + enableSuggestions: false, // avoid autocorrect autofocus: true, - onChanged: (value) => setState(() { + keyboardType: TextInputType.text, + textInputAction: TextInputAction.search, searchQuery = value; }), decoration: InputDecoration( From 84c45cd0a75e3d440b0dde39ccb7415492750bea Mon Sep 17 00:00:00 2001 From: Chaphasilor Date: Wed, 9 Oct 2024 14:26:27 +0200 Subject: [PATCH 03/15] debounce search to speed it up - combined with the changes made in a1179f11c118fb8392c51318327120ab819126e4, this should make search both fast and accurate --- lib/screens/music_screen.dart | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/lib/screens/music_screen.dart b/lib/screens/music_screen.dart index 53e5d860..e4de2c76 100644 --- a/lib/screens/music_screen.dart +++ b/lib/screens/music_screen.dart @@ -1,3 +1,4 @@ +import 'dart:async'; import 'dart:io'; import 'package:finamp/services/queue_service.dart'; @@ -203,6 +204,8 @@ class _MusicScreenState extends ConsumerState _buildTabController(); } + Timer? _debounce; + return PopScope( canPop: !isSearching, onPopInvoked: (popped) { @@ -223,6 +226,16 @@ class _MusicScreenState extends ConsumerState autofocus: true, keyboardType: TextInputType.text, textInputAction: TextInputAction.search, + onChanged: (value) { + if (_debounce?.isActive ?? false) _debounce!.cancel(); + _debounce = + Timer(const Duration(milliseconds: 400), () { + setState(() { + searchQuery = value; + }); + }); + }, + onSubmitted: (value) => setState(() { searchQuery = value; }), decoration: InputDecoration( From bd7032890d879c26f843d63787e82ffe5d8a0695 Mon Sep 17 00:00:00 2001 From: Chaphasilor Date: Wed, 9 Oct 2024 21:05:33 +0200 Subject: [PATCH 04/15] re-enable manual suggestions for search field --- lib/screens/music_screen.dart | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/screens/music_screen.dart b/lib/screens/music_screen.dart index e4de2c76..b3478d3d 100644 --- a/lib/screens/music_screen.dart +++ b/lib/screens/music_screen.dart @@ -222,7 +222,8 @@ class _MusicScreenState extends ConsumerState ? TextField( controller: textEditingController, autocorrect: false, // avoid autocorrect - enableSuggestions: false, // avoid autocorrect + enableSuggestions: + true, // keep suggestions which can be manually selected autofocus: true, keyboardType: TextInputType.text, textInputAction: TextInputAction.search, From 8740a43a77b2a9fc207c0bbe041fe5c5df6ccfb5 Mon Sep 17 00:00:00 2001 From: Chaphasilor Date: Wed, 9 Oct 2024 22:25:15 +0200 Subject: [PATCH 05/15] fix translation file syntax issues --- lib/l10n/app_en.arb | 38 +++++++++++++++++++++++++------------- 1 file changed, 25 insertions(+), 13 deletions(-) diff --git a/lib/l10n/app_en.arb b/lib/l10n/app_en.arb index 7638511f..5660c2ec 100644 --- a/lib/l10n/app_en.arb +++ b/lib/l10n/app_en.arb @@ -385,7 +385,7 @@ } }, "offlineSongCountArtist": "{count,plural,=1{{count} Track} other{{count} Tracks}} Downloaded", - "@offlineSongCountArtis": { + "@offlineSongCountArtist": { "placeholders": { "count": { "type": "int" @@ -507,7 +507,7 @@ "@playbackSpeedControlSettingSubtitle": { "description": "Subtitle for the playback speed visibility setting" }, - "playbackSpeedControlSettingDescription": "Automatic:\nFinamp tries to identify whether the track you are playing is a podcast or (part of) an audiobook. This is considered to be the case if the track is longer than {trackDuration} minutes, if the track's album is longer than {albumDuration} hours, or if the track has at least one of these genres assigned: {genreList}\nPlayback speed controls will then be shown in the player screen menu.\n\nShown:\nThe playback speed controls will always be shown in the player screen menu.\n\nHidden:\nThe playback speed controls in the player screen menu are always hidden.", + "playbackSpeedControlSettingDescription": "Automatic:\nFinamp tries to identify whether the track you are playing is a podcast or (part of) an audiobook. This is considered to be the case if the track is longer than {trackDuration} minutes, if the track''s album is longer than {albumDuration} hours, or if the track has at least one of these genres assigned: {genreList}\nPlayback speed controls will then be shown in the player screen menu.\n\nShown:\nThe playback speed controls will always be shown in the player screen menu.\n\nHidden:\nThe playback speed controls in the player screen menu are always hidden.", "@playbackSpeedControlSettingDescription": { "description": "Description for the dropdown that selects the replay gain mode, shown in a dialog that opens when the user presses the info icon next to the dropdown", "placeholders": { @@ -1070,14 +1070,20 @@ "@periodicPlaybackSessionUpdateFrequencySubtitle": { "description": "Description of the setting that controls how frequently (in seconds) the current playback session is reported to the Jellyfin server" }, -"periodicPlaybackSessionUpdateFrequencyDetails": "If the Jellyfin server hasn't received any updates from a client in the last 5 minutes, it assumes that playback has ended. This means that for tracks longer than 5 minutes, that playback could be incorrectly reported as having ended, which reduced the quality of the playback reporting data.", + "periodicPlaybackSessionUpdateFrequencyDetails": "If the Jellyfin server hasn''t received any updates from a client in the last 5 minutes, it assumes that playback has ended. This means that for tracks longer than 5 minutes, that playback could be incorrectly reported as having ended, which reduced the quality of the playback reporting data.", "@periodicPlaybackSessionUpdateFrequencyDetails": { "description": "Additional details for the setting that controls how frequently (in seconds) the current playback session is reported to the Jellyfin server" }, "topSongs": "Top Tracks", "@topSongs": {}, "albumCount": "{count,plural,=1{{count} Album} other{{count} Albums}}", - "@albumCount": {}, + "@albumCount": { + "placeholders": { + "count": { + "type": "int" + } + } + }, "shuffleAlbums": "Shuffle Albums", "@shuffleAlbums": { "description": "Label for action that shuffles all albums of an artist or genre" @@ -1103,8 +1109,14 @@ } } }, - "couldNotLoad": "Couldn't load {source, select, album{album} playlist{playlist} songMix{track mix} artistMix{artist mix} albumMix{album mix} genreMix{genre mix} favorites{favorites} allSongs{all tracks} filteredList{tracks} genre{genre} artist{artist} song{track} nextUpAlbum{album in next up} nextUpPlaylist{playlist in next up} nextUpArtist{artist in next up} other{}}", - "@couldNotLoad": {}, + "couldNotLoad": "Couldn''t load {source, select, album{album} playlist{playlist} songMix{track mix} artistMix{artist mix} albumMix{album mix} genreMix{genre mix} favorites{favorites} allSongs{all tracks} filteredList{tracks} genre{genre} artist{artist} song{track} nextUpAlbum{album in next up} nextUpPlaylist{playlist in next up} nextUpArtist{artist in next up} other{}}", + "@couldNotLoad": { + "placeholders": { + "source": { + "type": "String" + } + } + }, "confirm": "Confirm", "close": "Close", "showUncensoredLogMessage": "This log contains your login information. Show?", @@ -1137,7 +1149,7 @@ "@volumeNormalizationModeSelectorSubtitle": { "description": "Subtitle for the dropdown that selects the replay gain mode" }, - "volumeNormalizationModeSelectorDescription": "Hybrid (Track + Album):\nTrack gain is used for regular playback, but if an album is playing (either because it's the main playback queue source, or because it was added to the queue at some point), the album gain is used instead.\n\nTrack-based:\nTrack gain is always used, regardless of whether an album is playing or not.\n\nAlbums Only:\nVolume Normalization is only applied while playing albums (using the album gain), but not for individual tracks.", + "volumeNormalizationModeSelectorDescription": "Hybrid (Track + Album):\nTrack gain is used for regular playback, but if an album is playing (either because it''s the main playback queue source, or because it was added to the queue at some point), the album gain is used instead.\n\nTrack-based:\nTrack gain is always used, regardless of whether an album is playing or not.\n\nAlbums Only:\nVolume Normalization is only applied while playing albums (using the album gain), but not for individual tracks.", "@volumeNormalizationModeSelectorDescription": { "description": "Description for the dropdown that selects the replay gain mode, shown in a dialog that opens when the user presses the info icon next to the dropdown" }, @@ -1161,7 +1173,7 @@ "@volumeNormalizationIOSBaseGainEditorTitle": { "description": "Title for the input that sets the replay gain base gain on iOS and other non-Android platforms" }, - "volumeNormalizationIOSBaseGainEditorSubtitle": "Currently, Volume Normalization on iOS requires changing the playback volume to emulate the gain change. Since we can't increase the volume above 100%, we need to decrease the volume by default so that we can boost the volume of quiet tracks. The value is in decibels (dB), where -10 dB is ~30% volume, -4.5 dB is ~60% volume and -2 dB is ~80% volume.", + "volumeNormalizationIOSBaseGainEditorSubtitle": "Currently, Volume Normalization on iOS requires changing the playback volume to emulate the gain change. Since we can''t increase the volume above 100%, we need to decrease the volume by default so that we can boost the volume of quiet tracks. The value is in decibels (dB), where -10 dB is ~30% volume, -4.5 dB is ~60% volume and -2 dB is ~80% volume.", "@volumeNormalizationIOSBaseGainEditorSubtitle": { "description": "Subtitle for the input that sets the replay gain base gain on iOS and other non-Android platforms" }, @@ -1190,7 +1202,7 @@ "description": "Option to download item in long-press menu." }, "deleteItem": "Delete from device", - "@deletedItem": { + "@deleteItem": { "description": "Option to delete item in long-press menu." }, "repairComplete": "Downloads Repair complete.", @@ -1222,7 +1234,7 @@ } } }, - "activeDownloadsListHeader": "{itemCount} {typeName, select, downloading{Running} failed{Failed} syncFailed{Repeatedly Unsynced} enqueued{Queued} other{}} {itemCount, plural, =1{Download} other{Downloads}}}", + "activeDownloadsListHeader": "{itemCount} {typeName, select, downloading{Running} failed{Failed} syncFailed{Repeatedly Unsynced} enqueued{Queued} other{}} {itemCount, plural, =1{Download} other{Downloads}}", "@activeDownloadsListHeader": { "description": "Header text for lists of active downloads of a particular state.", "placeholders": { @@ -1234,7 +1246,7 @@ } } }, - "downloadLibraryPrompt": "Are you sure you want to download all contents of the library '{ libraryName }'?", + "downloadLibraryPrompt": "Are you sure you want to download all contents of the library ''{libraryName}''?", "@downloadLibraryPrompt": { "description": "Confirmation prompt before downloading entire library, which may be large.", "placeholders": { @@ -1297,7 +1309,7 @@ "@maxConcurrentDownloadsSubtitle": { "description": "Description of setting controlling max concurrent downloads." }, - "maxConcurrentDownloadsLabel": "{ count} Concurrent Downloads", + "maxConcurrentDownloadsLabel": "{count} Concurrent Downloads", "@maxConcurrentDownloadsLabel": { "description": "Label of values on max concurrent downloads slider", "placeholders": { @@ -1314,7 +1326,7 @@ "@downloadsWorkersSettingSubtitle": { "description": "Description of setting controlling download worker count." }, - "downloadsWorkersSettingLabel": "{ count} Download Workers", + "downloadsWorkersSettingLabel": "{count} Download Workers", "@downloadsWorkersSettingLabel": { "description": "Label of values on download worker count slider", "placeholders": { From aac06b38ee58c17e86950a7c30011393fcd81d87 Mon Sep 17 00:00:00 2001 From: Chaphasilor Date: Wed, 9 Oct 2024 22:49:13 +0200 Subject: [PATCH 06/15] add setting for hiding feature chips - also lays groundwork for planned further customization (including/excluding specific features, reordering) --- .../PlayerScreen/feature_chips.dart | 187 ++++++++++-------- lib/l10n/app_en.arb | 40 ++++ lib/models/finamp_models.dart | 132 ++++++++++++- lib/models/finamp_models.g.dart | 161 ++++++++++++++- .../customization_settings_screen.dart | 34 ++++ lib/screens/player_screen.dart | 4 + 6 files changed, 475 insertions(+), 83 deletions(-) diff --git a/lib/components/PlayerScreen/feature_chips.dart b/lib/components/PlayerScreen/feature_chips.dart index 29ef8a8e..3347fa7d 100644 --- a/lib/components/PlayerScreen/feature_chips.dart +++ b/lib/components/PlayerScreen/feature_chips.dart @@ -30,6 +30,9 @@ class FeatureState { final FinampSettings settings; final MetadataProvider? metadata; + FinampFeatureChipsConfiguration get configuration => + settings.featureChipsConfiguration; + bool get isDownloaded => metadata?.isDownloaded ?? false; bool get isTranscoding => !isDownloaded && (currentTrack?.item.extras?["shouldTranscode"] ?? false); @@ -63,102 +66,124 @@ class FeatureState { ), ); } + + for (var feature in configuration.features) { - // TODO this will likely be extremely outdated if offline, hide? - if (currentTrack?.baseItem?.userData?.playCount != null) { - features.add( - FeatureProperties( - text: AppLocalizations.of(context)! - .playCountValue(currentTrack!.baseItem!.userData?.playCount ?? 0), - ), - ); - } - - if (currentTrack?.baseItem?.people?.isNotEmpty ?? false) { - currentTrack?.baseItem?.people?.forEach((person) { - features.add( - FeatureProperties( - text: "${person.role}: ${person.name}", - ), - ); - }); - } - - if (currentTrack?.item.extras?["downloadedSongPath"] != null) { - features.add( - FeatureProperties( - text: AppLocalizations.of(context)!.playbackModeLocal, - ), - ); - } else { - if (isTranscoding) { + // TODO this will likely be extremely outdated if offline, hide? + if (feature == FinampFeatureChipType.playCount && + currentTrack?.baseItem?.userData?.playCount != null) { features.add( FeatureProperties( - text: AppLocalizations.of(context)!.playbackModeTranscoding, - ), - ); - } else { - features.add( - //TODO differentiate between direct streaming and direct playing - // const FeatureProperties( - // text: "Direct Streaming", - // ), - FeatureProperties( - text: AppLocalizations.of(context)!.playbackModeDirectPlaying, + type: feature, + text: AppLocalizations.of(context)!.playCountValue( + currentTrack!.baseItem!.userData?.playCount ?? 0), ), ); } - } - if (metadata?.mediaSourceInfo != null) { - if (bitrate != null) { - features.add( - FeatureProperties( - text: - "${container.toUpperCase()} @ ${AppLocalizations.of(context)!.kiloBitsPerSecondLabel(bitrate! ~/ 1000)}", - ), - ); + if (feature == FinampFeatureChipType.additionalPeople && + (currentTrack?.baseItem?.people?.isNotEmpty ?? false)) { + currentTrack?.baseItem?.people?.forEach((person) { + features.add( + FeatureProperties( + type: feature, + text: "${person.role}: ${person.name}", + ), + ); + }); } - if (bitDepth != null) { - features.add( - FeatureProperties( - text: AppLocalizations.of(context)!.numberAsBit(bitDepth!), - ), - ); + if (feature == FinampFeatureChipType.playbackMode) { + if (currentTrack?.item.extras?["downloadedSongPath"] != null) { + features.add( + FeatureProperties( + type: feature, + text: AppLocalizations.of(context)!.playbackModeLocal, + ), + ); + } else { + if (isTranscoding) { + features.add( + FeatureProperties( + type: feature, + text: AppLocalizations.of(context)!.playbackModeTranscoding, + ), + ); + } else { + features.add( + //TODO differentiate between direct streaming and direct playing + // const FeatureProperties( + // text: "Direct Streaming", + // ), + FeatureProperties( + type: feature, + text: AppLocalizations.of(context)!.playbackModeDirectPlaying, + ), + ); + } + } } - if (sampleRate != null) { - features.add( - FeatureProperties( - text: AppLocalizations.of(context)! - .numberAsKiloHertz(sampleRate! / 1000.0), - ), - ); + if (metadata?.mediaSourceInfo != null) { + if (feature == FinampFeatureChipType.codec || + feature == FinampFeatureChipType.bitRate) { + // only add this feature the first time + if (!features.any((f) => f.type == FinampFeatureChipType.codec)) { + features.add( + FeatureProperties( + type: feature, + text: + "${configuration.features.contains(FinampFeatureChipType.codec) ? container.toUpperCase() : ""}${configuration.features.contains(FinampFeatureChipType.codec) && configuration.features.contains(FinampFeatureChipType.bitRate) ? " @ " : ""}${configuration.features.contains(FinampFeatureChipType.bitRate) && bitrate != null ? AppLocalizations.of(context)!.kiloBitsPerSecondLabel(bitrate! ~/ 1000) : ""}", + ), + ); + } + } + + if (feature == FinampFeatureChipType.bitDepth && bitDepth != null) { + features.add( + FeatureProperties( + type: feature, + text: AppLocalizations.of(context)!.numberAsBit(bitDepth!), + ), + ); + } + + if (feature == FinampFeatureChipType.sampleRate && sampleRate != null) { + features.add( + FeatureProperties( + type: feature, + text: AppLocalizations.of(context)! + .numberAsKiloHertz(sampleRate! / 1000.0), + ), + ); + } + + if (feature == FinampFeatureChipType.size && size != null) { + features.add( + FeatureProperties( + type: feature, + text: FileSize.getSize(size), + ), + ); + } } - if (size != null) { - features.add( - FeatureProperties( - text: FileSize.getSize(size), - ), - ); + if (feature == FinampFeatureChipType.normalizationGain && + FinampSettingsHelper.finampSettings.volumeNormalizationActive) { + double? effectiveGainChange = + getEffectiveGainChange(currentTrack!.item, currentTrack!.baseItem); + if (effectiveGainChange != null) { + features.add( + FeatureProperties( + type: feature, + text: AppLocalizations.of(context)!.numberAsDecibel( + double.parse(effectiveGainChange.toStringAsFixed(1))), + ), + ); + } } - } - if (FinampSettingsHelper.finampSettings.volumeNormalizationActive) { - double? effectiveGainChange = - getEffectiveGainChange(currentTrack!.item, currentTrack!.baseItem); - if (effectiveGainChange != null) { - features.add( - FeatureProperties( - text: AppLocalizations.of(context)!.numberAsDecibel( - double.parse(effectiveGainChange.toStringAsFixed(1))), - ), - ); - } } - return features; } } @@ -166,9 +191,11 @@ class FeatureState { class FeatureProperties { const FeatureProperties({ required this.text, + this.type, }); final String text; + final FinampFeatureChipType? type; } class FeatureChips extends ConsumerWidget { diff --git a/lib/l10n/app_en.arb b/lib/l10n/app_en.arb index 5660c2ec..a400fc36 100644 --- a/lib/l10n/app_en.arb +++ b/lib/l10n/app_en.arb @@ -1728,5 +1728,45 @@ "nowPlayingBarTooltip": "Open Player Screen", "@nowPlayingBarTooltip": { "description": "Tooltip for the now playing bar at the bottom of the screen" + }, + "additionalPeople": "People", + "@additionalPeople": { + "description": "Label for the feature chips showing additional people in the credits of a track or album" + }, + "playbackMode": "Playback Mode", + "@playbackMode": { + "description": "Label for the feature chips showing the playback mode of a track. See [playbackModeLocal], [playbackModeDirectPlaying], and [playbackModeTranscoding]" + }, + "codec": "Codec", + "@codec": { + "description": "Label for the feature chips showing the codec of a track" + }, + "bitRate": "Bit Rate", + "@bitRate": { + "description": "Label for the feature chips showing the bit rate of a track" + }, + "bitDepth": "Bit Depth", + "@bitDepth": { + "description": "Label for the feature chips showing the bit depth of a track" + }, + "size": "Size", + "@size": { + "description": "Label for the feature chips showing the size (original file size or transcoded size, if available) of a track" + }, + "normalizationGain": "Gain", + "@normalizationGain": { + "description": "Label for the feature chips showing the normalization gain / LUFS offset of a track" + }, + "sampleRate": "Sample Rate", + "@sampleRate": { + "description": "Label for the feature chips showing the sample rate of a track" + }, + "showFeatureChipsToggleTitle": "Show Advanced Track Info", + "@showFeatureChipsToggleTitle": { + "description": "Title for the setting that controls if the feature chips showing advanced track info are shown on the player screen" + }, + "showFeatureChipsToggleSubtitle": "Show advanced track info like codec, bit rate, and more on the player screen.", + "@showFeatureChipsToggleSubtitle": { + "description": "Subtitle for the setting that controls if the feature chips showing advanced track info are shown on the player screen" } } diff --git a/lib/models/finamp_models.dart b/lib/models/finamp_models.dart index 41d13e3f..398973ad 100644 --- a/lib/models/finamp_models.dart +++ b/lib/models/finamp_models.dart @@ -113,6 +113,18 @@ const _showStopButtonOnMediaNotificationDefault = false; const _showSeekControlsOnMediaNotificationDefault = true; const _keepScreenOnOption = KeepScreenOnOption.whileLyrics; const _keepScreenOnWhilePluggedIn = true; +const _featureChipsConfigurationDefault = + FinampFeatureChipsConfiguration(enabled: true, features: [ + FinampFeatureChipType.playCount, + FinampFeatureChipType.additionalPeople, + FinampFeatureChipType.playbackMode, + FinampFeatureChipType.codec, + FinampFeatureChipType.bitRate, + FinampFeatureChipType.bitDepth, + FinampFeatureChipType.sampleRate, + FinampFeatureChipType.size, + FinampFeatureChipType.normalizationGain, +]); @HiveType(typeId: 28) class FinampSettings { @@ -196,7 +208,8 @@ class FinampSettings { this.showSeekControlsOnMediaNotification = _showSeekControlsOnMediaNotificationDefault, this.keepScreenOnOption = _keepScreenOnOption, - this.keepScreenOnWhilePluggedIn = _keepScreenOnWhilePluggedIn}); + this.keepScreenOnWhilePluggedIn = _keepScreenOnWhilePluggedIn, + this.featureChipsConfiguration = _featureChipsConfigurationDefault}); @HiveField(0, defaultValue: _isOfflineDefault) bool isOffline; @@ -433,6 +446,9 @@ class FinampSettings { @HiveField(73, defaultValue: _keepScreenOnWhilePluggedIn) bool keepScreenOnWhilePluggedIn; + @HiveField(74, defaultValue: _featureChipsConfigurationDefault) + FinampFeatureChipsConfiguration featureChipsConfiguration; + static Future create() async { final downloadLocation = await DownloadLocation.create( name: "Internal Storage", @@ -2234,3 +2250,117 @@ enum KeepScreenOnOption { } } } + +@HiveType(typeId: 73) +enum FinampFeatureChipType { + @HiveField(0) + playCount, + @HiveField(1) + additionalPeople, + @HiveField(2) + playbackMode, + @HiveField(3) + codec, + @HiveField(4) + bitRate, + @HiveField(5) + bitDepth, + @HiveField(6) + size, + @HiveField(7) + normalizationGain, + @HiveField(8) + sampleRate; + + /// Human-readable version of the [FinampFeatureChipType] + @override + @Deprecated("Use toLocalisedString when possible") + String toString() => _humanReadableName(this); + + String toLocalisedString(BuildContext context) => + _humanReadableLocalisedName(this, context); + + String _humanReadableName(FinampFeatureChipType featureChipType) { + switch (featureChipType) { + case FinampFeatureChipType.playCount: + return "Play Count"; + case FinampFeatureChipType.additionalPeople: + return "Additional People"; + case FinampFeatureChipType.playbackMode: + return "Playback Mode"; + case FinampFeatureChipType.codec: + return "codec"; + case FinampFeatureChipType.bitRate: + return "Bit Rate"; + case FinampFeatureChipType.bitDepth: + return "Bit Depth"; + case FinampFeatureChipType.size: + return "size"; + case FinampFeatureChipType.normalizationGain: + return "Normalization Gain"; + case FinampFeatureChipType.sampleRate: + return "Sample Rate"; + } + } + + String _humanReadableLocalisedName( + FinampFeatureChipType featureChipType, BuildContext context) { + switch (featureChipType) { + case FinampFeatureChipType.playCount: + return AppLocalizations.of(context)!.playCount; + case FinampFeatureChipType.additionalPeople: + return AppLocalizations.of(context)!.additionalPeople; + case FinampFeatureChipType.playbackMode: + return AppLocalizations.of(context)!.playbackMode; + case FinampFeatureChipType.codec: + return AppLocalizations.of(context)!.codec; + case FinampFeatureChipType.bitRate: + return AppLocalizations.of(context)!.bitRate; + case FinampFeatureChipType.bitDepth: + return AppLocalizations.of(context)!.bitDepth; + case FinampFeatureChipType.size: + return AppLocalizations.of(context)!.size; + case FinampFeatureChipType.normalizationGain: + return AppLocalizations.of(context)!.normalizationGain; + case FinampFeatureChipType.sampleRate: + return AppLocalizations.of(context)!.sampleRate; + } + } +} + +@JsonSerializable() +@HiveType(typeId: 74) +class FinampFeatureChipsConfiguration { + const FinampFeatureChipsConfiguration({ + required this.enabled, + required this.features, + }); + + @HiveField(0) + final bool enabled; + + @HiveField(1) + final List features; + + factory FinampFeatureChipsConfiguration.fromJson(Map json) => + _$FinampFeatureChipsConfigurationFromJson(json); + + Map toJson() => + _$FinampFeatureChipsConfigurationToJson(this); + + @override + String toString() { + return jsonEncode(toJson()); + } + + // implement copyWith + FinampFeatureChipsConfiguration copyWith({ + bool? enabled, + List? features, + }) { + return FinampFeatureChipsConfiguration( + enabled: enabled ?? this.enabled, + features: features ?? this.features, + ); + } +} diff --git a/lib/models/finamp_models.g.dart b/lib/models/finamp_models.g.dart index 4c9612b8..f70cd199 100644 --- a/lib/models/finamp_models.g.dart +++ b/lib/models/finamp_models.g.dart @@ -185,6 +185,19 @@ class FinampSettingsAdapter extends TypeAdapter { : fields[72] as KeepScreenOnOption, keepScreenOnWhilePluggedIn: fields[73] == null ? true : fields[73] as bool, + featureChipsConfiguration: fields[74] == null + ? const FinampFeatureChipsConfiguration(enabled: true, features: [ + FinampFeatureChipType.playCount, + FinampFeatureChipType.additionalPeople, + FinampFeatureChipType.playbackMode, + FinampFeatureChipType.codec, + FinampFeatureChipType.bitRate, + FinampFeatureChipType.bitDepth, + FinampFeatureChipType.sampleRate, + FinampFeatureChipType.size, + FinampFeatureChipType.normalizationGain + ]) + : fields[74] as FinampFeatureChipsConfiguration, ) ..disableGesture = fields[19] == null ? false : fields[19] as bool ..showFastScroller = fields[25] == null ? true : fields[25] as bool @@ -194,7 +207,7 @@ class FinampSettingsAdapter extends TypeAdapter { @override void write(BinaryWriter writer, FinampSettings obj) { writer - ..writeByte(72) + ..writeByte(73) ..writeByte(0) ..write(obj.isOffline) ..writeByte(1) @@ -338,7 +351,9 @@ class FinampSettingsAdapter extends TypeAdapter { ..writeByte(72) ..write(obj.keepScreenOnOption) ..writeByte(73) - ..write(obj.keepScreenOnWhilePluggedIn); + ..write(obj.keepScreenOnWhilePluggedIn) + ..writeByte(74) + ..write(obj.featureChipsConfiguration); } @override @@ -960,6 +975,44 @@ class MediaItemIdAdapter extends TypeAdapter { typeId == other.typeId; } +class FinampFeatureChipsConfigurationAdapter + extends TypeAdapter { + @override + final int typeId = 74; + + @override + FinampFeatureChipsConfiguration read(BinaryReader reader) { + final numOfFields = reader.readByte(); + final fields = { + for (int i = 0; i < numOfFields; i++) reader.readByte(): reader.read(), + }; + return FinampFeatureChipsConfiguration( + enabled: fields[0] as bool, + features: (fields[1] as List).cast(), + ); + } + + @override + void write(BinaryWriter writer, FinampFeatureChipsConfiguration obj) { + writer + ..writeByte(2) + ..writeByte(0) + ..write(obj.enabled) + ..writeByte(1) + ..write(obj.features); + } + + @override + int get hashCode => typeId.hashCode; + + @override + bool operator ==(Object other) => + identical(this, other) || + other is FinampFeatureChipsConfigurationAdapter && + runtimeType == other.runtimeType && + typeId == other.typeId; +} + class TabContentTypeAdapter extends TypeAdapter { @override final int typeId = 36; @@ -1878,6 +1931,80 @@ class KeepScreenOnOptionAdapter extends TypeAdapter { typeId == other.typeId; } +class FinampFeatureChipTypeAdapter extends TypeAdapter { + @override + final int typeId = 73; + + @override + FinampFeatureChipType read(BinaryReader reader) { + switch (reader.readByte()) { + case 0: + return FinampFeatureChipType.playCount; + case 1: + return FinampFeatureChipType.additionalPeople; + case 2: + return FinampFeatureChipType.playbackMode; + case 3: + return FinampFeatureChipType.codec; + case 4: + return FinampFeatureChipType.bitRate; + case 5: + return FinampFeatureChipType.bitDepth; + case 6: + return FinampFeatureChipType.size; + case 7: + return FinampFeatureChipType.normalizationGain; + case 8: + return FinampFeatureChipType.sampleRate; + default: + return FinampFeatureChipType.playCount; + } + } + + @override + void write(BinaryWriter writer, FinampFeatureChipType obj) { + switch (obj) { + case FinampFeatureChipType.playCount: + writer.writeByte(0); + break; + case FinampFeatureChipType.additionalPeople: + writer.writeByte(1); + break; + case FinampFeatureChipType.playbackMode: + writer.writeByte(2); + break; + case FinampFeatureChipType.codec: + writer.writeByte(3); + break; + case FinampFeatureChipType.bitRate: + writer.writeByte(4); + break; + case FinampFeatureChipType.bitDepth: + writer.writeByte(5); + break; + case FinampFeatureChipType.size: + writer.writeByte(6); + break; + case FinampFeatureChipType.normalizationGain: + writer.writeByte(7); + break; + case FinampFeatureChipType.sampleRate: + writer.writeByte(8); + break; + } + } + + @override + int get hashCode => typeId.hashCode; + + @override + bool operator ==(Object other) => + identical(this, other) || + other is FinampFeatureChipTypeAdapter && + runtimeType == other.runtimeType && + typeId == other.typeId; +} + // ************************************************************************** // IsarCollectionGenerator // ************************************************************************** @@ -6964,3 +7091,33 @@ const _$MediaItemParentTypeEnumMap = { MediaItemParentType.rootCollection: 'rootCollection', MediaItemParentType.instantMix: 'instantMix', }; + +FinampFeatureChipsConfiguration _$FinampFeatureChipsConfigurationFromJson( + Map json) => + FinampFeatureChipsConfiguration( + enabled: json['enabled'] as bool, + features: (json['features'] as List) + .map((e) => $enumDecode(_$FinampFeatureChipTypeEnumMap, e)) + .toList(), + ); + +Map _$FinampFeatureChipsConfigurationToJson( + FinampFeatureChipsConfiguration instance) => + { + 'enabled': instance.enabled, + 'features': instance.features + .map((e) => _$FinampFeatureChipTypeEnumMap[e]!) + .toList(), + }; + +const _$FinampFeatureChipTypeEnumMap = { + FinampFeatureChipType.playCount: 'playCount', + FinampFeatureChipType.additionalPeople: 'additionalPeople', + FinampFeatureChipType.playbackMode: 'playbackMode', + FinampFeatureChipType.codec: 'codec', + FinampFeatureChipType.bitRate: 'bitRate', + FinampFeatureChipType.bitDepth: 'bitDepth', + FinampFeatureChipType.size: 'size', + FinampFeatureChipType.normalizationGain: 'normalizationGain', + FinampFeatureChipType.sampleRate: 'sampleRate', +}; diff --git a/lib/screens/customization_settings_screen.dart b/lib/screens/customization_settings_screen.dart index d8905035..b8797c12 100644 --- a/lib/screens/customization_settings_screen.dart +++ b/lib/screens/customization_settings_screen.dart @@ -41,6 +41,7 @@ class _CustomizationSettingsScreenState const PlaybackSpeedControlVisibilityDropdownListTile(), if (!Platform.isIOS) const ShowStopButtonOnMediaNotificationToggle(), const ShowSeekControlsOnMediaNotificationToggle(), + const ShowFeatureChipsToggle(), ], ), ); @@ -109,3 +110,36 @@ class ShowSeekControlsOnMediaNotificationToggle extends StatelessWidget { ); } } + +class ShowFeatureChipsToggle extends StatelessWidget { + const ShowFeatureChipsToggle({super.key}); + + @override + Widget build(BuildContext context) { + return ValueListenableBuilder>( + valueListenable: FinampSettingsHelper.finampSettingsListener, + builder: (context, box, child) { + bool? featureChipsEnabled = + box.get("FinampSettings")?.featureChipsConfiguration.enabled; + + return SwitchListTile.adaptive( + title: + Text(AppLocalizations.of(context)!.showFeatureChipsToggleTitle), + subtitle: Text( + AppLocalizations.of(context)!.showFeatureChipsToggleSubtitle), + value: featureChipsEnabled ?? false, + onChanged: featureChipsEnabled == null + ? null + : (value) { + FinampSettings finampSettingsTemp = + box.get("FinampSettings")!; + finampSettingsTemp.featureChipsConfiguration = + finampSettingsTemp.featureChipsConfiguration + .copyWith(enabled: value); + box.put("FinampSettings", finampSettingsTemp); + }, + ); + }, + ); + } +} diff --git a/lib/screens/player_screen.dart b/lib/screens/player_screen.dart index 1f786163..f700e01d 100644 --- a/lib/screens/player_screen.dart +++ b/lib/screens/player_screen.dart @@ -612,6 +612,10 @@ class PlayerHideableController { _visible.remove(PlayerHideable.controlsPaddingSmall); _visible.remove(PlayerHideable.controlsPaddingBig); } + if (!FinampSettingsHelper + .finampSettings.featureChipsConfiguration.enabled) { + _visible.remove(PlayerHideable.features); + } } /// If we have space for vertical padding, put 33% between control elements and From 79771f5a917653d9f1c697948897e48641980fcf Mon Sep 17 00:00:00 2001 From: Chaphasilor Date: Wed, 16 Oct 2024 14:47:15 +0200 Subject: [PATCH 07/15] log more chopper output, show snackbar for player errors --- lib/services/finamp_logs_helper.dart | 2 +- lib/services/music_player_background_task.dart | 3 +++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/lib/services/finamp_logs_helper.dart b/lib/services/finamp_logs_helper.dart index 157f2f31..3d86a8a3 100644 --- a/lib/services/finamp_logs_helper.dart +++ b/lib/services/finamp_logs_helper.dart @@ -34,7 +34,7 @@ class FinampLogsHelper { var message = log.censoredMessage; if (log.stackTrace == null) { // Truncate long messages from chopper, but leave long stack traces - message = message.substring(0, min(1024, message.length)); + message = message.substring(0, min(1024 * 5, message.length)); } _logFileWriter!.writeln(message); } diff --git a/lib/services/music_player_background_task.dart b/lib/services/music_player_background_task.dart index 553c3c16..73941aa5 100644 --- a/lib/services/music_player_background_task.dart +++ b/lib/services/music_player_background_task.dart @@ -202,11 +202,14 @@ class MusicPlayerBackgroundTask extends BaseAudioHandler { } on PlayerException catch (e) { _audioServiceBackgroundTaskLogger .severe("Player error code ${e.code}: ${e.message}"); + GlobalSnackbar.error(e); } on PlayerInterruptedException catch (e) { _audioServiceBackgroundTaskLogger .warning("Player interrupted: ${e.message}"); + GlobalSnackbar.error(e); } catch (e) { _audioServiceBackgroundTaskLogger.severe("Player error ${e.toString()}"); + GlobalSnackbar.error(e); } } From 8f3c8fd7482afd938747a1fe6d992e1b4194d292 Mon Sep 17 00:00:00 2001 From: James Harvey <44349936+jmshrv@users.noreply.github.com> Date: Thu, 17 Oct 2024 02:05:55 +0100 Subject: [PATCH 08/15] Add missing Hive adapters for feature chips --- lib/gen/assets.gen.dart | 21 +++++++++++++++++---- lib/main.dart | 2 ++ macos/Podfile.lock | 2 +- 3 files changed, 20 insertions(+), 5 deletions(-) diff --git a/lib/gen/assets.gen.dart b/lib/gen/assets.gen.dart index 6449e43d..447cb0e1 100644 --- a/lib/gen/assets.gen.dart +++ b/lib/gen/assets.gen.dart @@ -19,16 +19,24 @@ class $ImagesGen { AssetGenImage get finamp => const AssetGenImage('images/finamp.png'); /// File path: images/finamp_cropped.png - AssetGenImage get finampCropped => + AssetGenImage get finampCroppedPng => const AssetGenImage('images/finamp_cropped.png'); + /// File path: images/finamp_cropped.svg + String get finampCroppedSvg => 'images/finamp_cropped.svg'; + /// File path: images/jellyfin-icon-transparent.png AssetGenImage get jellyfinIconTransparent => const AssetGenImage('images/jellyfin-icon-transparent.png'); /// List of all assets - List get values => - [albumWhite, finamp, finampCropped, jellyfinIconTransparent]; + List get values => [ + albumWhite, + finamp, + finampCroppedPng, + finampCroppedSvg, + jellyfinIconTransparent + ]; } class Assets { @@ -38,11 +46,16 @@ class Assets { } class AssetGenImage { - const AssetGenImage(this._assetName, {this.size = null}); + const AssetGenImage( + this._assetName, { + this.size, + this.flavors = const {}, + }); final String _assetName; final Size? size; + final Set flavors; Image image({ Key? key, diff --git a/lib/main.dart b/lib/main.dart index 298d1e92..7371c8e9 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -221,6 +221,8 @@ Future setupHive() async { Hive.registerAdapter(LyricsAlignmentAdapter()); Hive.registerAdapter(LyricsFontSizeAdapter()); Hive.registerAdapter(KeepScreenOnOptionAdapter()); + Hive.registerAdapter(FinampFeatureChipsConfigurationAdapter()); + Hive.registerAdapter(FinampFeatureChipTypeAdapter()); final dir = (Platform.isAndroid || Platform.isIOS) ? await getApplicationDocumentsDirectory() diff --git a/macos/Podfile.lock b/macos/Podfile.lock index c40c5a8e..0ef2d098 100644 --- a/macos/Podfile.lock +++ b/macos/Podfile.lock @@ -99,7 +99,7 @@ SPEC CHECKSUMS: screen_retriever: 59634572a57080243dd1bf715e55b6c54f241a38 share_plus: 36537c04ce0c3e3f5bd297ce4318b6d5ee5fd6cf sqflite: 673a0e54cc04b7d6dba8d24fb8095b31c3a99eec - url_launcher_macos: 5f437abeda8c85500ceb03f5c1938a8c5a705399 + url_launcher_macos: c82c93949963e55b228a30115bd219499a6fe404 wakelock_plus: 4783562c9a43d209c458cb9b30692134af456269 window_manager: 3a1844359a6295ab1e47659b1a777e36773cd6e8 From 292afff087b2b905ca3335dfde9e124ca6947a52 Mon Sep 17 00:00:00 2001 From: James Harvey <44349936+jmshrv@users.noreply.github.com> Date: Thu, 17 Oct 2024 02:20:47 +0100 Subject: [PATCH 09/15] Make client discovery socket nullable instead of late Noticed that it was still null for some reason when logging in, and was causing errors since dispose() was being called and breaking when closing the socket. --- lib/components/LoginScreen/login_flow.dart | 30 ++++++++++++---------- 1 file changed, 17 insertions(+), 13 deletions(-) diff --git a/lib/components/LoginScreen/login_flow.dart b/lib/components/LoginScreen/login_flow.dart index 4b5dd9da..8fcdc89c 100644 --- a/lib/components/LoginScreen/login_flow.dart +++ b/lib/components/LoginScreen/login_flow.dart @@ -270,21 +270,25 @@ class ConnectionState { class JellyfinServerClientDiscovery { static final _clientDiscoveryLogger = Logger("JellyfinServerClientDiscovery"); - late RawDatagramSocket socket; - bool isDisposed = false; + RawDatagramSocket? _socket; + bool _isDisposed = false; void discoverServers( void Function(ClientDiscoveryResponse response) onServerFound) async { - isDisposed = false; + _isDisposed = false; - socket = await RawDatagramSocket.bind(InternetAddress.anyIPv4, 0); - socket.broadcastEnabled = + _socket = await RawDatagramSocket.bind(InternetAddress.anyIPv4, 0); + + // We have to use ? throughout since _socket isn't final, although at this + // point in the code it should never be null + + _socket?.broadcastEnabled = true; // important to allow sending to broadcast address - socket.multicastHops = 5; // to account for weird network setups + _socket?.multicastHops = 5; // to account for weird network setups - socket.listen((event) { + _socket?.listen((event) { if (event == RawSocketEvent.read) { - final datagram = socket.receive(); + final datagram = _socket?.receive(); if (datagram != null) { _clientDiscoveryLogger .finest("Received datagram: ${utf8.decode(datagram.data)}"); @@ -305,16 +309,16 @@ class JellyfinServerClientDiscovery { _clientDiscoveryLogger.fine("Sending discovery messages"); - socket.send(message.codeUnits, broadcastAddress, destinationPort); + _socket?.send(message.codeUnits, broadcastAddress, destinationPort); - while (!isDisposed) { + while (!_isDisposed) { await Future.delayed(const Duration(milliseconds: 1500)); - socket.send(message.codeUnits, broadcastAddress, destinationPort); + _socket?.send(message.codeUnits, broadcastAddress, destinationPort); } } void dispose() { - isDisposed = true; - socket.close(); + _isDisposed = true; + _socket?.close(); } } From 6a1610ede1904fd52da6e2351c8c414ff5f727a3 Mon Sep 17 00:00:00 2001 From: Max Rumpf Date: Tue, 22 Oct 2024 17:19:58 +0200 Subject: [PATCH 10/15] Fix pub get failure (#931) Instead of loading isar_generator from a (now deleted) fork, we can also use a dependency override: isar/isar#1505 --- pubspec.lock | 11 +++++------ pubspec.yaml | 13 ++++++------- 2 files changed, 11 insertions(+), 13 deletions(-) diff --git a/pubspec.lock b/pubspec.lock index d640da1c..afedeb78 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -15,7 +15,7 @@ packages: source: sdk version: "0.3.2" analyzer: - dependency: transitive + dependency: "direct overridden" description: name: analyzer sha256: b652861553cd3990d8ed361f7979dc6d7053a9ac8843fa73820ab68ce5410139 @@ -782,11 +782,10 @@ packages: isar_generator: dependency: "direct dev" description: - path: "packages/isar_generator" - ref: "70a5abd2b36d265a2eef0141f98f312a8710e60c" - resolved-ref: "70a5abd2b36d265a2eef0141f98f312a8710e60c" - url: "https://github.com/ndelanou/isar.git" - source: git + name: isar_generator + sha256: "76c121e1295a30423604f2f819bc255bc79f852f3bc8743a24017df6068ad133" + url: "https://pub.dev" + source: hosted version: "3.1.0+1" js: dependency: transitive diff --git a/pubspec.yaml b/pubspec.yaml index 34ddcee0..4ed5f370 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -120,15 +120,14 @@ dev_dependencies: riverpod_generator: ^2.3.9 custom_lint: riverpod_lint: ^2.3.7 - # isar_generator requires analyzer <6.0.0 by default, but 6.x.0 doesn't have breaking changes - # Using fork of 3.1.0+1 with pubspec updated to analyzer: "^6.0.0" - isar_generator: - git: - url: https://github.com/ndelanou/isar.git - ref: 70a5abd2b36d265a2eef0141f98f312a8710e60c - path: packages/isar_generator + isar_generator: ^3.1.0+1 msix: ^3.16.7 +dependency_overrides: + # isar_generator requires analyzer <6.0.0 by default, but 6.x.0 doesn't have breaking changes + # Overriding the package version allows us to use the latest version. + analyzer: ^6.0.0 + # For information on the generic Dart part of this file, see the # following page: https://dart.dev/tools/pub/pubspec From 346912fb100ddfee556030ce10dd35bab8063857 Mon Sep 17 00:00:00 2001 From: Maxr1998 Date: Tue, 22 Oct 2024 14:58:02 +0200 Subject: [PATCH 11/15] Initialize system locale for intl The intl library can fall back to the system locale (if not using a manually selected locale from settings). For this to work, it needs to be configured once. --- lib/main.dart | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/lib/main.dart b/lib/main.dart index 7371c8e9..5c941048 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -32,6 +32,7 @@ import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:get_it/get_it.dart'; import 'package:hive_flutter/hive_flutter.dart'; import 'package:intl/date_symbol_data_local.dart'; +import 'package:intl/intl_standalone.dart'; import 'package:isar/isar.dart'; import 'package:logging/logging.dart'; import 'package:path_provider/path_provider.dart'; @@ -111,12 +112,8 @@ void main() async { SystemChrome.setSystemUIOverlayStyle( const SystemUiOverlayStyle(statusBarBrightness: Brightness.dark)); - final String localeString = (LocaleHelper.locale != null) - ? ((LocaleHelper.locale?.countryCode != null) - ? "${LocaleHelper.locale?.languageCode.toLowerCase()}_${LocaleHelper.locale?.countryCode?.toUpperCase()}" - : LocaleHelper.locale.toString()) - : "en_US"; - await initializeDateFormatting(localeString, null); + await findSystemLocale(); + await initializeDateFormatting(); runApp(const Finamp()); } From 2bb4cd6e8c1492278b5107c4e3bd2ddc56d4d30a Mon Sep 17 00:00:00 2001 From: Maxr1998 Date: Tue, 22 Oct 2024 15:02:05 +0200 Subject: [PATCH 12/15] Fall back to system locale for dates in playback history --- .../PlaybackHistoryScreen/playback_history_list.dart | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/lib/components/PlaybackHistoryScreen/playback_history_list.dart b/lib/components/PlaybackHistoryScreen/playback_history_list.dart index b5259cea..efc9d92c 100644 --- a/lib/components/PlaybackHistoryScreen/playback_history_list.dart +++ b/lib/components/PlaybackHistoryScreen/playback_history_list.dart @@ -73,11 +73,12 @@ class PlaybackHistoryList extends StatelessWidget { ); final now = DateTime.now(); - final String localeString = (LocaleHelper.locale != null) - ? ((LocaleHelper.locale?.countryCode != null) - ? "${LocaleHelper.locale?.languageCode.toLowerCase()}_${LocaleHelper.locale?.countryCode?.toUpperCase()}" - : LocaleHelper.locale.toString()) - : "en_US"; + final settingsLocale = LocaleHelper.locale; + final String? localeString = settingsLocale != null + ? (settingsLocale.countryCode != null + ? "${settingsLocale.languageCode.toLowerCase()}_${settingsLocale.countryCode?.toUpperCase()}" + : settingsLocale.toString()) + : null; return index == 0 ? Column( From 7f4457f8dc7be08ef4c648a3649fcb53df5893a6 Mon Sep 17 00:00:00 2001 From: Maxr1998 Date: Tue, 22 Oct 2024 15:02:27 +0200 Subject: [PATCH 13/15] Code cleanup --- .../LanguageSelectionScreen/language_list.dart | 15 ++++++++------- .../playback_history_list.dart | 9 ++------- lib/main.dart | 14 ++++++-------- 3 files changed, 16 insertions(+), 22 deletions(-) diff --git a/lib/components/LanguageSelectionScreen/language_list.dart b/lib/components/LanguageSelectionScreen/language_list.dart index ff91f64c..3e7b02a3 100644 --- a/lib/components/LanguageSelectionScreen/language_list.dart +++ b/lib/components/LanguageSelectionScreen/language_list.dart @@ -67,19 +67,20 @@ class LanguageListTile extends StatelessWidget { this.locale, }); - final Locale? locale; + final Locale? locale; // null if system language @override Widget build(BuildContext context) { return RadioListTile( title: Text(locale?.nativeDisplayLanguage ?? AppLocalizations.of(context)!.system), - subtitle: locale == null - ? null - : Text((LocaleHelper.locale == null - ? locale!.defaultDisplayLanguage - : locale!.displayLanguageIn(LocaleHelper.locale!)) ?? - "???"), + subtitle: locale != null + ? Text( + LocaleHelper.locale != null + ? locale!.displayLanguageIn(LocaleHelper.locale!) + : locale!.defaultDisplayLanguage, + ) + : null, value: locale, groupValue: LocaleHelper.locale, onChanged: (_) { diff --git a/lib/components/PlaybackHistoryScreen/playback_history_list.dart b/lib/components/PlaybackHistoryScreen/playback_history_list.dart index efc9d92c..981d10ce 100644 --- a/lib/components/PlaybackHistoryScreen/playback_history_list.dart +++ b/lib/components/PlaybackHistoryScreen/playback_history_list.dart @@ -4,16 +4,15 @@ import 'package:finamp/services/audio_service_helper.dart'; import 'package:finamp/services/locale_helper.dart'; import 'package:flutter/material.dart'; import 'package:flutter_gen/gen_l10n/app_localizations.dart'; -import 'package:intl/date_symbol_data_local.dart'; import 'package:get_it/get_it.dart'; import 'package:intl/intl.dart'; -import '../../services/playback_history_service.dart'; import '../../models/jellyfin_models.dart' as jellyfin_models; +import '../../services/playback_history_service.dart'; import 'playback_history_list_tile.dart'; class PlaybackHistoryList extends StatelessWidget { - const PlaybackHistoryList({Key? key}) : super(key: key); + const PlaybackHistoryList({super.key}); @override Widget build(BuildContext context) { @@ -28,13 +27,9 @@ class PlaybackHistoryList extends StatelessWidget { builder: (context, snapshot) { if (snapshot.hasData) { history = snapshot.data; - // groupedHistory = playbackHistoryService.getHistoryGroupedByDate(); - // groupedHistory = playbackHistoryService.getHistoryGroupedByHour(); groupedHistory = playbackHistoryService.getHistoryGroupedDynamically(); - print(groupedHistory); - return CustomScrollView( // use nested SliverList.builder()s to show history items grouped by date slivers: groupedHistory.map((group) { diff --git a/lib/main.dart b/lib/main.dart index 5c941048..e1bbb61a 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -1,6 +1,9 @@ import 'dart:async'; import 'dart:io'; +import 'package:audio_service/audio_service.dart'; +import 'package:audio_session/audio_session.dart'; +import 'package:background_downloader/background_downloader.dart'; import 'package:finamp/color_schemes.g.dart'; import 'package:finamp/gen/assets.gen.dart'; import 'package:finamp/screens/downloads_settings_screen.dart'; @@ -21,9 +24,6 @@ import 'package:finamp/services/offline_listen_helper.dart'; import 'package:finamp/services/playback_history_service.dart'; import 'package:finamp/services/queue_service.dart'; import 'package:finamp/services/theme_provider.dart'; -import 'package:audio_service/audio_service.dart'; -import 'package:audio_session/audio_session.dart'; -import 'package:background_downloader/background_downloader.dart'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:flutter_gen/gen_l10n/app_localizations.dart'; @@ -35,10 +35,10 @@ import 'package:intl/date_symbol_data_local.dart'; import 'package:intl/intl_standalone.dart'; import 'package:isar/isar.dart'; import 'package:logging/logging.dart'; +import 'package:path/path.dart' as path_helper; import 'package:path_provider/path_provider.dart'; import 'package:uuid/uuid.dart'; import 'package:window_manager/window_manager.dart'; -import 'package:path/path.dart' as path_helper; import 'components/LogsScreen/copy_logs_button.dart'; import 'components/LogsScreen/share_logs_button.dart'; @@ -316,8 +316,8 @@ Future _setupPlaybackServices() async { // notificationColor: TODO use the theme color for older versions of Android, preloadArtwork: false, androidBrowsableRootExtras: { - "android.media.browse.SEARCH_SUPPORTED": - true, // support showing search button on Android Auto as well as alternative search results on the player screen after voice search + // support showing search button on Android Auto as well as alternative search results on the player screen after voice search + "android.media.browse.SEARCH_SUPPORTED": true, // see https://developer.android.com/reference/androidx/media/utils/MediaConstants#DESCRIPTION_EXTRAS_VALUE_CONTENT_STYLE_GRID_ITEM() "android.media.browse.CONTENT_STYLE_BROWSABLE_HINT": FinampSettingsHelper.finampSettings.contentViewType == @@ -331,8 +331,6 @@ Future _setupPlaybackServices() async { : 2, }), ); - // GetIt.instance.registerSingletonAsync( - // () async => ); GetIt.instance.registerSingleton(audioHandler); GetIt.instance.registerSingleton(QueueService()); From 98b71f4ce79a1edba68aade0c1ab6f835876d605 Mon Sep 17 00:00:00 2001 From: Maxr1998 Date: Tue, 22 Oct 2024 15:08:44 +0200 Subject: [PATCH 14/15] Extract localeString getter --- .../PlaybackHistoryScreen/playback_history_list.dart | 7 +------ lib/services/locale_helper.dart | 9 +++++++++ 2 files changed, 10 insertions(+), 6 deletions(-) diff --git a/lib/components/PlaybackHistoryScreen/playback_history_list.dart b/lib/components/PlaybackHistoryScreen/playback_history_list.dart index 981d10ce..cc0dd379 100644 --- a/lib/components/PlaybackHistoryScreen/playback_history_list.dart +++ b/lib/components/PlaybackHistoryScreen/playback_history_list.dart @@ -68,12 +68,7 @@ class PlaybackHistoryList extends StatelessWidget { ); final now = DateTime.now(); - final settingsLocale = LocaleHelper.locale; - final String? localeString = settingsLocale != null - ? (settingsLocale.countryCode != null - ? "${settingsLocale.languageCode.toLowerCase()}_${settingsLocale.countryCode?.toUpperCase()}" - : settingsLocale.toString()) - : null; + final String? localeString = LocaleHelper.localeString; return index == 0 ? Column( diff --git a/lib/services/locale_helper.dart b/lib/services/locale_helper.dart index 34f401d3..1f81fa52 100644 --- a/lib/services/locale_helper.dart +++ b/lib/services/locale_helper.dart @@ -10,6 +10,15 @@ class LocaleHelper { static Locale? get locale => Hive.box(boxName).get(boxName); + static String? get localeString { + final locale = LocaleHelper.locale; + return locale != null + ? (locale.countryCode != null + ? "${locale.languageCode.toLowerCase()}_${locale.countryCode?.toUpperCase()}" + : locale.toString()) + : null; + } + static void setLocale(Locale? locale) { Hive.box(boxName).put(boxName, locale); } From 999688906d7a86ef64380fee5c032dd2abd034a4 Mon Sep 17 00:00:00 2001 From: Chaphasilor Date: Sun, 27 Oct 2024 19:11:39 +0100 Subject: [PATCH 15/15] upgrade dependencies --- .github/workflows/build.yml | 2 + .../PlayerScreen/artist_chip.g.dart | 4 +- lib/services/audio_service_smtc.dart | 7 +- lib/services/favorite_provider.g.dart | 4 +- lib/services/finamp_settings_helper.g.dart | 4 +- linux/flutter/generated_plugin_registrant.cc | 8 +- linux/flutter/generated_plugins.cmake | 2 +- pubspec.lock | 192 ++++++++++-------- pubspec.yaml | 44 ++-- .../flutter/generated_plugin_registrant.cc | 6 +- windows/flutter/generated_plugins.cmake | 2 +- 11 files changed, 150 insertions(+), 125 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index d4e642ae..e37a1c04 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -121,6 +121,8 @@ jobs: # with: # distribution: 'zulu' # java-version: '17' + - name: Set up Rust (for smtc_windows) + uses: hecrj/setup-rust-action@v2 - name: Set up Flutter uses: subosito/flutter-action@v2 with: diff --git a/lib/components/PlayerScreen/artist_chip.g.dart b/lib/components/PlayerScreen/artist_chip.g.dart index b023dc96..46a95db0 100644 --- a/lib/components/PlayerScreen/artist_chip.g.dart +++ b/lib/components/PlayerScreen/artist_chip.g.dart @@ -142,6 +142,8 @@ class ArtistItemProvider extends AutoDisposeFutureProvider { } } +@Deprecated('Will be removed in 3.0. Use Ref instead') +// ignore: unused_element mixin ArtistItemRef on AutoDisposeFutureProviderRef { /// The parameter `id` of this provider. String get id; @@ -155,4 +157,4 @@ class _ArtistItemProviderElement String get id => (origin as ArtistItemProvider).id; } // ignore_for_file: type=lint -// ignore_for_file: subtype_of_sealed_class, invalid_use_of_internal_member, invalid_use_of_visible_for_testing_member +// ignore_for_file: subtype_of_sealed_class, invalid_use_of_internal_member, invalid_use_of_visible_for_testing_member, deprecated_member_use_from_same_package diff --git a/lib/services/audio_service_smtc.dart b/lib/services/audio_service_smtc.dart index 0f576bf5..45ba1557 100644 --- a/lib/services/audio_service_smtc.dart +++ b/lib/services/audio_service_smtc.dart @@ -15,6 +15,7 @@ class AudioServiceSMTC extends AudioServicePlatform { // initialize SMTC //TODO we should call smtc.dispose() before the app is closed to prevent a background process from continuing to run // https://pub.dev/packages/flutter_window_close could be used to detect when the app is closed + await SMTCWindows.initialize(); smtc = SMTCWindows( // Which buttons to show in the OS media player config: const SMTCConfig( @@ -62,12 +63,12 @@ class AudioServiceSMTC extends AudioServicePlatform { if (request.state.playing && !smtc.enabled) { await smtc .enableSmtc() - .then((value) => smtc.setPlaybackStatus(PlaybackStatus.Playing)); + .then((value) => smtc.setPlaybackStatus(PlaybackStatus.playing)); } else { await smtc.setPosition(request.state.updatePosition); await smtc.setPlaybackStatus(request.state.playing - ? PlaybackStatus.Playing - : PlaybackStatus.Paused); + ? PlaybackStatus.playing + : PlaybackStatus.paused); await smtc.setRepeatMode(switch (request.state.repeatMode) { AudioServiceRepeatModeMessage.none => RepeatMode.none, diff --git a/lib/services/favorite_provider.g.dart b/lib/services/favorite_provider.g.dart index 55974192..a5df6812 100644 --- a/lib/services/favorite_provider.g.dart +++ b/lib/services/favorite_provider.g.dart @@ -155,6 +155,8 @@ class IsFavoriteProvider } } +@Deprecated('Will be removed in 3.0. Use Ref instead') +// ignore: unused_element mixin IsFavoriteRef on AutoDisposeNotifierProviderRef { /// The parameter `value` of this provider. FavoriteRequest get value; @@ -169,4 +171,4 @@ class _IsFavoriteProviderElement FavoriteRequest get value => (origin as IsFavoriteProvider).value; } // ignore_for_file: type=lint -// ignore_for_file: subtype_of_sealed_class, invalid_use_of_internal_member, invalid_use_of_visible_for_testing_member +// ignore_for_file: subtype_of_sealed_class, invalid_use_of_internal_member, invalid_use_of_visible_for_testing_member, deprecated_member_use_from_same_package diff --git a/lib/services/finamp_settings_helper.g.dart b/lib/services/finamp_settings_helper.g.dart index 52790116..ee94256f 100644 --- a/lib/services/finamp_settings_helper.g.dart +++ b/lib/services/finamp_settings_helper.g.dart @@ -21,6 +21,8 @@ final finampSettingsProvider = allTransitiveDependencies: null, ); +@Deprecated('Will be removed in 3.0. Use Ref instead') +// ignore: unused_element typedef FinampSettingsRef = AutoDisposeStreamProviderRef; // ignore_for_file: type=lint -// ignore_for_file: subtype_of_sealed_class, invalid_use_of_internal_member, invalid_use_of_visible_for_testing_member +// ignore_for_file: subtype_of_sealed_class, invalid_use_of_internal_member, invalid_use_of_visible_for_testing_member, deprecated_member_use_from_same_package diff --git a/linux/flutter/generated_plugin_registrant.cc b/linux/flutter/generated_plugin_registrant.cc index 5138914f..ce4bfd2c 100644 --- a/linux/flutter/generated_plugin_registrant.cc +++ b/linux/flutter/generated_plugin_registrant.cc @@ -8,7 +8,7 @@ #include #include -#include +#include #include #include @@ -19,9 +19,9 @@ void fl_register_plugins(FlPluginRegistry* registry) { g_autoptr(FlPluginRegistrar) media_kit_libs_linux_registrar = fl_plugin_registry_get_registrar_for_plugin(registry, "MediaKitLibsLinuxPlugin"); media_kit_libs_linux_plugin_register_with_registrar(media_kit_libs_linux_registrar); - g_autoptr(FlPluginRegistrar) screen_retriever_registrar = - fl_plugin_registry_get_registrar_for_plugin(registry, "ScreenRetrieverPlugin"); - screen_retriever_plugin_register_with_registrar(screen_retriever_registrar); + g_autoptr(FlPluginRegistrar) screen_retriever_linux_registrar = + fl_plugin_registry_get_registrar_for_plugin(registry, "ScreenRetrieverLinuxPlugin"); + screen_retriever_linux_plugin_register_with_registrar(screen_retriever_linux_registrar); g_autoptr(FlPluginRegistrar) url_launcher_linux_registrar = fl_plugin_registry_get_registrar_for_plugin(registry, "UrlLauncherPlugin"); url_launcher_plugin_register_with_registrar(url_launcher_linux_registrar); diff --git a/linux/flutter/generated_plugins.cmake b/linux/flutter/generated_plugins.cmake index c9db8aad..62e6ea32 100644 --- a/linux/flutter/generated_plugins.cmake +++ b/linux/flutter/generated_plugins.cmake @@ -5,7 +5,7 @@ list(APPEND FLUTTER_PLUGIN_LIST isar_flutter_libs media_kit_libs_linux - screen_retriever + screen_retriever_linux url_launcher_linux window_manager ) diff --git a/pubspec.lock b/pubspec.lock index afedeb78..3f668f3d 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -34,10 +34,10 @@ packages: dependency: "direct main" description: name: app_set_id - sha256: "455b04bc03fd9b1b66a50bbca74278d973ac4e6f2c03d5dd4707bb071613a7e5" + sha256: "362d61e013f400666c6e0f57d56ab9d32505e011e4ca4dfb779fd80c9d9505b0" url: "https://pub.dev" source: hosted - version: "1.2.0" + version: "1.2.1" archive: dependency: transitive description: @@ -114,10 +114,10 @@ packages: dependency: "direct main" description: name: background_downloader - sha256: "6b73fa5d20c47e855f6ef3ed6fb3e0d164141d8ae7d43ca0a42c78f90eaa15e7" + sha256: "91448c0fcb41af14ede14485c33b8ca684fcd6c0ac0a439be9f83fa964753e13" url: "https://pub.dev" source: hosted - version: "8.5.6" + version: "8.6.0" balanced_text: dependency: "direct main" description: @@ -131,10 +131,10 @@ packages: dependency: "direct main" description: name: battery_plus - sha256: ccc1322fee1153a0f89e663e0eac2f64d659da506454cf24dcad75eb08ae138b + sha256: "220c8f1961efb01d6870493b5ac5a80afaeaffc8757f7a11ed3025a8570d29e7" url: "https://pub.dev" source: hosted - version: "6.0.2" + version: "6.2.0" battery_plus_platform_interface: dependency: transitive description: @@ -395,10 +395,10 @@ packages: dependency: "direct main" description: name: device_info_plus - sha256: a7fd703482b391a87d60b6061d04dfdeab07826b96f9abd8f5ed98068acc0074 + sha256: c4af09051b4f0508f6c1dc0a5c085bf014d5c9a4a0678ce1799c2b4d716387a0 url: "https://pub.dev" source: hosted - version: "10.1.2" + version: "11.1.0" device_info_plus_platform_interface: dependency: transitive description: @@ -419,10 +419,10 @@ packages: dependency: transitive description: name: fading_edge_scrollview - sha256: c25c2231652ce774cc31824d0112f11f653881f43d7f5302c05af11942052031 + sha256: "1f84fe3ea8e251d00d5735e27502a6a250e4aa3d3b330d3fdcb475af741464ef" url: "https://pub.dev" source: hosted - version: "3.0.0" + version: "4.1.1" fake_async: dependency: transitive description: @@ -451,10 +451,10 @@ packages: dependency: "direct main" description: name: file_picker - sha256: "825aec673606875c33cd8d3c4083f1a3c3999015a84178b317b7ef396b7384f3" + sha256: aac85f20436608e01a6ffd1fdd4e746a7f33c93a2c83752e626bdfaea139b877 url: "https://pub.dev" source: hosted - version: "8.0.7" + version: "8.1.3" file_sizes: dependency: "direct main" description: @@ -488,10 +488,10 @@ packages: dependency: "direct main" description: name: flutter_cache_manager - sha256: "8207f27539deb83732fdda03e259349046a39a4c767269285f449ade355d54ba" + sha256: "400b6592f16a4409a7f2bb929a9a7e38c72cceb8ffb99ee57bbf2cb2cecf8386" url: "https://pub.dev" source: hosted - version: "3.3.1" + version: "3.4.1" flutter_gen_core: dependency: transitive description: @@ -512,18 +512,18 @@ packages: dependency: "direct dev" description: name: flutter_launcher_icons - sha256: "526faf84284b86a4cb36d20a5e45147747b7563d921373d4ee0559c54fcdbcea" + sha256: "619817c4b65b322b5104b6bb6dfe6cda62d9729bd7ad4303ecc8b4e690a67a77" url: "https://pub.dev" source: hosted - version: "0.13.1" + version: "0.14.1" flutter_lints: dependency: "direct dev" description: name: flutter_lints - sha256: "3f41d009ba7172d5ff9be5f6e6e6abb4300e263aab8866d2a0842ed2a70f8f0c" + sha256: "5398f14efa795ffb7a33e9b6a08798b26a180edac4ad7db3f231e40f82ce11e1" url: "https://pub.dev" source: hosted - version: "4.0.0" + version: "5.0.0" flutter_localizations: dependency: "direct main" description: flutter @@ -541,18 +541,18 @@ packages: dependency: "direct main" description: name: flutter_riverpod - sha256: "0f1974eff5bbe774bf1d870e406fc6f29e3d6f1c46bd9c58e7172ff68a785d7d" + sha256: "9532ee6db4a943a1ed8383072a2e3eeda041db5657cdf6d2acecf3c21ecbe7e1" url: "https://pub.dev" source: hosted - version: "2.5.1" + version: "2.6.1" flutter_rust_bridge: dependency: transitive description: name: flutter_rust_bridge - sha256: e12415c3bce49bcbc3fed383f0ea41ad7d828f6cf0eccba0588ffa5a812fe522 + sha256: "0ad5079de35d317650fec59b26cb4d0c116ebc2ce703a29f9367513b8a91c287" url: "https://pub.dev" source: hosted - version: "1.82.1" + version: "2.5.0" flutter_staggered_grid_view: dependency: transitive description: @@ -565,10 +565,10 @@ packages: dependency: "direct main" description: name: flutter_sticky_header - sha256: "017f398fbb45a589e01491861ca20eb6570a763fd9f3888165a978e11248c709" + sha256: "7f76d24d119424ca0c95c146b8627a457e8de8169b0d584f766c2c545db8f8be" url: "https://pub.dev" source: hosted - version: "0.6.5" + version: "0.7.0" flutter_svg: dependency: "direct main" description: @@ -815,18 +815,18 @@ packages: dependency: "direct main" description: name: just_audio - sha256: d8e8aaf417d33e345299c17f6457f72bd4ba0c549dc34607abb5183a354edc4d + sha256: b41646a8241688f1d99c2e69c4da2bb26aa4b3a99795f6ff205c2a165e033fda url: "https://pub.dev" source: hosted - version: "0.9.40" + version: "0.9.41" just_audio_media_kit: dependency: "direct main" description: name: just_audio_media_kit - sha256: "7f57d317fafa04cb3e70b924e8f632ffb7eca7a97a369e1e44738ed89fbd5da1" + sha256: "9f3517213dfc7bbaf6980656feb66c35600f114c7efc0b5b3f4476cd5c18b45e" url: "https://pub.dev" source: hosted - version: "2.0.5" + version: "2.0.6" just_audio_platform_interface: dependency: transitive description: @@ -871,10 +871,10 @@ packages: dependency: transitive description: name: lints - sha256: "976c774dd944a42e83e2467f4cc670daef7eed6295b10b36ae8c85bcbf828235" + sha256: "3315600f3fb3b135be672bf4a178c55f274bebe368325ae18462c89ac1e3b413" url: "https://pub.dev" source: hosted - version: "4.0.0" + version: "5.0.0" locale_names: dependency: "direct main" description: @@ -887,10 +887,10 @@ packages: dependency: "direct main" description: name: logging - sha256: "623a88c9594aa774443aa3eb2d41807a48486b5613e67599fb4c41c0ad47c340" + sha256: c8245ada5f1717ed44271ed1c26b8ce85ca3228fd2ffdb75468ab01979309d61 url: "https://pub.dev" source: hosted - version: "1.2.0" + version: "1.3.0" macros: dependency: transitive description: @@ -903,10 +903,10 @@ packages: dependency: "direct main" description: name: marquee - sha256: "4b5243d2804373bdc25fc93d42c3b402d6ec1f4ee8d0bb72276edd04ae7addb8" + sha256: a87e7e80c5d21434f90ad92add9f820cf68be374b226404fe881d2bba7be0862 url: "https://pub.dev" source: hosted - version: "2.2.3" + version: "2.3.0" matcher: dependency: transitive description: @@ -1197,14 +1197,6 @@ packages: url: "https://pub.dev" source: hosted version: "1.3.0" - puppeteer: - dependency: transitive - description: - name: puppeteer - sha256: fc33b2a12731e0b9e16c40cd91ea2b6886bcc24037a435fceb59b786d4074f2b - url: "https://pub.dev" - source: hosted - version: "3.15.0" qs_dart: dependency: transitive description: @@ -1225,42 +1217,42 @@ packages: dependency: transitive description: name: riverpod - sha256: f21b32ffd26a36555e501b04f4a5dca43ed59e16343f1a30c13632b2351dfa4d + sha256: "59062512288d3056b2321804332a13ffdd1bf16df70dcc8e506e411280a72959" url: "https://pub.dev" source: hosted - version: "2.5.1" + version: "2.6.1" riverpod_analyzer_utils: dependency: transitive description: name: riverpod_analyzer_utils - sha256: ee72770090078e6841d51355292335f1bc254907c6694283389dcb8156d99a4d + sha256: "0dcb0af32d561f8fa000c6a6d95633c9fb08ea8a8df46e3f9daca59f11218167" url: "https://pub.dev" source: hosted - version: "0.5.3" + version: "0.5.6" riverpod_annotation: dependency: "direct main" description: name: riverpod_annotation - sha256: e5e796c0eba4030c704e9dae1b834a6541814963292839dcf9638d53eba84f5c + sha256: e14b0bf45b71326654e2705d462f21b958f987087be850afd60578fcd502d1b8 url: "https://pub.dev" source: hosted - version: "2.3.5" + version: "2.6.1" riverpod_generator: dependency: "direct dev" description: name: riverpod_generator - sha256: "1ad626afbd8b01d168870b13c0b036f8a5bdb57c14cd426dc5b4595466bd6e2f" + sha256: "851aedac7ad52693d12af3bf6d92b1626d516ed6b764eb61bf19e968b5e0b931" url: "https://pub.dev" source: hosted - version: "2.4.2" + version: "2.6.1" riverpod_lint: dependency: "direct dev" description: name: riverpod_lint - sha256: b95a8cdc6102397f7d51037131c25ce7e51be900be021af4bf0c2d6f1b8f7aa7 + sha256: "0684c21a9a4582c28c897d55c7b611fa59a351579061b43f8c92c005804e63a8" url: "https://pub.dev" source: hosted - version: "2.3.12" + version: "2.6.1" rxdart: dependency: "direct main" description: @@ -1281,10 +1273,42 @@ packages: dependency: transitive description: name: screen_retriever - sha256: "6ee02c8a1158e6dae7ca430da79436e3b1c9563c8cf02f524af997c201ac2b90" + sha256: "570dbc8e4f70bac451e0efc9c9bb19fa2d6799a11e6ef04f946d7886d2e23d0c" + url: "https://pub.dev" + source: hosted + version: "0.2.0" + screen_retriever_linux: + dependency: transitive + description: + name: screen_retriever_linux + sha256: f7f8120c92ef0784e58491ab664d01efda79a922b025ff286e29aa123ea3dd18 + url: "https://pub.dev" + source: hosted + version: "0.2.0" + screen_retriever_macos: + dependency: transitive + description: + name: screen_retriever_macos + sha256: "71f956e65c97315dd661d71f828708bd97b6d358e776f1a30d5aa7d22d78a149" + url: "https://pub.dev" + source: hosted + version: "0.2.0" + screen_retriever_platform_interface: + dependency: transitive + description: + name: screen_retriever_platform_interface + sha256: ee197f4581ff0d5608587819af40490748e1e39e648d7680ecf95c05197240c0 + url: "https://pub.dev" + source: hosted + version: "0.2.0" + screen_retriever_windows: + dependency: transitive + description: + name: screen_retriever_windows + sha256: "449ee257f03ca98a57288ee526a301a430a344a161f9202b4fcc38576716fe13" url: "https://pub.dev" source: hosted - version: "0.1.9" + version: "0.2.0" scroll_to_index: dependency: "direct main" description: @@ -1297,18 +1321,18 @@ packages: dependency: "direct main" description: name: share_plus - sha256: ef3489a969683c4f3d0239010cc8b7a2a46543a8d139e111c06c558875083544 + sha256: "3af2cda1752e5c24f2fc04b6083b40f013ffe84fb90472f30c6499a9213d5442" url: "https://pub.dev" source: hosted - version: "9.0.0" + version: "10.1.1" share_plus_platform_interface: dependency: transitive description: name: share_plus_platform_interface - sha256: "0f9e4418835d1b2c3ae78fdb918251959106cefdbc4dd43526e182f80e82f6d4" + sha256: c57c0bbfec7142e3a0f55633be504b796af72e60e3c791b44d5a017b985f7a48 url: "https://pub.dev" source: hosted - version: "4.0.0" + version: "5.0.1" shelf: dependency: transitive description: @@ -1317,14 +1341,6 @@ packages: url: "https://pub.dev" source: hosted version: "1.4.1" - shelf_static: - dependency: transitive - description: - name: shelf_static - sha256: c87c3875f91262785dade62d135760c2c69cb217ac759485334c5857ad89f6e3 - url: "https://pub.dev" - source: hosted - version: "1.1.3" shelf_web_socket: dependency: transitive description: @@ -1358,10 +1374,10 @@ packages: dependency: "direct main" description: name: smtc_windows - sha256: "799bbe0f8e4436da852c5dcc0be482c97b8ae0f504f65c6b750cd239b4835aa0" + sha256: "80f7c10867da485ffdf87f842bf27e6763589933c18c11af5dc1cd1e158c3154" url: "https://pub.dev" source: hosted - version: "0.1.2" + version: "1.0.0" source_gen: dependency: transitive description: @@ -1395,6 +1411,14 @@ packages: url: "https://github.com/odriverobotics/split_view.git" source: git version: "3.2.1" + sprintf: + dependency: transitive + description: + name: sprintf + sha256: "1fc9ffe69d4df602376b52949af107d8f5703b77cda567c4d7d86a0693120f23" + url: "https://pub.dev" + source: hosted + version: "7.0.0" sqflite: dependency: transitive description: @@ -1491,14 +1515,6 @@ packages: url: "https://pub.dev" source: hosted version: "1.0.1" - tuple: - dependency: transitive - description: - name: tuple - sha256: a97ce2013f240b2f3807bcbaf218765b6f301c3eff91092bcfa23a039e7dd151 - url: "https://pub.dev" - source: hosted - version: "2.0.2" typed_data: dependency: transitive description: @@ -1543,10 +1559,10 @@ packages: dependency: "direct main" description: name: url_launcher - sha256: "21b704ce5fa560ea9f3b525b43601c678728ba46725bab9b01187b4831377ed3" + sha256: "9d06212b1362abc2f0f0d78e6f09f726608c74e3b9462e8368bb03314aa8d603" url: "https://pub.dev" source: hosted - version: "6.3.0" + version: "6.3.1" url_launcher_android: dependency: transitive description: @@ -1607,18 +1623,18 @@ packages: dependency: "direct main" description: name: uuid - sha256: "648e103079f7c64a36dc7d39369cabb358d377078a051d6ae2ad3aa539519313" + sha256: a5be9ef6618a7ac1e964353ef476418026db906c4facdedaa299b7a2e71690ff url: "https://pub.dev" source: hosted - version: "3.0.7" + version: "4.5.1" value_layout_builder: dependency: transitive description: name: value_layout_builder - sha256: "98202ec1807e94ac72725b7f0d15027afde513c55c69ff3f41bcfccb950831bc" + sha256: c02511ea91ca5c643b514a33a38fa52536f74aa939ec367d02938b5ede6807fa url: "https://pub.dev" source: hosted - version: "0.3.1" + version: "0.4.0" vector_graphics: dependency: transitive description: @@ -1703,18 +1719,18 @@ packages: dependency: transitive description: name: web - sha256: "97da13628db363c635202ad97068d47c5b8aa555808e7a9411963c533b449b27" + sha256: cd3543bd5798f6ad290ea73d210f423502e71900302dde696f8bff84bf89a1cb url: "https://pub.dev" source: hosted - version: "0.5.1" + version: "1.1.0" web_socket_channel: dependency: transitive description: name: web_socket_channel - sha256: "58c6666b342a38816b2e7e50ed0f1e261959630becd4c879c4f26bfa14aa5a42" + sha256: d88238e5eac9a42bb43ca4e721edba3c08c6354d4a53063afaa568516217621b url: "https://pub.dev" source: hosted - version: "2.4.5" + version: "2.4.0" win32: dependency: transitive description: @@ -1735,10 +1751,10 @@ packages: dependency: "direct main" description: name: window_manager - sha256: "8699323b30da4cdbe2aa2e7c9de567a6abd8a97d9a5c850a3c86dcd0b34bbfbf" + sha256: "732896e1416297c63c9e3fb95aea72d0355f61390263982a47fd519169dc5059" url: "https://pub.dev" source: hosted - version: "0.3.9" + version: "0.4.3" xdg_directories: dependency: transitive description: diff --git a/pubspec.yaml b/pubspec.yaml index 4ed5f370..b7b6eeaa 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -26,12 +26,12 @@ dependencies: flutter_localizations: sdk: flutter - background_downloader: ^8.4.1 + background_downloader: ^8.6.0 json_annotation: ^4.8.1 chopper: ^8.0.0 get_it: ^7.2.0 - just_audio: ^0.9.37 - just_audio_media_kit: ^2.0.4 + just_audio: ^0.9.41 + just_audio_media_kit: ^2.0.6 media_kit_libs_linux: ^1.1.3 # Transcoding does not work on windows with current media-kit release. This fork uses the most recent @@ -41,7 +41,7 @@ dependencies: url: https://github.com/Komodo5197/media-kit.git ref: 475a08cc97b94702f774bc906e1472b5bddc932b path: libs/windows/media_kit_libs_windows_audio - smtc_windows: ^0.1.2 + smtc_windows: ^1.0.0 audio_service: ^0.18.13 audio_service_mpris: ^0.1.3 audio_service_platform_interface: ^0.1.1 @@ -52,17 +52,17 @@ dependencies: hive: ^2.2.3 hive_flutter: ^1.1.0 file_sizes: ^1.0.6 - logging: ^1.1.1 + logging: ^1.3.0 collection: ^1.18.0 clipboard: ^0.1.3 - file_picker: ^8.0.3 + file_picker: ^8.1.3 permission_handler: ^11.3.1 provider: ^6.0.5 - uuid: ^3.0.7 + uuid: ^4.5.1 infinite_scroll_pagination: ^4.0.0 - flutter_sticky_header: ^0.6.5 - device_info_plus: ^10.0.1 - app_set_id: ^1.2.0 + flutter_sticky_header: ^0.7.0 + device_info_plus: ^11.1.0 + app_set_id: ^1.2.1 package_info_plus: ^8.0.0 octo_image: ^2.0.0 # Main split view package does not seem actively maintained. Use fork with ability to specify @@ -71,14 +71,14 @@ dependencies: git: url: https://github.com/odriverobotics/split_view.git ref: 8b2b0f0e1c8470183cb2df40815a05bfdb3fe219 - share_plus: ^9.0.0 + share_plus: ^10.1.1 isar: ^3.1.0 isar_flutter_libs: ^3.1.0 path: ^1.9.0 intl: '>=0.18.1 < 1.0.0' auto_size_text: ^3.0.0 - marquee: ^2.2.3 + marquee: ^2.3.0 palette_generator: git: url: https://github.com/jmshrv/packages.git @@ -86,12 +86,12 @@ dependencies: ref: 4992c3b path: packages/palette_generator flutter_tabler_icons: ^1.27.0 - flutter_riverpod: ^2.4.9 - riverpod_annotation: ^2.3.3 + flutter_riverpod: ^2.6.1 + riverpod_annotation: ^2.6.1 locale_names: ^1.1.1 flutter_vibrate: ^1.3.0 mini_music_visualizer: ^1.0.2 - flutter_cache_manager: ^3.3.1 + flutter_cache_manager: ^3.4.1 # fix not showing elipses when maxLines==1 balanced_text: git: @@ -100,10 +100,10 @@ dependencies: flutter_to_airplay: ^2.0.4 flutter_blurhash: ^0.8.2 scroll_to_index: ^3.0.1 - window_manager: ^0.3.8 - url_launcher: ^6.2.6 + window_manager: ^0.4.3 + url_launcher: ^6.3.1 wakelock_plus: ^1.2.8 - battery_plus: ^6.0.2 + battery_plus: ^6.2.0 focus_on_it: ^2.0.1 flutter_svg: ^2.0.10+1 @@ -115,11 +115,11 @@ dev_dependencies: chopper_generator: ^8.0.0 hive_generator: ^2.0.0 json_serializable: ^6.7.1 - flutter_launcher_icons: ^0.13.1 - flutter_lints: ^4.0.0 - riverpod_generator: ^2.3.9 + flutter_launcher_icons: ^0.14.1 + flutter_lints: ^5.0.0 + riverpod_generator: ^2.6.1 custom_lint: - riverpod_lint: ^2.3.7 + riverpod_lint: ^2.6.1 isar_generator: ^3.1.0+1 msix: ^3.16.7 diff --git a/windows/flutter/generated_plugin_registrant.cc b/windows/flutter/generated_plugin_registrant.cc index 8c09f956..9cb07519 100644 --- a/windows/flutter/generated_plugin_registrant.cc +++ b/windows/flutter/generated_plugin_registrant.cc @@ -10,7 +10,7 @@ #include #include #include -#include +#include #include #include #include @@ -24,8 +24,8 @@ void RegisterPlugins(flutter::PluginRegistry* registry) { registry->GetRegistrarForPlugin("MediaKitLibsWindowsAudioPluginCApi")); PermissionHandlerWindowsPluginRegisterWithRegistrar( registry->GetRegistrarForPlugin("PermissionHandlerWindowsPlugin")); - ScreenRetrieverPluginRegisterWithRegistrar( - registry->GetRegistrarForPlugin("ScreenRetrieverPlugin")); + ScreenRetrieverWindowsPluginCApiRegisterWithRegistrar( + registry->GetRegistrarForPlugin("ScreenRetrieverWindowsPluginCApi")); SharePlusWindowsPluginCApiRegisterWithRegistrar( registry->GetRegistrarForPlugin("SharePlusWindowsPluginCApi")); UrlLauncherWindowsRegisterWithRegistrar( diff --git a/windows/flutter/generated_plugins.cmake b/windows/flutter/generated_plugins.cmake index 41be227b..315d05f4 100644 --- a/windows/flutter/generated_plugins.cmake +++ b/windows/flutter/generated_plugins.cmake @@ -7,7 +7,7 @@ list(APPEND FLUTTER_PLUGIN_LIST isar_flutter_libs media_kit_libs_windows_audio permission_handler_windows - screen_retriever + screen_retriever_windows share_plus url_launcher_windows window_manager