Compare commits
10 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
611b5001be | ||
|
|
923cfd5bc9 | ||
|
|
36d2320e70 | ||
|
|
17713ee400 | ||
|
|
ee3465868e | ||
|
|
9e8141a8d9 | ||
|
|
043e1b39b0 | ||
|
|
938c1de906 | ||
|
|
a0dfe63660 | ||
|
|
28c2f87b26 |
18
CHANGELOG.md
18
CHANGELOG.md
@@ -1,10 +1,16 @@
|
|||||||
# Changelog
|
# Changelog
|
||||||
|
|
||||||
|
|
||||||
## Pending release..
|
## Pending release..
|
||||||
|
* fix: reverts change causing album disc/track list to get out of order by @eddyizm in https://github.com/eddyizm/tempus/pull/237
|
||||||
|
* fix: Add listener to enable equalizer when audioSessionId changes by @jaime-grj in https://github.com/eddyizm/tempus/pull/235
|
||||||
|
|
||||||
|
**Full Changelog**: https://github.com/eddyizm/tempus/compare/v4.1.0...v4.1.2
|
||||||
|
|
||||||
|
## [4.1.0](https://github.com/eddyizm/tempo/releases/tag/v4.1.0) (2025-11-05)
|
||||||
|
## What's Changed
|
||||||
* chore(i18n): Update Spanish (es-ES) translation by @jaime-grj in https://github.com/eddyizm/tempus/pull/205
|
* chore(i18n): Update Spanish (es-ES) translation by @jaime-grj in https://github.com/eddyizm/tempus/pull/205
|
||||||
* feat: shuffle for artists without using `getTopSongs` by @pca006132 in https://github.com/eddyizm/tempus/pull/207
|
* shuffle for artists without using `getTopSongs` by @pca006132 in https://github.com/eddyizm/tempus/pull/207
|
||||||
* chore: Update USAGE.md with instant mix details by @zc-devs in https://github.com/eddyizm/tempus/pull/220
|
* Update USAGE.md with instant mix details by @zc-devs in https://github.com/eddyizm/tempus/pull/220
|
||||||
* feat: sort artists by album count by @pca006132 in https://github.com/eddyizm/tempus/pull/206
|
* feat: sort artists by album count by @pca006132 in https://github.com/eddyizm/tempus/pull/206
|
||||||
* Fix downloaded tab performance by @pca006132 in https://github.com/eddyizm/tempus/pull/210
|
* Fix downloaded tab performance by @pca006132 in https://github.com/eddyizm/tempus/pull/210
|
||||||
* fix: remove NestedScrollViews for fragment_album_page by @pca006132 in https://github.com/eddyizm/tempus/pull/216
|
* fix: remove NestedScrollViews for fragment_album_page by @pca006132 in https://github.com/eddyizm/tempus/pull/216
|
||||||
@@ -12,8 +18,12 @@
|
|||||||
* fix: do not override getItemViewType and getItemId by @pca006132 in https://github.com/eddyizm/tempus/pull/221
|
* fix: do not override getItemViewType and getItemId by @pca006132 in https://github.com/eddyizm/tempus/pull/221
|
||||||
* chore: update media3 dependencies by @pca006132 in https://github.com/eddyizm/tempus/pull/217
|
* chore: update media3 dependencies by @pca006132 in https://github.com/eddyizm/tempus/pull/217
|
||||||
* fix: update MediaItems after network change by @pca006132 in https://github.com/eddyizm/tempus/pull/222
|
* fix: update MediaItems after network change by @pca006132 in https://github.com/eddyizm/tempus/pull/222
|
||||||
|
* fix: skip mapping downloaded item by @pca006132 in https://github.com/eddyizm/tempus/pull/228
|
||||||
|
|
||||||
---
|
## New Contributors
|
||||||
|
* @pca006132 made their first contribution in https://github.com/eddyizm/tempus/pull/207
|
||||||
|
|
||||||
|
**Full Changelog**: https://github.com/eddyizm/tempus/compare/v4.0.7...v4.1.0
|
||||||
|
|
||||||
## [4.0.7](https://github.com/eddyizm/tempo/releases/tag/v4.0.7) (2025-10-28)
|
## [4.0.7](https://github.com/eddyizm/tempo/releases/tag/v4.0.7) (2025-10-28)
|
||||||
## What's Changed
|
## What's Changed
|
||||||
|
|||||||
@@ -10,8 +10,8 @@ android {
|
|||||||
minSdkVersion 24
|
minSdkVersion 24
|
||||||
targetSdk 35
|
targetSdk 35
|
||||||
|
|
||||||
versionCode 3
|
versionCode 4
|
||||||
versionName '4.1.0'
|
versionName '4.1.3'
|
||||||
testInstrumentationRunner 'androidx.test.runner.AndroidJUnitRunner'
|
testInstrumentationRunner 'androidx.test.runner.AndroidJUnitRunner'
|
||||||
|
|
||||||
javaCompileOptions {
|
javaCompileOptions {
|
||||||
|
|||||||
@@ -82,6 +82,7 @@ class MediaService : MediaLibraryService() {
|
|||||||
private const val CUSTOM_COMMAND_TOGGLE_REPEAT_MODE_ALL =
|
private const val CUSTOM_COMMAND_TOGGLE_REPEAT_MODE_ALL =
|
||||||
"android.media3.session.demo.REPEAT_ALL"
|
"android.media3.session.demo.REPEAT_ALL"
|
||||||
const val ACTION_BIND_EQUALIZER = "com.cappielloantonio.tempo.service.BIND_EQUALIZER"
|
const val ACTION_BIND_EQUALIZER = "com.cappielloantonio.tempo.service.BIND_EQUALIZER"
|
||||||
|
const val ACTION_EQUALIZER_UPDATED = "com.cappielloantonio.tempo.service.EQUALIZER_UPDATED"
|
||||||
}
|
}
|
||||||
|
|
||||||
fun updateMediaItems() {
|
fun updateMediaItems() {
|
||||||
@@ -283,16 +284,7 @@ class MediaService : MediaLibraryService() {
|
|||||||
private fun initializeEqualizerManager() {
|
private fun initializeEqualizerManager() {
|
||||||
equalizerManager = EqualizerManager()
|
equalizerManager = EqualizerManager()
|
||||||
val audioSessionId = player.audioSessionId
|
val audioSessionId = player.audioSessionId
|
||||||
if (equalizerManager.attachToSession(audioSessionId)) {
|
attachEqualizerIfPossible(audioSessionId)
|
||||||
val enabled = Preferences.isEqualizerEnabled()
|
|
||||||
equalizerManager.setEnabled(enabled)
|
|
||||||
|
|
||||||
val bands = equalizerManager.getNumberOfBands()
|
|
||||||
val savedLevels = Preferences.getEqualizerBandLevels(bands)
|
|
||||||
for (i in 0 until bands) {
|
|
||||||
equalizerManager.setBandLevel(i.toShort(), savedLevels[i])
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun initializeMediaLibrarySession() {
|
private fun initializeMediaLibrarySession() {
|
||||||
@@ -426,6 +418,10 @@ class MediaService : MediaLibraryService() {
|
|||||||
customLayout = librarySessionCallback.buildCustomLayout(player)
|
customLayout = librarySessionCallback.buildCustomLayout(player)
|
||||||
mediaLibrarySession.setCustomLayout(customLayout)
|
mediaLibrarySession.setCustomLayout(customLayout)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun onAudioSessionIdChanged(audioSessionId: Int) {
|
||||||
|
attachEqualizerIfPossible(audioSessionId)
|
||||||
|
}
|
||||||
})
|
})
|
||||||
if (player.isPlaying) {
|
if (player.isPlaying) {
|
||||||
scheduleWidgetUpdates()
|
scheduleWidgetUpdates()
|
||||||
@@ -541,6 +537,21 @@ class MediaService : MediaLibraryService() {
|
|||||||
widgetUpdateScheduled = false
|
widgetUpdateScheduled = false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun attachEqualizerIfPossible(audioSessionId: Int): Boolean {
|
||||||
|
if (audioSessionId == 0 || audioSessionId == -1) return false
|
||||||
|
val attached = equalizerManager.attachToSession(audioSessionId)
|
||||||
|
if (attached) {
|
||||||
|
val enabled = Preferences.isEqualizerEnabled()
|
||||||
|
equalizerManager.setEnabled(enabled)
|
||||||
|
val bands = equalizerManager.getNumberOfBands()
|
||||||
|
val savedLevels = Preferences.getEqualizerBandLevels(bands)
|
||||||
|
for (i in 0 until bands) {
|
||||||
|
equalizerManager.setBandLevel(i.toShort(), savedLevels[i])
|
||||||
|
}
|
||||||
|
sendBroadcast(Intent(ACTION_EQUALIZER_UPDATED))
|
||||||
|
}
|
||||||
|
return attached
|
||||||
|
}
|
||||||
|
|
||||||
private fun getRenderersFactory() = DownloadUtil.buildRenderersFactory(this, false)
|
private fun getRenderersFactory() = DownloadUtil.buildRenderersFactory(this, false)
|
||||||
|
|
||||||
|
|||||||
@@ -105,6 +105,16 @@ public class AlbumCatalogueAdapter extends RecyclerView.Adapter<AlbumCatalogueAd
|
|||||||
filtering.filter(currentFilter);
|
filtering.filter(currentFilter);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getItemViewType(int position) {
|
||||||
|
return position;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public long getItemId(int position) {
|
||||||
|
return position;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Filter getFilter() {
|
public Filter getFilter() {
|
||||||
return filtering;
|
return filtering;
|
||||||
|
|||||||
@@ -66,6 +66,16 @@ public class ArtistAdapter extends RecyclerView.Adapter<ArtistAdapter.ViewHolder
|
|||||||
notifyDataSetChanged();
|
notifyDataSetChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getItemViewType(int position) {
|
||||||
|
return position;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public long getItemId(int position) {
|
||||||
|
return position;
|
||||||
|
}
|
||||||
|
|
||||||
public class ViewHolder extends RecyclerView.ViewHolder {
|
public class ViewHolder extends RecyclerView.ViewHolder {
|
||||||
ItemLibraryArtistBinding item;
|
ItemLibraryArtistBinding item;
|
||||||
|
|
||||||
|
|||||||
@@ -97,6 +97,16 @@ public class ArtistCatalogueAdapter extends RecyclerView.Adapter<ArtistCatalogue
|
|||||||
notifyDataSetChanged();
|
notifyDataSetChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getItemViewType(int position) {
|
||||||
|
return position;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public long getItemId(int position) {
|
||||||
|
return position;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Filter getFilter() {
|
public Filter getFilter() {
|
||||||
return filtering;
|
return filtering;
|
||||||
|
|||||||
@@ -113,6 +113,16 @@ public class ArtistHorizontalAdapter extends RecyclerView.Adapter<ArtistHorizont
|
|||||||
return artists.get(id);
|
return artists.get(id);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getItemViewType(int position) {
|
||||||
|
return position;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public long getItemId(int position) {
|
||||||
|
return position;
|
||||||
|
}
|
||||||
|
|
||||||
public class ViewHolder extends RecyclerView.ViewHolder {
|
public class ViewHolder extends RecyclerView.ViewHolder {
|
||||||
ItemHorizontalArtistBinding item;
|
ItemHorizontalArtistBinding item;
|
||||||
|
|
||||||
|
|||||||
@@ -60,6 +60,16 @@ public class ArtistSimilarAdapter extends RecyclerView.Adapter<ArtistSimilarAdap
|
|||||||
notifyDataSetChanged();
|
notifyDataSetChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getItemViewType(int position) {
|
||||||
|
return position;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public long getItemId(int position) {
|
||||||
|
return position;
|
||||||
|
}
|
||||||
|
|
||||||
public class ViewHolder extends RecyclerView.ViewHolder {
|
public class ViewHolder extends RecyclerView.ViewHolder {
|
||||||
ItemLibrarySimilarArtistBinding item;
|
ItemLibrarySimilarArtistBinding item;
|
||||||
|
|
||||||
|
|||||||
@@ -96,6 +96,16 @@ public class DownloadHorizontalAdapter extends RecyclerView.Adapter<DownloadHori
|
|||||||
return shuffling;
|
return shuffling;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getItemViewType(int position) {
|
||||||
|
return position;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public long getItemId(int position) {
|
||||||
|
return position;
|
||||||
|
}
|
||||||
|
|
||||||
private List<Child> groupSong(List<Child> songs) {
|
private List<Child> groupSong(List<Child> songs) {
|
||||||
switch (view) {
|
switch (view) {
|
||||||
case Constants.DOWNLOAD_TYPE_TRACK:
|
case Constants.DOWNLOAD_TYPE_TRACK:
|
||||||
|
|||||||
@@ -95,6 +95,16 @@ public class PodcastChannelCatalogueAdapter extends RecyclerView.Adapter<Podcast
|
|||||||
notifyDataSetChanged();
|
notifyDataSetChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getItemViewType(int position) {
|
||||||
|
return position;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public long getItemId(int position) {
|
||||||
|
return position;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Filter getFilter() {
|
public Filter getFilter() {
|
||||||
return filtering;
|
return filtering;
|
||||||
|
|||||||
@@ -71,6 +71,16 @@ public class PodcastEpisodeAdapter extends RecyclerView.Adapter<PodcastEpisodeAd
|
|||||||
notifyDataSetChanged();
|
notifyDataSetChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getItemViewType(int position) {
|
||||||
|
return position;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public long getItemId(int position) {
|
||||||
|
return position;
|
||||||
|
}
|
||||||
|
|
||||||
public class ViewHolder extends RecyclerView.ViewHolder {
|
public class ViewHolder extends RecyclerView.ViewHolder {
|
||||||
ItemHomePodcastEpisodeBinding item;
|
ItemHomePodcastEpisodeBinding item;
|
||||||
|
|
||||||
|
|||||||
@@ -252,6 +252,16 @@ public class SongHorizontalAdapter extends RecyclerView.Adapter<SongHorizontalAd
|
|||||||
notifyDataSetChanged();
|
notifyDataSetChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getItemViewType(int position) {
|
||||||
|
return position;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public long getItemId(int position) {
|
||||||
|
return position;
|
||||||
|
}
|
||||||
|
|
||||||
public void setPlaybackState(String mediaId, boolean playing) {
|
public void setPlaybackState(String mediaId, boolean playing) {
|
||||||
String oldId = this.currentPlayingId;
|
String oldId = this.currentPlayingId;
|
||||||
boolean oldPlaying = this.isPlaying;
|
boolean oldPlaying = this.isPlaying;
|
||||||
|
|||||||
@@ -3,7 +3,9 @@ package com.cappielloantonio.tempo.ui.fragment
|
|||||||
import android.content.ComponentName
|
import android.content.ComponentName
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
|
import android.content.IntentFilter
|
||||||
import android.content.ServiceConnection
|
import android.content.ServiceConnection
|
||||||
|
import android.content.BroadcastReceiver
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.os.IBinder
|
import android.os.IBinder
|
||||||
import android.view.Gravity
|
import android.view.Gravity
|
||||||
@@ -12,6 +14,7 @@ import android.view.View
|
|||||||
import android.view.ViewGroup
|
import android.view.ViewGroup
|
||||||
import android.widget.*
|
import android.widget.*
|
||||||
import androidx.annotation.OptIn
|
import androidx.annotation.OptIn
|
||||||
|
import androidx.core.content.ContextCompat
|
||||||
import androidx.fragment.app.Fragment
|
import androidx.fragment.app.Fragment
|
||||||
import androidx.media3.common.util.UnstableApi
|
import androidx.media3.common.util.UnstableApi
|
||||||
import com.cappielloantonio.tempo.R
|
import com.cappielloantonio.tempo.R
|
||||||
@@ -28,6 +31,17 @@ class EqualizerFragment : Fragment() {
|
|||||||
private lateinit var safeSpace: Space
|
private lateinit var safeSpace: Space
|
||||||
private val bandSeekBars = mutableListOf<SeekBar>()
|
private val bandSeekBars = mutableListOf<SeekBar>()
|
||||||
|
|
||||||
|
private var receiverRegistered = false
|
||||||
|
private val equalizerUpdatedReceiver = object : BroadcastReceiver() {
|
||||||
|
@OptIn(UnstableApi::class)
|
||||||
|
override fun onReceive(context: Context?, intent: Intent?) {
|
||||||
|
if (intent?.action == MediaService.ACTION_EQUALIZER_UPDATED) {
|
||||||
|
initUI()
|
||||||
|
restoreEqualizerPreferences()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private val connection = object : ServiceConnection {
|
private val connection = object : ServiceConnection {
|
||||||
@OptIn(UnstableApi::class)
|
@OptIn(UnstableApi::class)
|
||||||
override fun onServiceConnected(className: ComponentName, service: IBinder) {
|
override fun onServiceConnected(className: ComponentName, service: IBinder) {
|
||||||
@@ -49,12 +63,29 @@ class EqualizerFragment : Fragment() {
|
|||||||
intent.action = MediaService.ACTION_BIND_EQUALIZER
|
intent.action = MediaService.ACTION_BIND_EQUALIZER
|
||||||
requireActivity().bindService(intent, connection, Context.BIND_AUTO_CREATE)
|
requireActivity().bindService(intent, connection, Context.BIND_AUTO_CREATE)
|
||||||
}
|
}
|
||||||
|
if (!receiverRegistered) {
|
||||||
|
ContextCompat.registerReceiver(
|
||||||
|
requireContext(),
|
||||||
|
equalizerUpdatedReceiver,
|
||||||
|
IntentFilter(MediaService.ACTION_EQUALIZER_UPDATED),
|
||||||
|
ContextCompat.RECEIVER_NOT_EXPORTED
|
||||||
|
)
|
||||||
|
receiverRegistered = true
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onStop() {
|
override fun onStop() {
|
||||||
super.onStop()
|
super.onStop()
|
||||||
requireActivity().unbindService(connection)
|
requireActivity().unbindService(connection)
|
||||||
equalizerManager = null
|
equalizerManager = null
|
||||||
|
if (receiverRegistered) {
|
||||||
|
try {
|
||||||
|
requireContext().unregisterReceiver(equalizerUpdatedReceiver)
|
||||||
|
} catch (_: Exception) {
|
||||||
|
// ignore if not registered
|
||||||
|
}
|
||||||
|
receiverRegistered = false
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onCreateView(
|
override fun onCreateView(
|
||||||
@@ -234,4 +265,4 @@ class EqualizerFragment : Fragment() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun Int.dpToPx(context: Context): Int =
|
private fun Int.dpToPx(context: Context): Int =
|
||||||
(this * context.resources.displayMetrics.density).toInt()
|
(this * context.resources.displayMetrics.density).toInt()
|
||||||
|
|||||||
@@ -60,6 +60,7 @@ class MediaService : MediaLibraryService(), SessionAvailabilityListener {
|
|||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
const val ACTION_BIND_EQUALIZER = "com.cappielloantonio.tempo.service.BIND_EQUALIZER"
|
const val ACTION_BIND_EQUALIZER = "com.cappielloantonio.tempo.service.BIND_EQUALIZER"
|
||||||
|
const val ACTION_EQUALIZER_UPDATED = "com.cappielloantonio.tempo.service.EQUALIZER_UPDATED"
|
||||||
}
|
}
|
||||||
private val widgetUpdateHandler = Handler(Looper.getMainLooper())
|
private val widgetUpdateHandler = Handler(Looper.getMainLooper())
|
||||||
private var widgetUpdateScheduled = false
|
private var widgetUpdateScheduled = false
|
||||||
|
|||||||
2
fastlane/metadata/android/en-US/changelogs/4.txt
Normal file
2
fastlane/metadata/android/en-US/changelogs/4.txt
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
reverts change causing album disc/track list to get out of order
|
||||||
|
Add listener to enable equalizer when audioSessionId
|
||||||
Reference in New Issue
Block a user