From 177fc5670c5054e8f04faa9eb34870784e8c4395 Mon Sep 17 00:00:00 2001 From: le-firehawk Date: Tue, 5 Aug 2025 22:39:41 +0930 Subject: [PATCH 01/16] feat: Fix lyric scrolling during playback, keep screen on while viewing --- .../ui/fragment/PlayerLyricsFragment.java | 23 +++++++++++++++---- 1 file changed, 19 insertions(+), 4 deletions(-) diff --git a/app/src/main/java/com/cappielloantonio/tempo/ui/fragment/PlayerLyricsFragment.java b/app/src/main/java/com/cappielloantonio/tempo/ui/fragment/PlayerLyricsFragment.java index 58e7a7c5..7140632f 100644 --- a/app/src/main/java/com/cappielloantonio/tempo/ui/fragment/PlayerLyricsFragment.java +++ b/app/src/main/java/com/cappielloantonio/tempo/ui/fragment/PlayerLyricsFragment.java @@ -6,11 +6,13 @@ import android.os.Bundle; import android.os.Handler; import android.text.Spannable; import android.text.SpannableString; +import android.text.Layout; import android.text.style.ForegroundColorSpan; import android.util.Log; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; +import android.view.WindowManager; import androidx.annotation.NonNull; import androidx.annotation.Nullable; @@ -28,6 +30,7 @@ import com.cappielloantonio.tempo.subsonic.models.Line; import com.cappielloantonio.tempo.subsonic.models.LyricsList; import com.cappielloantonio.tempo.util.MusicUtil; import com.cappielloantonio.tempo.util.OpenSubsonicExtensionsUtil; +import com.cappielloantonio.tempo.util.Preferences; import com.cappielloantonio.tempo.viewmodel.PlayerBottomSheetViewModel; import com.google.common.util.concurrent.ListenableFuture; import com.google.common.util.concurrent.MoreExecutors; @@ -76,12 +79,16 @@ public class PlayerLyricsFragment extends Fragment { public void onResume() { super.onResume(); bindMediaController(); + requireActivity().getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON); } @Override public void onPause() { super.onPause(); releaseHandler(); + if (!Preferences.isDisplayAlwaysOn()) { + requireActivity().getWindow().clearFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON); + } } @Override @@ -281,10 +288,18 @@ public class PlayerLyricsFragment extends Fragment { } private int getScroll(List lines, Line toHighlight) { - int lineHeight = bind.nowPlayingSongLyricsTextView.getLineHeight(); - int lineCount = getLineCount(lines, toHighlight); - int scrollViewHeight = bind.nowPlayingSongLyricsSrollView.getHeight(); + int startIndex = getStartPosition(lines, toHighlight); + Layout layout = bind.nowPlayingSongLyricsTextView.getLayout(); + if (layout == null) return 0; - return lineHeight * lineCount < scrollViewHeight / 2 ? 0 : lineHeight * lineCount - scrollViewHeight / 2 + lineHeight; + int line = layout.getLineForOffset(startIndex); + int lineTop = layout.getLineTop(line); + int lineBottom = layout.getLineBottom(line); + int lineCenter = (lineTop + lineBottom) / 2; + + int scrollViewHeight = bind.nowPlayingSongLyricsSrollView.getHeight(); + int scroll = lineCenter - scrollViewHeight / 2; + + return Math.max(scroll, 0); } } \ No newline at end of file From 181af686c2911648ff30b79c703704acf5f9ee59 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jaime=20Garc=C3=ADa?= <55400857+jaime-grj@users.noreply.github.com> Date: Wed, 6 Aug 2025 01:49:30 +0200 Subject: [PATCH 02/16] feat: show sampling rate and bit depth if available --- .../tempo/database/AppDatabase.java | 4 +- .../tempo/model/Chronology.kt | 2 + .../com/cappielloantonio/tempo/model/Queue.kt | 2 + .../tempo/subsonic/models/Child.kt | 6 +++ .../tempo/ui/dialog/TrackInfoDialog.java | 2 + .../ui/fragment/PlayerControllerFragment.java | 15 +++++- .../tempo/util/MappingUtil.java | 2 + .../tempo/util/MusicUtil.java | 7 +++ app/src/main/res/layout/dialog_track_info.xml | 52 +++++++++++++++++++ app/src/main/res/values-es-rES/strings.xml | 2 + app/src/main/res/values/strings.xml | 2 + 11 files changed, 93 insertions(+), 3 deletions(-) diff --git a/app/src/main/java/com/cappielloantonio/tempo/database/AppDatabase.java b/app/src/main/java/com/cappielloantonio/tempo/database/AppDatabase.java index ed37106b..b19e934f 100644 --- a/app/src/main/java/com/cappielloantonio/tempo/database/AppDatabase.java +++ b/app/src/main/java/com/cappielloantonio/tempo/database/AppDatabase.java @@ -28,9 +28,9 @@ import com.cappielloantonio.tempo.subsonic.models.Playlist; @UnstableApi @Database( - version = 10, + version = 11, entities = {Queue.class, Server.class, RecentSearch.class, Download.class, Chronology.class, Favorite.class, SessionMediaItem.class, Playlist.class}, - autoMigrations = {@AutoMigration(from = 9, to = 10)} + autoMigrations = {@AutoMigration(from = 10, to = 11)} ) @TypeConverters({DateConverters.class}) public abstract class AppDatabase extends RoomDatabase { diff --git a/app/src/main/java/com/cappielloantonio/tempo/model/Chronology.kt b/app/src/main/java/com/cappielloantonio/tempo/model/Chronology.kt index c84781a3..18a77bfa 100644 --- a/app/src/main/java/com/cappielloantonio/tempo/model/Chronology.kt +++ b/app/src/main/java/com/cappielloantonio/tempo/model/Chronology.kt @@ -37,6 +37,8 @@ class Chronology(@PrimaryKey override val id: String) : Child(id) { transcodedSuffix = mediaItem.mediaMetadata.extras!!.getString("transcodedSuffix") duration = mediaItem.mediaMetadata.extras!!.getInt("duration") bitrate = mediaItem.mediaMetadata.extras!!.getInt("bitrate") + samplingRate = mediaItem.mediaMetadata.extras!!.getInt("samplingRate") + bitDepth = mediaItem.mediaMetadata.extras!!.getInt("bitDepth") path = mediaItem.mediaMetadata.extras!!.getString("path") isVideo = mediaItem.mediaMetadata.extras!!.getBoolean("isVideo") userRating = mediaItem.mediaMetadata.extras!!.getInt("userRating") diff --git a/app/src/main/java/com/cappielloantonio/tempo/model/Queue.kt b/app/src/main/java/com/cappielloantonio/tempo/model/Queue.kt index a5f66ada..ca2300c2 100644 --- a/app/src/main/java/com/cappielloantonio/tempo/model/Queue.kt +++ b/app/src/main/java/com/cappielloantonio/tempo/model/Queue.kt @@ -41,6 +41,8 @@ class Queue(override val id: String) : Child(id) { transcodedSuffix = child.transcodedSuffix duration = child.duration bitrate = child.bitrate + samplingRate = child.samplingRate + bitDepth = child.bitDepth path = child.path isVideo = child.isVideo userRating = child.userRating diff --git a/app/src/main/java/com/cappielloantonio/tempo/subsonic/models/Child.kt b/app/src/main/java/com/cappielloantonio/tempo/subsonic/models/Child.kt index 6299dfe2..15057cf7 100644 --- a/app/src/main/java/com/cappielloantonio/tempo/subsonic/models/Child.kt +++ b/app/src/main/java/com/cappielloantonio/tempo/subsonic/models/Child.kt @@ -50,6 +50,12 @@ open class Child( @ColumnInfo("bitrate") @SerializedName("bitRate") var bitrate: Int? = null, + @ColumnInfo("sampling_rate") + @SerializedName("samplingRate") + var samplingRate: Int? = null, + @ColumnInfo("bit_depth") + @SerializedName("bitDepth") + var bitDepth: Int? = null, @ColumnInfo var path: String? = null, @ColumnInfo(name = "is_video") diff --git a/app/src/main/java/com/cappielloantonio/tempo/ui/dialog/TrackInfoDialog.java b/app/src/main/java/com/cappielloantonio/tempo/ui/dialog/TrackInfoDialog.java index ca9b6d20..84afcb6a 100644 --- a/app/src/main/java/com/cappielloantonio/tempo/ui/dialog/TrackInfoDialog.java +++ b/app/src/main/java/com/cappielloantonio/tempo/ui/dialog/TrackInfoDialog.java @@ -72,6 +72,8 @@ public class TrackInfoDialog extends DialogFragment { bind.transcodedSuffixValueSector.setText(mediaMetadata.extras.getString("transcodedSuffix", getString(R.string.label_placeholder))); bind.durationValueSector.setText(MusicUtil.getReadableDurationString(mediaMetadata.extras.getInt("duration", 0), false)); bind.bitrateValueSector.setText(mediaMetadata.extras.getInt("bitrate", 0) + " kbps"); + bind.samplingRateValueSector.setText(mediaMetadata.extras.getInt("samplingRate", 0) != 0 ? mediaMetadata.extras.getInt("samplingRate", 0) + " Hz" : getString(R.string.label_placeholder)); + bind.bitDepthValueSector.setText(mediaMetadata.extras.getInt("bitDepth", 0) != 0 ? mediaMetadata.extras.getInt("bitDepth", 0) + " bits" : getString(R.string.label_placeholder)); bind.pathValueSector.setText(mediaMetadata.extras.getString("path", getString(R.string.label_placeholder))); bind.discNumberValueSector.setText(String.valueOf(mediaMetadata.extras.getInt("discNumber", 0))); } diff --git a/app/src/main/java/com/cappielloantonio/tempo/ui/fragment/PlayerControllerFragment.java b/app/src/main/java/com/cappielloantonio/tempo/ui/fragment/PlayerControllerFragment.java index d1daae9b..37cd9f10 100644 --- a/app/src/main/java/com/cappielloantonio/tempo/ui/fragment/PlayerControllerFragment.java +++ b/app/src/main/java/com/cappielloantonio/tempo/ui/fragment/PlayerControllerFragment.java @@ -2,6 +2,7 @@ package com.cappielloantonio.tempo.ui.fragment; import android.content.ComponentName; import android.os.Bundle; +import android.text.TextUtils; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; @@ -40,6 +41,9 @@ import com.google.android.material.elevation.SurfaceColors; import com.google.common.util.concurrent.ListenableFuture; import com.google.common.util.concurrent.MoreExecutors; +import java.text.DecimalFormat; +import java.util.ArrayList; +import java.util.List; import java.util.Objects; @UnstableApi @@ -190,14 +194,23 @@ public class PlayerControllerFragment extends Fragment { if (mediaMetadata.extras != null) { String extension = mediaMetadata.extras.getString("suffix", "Unknown format"); String bitrate = mediaMetadata.extras.getInt("bitrate", 0) != 0 ? mediaMetadata.extras.getInt("bitrate", 0) + "kbps" : "Original"; + String samplingRate = mediaMetadata.extras.getInt("samplingRate", 0) != 0 ? new DecimalFormat("0.#").format(mediaMetadata.extras.getInt("samplingRate", 0) / 1000.0) + "kHz" : ""; + String bitDepth = mediaMetadata.extras.getInt("bitDepth", 0) != 0 ? mediaMetadata.extras.getInt("bitDepth", 0) + "b" : ""; playerMediaExtension.setText(extension); if (bitrate.equals("Original")) { playerMediaBitrate.setVisibility(View.GONE); } else { + List mediaQualityItems = new ArrayList<>(); + + if (!bitrate.trim().isEmpty()) mediaQualityItems.add(bitrate); + if (!bitDepth.trim().isEmpty()) mediaQualityItems.add(bitDepth); + if (!samplingRate.trim().isEmpty()) mediaQualityItems.add(samplingRate); + + String mediaQuality = TextUtils.join(" • ", mediaQualityItems); playerMediaBitrate.setVisibility(View.VISIBLE); - playerMediaBitrate.setText(bitrate); + playerMediaBitrate.setText(mediaQuality); } } diff --git a/app/src/main/java/com/cappielloantonio/tempo/util/MappingUtil.java b/app/src/main/java/com/cappielloantonio/tempo/util/MappingUtil.java index be531eda..1b88774d 100644 --- a/app/src/main/java/com/cappielloantonio/tempo/util/MappingUtil.java +++ b/app/src/main/java/com/cappielloantonio/tempo/util/MappingUtil.java @@ -54,6 +54,8 @@ public class MappingUtil { bundle.putString("transcodedSuffix", media.getTranscodedSuffix()); bundle.putInt("duration", media.getDuration() != null ? media.getDuration() : 0); bundle.putInt("bitrate", media.getBitrate() != null ? media.getBitrate() : 0); + bundle.putInt("samplingRate", media.getSamplingRate() != null ? media.getSamplingRate() : 0); + bundle.putInt("bitDepth", media.getBitDepth() != null ? media.getBitDepth() : 0); bundle.putString("path", media.getPath()); bundle.putBoolean("isVideo", media.isVideo()); bundle.putInt("userRating", media.getUserRating() != null ? media.getUserRating() : 0); diff --git a/app/src/main/java/com/cappielloantonio/tempo/util/MusicUtil.java b/app/src/main/java/com/cappielloantonio/tempo/util/MusicUtil.java index fddb4cce..696b5b9d 100644 --- a/app/src/main/java/com/cappielloantonio/tempo/util/MusicUtil.java +++ b/app/src/main/java/com/cappielloantonio/tempo/util/MusicUtil.java @@ -15,6 +15,7 @@ import com.cappielloantonio.tempo.repository.DownloadRepository; import com.cappielloantonio.tempo.subsonic.models.Child; import java.text.CharacterIterator; +import java.text.DecimalFormat; import java.text.StringCharacterIterator; import java.util.ArrayList; import java.util.List; @@ -163,6 +164,12 @@ public class MusicUtil { " " + child.getBitrate() + "kbps" + + " • " + + (child.getBitDepth() != null && child.getBitDepth() != 0 + ? child.getBitDepth() + "/" + (child.getSamplingRate() != null ? child.getSamplingRate() / 1000 : "") + : (child.getSamplingRate() != null + ? new DecimalFormat("0.#").format(child.getSamplingRate() / 1000.0) + "kHz" + : "")) + " " + child.getSuffix(); } diff --git a/app/src/main/res/layout/dialog_track_info.xml b/app/src/main/res/layout/dialog_track_info.xml index ee6eb8b8..ae72877f 100644 --- a/app/src/main/res/layout/dialog_track_info.xml +++ b/app/src/main/res/layout/dialog_track_info.xml @@ -391,6 +391,58 @@ android:text="@string/label_placeholder" /> + + + + + + + + + + + + + + + + + + Interno Álbum Artista + Profundidad de bits Tasa de bits + Tasa de muestreo Tipo de contenido Aceptar Tipo de contenido en la transcodificación diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 8ecb78af..a05234fb 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -395,6 +395,7 @@ https://buymeacoffee.com/a.cappiello Album Artist + Bit depth Bitrate Content Type OK @@ -403,6 +404,7 @@ Duration Genre Path + Sampling rate Size Suffix The file has been downloaded using the Subsonic APIs. The codec and bitrate of the file remain unchanged from the source file. From 44f8160e21c736775c1a6b73a78c177cd829378f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jaime=20Garc=C3=ADa?= <55400857+jaime-grj@users.noreply.github.com> Date: Thu, 7 Aug 2025 02:38:17 +0200 Subject: [PATCH 03/16] fix: fixed incorrect album release date, hid release date TextView when there is no data --- .../tempo/subsonic/models/ItemDate.kt | 17 +++++++++++++---- .../tempo/ui/fragment/AlbumPageFragment.java | 9 ++++++--- 2 files changed, 19 insertions(+), 7 deletions(-) diff --git a/app/src/main/java/com/cappielloantonio/tempo/subsonic/models/ItemDate.kt b/app/src/main/java/com/cappielloantonio/tempo/subsonic/models/ItemDate.kt index e32e9842..3a77e93f 100644 --- a/app/src/main/java/com/cappielloantonio/tempo/subsonic/models/ItemDate.kt +++ b/app/src/main/java/com/cappielloantonio/tempo/subsonic/models/ItemDate.kt @@ -14,11 +14,20 @@ open class ItemDate : Parcelable { var month: Int? = null var day: Int? = null - fun getFormattedDate(): String { - val calendar = Calendar.getInstance() - val dateFormat = SimpleDateFormat("MMMM dd, yyyy", Locale.getDefault()) + fun getFormattedDate(): String? { + if (year == null && month == null && day == null) return null - calendar.set(year ?: 0, month ?: 0, day ?: 0) + val calendar = Calendar.getInstance() + val dateFormat = if (month == null && day == null) { + SimpleDateFormat("yyyy", Locale.getDefault()) + } else if (day == null) { + SimpleDateFormat("MMMM yyyy", Locale.getDefault()) + } + else{ + SimpleDateFormat("MMMM dd, yyyy", Locale.getDefault()) + } + + calendar.set(year ?: 0, month ?: 1, day ?: 1) // Default to 1 if day is null return dateFormat.format(calendar.time) } diff --git a/app/src/main/java/com/cappielloantonio/tempo/ui/fragment/AlbumPageFragment.java b/app/src/main/java/com/cappielloantonio/tempo/ui/fragment/AlbumPageFragment.java index f830888e..83bc8ece 100644 --- a/app/src/main/java/com/cappielloantonio/tempo/ui/fragment/AlbumPageFragment.java +++ b/app/src/main/java/com/cappielloantonio/tempo/ui/fragment/AlbumPageFragment.java @@ -149,13 +149,16 @@ public class AlbumPageFragment extends Fragment implements ClickCallback { bind.albumGenresTextview.setText(album.getGenre()); if (album.getReleaseDate() != null && album.getOriginalReleaseDate() != null) { - bind.albumReleaseYearsTextview.setVisibility(View.VISIBLE); + if (album.getReleaseDate().getFormattedDate() != null || album.getOriginalReleaseDate().getFormattedDate() != null) + bind.albumReleaseYearsTextview.setVisibility(View.VISIBLE); + else + bind.albumReleaseYearsTextview.setVisibility(View.GONE); - if (album.getReleaseDate() == null || album.getOriginalReleaseDate() == null) { + if (album.getReleaseDate().getFormattedDate() == null || album.getOriginalReleaseDate().getFormattedDate() == null) { bind.albumReleaseYearsTextview.setText(getString(R.string.album_page_release_date_label, album.getReleaseDate() != null ? album.getReleaseDate().getFormattedDate() : album.getOriginalReleaseDate().getFormattedDate())); } - if (album.getReleaseDate() != null && album.getOriginalReleaseDate() != null) { + if (album.getReleaseDate().getFormattedDate() != null && album.getOriginalReleaseDate().getFormattedDate() != null) { if (Objects.equals(album.getReleaseDate().getYear(), album.getOriginalReleaseDate().getYear()) && Objects.equals(album.getReleaseDate().getMonth(), album.getOriginalReleaseDate().getMonth()) && Objects.equals(album.getReleaseDate().getDay(), album.getOriginalReleaseDate().getDay())) { bind.albumReleaseYearsTextview.setText(getString(R.string.album_page_release_date_label, album.getReleaseDate().getFormattedDate())); } else { From 1f347209b5572b6fc685d26a68cdc68c465ce99c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jaime=20Garc=C3=ADa?= <55400857+jaime-grj@users.noreply.github.com> Date: Thu, 7 Aug 2025 02:46:57 +0200 Subject: [PATCH 04/16] fix: don't show empty genre TextView if album has no genre --- .../tempo/ui/fragment/AlbumPageFragment.java | 5 ++++- app/src/main/res/layout/fragment_album_page.xml | 4 +++- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/com/cappielloantonio/tempo/ui/fragment/AlbumPageFragment.java b/app/src/main/java/com/cappielloantonio/tempo/ui/fragment/AlbumPageFragment.java index 83bc8ece..2d256443 100644 --- a/app/src/main/java/com/cappielloantonio/tempo/ui/fragment/AlbumPageFragment.java +++ b/app/src/main/java/com/cappielloantonio/tempo/ui/fragment/AlbumPageFragment.java @@ -146,7 +146,10 @@ public class AlbumPageFragment extends Fragment implements ClickCallback { bind.albumArtistLabel.setText(album.getArtist()); bind.albumReleaseYearLabel.setText(album.getYear() != 0 ? String.valueOf(album.getYear()) : ""); bind.albumSongCountDurationTextview.setText(getString(R.string.album_page_tracks_count_and_duration, album.getSongCount(), album.getDuration() != null ? album.getDuration() / 60 : 0)); - bind.albumGenresTextview.setText(album.getGenre()); + if (album.getGenre() != null && !album.getGenre().isEmpty()) { + bind.albumGenresTextview.setText(album.getGenre()); + bind.albumGenresTextview.setVisibility(View.VISIBLE); + } if (album.getReleaseDate() != null && album.getOriginalReleaseDate() != null) { if (album.getReleaseDate().getFormattedDate() != null || album.getOriginalReleaseDate().getFormattedDate() != null) diff --git a/app/src/main/res/layout/fragment_album_page.xml b/app/src/main/res/layout/fragment_album_page.xml index 0e58bf74..411d5c1c 100644 --- a/app/src/main/res/layout/fragment_album_page.xml +++ b/app/src/main/res/layout/fragment_album_page.xml @@ -126,9 +126,11 @@ android:layout_marginEnd="18dp" android:text="@string/label_placeholder" android:textAlignment="center" + android:visibility="gone" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" - app:layout_constraintTop_toTopOf="parent" /> + app:layout_constraintTop_toTopOf="parent" + tools:visibility="visible" /> Date: Thu, 7 Aug 2025 02:56:44 +0200 Subject: [PATCH 05/16] fix: don't show empty year TextView if album has no year --- .../cappielloantonio/tempo/ui/fragment/AlbumPageFragment.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/java/com/cappielloantonio/tempo/ui/fragment/AlbumPageFragment.java b/app/src/main/java/com/cappielloantonio/tempo/ui/fragment/AlbumPageFragment.java index 2d256443..31248768 100644 --- a/app/src/main/java/com/cappielloantonio/tempo/ui/fragment/AlbumPageFragment.java +++ b/app/src/main/java/com/cappielloantonio/tempo/ui/fragment/AlbumPageFragment.java @@ -144,7 +144,7 @@ public class AlbumPageFragment extends Fragment implements ClickCallback { bind.albumNameLabel.setText(album.getName()); bind.albumArtistLabel.setText(album.getArtist()); - bind.albumReleaseYearLabel.setText(album.getYear() != 0 ? String.valueOf(album.getYear()) : ""); + bind.albumReleaseYearLabel.setVisibility(album.getYear() != 0 ? View.VISIBLE : View.GONE); bind.albumSongCountDurationTextview.setText(getString(R.string.album_page_tracks_count_and_duration, album.getSongCount(), album.getDuration() != null ? album.getDuration() / 60 : 0)); if (album.getGenre() != null && !album.getGenre().isEmpty()) { bind.albumGenresTextview.setText(album.getGenre()); From d49d37d1fd3404134e2d7b3edbf90b1a94636ac1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jaime=20Garc=C3=ADa?= <55400857+jaime-grj@users.noreply.github.com> Date: Thu, 7 Aug 2025 03:06:01 +0200 Subject: [PATCH 06/16] chore: remove comment --- .../java/com/cappielloantonio/tempo/subsonic/models/ItemDate.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/java/com/cappielloantonio/tempo/subsonic/models/ItemDate.kt b/app/src/main/java/com/cappielloantonio/tempo/subsonic/models/ItemDate.kt index 3a77e93f..5de2fbc6 100644 --- a/app/src/main/java/com/cappielloantonio/tempo/subsonic/models/ItemDate.kt +++ b/app/src/main/java/com/cappielloantonio/tempo/subsonic/models/ItemDate.kt @@ -27,7 +27,7 @@ open class ItemDate : Parcelable { SimpleDateFormat("MMMM dd, yyyy", Locale.getDefault()) } - calendar.set(year ?: 0, month ?: 1, day ?: 1) // Default to 1 if day is null + calendar.set(year ?: 0, month ?: 1, day ?: 1) return dateFormat.format(calendar.time) } From 98db83f11add790c08c7ab03e4d9f1f0fdd17bdc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jaime=20Garc=C3=ADa?= <55400857+jaime-grj@users.noreply.github.com> Date: Thu, 7 Aug 2025 03:26:04 +0200 Subject: [PATCH 07/16] fix: set album year in AlbumPageFragment --- .../cappielloantonio/tempo/ui/fragment/AlbumPageFragment.java | 1 + 1 file changed, 1 insertion(+) diff --git a/app/src/main/java/com/cappielloantonio/tempo/ui/fragment/AlbumPageFragment.java b/app/src/main/java/com/cappielloantonio/tempo/ui/fragment/AlbumPageFragment.java index 31248768..8ea66d2f 100644 --- a/app/src/main/java/com/cappielloantonio/tempo/ui/fragment/AlbumPageFragment.java +++ b/app/src/main/java/com/cappielloantonio/tempo/ui/fragment/AlbumPageFragment.java @@ -144,6 +144,7 @@ public class AlbumPageFragment extends Fragment implements ClickCallback { bind.albumNameLabel.setText(album.getName()); bind.albumArtistLabel.setText(album.getArtist()); + bind.albumReleaseYearLabel.setText(album.getYear() != 0 ? String.valueOf(album.getYear()) : ""); bind.albumReleaseYearLabel.setVisibility(album.getYear() != 0 ? View.VISIBLE : View.GONE); bind.albumSongCountDurationTextview.setText(getString(R.string.album_page_tracks_count_and_duration, album.getSongCount(), album.getDuration() != null ? album.getDuration() / 60 : 0)); if (album.getGenre() != null && !album.getGenre().isEmpty()) { From e1aeccdd85fb446691ad64258671146913f5f6da Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jaime=20Garc=C3=ADa?= <55400857+jaime-grj@users.noreply.github.com> Date: Thu, 7 Aug 2025 04:18:25 +0200 Subject: [PATCH 08/16] fix: hide genre in AlbumPageFragment properly --- .../cappielloantonio/tempo/ui/fragment/AlbumPageFragment.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/app/src/main/java/com/cappielloantonio/tempo/ui/fragment/AlbumPageFragment.java b/app/src/main/java/com/cappielloantonio/tempo/ui/fragment/AlbumPageFragment.java index 8ea66d2f..dc02dcbe 100644 --- a/app/src/main/java/com/cappielloantonio/tempo/ui/fragment/AlbumPageFragment.java +++ b/app/src/main/java/com/cappielloantonio/tempo/ui/fragment/AlbumPageFragment.java @@ -151,6 +151,9 @@ public class AlbumPageFragment extends Fragment implements ClickCallback { bind.albumGenresTextview.setText(album.getGenre()); bind.albumGenresTextview.setVisibility(View.VISIBLE); } + else{ + bind.albumGenresTextview.setVisibility(View.GONE); + } if (album.getReleaseDate() != null && album.getOriginalReleaseDate() != null) { if (album.getReleaseDate().getFormattedDate() != null || album.getOriginalReleaseDate().getFormattedDate() != null) From 7fdffa7f6f6f354c554e84046a252670d8a6cabe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jaime=20Garc=C3=ADa?= <55400857+jaime-grj@users.noreply.github.com> Date: Fri, 8 Aug 2025 22:15:52 +0200 Subject: [PATCH 09/16] fix: check for IP connectivity instead of Internet access --- .../com/cappielloantonio/tempo/subsonic/utils/CacheUtil.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/java/com/cappielloantonio/tempo/subsonic/utils/CacheUtil.java b/app/src/main/java/com/cappielloantonio/tempo/subsonic/utils/CacheUtil.java index 63bde7aa..047b0010 100644 --- a/app/src/main/java/com/cappielloantonio/tempo/subsonic/utils/CacheUtil.java +++ b/app/src/main/java/com/cappielloantonio/tempo/subsonic/utils/CacheUtil.java @@ -48,7 +48,7 @@ public class CacheUtil { NetworkCapabilities capabilities = connectivityManager.getNetworkCapabilities(network); if (capabilities != null) { - return capabilities.hasCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET) && capabilities.hasCapability(NetworkCapabilities.NET_CAPABILITY_VALIDATED); + return capabilities.hasCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET); } } } From 8a57f8f389a3782b0ff99287601265f219e8ab96 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jaime=20Garc=C3=ADa?= <55400857+jaime-grj@users.noreply.github.com> Date: Sat, 9 Aug 2025 02:52:07 +0200 Subject: [PATCH 10/16] fix: show "System default" language option, sort languages alphabetically --- .../tempo/ui/fragment/SettingsFragment.java | 18 ++++++++++--- .../cappielloantonio/tempo/util/UIUtil.java | 27 +++++++++++++++---- app/src/main/res/values-es-rES/strings.xml | 1 + app/src/main/res/values/strings.xml | 1 + 4 files changed, 38 insertions(+), 9 deletions(-) diff --git a/app/src/main/java/com/cappielloantonio/tempo/ui/fragment/SettingsFragment.java b/app/src/main/java/com/cappielloantonio/tempo/ui/fragment/SettingsFragment.java index a02aaa65..6e0d7109 100644 --- a/app/src/main/java/com/cappielloantonio/tempo/ui/fragment/SettingsFragment.java +++ b/app/src/main/java/com/cappielloantonio/tempo/ui/fragment/SettingsFragment.java @@ -201,12 +201,22 @@ public class SettingsFragment extends PreferenceFragmentCompat { localePref.setEntries(entries); localePref.setEntryValues(entryValues); - localePref.setDefaultValue(entryValues[0]); - localePref.setSummary(Locale.forLanguageTag(localePref.getValue()).getDisplayLanguage()); + String value = localePref.getValue(); + if ("default".equals(value)) { + localePref.setSummary(requireContext().getString(R.string.settings_system_language)); + } else { + localePref.setSummary(Locale.forLanguageTag(value).getDisplayLanguage()); + } localePref.setOnPreferenceChangeListener((preference, newValue) -> { - LocaleListCompat appLocale = LocaleListCompat.forLanguageTags((String) newValue); - AppCompatDelegate.setApplicationLocales(appLocale); + if ("default".equals(newValue)) { + AppCompatDelegate.setApplicationLocales(LocaleListCompat.getEmptyLocaleList()); + preference.setSummary(requireContext().getString(R.string.settings_system_language)); + } else { + LocaleListCompat appLocale = LocaleListCompat.forLanguageTags((String) newValue); + AppCompatDelegate.setApplicationLocales(appLocale); + preference.setSummary(Locale.forLanguageTag((String) newValue).getDisplayLanguage()); + } return true; }); } diff --git a/app/src/main/java/com/cappielloantonio/tempo/util/UIUtil.java b/app/src/main/java/com/cappielloantonio/tempo/util/UIUtil.java index bbbdf988..f9b7fdba 100644 --- a/app/src/main/java/com/cappielloantonio/tempo/util/UIUtil.java +++ b/app/src/main/java/com/cappielloantonio/tempo/util/UIUtil.java @@ -8,6 +8,7 @@ import android.graphics.drawable.InsetDrawable; import androidx.core.os.LocaleListCompat; import androidx.recyclerview.widget.DividerItemDecoration; +import com.cappielloantonio.tempo.App; import com.cappielloantonio.tempo.R; import org.xmlpull.v1.XmlPullParser; @@ -15,9 +16,10 @@ import org.xmlpull.v1.XmlPullParserException; import java.io.IOException; import java.text.SimpleDateFormat; +import java.util.AbstractMap; import java.util.ArrayList; import java.util.Date; -import java.util.HashMap; +import java.util.LinkedHashMap; import java.util.List; import java.util.Locale; import java.util.Map; @@ -74,17 +76,32 @@ public class UIUtil { public static Map getLangPreferenceDropdownEntries(Context context) { LocaleListCompat localeList = getLocalesFromResources(context); - Map map = new HashMap<>(); + List> localeArrayList = new ArrayList<>(); + + String systemDefaultLabel = App.getContext().getString(R.string.settings_system_language); + String systemDefaultValue = "default"; for (int i = 0; i < localeList.size(); i++) { Locale locale = localeList.get(i); - if (locale != null) { - map.put(Util.toPascalCase(locale.getDisplayName()), locale.toLanguageTag()); + localeArrayList.add( + new AbstractMap.SimpleEntry<>( + Util.toPascalCase(locale.getDisplayName()), + locale.toLanguageTag() + ) + ); } } - return map; + localeArrayList.sort(Map.Entry.comparingByKey(String.CASE_INSENSITIVE_ORDER)); + + LinkedHashMap orderedMap = new LinkedHashMap<>(); + orderedMap.put(systemDefaultLabel, systemDefaultValue); + for (Map.Entry entry : localeArrayList) { + orderedMap.put(entry.getKey(), entry.getValue()); + } + + return orderedMap; } public static String getReadableDate(Date date) { diff --git a/app/src/main/res/values-es-rES/strings.xml b/app/src/main/res/values-es-rES/strings.xml index d2c21d36..00e9aaf2 100644 --- a/app/src/main/res/values-es-rES/strings.xml +++ b/app/src/main/res/values-es-rES/strings.xml @@ -164,6 +164,7 @@ Artista Resolución de la imagen Idioma + Idioma del sistema Cerrar sesión https://github.com/eddyizm/tempo Siga el desarrollo diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 8ecb78af..de2efa0e 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -319,6 +319,7 @@ If enabled, sets a curvature angle for all rendered covers. The changes will take effect on restart. Scan library Enable music scrobbling + System language Enable music sharing Size of streaming cache Streaming cache storage From f53461382cdde26ed42d9392a3c82983ca24be93 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jaime=20Garc=C3=ADa?= <55400857+jaime-grj@users.noreply.github.com> Date: Sat, 9 Aug 2025 02:53:20 +0200 Subject: [PATCH 11/16] fix: include country when showing language in settings --- .../cappielloantonio/tempo/ui/fragment/SettingsFragment.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/com/cappielloantonio/tempo/ui/fragment/SettingsFragment.java b/app/src/main/java/com/cappielloantonio/tempo/ui/fragment/SettingsFragment.java index 6e0d7109..10f5d5a9 100644 --- a/app/src/main/java/com/cappielloantonio/tempo/ui/fragment/SettingsFragment.java +++ b/app/src/main/java/com/cappielloantonio/tempo/ui/fragment/SettingsFragment.java @@ -205,7 +205,7 @@ public class SettingsFragment extends PreferenceFragmentCompat { if ("default".equals(value)) { localePref.setSummary(requireContext().getString(R.string.settings_system_language)); } else { - localePref.setSummary(Locale.forLanguageTag(value).getDisplayLanguage()); + localePref.setSummary(Locale.forLanguageTag(value).getDisplayName()); } localePref.setOnPreferenceChangeListener((preference, newValue) -> { @@ -215,7 +215,7 @@ public class SettingsFragment extends PreferenceFragmentCompat { } else { LocaleListCompat appLocale = LocaleListCompat.forLanguageTags((String) newValue); AppCompatDelegate.setApplicationLocales(appLocale); - preference.setSummary(Locale.forLanguageTag((String) newValue).getDisplayLanguage()); + preference.setSummary(Locale.forLanguageTag((String) newValue).getDisplayName()); } return true; }); From 77ac195f32d5404a142ebdf6b6f2a27daba9de6e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jaime=20Garc=C3=ADa?= <55400857+jaime-grj@users.noreply.github.com> Date: Sat, 9 Aug 2025 13:22:25 +0200 Subject: [PATCH 12/16] fix: make hardcoded strings in home fragment dynamic --- .../cappielloantonio/tempo/ui/fragment/HomeFragment.java | 6 +++--- app/src/main/res/values-es-rES/strings.xml | 3 +++ app/src/main/res/values/strings.xml | 3 +++ 3 files changed, 9 insertions(+), 3 deletions(-) diff --git a/app/src/main/java/com/cappielloantonio/tempo/ui/fragment/HomeFragment.java b/app/src/main/java/com/cappielloantonio/tempo/ui/fragment/HomeFragment.java index 8cb4dffc..a0d0380c 100644 --- a/app/src/main/java/com/cappielloantonio/tempo/ui/fragment/HomeFragment.java +++ b/app/src/main/java/com/cappielloantonio/tempo/ui/fragment/HomeFragment.java @@ -80,13 +80,13 @@ public class HomeFragment extends Fragment { private void initHomePager() { HomePager pager = new HomePager(this); - pager.addFragment(new HomeTabMusicFragment(), "Music", R.drawable.ic_home); + pager.addFragment(new HomeTabMusicFragment(), getString(R.string.home_section_music), R.drawable.ic_home); if (Preferences.isPodcastSectionVisible()) - pager.addFragment(new HomeTabPodcastFragment(), "Podcast", R.drawable.ic_graphic_eq); + pager.addFragment(new HomeTabPodcastFragment(), getString(R.string.home_section_podcast), R.drawable.ic_graphic_eq); if (Preferences.isRadioSectionVisible()) - pager.addFragment(new HomeTabRadioFragment(), "Radio", R.drawable.ic_play_for_work); + pager.addFragment(new HomeTabRadioFragment(), getString(R.string.home_section_radio), R.drawable.ic_play_for_work); bind.homeViewPager.setAdapter(pager); bind.homeViewPager.setOffscreenPageLimit(3); diff --git a/app/src/main/res/values-es-rES/strings.xml b/app/src/main/res/values-es-rES/strings.xml index d2c21d36..9d6827fe 100644 --- a/app/src/main/res/values-es-rES/strings.xml +++ b/app/src/main/res/values-es-rES/strings.xml @@ -104,6 +104,9 @@ Guardar Reorganizar la página de inicio Tenga en cuenta que para que los cambios surtan efecto, hay que reiniciar la aplicación. + Música + Pódcasts + Radio Mejores pistas de tus artistas favoritos Iniciar mix desde una cación que te gustó Añadir una nueva emisora de radio diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 8ecb78af..91766091 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -105,6 +105,9 @@ Save Rearrange home Please note that in order for the changes made to take effect, it is necessary to restart the application. + Music + Podcast + Radio Top songs of your favorite artists Start mix from a song you liked Add a new radio From 4dfd346da59f448bc1ba83f25572de5b5707cb7f Mon Sep 17 00:00:00 2001 From: eddyizm Date: Sat, 9 Aug 2025 10:27:11 -0700 Subject: [PATCH 13/16] chore: added changelog to track updates since fork --- CHANGELOG.md | 38 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) create mode 100644 CHANGELOG.md diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 00000000..1b11e834 --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,38 @@ +# Changelog + +***This log is for this fork to detail updates since 3.9.0 from the main repo.*** + +## Unreleased + +**Housekeeping:** + +- [Chore] Added change log. + +**Merged pull requests:** + +- [Fix] make hardcoded strings in home fragment dynamic [\#27](https://github.com/eddyizm/tempo/pull/22) ([jaime-grj](https://github.com/jaime-grj)) + +- [Fix] show "System default" language option, sort languages alphabetically, include country when showing language in settings [\#26](https://github.com/eddyizm/tempo/pull/26) ([jaime-grj ](https://github.com/jaime-grj)) + +- [Fix] check for IP connectivity instead of Internet access [\#25](https://github.com/eddyizm/tempo/pull/25) ([jaime-grj](https://github.com/jaime-grj)) + +- [Fix] hide unnecessary TextViews in AlbumPageFragment when there is no data, fixed incorrect album release date [\#24](https://github.com/eddyizm/tempo/pull/24) ([jaime-grj](https://github.com/jaime-grj)) + +- [Feat] show sampling rate and bit depth if available [\#22](https://github.com/eddyizm/tempo/pull/22) ([jaime-grj](https://github.com/jaime-grj)) + +- [Feat] Fix lyric scrolling during playback, keep screen on while viewing [\#20](https://github.com/eddyizm/tempo/pull/20) ([le-firehawk](https://github.com/le-firehawk)) + +## [3.10.0](https://github.com/eddyizm/tempo/releases/tag/v3.10.0) (2025-08-04) + +**Merged pull requests:** + +- [Fix] redirection to artist fragment on artist label click [\#379](https://github.com/CappielloAntonio/tempo/pull/379) +- [Fix] Player queue lag, limits [\#385](https://github.com/CappielloAntonio/tempo/pull/385) +- [Fix] crash when sorting albums with a null artist [\#389](https://github.com/CappielloAntonio/tempo/pull/389) +- [Feat] Display toast message after adding a song to a playlist [\#371](https://github.com/CappielloAntonio/tempo/pull/371) +- [Feat] Album add to playlist context menu item [\#367](https://github.com/CappielloAntonio/tempo/pull/367) +- [Feat] Store and retrieve replay and shuffle states in preferences [\#397](https://github.com/CappielloAntonio/tempo/pull/397) +- [Feat] Enhance Android media player notification window #400 + [\#400](https://github.com/CappielloAntonio/tempo/pull/400) +- [Chore] Spanish translation [\#374](https://github.com/CappielloAntonio/tempo/pull/374) +- [Chore] Polish translation [\#378](https://github.com/CappielloAntonio/tempo/pull/378) From 7ccc0a0cf8120127a8b8e1932599825bd8901dfa Mon Sep 17 00:00:00 2001 From: eddyizm Date: Sat, 9 Aug 2025 10:39:46 -0700 Subject: [PATCH 14/16] chore: adding the new json schme and bumping the versions for release --- app/build.gradle | 4 +- .../11.json | 1101 +++++++++++++++++ 2 files changed, 1103 insertions(+), 2 deletions(-) create mode 100644 app/schemas/com.cappielloantonio.tempo.database.AppDatabase/11.json diff --git a/app/build.gradle b/app/build.gradle index 2d176a6b..f301fe1c 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -10,8 +10,8 @@ android { minSdkVersion 24 targetSdk 35 - versionCode 26 - versionName '3.10.0' + versionCode 27 + versionName '3.11.0' testInstrumentationRunner 'androidx.test.runner.AndroidJUnitRunner' diff --git a/app/schemas/com.cappielloantonio.tempo.database.AppDatabase/11.json b/app/schemas/com.cappielloantonio.tempo.database.AppDatabase/11.json new file mode 100644 index 00000000..9febeba2 --- /dev/null +++ b/app/schemas/com.cappielloantonio.tempo.database.AppDatabase/11.json @@ -0,0 +1,1101 @@ +{ + "formatVersion": 1, + "database": { + "version": 11, + "identityHash": "cceefd0896d9f0e949a30b53dd682bee", + "entities": [ + { + "tableName": "queue", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` TEXT NOT NULL, `track_order` INTEGER NOT NULL, `last_play` INTEGER NOT NULL, `playing_changed` INTEGER NOT NULL, `stream_id` TEXT, `parent_id` TEXT, `is_dir` INTEGER NOT NULL, `title` TEXT, `album` TEXT, `artist` TEXT, `track` INTEGER, `year` INTEGER, `genre` TEXT, `cover_art_id` TEXT, `size` INTEGER, `content_type` TEXT, `suffix` TEXT, `transcoding_content_type` TEXT, `transcoded_suffix` TEXT, `duration` INTEGER, `bitrate` INTEGER, `sampling_rate` INTEGER, `bit_depth` INTEGER, `path` TEXT, `is_video` INTEGER NOT NULL, `user_rating` INTEGER, `average_rating` REAL, `play_count` INTEGER, `disc_number` INTEGER, `created` INTEGER, `starred` INTEGER, `album_id` TEXT, `artist_id` TEXT, `type` TEXT, `bookmark_position` INTEGER, `original_width` INTEGER, `original_height` INTEGER, PRIMARY KEY(`track_order`))", + "fields": [ + { + "fieldPath": "id", + "columnName": "id", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "trackOrder", + "columnName": "track_order", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "lastPlay", + "columnName": "last_play", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "playingChanged", + "columnName": "playing_changed", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "streamId", + "columnName": "stream_id", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "parentId", + "columnName": "parent_id", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "isDir", + "columnName": "is_dir", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "title", + "columnName": "title", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "album", + "columnName": "album", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "artist", + "columnName": "artist", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "track", + "columnName": "track", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "year", + "columnName": "year", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "genre", + "columnName": "genre", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "coverArtId", + "columnName": "cover_art_id", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "size", + "columnName": "size", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "contentType", + "columnName": "content_type", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "suffix", + "columnName": "suffix", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "transcodedContentType", + "columnName": "transcoding_content_type", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "transcodedSuffix", + "columnName": "transcoded_suffix", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "duration", + "columnName": "duration", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "bitrate", + "columnName": "bitrate", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "samplingRate", + "columnName": "sampling_rate", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "bitDepth", + "columnName": "bit_depth", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "path", + "columnName": "path", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "isVideo", + "columnName": "is_video", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "userRating", + "columnName": "user_rating", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "averageRating", + "columnName": "average_rating", + "affinity": "REAL", + "notNull": false + }, + { + "fieldPath": "playCount", + "columnName": "play_count", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "discNumber", + "columnName": "disc_number", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "created", + "columnName": "created", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "starred", + "columnName": "starred", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "albumId", + "columnName": "album_id", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "artistId", + "columnName": "artist_id", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "type", + "columnName": "type", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "bookmarkPosition", + "columnName": "bookmark_position", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "originalWidth", + "columnName": "original_width", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "originalHeight", + "columnName": "original_height", + "affinity": "INTEGER", + "notNull": false + } + ], + "primaryKey": { + "autoGenerate": false, + "columnNames": [ + "track_order" + ] + }, + "indices": [], + "foreignKeys": [] + }, + { + "tableName": "server", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` TEXT NOT NULL, `server_name` TEXT NOT NULL, `username` TEXT NOT NULL, `password` TEXT NOT NULL, `address` TEXT NOT NULL, `local_address` TEXT, `timestamp` INTEGER NOT NULL, `low_security` INTEGER NOT NULL DEFAULT false, PRIMARY KEY(`id`))", + "fields": [ + { + "fieldPath": "serverId", + "columnName": "id", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "serverName", + "columnName": "server_name", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "username", + "columnName": "username", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "password", + "columnName": "password", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "address", + "columnName": "address", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "localAddress", + "columnName": "local_address", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "timestamp", + "columnName": "timestamp", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "isLowSecurity", + "columnName": "low_security", + "affinity": "INTEGER", + "notNull": true, + "defaultValue": "false" + } + ], + "primaryKey": { + "autoGenerate": false, + "columnNames": [ + "id" + ] + }, + "indices": [], + "foreignKeys": [] + }, + { + "tableName": "recent_search", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`search` TEXT NOT NULL, PRIMARY KEY(`search`))", + "fields": [ + { + "fieldPath": "search", + "columnName": "search", + "affinity": "TEXT", + "notNull": true + } + ], + "primaryKey": { + "autoGenerate": false, + "columnNames": [ + "search" + ] + }, + "indices": [], + "foreignKeys": [] + }, + { + "tableName": "download", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` TEXT NOT NULL, `playlist_id` TEXT, `playlist_name` TEXT, `download_state` INTEGER NOT NULL DEFAULT 1, `download_uri` TEXT DEFAULT '', `parent_id` TEXT, `is_dir` INTEGER NOT NULL, `title` TEXT, `album` TEXT, `artist` TEXT, `track` INTEGER, `year` INTEGER, `genre` TEXT, `cover_art_id` TEXT, `size` INTEGER, `content_type` TEXT, `suffix` TEXT, `transcoding_content_type` TEXT, `transcoded_suffix` TEXT, `duration` INTEGER, `bitrate` INTEGER, `sampling_rate` INTEGER, `bit_depth` INTEGER, `path` TEXT, `is_video` INTEGER NOT NULL, `user_rating` INTEGER, `average_rating` REAL, `play_count` INTEGER, `disc_number` INTEGER, `created` INTEGER, `starred` INTEGER, `album_id` TEXT, `artist_id` TEXT, `type` TEXT, `bookmark_position` INTEGER, `original_width` INTEGER, `original_height` INTEGER, PRIMARY KEY(`id`))", + "fields": [ + { + "fieldPath": "id", + "columnName": "id", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "playlistId", + "columnName": "playlist_id", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "playlistName", + "columnName": "playlist_name", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "downloadState", + "columnName": "download_state", + "affinity": "INTEGER", + "notNull": true, + "defaultValue": "1" + }, + { + "fieldPath": "downloadUri", + "columnName": "download_uri", + "affinity": "TEXT", + "notNull": false, + "defaultValue": "''" + }, + { + "fieldPath": "parentId", + "columnName": "parent_id", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "isDir", + "columnName": "is_dir", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "title", + "columnName": "title", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "album", + "columnName": "album", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "artist", + "columnName": "artist", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "track", + "columnName": "track", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "year", + "columnName": "year", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "genre", + "columnName": "genre", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "coverArtId", + "columnName": "cover_art_id", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "size", + "columnName": "size", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "contentType", + "columnName": "content_type", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "suffix", + "columnName": "suffix", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "transcodedContentType", + "columnName": "transcoding_content_type", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "transcodedSuffix", + "columnName": "transcoded_suffix", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "duration", + "columnName": "duration", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "bitrate", + "columnName": "bitrate", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "samplingRate", + "columnName": "sampling_rate", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "bitDepth", + "columnName": "bit_depth", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "path", + "columnName": "path", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "isVideo", + "columnName": "is_video", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "userRating", + "columnName": "user_rating", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "averageRating", + "columnName": "average_rating", + "affinity": "REAL", + "notNull": false + }, + { + "fieldPath": "playCount", + "columnName": "play_count", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "discNumber", + "columnName": "disc_number", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "created", + "columnName": "created", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "starred", + "columnName": "starred", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "albumId", + "columnName": "album_id", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "artistId", + "columnName": "artist_id", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "type", + "columnName": "type", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "bookmarkPosition", + "columnName": "bookmark_position", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "originalWidth", + "columnName": "original_width", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "originalHeight", + "columnName": "original_height", + "affinity": "INTEGER", + "notNull": false + } + ], + "primaryKey": { + "autoGenerate": false, + "columnNames": [ + "id" + ] + }, + "indices": [], + "foreignKeys": [] + }, + { + "tableName": "chronology", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` TEXT NOT NULL, `timestamp` INTEGER NOT NULL, `server` TEXT, `parent_id` TEXT, `is_dir` INTEGER NOT NULL, `title` TEXT, `album` TEXT, `artist` TEXT, `track` INTEGER, `year` INTEGER, `genre` TEXT, `cover_art_id` TEXT, `size` INTEGER, `content_type` TEXT, `suffix` TEXT, `transcoding_content_type` TEXT, `transcoded_suffix` TEXT, `duration` INTEGER, `bitrate` INTEGER, `sampling_rate` INTEGER, `bit_depth` INTEGER, `path` TEXT, `is_video` INTEGER NOT NULL, `user_rating` INTEGER, `average_rating` REAL, `play_count` INTEGER, `disc_number` INTEGER, `created` INTEGER, `starred` INTEGER, `album_id` TEXT, `artist_id` TEXT, `type` TEXT, `bookmark_position` INTEGER, `original_width` INTEGER, `original_height` INTEGER, PRIMARY KEY(`id`))", + "fields": [ + { + "fieldPath": "id", + "columnName": "id", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "timestamp", + "columnName": "timestamp", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "server", + "columnName": "server", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "parentId", + "columnName": "parent_id", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "isDir", + "columnName": "is_dir", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "title", + "columnName": "title", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "album", + "columnName": "album", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "artist", + "columnName": "artist", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "track", + "columnName": "track", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "year", + "columnName": "year", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "genre", + "columnName": "genre", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "coverArtId", + "columnName": "cover_art_id", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "size", + "columnName": "size", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "contentType", + "columnName": "content_type", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "suffix", + "columnName": "suffix", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "transcodedContentType", + "columnName": "transcoding_content_type", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "transcodedSuffix", + "columnName": "transcoded_suffix", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "duration", + "columnName": "duration", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "bitrate", + "columnName": "bitrate", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "samplingRate", + "columnName": "sampling_rate", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "bitDepth", + "columnName": "bit_depth", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "path", + "columnName": "path", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "isVideo", + "columnName": "is_video", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "userRating", + "columnName": "user_rating", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "averageRating", + "columnName": "average_rating", + "affinity": "REAL", + "notNull": false + }, + { + "fieldPath": "playCount", + "columnName": "play_count", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "discNumber", + "columnName": "disc_number", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "created", + "columnName": "created", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "starred", + "columnName": "starred", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "albumId", + "columnName": "album_id", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "artistId", + "columnName": "artist_id", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "type", + "columnName": "type", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "bookmarkPosition", + "columnName": "bookmark_position", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "originalWidth", + "columnName": "original_width", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "originalHeight", + "columnName": "original_height", + "affinity": "INTEGER", + "notNull": false + } + ], + "primaryKey": { + "autoGenerate": false, + "columnNames": [ + "id" + ] + }, + "indices": [], + "foreignKeys": [] + }, + { + "tableName": "favorite", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`timestamp` INTEGER NOT NULL, `songId` TEXT, `albumId` TEXT, `artistId` TEXT, `toStar` INTEGER NOT NULL, PRIMARY KEY(`timestamp`))", + "fields": [ + { + "fieldPath": "timestamp", + "columnName": "timestamp", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "songId", + "columnName": "songId", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "albumId", + "columnName": "albumId", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "artistId", + "columnName": "artistId", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "toStar", + "columnName": "toStar", + "affinity": "INTEGER", + "notNull": true + } + ], + "primaryKey": { + "autoGenerate": false, + "columnNames": [ + "timestamp" + ] + }, + "indices": [], + "foreignKeys": [] + }, + { + "tableName": "session_media_item", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`index` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `id` TEXT, `parent_id` TEXT, `is_dir` INTEGER NOT NULL, `title` TEXT, `album` TEXT, `artist` TEXT, `track` INTEGER, `year` INTEGER, `genre` TEXT, `cover_art_id` TEXT, `size` INTEGER, `content_type` TEXT, `suffix` TEXT, `transcoding_content_type` TEXT, `transcoded_suffix` TEXT, `duration` INTEGER, `bitrate` INTEGER, `path` TEXT, `is_video` INTEGER NOT NULL, `user_rating` INTEGER, `average_rating` REAL, `play_count` INTEGER, `disc_number` INTEGER, `created` INTEGER, `starred` INTEGER, `album_id` TEXT, `artist_id` TEXT, `type` TEXT, `bookmark_position` INTEGER, `original_width` INTEGER, `original_height` INTEGER, `stream_id` TEXT, `stream_url` TEXT, `timestamp` INTEGER)", + "fields": [ + { + "fieldPath": "index", + "columnName": "index", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "id", + "columnName": "id", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "parentId", + "columnName": "parent_id", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "isDir", + "columnName": "is_dir", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "title", + "columnName": "title", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "album", + "columnName": "album", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "artist", + "columnName": "artist", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "track", + "columnName": "track", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "year", + "columnName": "year", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "genre", + "columnName": "genre", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "coverArtId", + "columnName": "cover_art_id", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "size", + "columnName": "size", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "contentType", + "columnName": "content_type", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "suffix", + "columnName": "suffix", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "transcodedContentType", + "columnName": "transcoding_content_type", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "transcodedSuffix", + "columnName": "transcoded_suffix", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "duration", + "columnName": "duration", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "bitrate", + "columnName": "bitrate", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "path", + "columnName": "path", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "isVideo", + "columnName": "is_video", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "userRating", + "columnName": "user_rating", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "averageRating", + "columnName": "average_rating", + "affinity": "REAL", + "notNull": false + }, + { + "fieldPath": "playCount", + "columnName": "play_count", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "discNumber", + "columnName": "disc_number", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "created", + "columnName": "created", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "starred", + "columnName": "starred", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "albumId", + "columnName": "album_id", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "artistId", + "columnName": "artist_id", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "type", + "columnName": "type", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "bookmarkPosition", + "columnName": "bookmark_position", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "originalWidth", + "columnName": "original_width", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "originalHeight", + "columnName": "original_height", + "affinity": "INTEGER", + "notNull": false + }, + { + "fieldPath": "streamId", + "columnName": "stream_id", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "streamUrl", + "columnName": "stream_url", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "timestamp", + "columnName": "timestamp", + "affinity": "INTEGER", + "notNull": false + } + ], + "primaryKey": { + "autoGenerate": true, + "columnNames": [ + "index" + ] + }, + "indices": [], + "foreignKeys": [] + }, + { + "tableName": "playlist", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` TEXT NOT NULL, `name` TEXT, `duration` INTEGER NOT NULL, `coverArt` TEXT, PRIMARY KEY(`id`))", + "fields": [ + { + "fieldPath": "id", + "columnName": "id", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "name", + "columnName": "name", + "affinity": "TEXT", + "notNull": false + }, + { + "fieldPath": "duration", + "columnName": "duration", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "coverArtId", + "columnName": "coverArt", + "affinity": "TEXT", + "notNull": false + } + ], + "primaryKey": { + "autoGenerate": false, + "columnNames": [ + "id" + ] + }, + "indices": [], + "foreignKeys": [] + } + ], + "views": [], + "setupQueries": [ + "CREATE TABLE IF NOT EXISTS room_master_table (id INTEGER PRIMARY KEY,identity_hash TEXT)", + "INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, 'cceefd0896d9f0e949a30b53dd682bee')" + ] + } +} \ No newline at end of file From ba09f1f9acec1ad061ed72e647df06fe89d13a66 Mon Sep 17 00:00:00 2001 From: eddyizm Date: Sat, 9 Aug 2025 10:51:09 -0700 Subject: [PATCH 15/16] chore: updated readme and change log --- CHANGELOG.md | 5 ++++- README.md | 11 +---------- 2 files changed, 5 insertions(+), 11 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1b11e834..e17d249b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,7 +2,10 @@ ***This log is for this fork to detail updates since 3.9.0 from the main repo.*** -## Unreleased +## [3.11.1](https://github.com/eddyizm/tempo/releases/tag/v3.11.1) (2025-08-09) + + +([Full Changelog](https://github.com/eddyizm/tempo/compare/v3.10.0...eddyizm:tempo:v3.11.1?expand=1)) **Housekeeping:** diff --git a/README.md b/README.md index b6a17bb7..cf157638 100644 --- a/README.md +++ b/README.md @@ -26,16 +26,7 @@ Tempo does not rely on magic algorithms to decide what you should listen to. Ins This fork is my attempt to keep development moving forward and merge in PR's that have been sitting for a while in the main repo. Thankful to @CappielloAntonio for the amazing app and hopefully we can continue to build on top of it. I will only be releasing on github and if I am not able to merge back to the main repo, I plan to rename the app to be able to publish it to fdroid and possibly google play? We will see. -[v3.10.0](https://github.com/eddyizm/tempo/releases/tag/v3.10.0) applies the following PR's (fix/feat/chore): -fix: [379](https://github.com/CappielloAntonio/tempo/pull/379) -Fix: redirection to artist fragment on artist label click -fix: [385](https://github.com/CappielloAntonio/tempo/pull/385) -Player queue lag, limits -fix: [389](https://github.com/CappielloAntonio/tempo/pull/389) -Fix crash when sorting albums with a null artist -feat: [371](https://github.com/CappielloAntonio/tempo/pull/371) -Display toast message after adding a song to a playlist -feat: [367](https://github.com/CappielloAntonio/tempo/pull/367) -Album add to playlist context menu item -chore: [374](https://github.com/CappielloAntonio/tempo/pull/374) -Spanish translation -feat: [397](https://github.com/CappielloAntonio/tempo/pull/397) -Store and retrieve replay and shuffle states in preferences -feat:[400](https://github.com/CappielloAntonio/tempo/pull/400) - enhance Android media player notification window -chore: [378](https://github.com/CappielloAntonio/tempo/pull/378) Polish translation +Moved details to [CHANGELOG.md](https://github.com/eddyizm/tempo/blob/main/CHANGELOG.md) ## Features - **Subsonic Integration**: Tempo seamlessly integrates with your Subsonic server, providing you with easy access to your entire music collection on the go. From 3d5ef1d900e6659115adf2cec07e0360bf476376 Mon Sep 17 00:00:00 2001 From: eddyizm Date: Sat, 9 Aug 2025 10:56:18 -0700 Subject: [PATCH 16/16] chore: more version syncing --- CHANGELOG.md | 4 ++-- app/build.gradle | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index e17d249b..c42c6bff 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,10 +2,10 @@ ***This log is for this fork to detail updates since 3.9.0 from the main repo.*** -## [3.11.1](https://github.com/eddyizm/tempo/releases/tag/v3.11.1) (2025-08-09) +## [3.11.2](https://github.com/eddyizm/tempo/releases/tag/v3.11.2) (2025-08-09) -([Full Changelog](https://github.com/eddyizm/tempo/compare/v3.10.0...eddyizm:tempo:v3.11.1?expand=1)) +([Full Changelog](https://github.com/eddyizm/tempo/compare/v3.10.0...eddyizm:tempo:v3.11.2?expand=1)) **Housekeeping:** diff --git a/app/build.gradle b/app/build.gradle index f301fe1c..ea649294 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -11,7 +11,7 @@ android { targetSdk 35 versionCode 27 - versionName '3.11.0' + versionName '3.11.2' testInstrumentationRunner 'androidx.test.runner.AndroidJUnitRunner'