add detailed song information to Now Playing
Signed-off-by: Holger Müller <github@euhm.de>
This commit is contained in:
parent
dee4675715
commit
ae2055e324
|
@ -13,26 +13,13 @@ import android.graphics.Point
|
||||||
import android.graphics.drawable.Drawable
|
import android.graphics.drawable.Drawable
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.os.Handler
|
import android.os.Handler
|
||||||
import android.view.ContextMenu
|
import android.text.TextUtils
|
||||||
|
import android.view.*
|
||||||
import android.view.ContextMenu.ContextMenuInfo
|
import android.view.ContextMenu.ContextMenuInfo
|
||||||
import android.view.GestureDetector
|
|
||||||
import android.view.LayoutInflater
|
|
||||||
import android.view.Menu
|
|
||||||
import android.view.MenuInflater
|
|
||||||
import android.view.MenuItem
|
|
||||||
import android.view.MotionEvent
|
|
||||||
import android.view.View
|
|
||||||
import android.view.ViewGroup
|
|
||||||
import android.view.WindowManager
|
|
||||||
import android.view.animation.AnimationUtils
|
import android.view.animation.AnimationUtils
|
||||||
|
import android.widget.*
|
||||||
import android.widget.AdapterView.AdapterContextMenuInfo
|
import android.widget.AdapterView.AdapterContextMenuInfo
|
||||||
import android.widget.EditText
|
|
||||||
import android.widget.ImageView
|
|
||||||
import android.widget.LinearLayout
|
|
||||||
import android.widget.SeekBar
|
|
||||||
import android.widget.SeekBar.OnSeekBarChangeListener
|
import android.widget.SeekBar.OnSeekBarChangeListener
|
||||||
import android.widget.TextView
|
|
||||||
import android.widget.ViewFlipper
|
|
||||||
import androidx.core.view.isVisible
|
import androidx.core.view.isVisible
|
||||||
import androidx.fragment.app.Fragment
|
import androidx.fragment.app.Fragment
|
||||||
import androidx.navigation.Navigation
|
import androidx.navigation.Navigation
|
||||||
|
@ -42,24 +29,12 @@ import androidx.recyclerview.widget.LinearLayoutManager
|
||||||
import androidx.recyclerview.widget.LinearSmoothScroller
|
import androidx.recyclerview.widget.LinearSmoothScroller
|
||||||
import androidx.recyclerview.widget.RecyclerView
|
import androidx.recyclerview.widget.RecyclerView
|
||||||
import io.reactivex.rxjava3.disposables.Disposable
|
import io.reactivex.rxjava3.disposables.Disposable
|
||||||
import java.text.DateFormat
|
|
||||||
import java.text.SimpleDateFormat
|
|
||||||
import java.util.ArrayList
|
|
||||||
import java.util.Date
|
|
||||||
import java.util.Locale
|
|
||||||
import java.util.concurrent.CancellationException
|
|
||||||
import java.util.concurrent.Executors
|
|
||||||
import java.util.concurrent.ScheduledExecutorService
|
|
||||||
import java.util.concurrent.TimeUnit
|
|
||||||
import kotlin.math.abs
|
|
||||||
import kotlin.math.max
|
|
||||||
import kotlinx.coroutines.CoroutineScope
|
import kotlinx.coroutines.CoroutineScope
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
import kotlinx.coroutines.cancel
|
import kotlinx.coroutines.cancel
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
import org.koin.android.ext.android.inject
|
import org.koin.android.ext.android.inject
|
||||||
import org.koin.core.component.KoinComponent
|
import org.koin.core.component.KoinComponent
|
||||||
import org.koin.core.component.get
|
|
||||||
import org.moire.ultrasonic.R
|
import org.moire.ultrasonic.R
|
||||||
import org.moire.ultrasonic.adapters.BaseAdapter
|
import org.moire.ultrasonic.adapters.BaseAdapter
|
||||||
import org.moire.ultrasonic.adapters.TrackViewBinder
|
import org.moire.ultrasonic.adapters.TrackViewBinder
|
||||||
|
@ -79,14 +54,19 @@ import org.moire.ultrasonic.service.RxBus
|
||||||
import org.moire.ultrasonic.subsonic.ImageLoaderProvider
|
import org.moire.ultrasonic.subsonic.ImageLoaderProvider
|
||||||
import org.moire.ultrasonic.subsonic.NetworkAndStorageChecker
|
import org.moire.ultrasonic.subsonic.NetworkAndStorageChecker
|
||||||
import org.moire.ultrasonic.subsonic.ShareHandler
|
import org.moire.ultrasonic.subsonic.ShareHandler
|
||||||
import org.moire.ultrasonic.util.CancellationToken
|
import org.moire.ultrasonic.util.*
|
||||||
import org.moire.ultrasonic.util.CommunicationError
|
|
||||||
import org.moire.ultrasonic.util.Constants
|
|
||||||
import org.moire.ultrasonic.util.Settings
|
|
||||||
import org.moire.ultrasonic.util.Util
|
|
||||||
import org.moire.ultrasonic.view.AutoRepeatButton
|
import org.moire.ultrasonic.view.AutoRepeatButton
|
||||||
import org.moire.ultrasonic.view.VisualizerView
|
import org.moire.ultrasonic.view.VisualizerView
|
||||||
import timber.log.Timber
|
import timber.log.Timber
|
||||||
|
import java.text.DateFormat
|
||||||
|
import java.text.SimpleDateFormat
|
||||||
|
import java.util.*
|
||||||
|
import java.util.concurrent.CancellationException
|
||||||
|
import java.util.concurrent.Executors
|
||||||
|
import java.util.concurrent.ScheduledExecutorService
|
||||||
|
import java.util.concurrent.TimeUnit
|
||||||
|
import kotlin.math.abs
|
||||||
|
import kotlin.math.max
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Contains the Music Player screen of Ultrasonic with playback controls and the playlist
|
* Contains the Music Player screen of Ultrasonic with playback controls and the playlist
|
||||||
|
@ -139,6 +119,7 @@ class PlayerFragment :
|
||||||
private lateinit var songTitleTextView: TextView
|
private lateinit var songTitleTextView: TextView
|
||||||
private lateinit var albumTextView: TextView
|
private lateinit var albumTextView: TextView
|
||||||
private lateinit var artistTextView: TextView
|
private lateinit var artistTextView: TextView
|
||||||
|
private lateinit var detailsTextView: TextView
|
||||||
private lateinit var albumArtImageView: ImageView
|
private lateinit var albumArtImageView: ImageView
|
||||||
private lateinit var playlistView: RecyclerView
|
private lateinit var playlistView: RecyclerView
|
||||||
private lateinit var positionTextView: TextView
|
private lateinit var positionTextView: TextView
|
||||||
|
@ -176,6 +157,7 @@ class PlayerFragment :
|
||||||
songTitleTextView = view.findViewById(R.id.current_playing_song)
|
songTitleTextView = view.findViewById(R.id.current_playing_song)
|
||||||
albumTextView = view.findViewById(R.id.current_playing_album)
|
albumTextView = view.findViewById(R.id.current_playing_album)
|
||||||
artistTextView = view.findViewById(R.id.current_playing_artist)
|
artistTextView = view.findViewById(R.id.current_playing_artist)
|
||||||
|
detailsTextView = view.findViewById(R.id.current_playing_details)
|
||||||
albumArtImageView = view.findViewById(R.id.current_playing_album_art_image)
|
albumArtImageView = view.findViewById(R.id.current_playing_album_art_image)
|
||||||
positionTextView = view.findViewById(R.id.current_playing_position)
|
positionTextView = view.findViewById(R.id.current_playing_position)
|
||||||
downloadTrackTextView = view.findViewById(R.id.current_playing_track)
|
downloadTrackTextView = view.findViewById(R.id.current_playing_track)
|
||||||
|
@ -981,6 +963,21 @@ class PlayerFragment :
|
||||||
songTitleTextView.text = currentSong!!.title
|
songTitleTextView.text = currentSong!!.title
|
||||||
albumTextView.text = currentSong!!.album
|
albumTextView.text = currentSong!!.album
|
||||||
artistTextView.text = currentSong!!.artist
|
artistTextView.text = currentSong!!.artist
|
||||||
|
|
||||||
|
val fileFormat: String? =
|
||||||
|
if (TextUtils.isEmpty(currentSong!!.transcodedSuffix) ||
|
||||||
|
currentSong!!.transcodedSuffix == currentSong!!.suffix ||
|
||||||
|
currentSong!!.isVideo)
|
||||||
|
currentSong!!.suffix
|
||||||
|
else
|
||||||
|
String.format(Locale.ROOT, "%s > %s", currentSong!!.suffix, currentSong!!.transcodedSuffix)
|
||||||
|
val details: String =
|
||||||
|
String.format(
|
||||||
|
Util.appContext().getString(R.string.song_details_nowplaying),
|
||||||
|
currentSong!!.genre, currentSong!!.year, currentSong!!.bitRate, fileFormat)
|
||||||
|
detailsTextView.text = details
|
||||||
|
detailsTextView.visibility = if (Settings.showNowPlayingDetails) View.VISIBLE else View.GONE
|
||||||
|
|
||||||
downloadTrackTextView.text = trackFormat
|
downloadTrackTextView.text = trackFormat
|
||||||
downloadTotalDurationTextView.text = duration
|
downloadTotalDurationTextView.text = duration
|
||||||
imageLoaderProvider.getImageLoader()
|
imageLoaderProvider.getImageLoader()
|
||||||
|
@ -991,6 +988,7 @@ class PlayerFragment :
|
||||||
songTitleTextView.text = null
|
songTitleTextView.text = null
|
||||||
albumTextView.text = null
|
albumTextView.text = null
|
||||||
artistTextView.text = null
|
artistTextView.text = null
|
||||||
|
detailsTextView.text = null
|
||||||
downloadTrackTextView.text = null
|
downloadTrackTextView.text = null
|
||||||
downloadTotalDurationTextView.text = null
|
downloadTotalDurationTextView.text = null
|
||||||
imageLoaderProvider.getImageLoader()
|
imageLoaderProvider.getImageLoader()
|
||||||
|
|
|
@ -90,6 +90,7 @@ object Constants {
|
||||||
const val PREFERENCES_KEY_CLEAR_SEARCH_HISTORY = "clearSearchHistory"
|
const val PREFERENCES_KEY_CLEAR_SEARCH_HISTORY = "clearSearchHistory"
|
||||||
const val PREFERENCES_KEY_DOWNLOAD_TRANSITION = "transitionToDownloadOnPlay"
|
const val PREFERENCES_KEY_DOWNLOAD_TRANSITION = "transitionToDownloadOnPlay"
|
||||||
const val PREFERENCES_KEY_INCREMENT_TIME = "incrementTime"
|
const val PREFERENCES_KEY_INCREMENT_TIME = "incrementTime"
|
||||||
|
const val PREFERENCES_KEY_SHOW_NOW_PLAYING_DETAILS = "showNowPlayingDetails"
|
||||||
const val PREFERENCES_KEY_ID3_TAGS = "useId3Tags"
|
const val PREFERENCES_KEY_ID3_TAGS = "useId3Tags"
|
||||||
const val PREFERENCES_KEY_SHOW_ARTIST_PICTURE = "showArtistPicture"
|
const val PREFERENCES_KEY_SHOW_ARTIST_PICTURE = "showArtistPicture"
|
||||||
const val PREFERENCES_KEY_TEMP_LOSS = "tempLoss"
|
const val PREFERENCES_KEY_TEMP_LOSS = "tempLoss"
|
||||||
|
|
|
@ -189,6 +189,10 @@ object Settings {
|
||||||
true
|
true
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@JvmStatic
|
||||||
|
var showNowPlayingDetails
|
||||||
|
by BooleanSetting(Constants.PREFERENCES_KEY_SHOW_NOW_PLAYING_DETAILS, false)
|
||||||
|
|
||||||
@JvmStatic
|
@JvmStatic
|
||||||
var shouldUseId3Tags
|
var shouldUseId3Tags
|
||||||
by BooleanSetting(Constants.PREFERENCES_KEY_ID3_TAGS, false)
|
by BooleanSetting(Constants.PREFERENCES_KEY_ID3_TAGS, false)
|
||||||
|
|
|
@ -9,6 +9,7 @@
|
||||||
a:layout_marginEnd="12dp" >
|
a:layout_marginEnd="12dp" >
|
||||||
|
|
||||||
<LinearLayout
|
<LinearLayout
|
||||||
|
a:id="@+id/current_playing"
|
||||||
a:layout_width="wrap_content"
|
a:layout_width="wrap_content"
|
||||||
a:layout_height="wrap_content"
|
a:layout_height="wrap_content"
|
||||||
a:layout_alignParentLeft="true"
|
a:layout_alignParentLeft="true"
|
||||||
|
@ -19,9 +20,9 @@
|
||||||
a:layout_width="wrap_content"
|
a:layout_width="wrap_content"
|
||||||
a:layout_height="wrap_content"
|
a:layout_height="wrap_content"
|
||||||
a:layout_marginEnd="10dip"
|
a:layout_marginEnd="10dip"
|
||||||
a:paddingRight="30dip"
|
|
||||||
a:ellipsize="marquee"
|
a:ellipsize="marquee"
|
||||||
a:gravity="left"
|
a:gravity="left"
|
||||||
|
a:paddingRight="30dip"
|
||||||
a:singleLine="true"
|
a:singleLine="true"
|
||||||
a:textAppearance="?android:attr/textAppearanceLarge"
|
a:textAppearance="?android:attr/textAppearanceLarge"
|
||||||
a:textStyle="bold"
|
a:textStyle="bold"
|
||||||
|
@ -78,5 +79,15 @@
|
||||||
|
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
a:id="@+id/current_playing_details"
|
||||||
|
a:layout_width="fill_parent"
|
||||||
|
a:layout_height="wrap_content"
|
||||||
|
a:layout_below="@id/current_playing"
|
||||||
|
a:ellipsize="start"
|
||||||
|
a:gravity="center_horizontal"
|
||||||
|
a:singleLine="true"
|
||||||
|
a:textAppearance="?android:attr/textAppearanceSmall"
|
||||||
|
tools:text="Details" />
|
||||||
|
|
||||||
</RelativeLayout>
|
</RelativeLayout>
|
|
@ -323,6 +323,8 @@
|
||||||
<string name="settings.summary.enable_ldap_users_support">This forces the app to always send the password unencrypted. Useful if the Subsonic server does not support the new authentication API for the users.</string>
|
<string name="settings.summary.enable_ldap_users_support">This forces the app to always send the password unencrypted. Useful if the Subsonic server does not support the new authentication API for the users.</string>
|
||||||
<string name="settings.use_folder_for_album_artist">Use Folders For Artist Name</string>
|
<string name="settings.use_folder_for_album_artist">Use Folders For Artist Name</string>
|
||||||
<string name="settings.use_folder_for_album_artist_summary">Assume top-level folder is the name of the album artist</string>
|
<string name="settings.use_folder_for_album_artist_summary">Assume top-level folder is the name of the album artist</string>
|
||||||
|
<string name="settings.show_now_playing_details_summary">Show more song details in Now Playing (genre, year, bitrate)</string>
|
||||||
|
<string name="settings.show_now_playing_details">Show details in Now Playing</string>
|
||||||
<string name="settings.use_id3">Browse Using ID3 Tags</string>
|
<string name="settings.use_id3">Browse Using ID3 Tags</string>
|
||||||
<string name="settings.use_id3_summary">Use ID3 tag methods instead of file system based methods</string>
|
<string name="settings.use_id3_summary">Use ID3 tag methods instead of file system based methods</string>
|
||||||
<string name="settings.show_artist_picture">Show artist picture in artist list</string>
|
<string name="settings.show_artist_picture">Show artist picture in artist list</string>
|
||||||
|
@ -332,6 +334,7 @@
|
||||||
<string name="settings.wifi_required_title">Download on Wi-Fi only</string>
|
<string name="settings.wifi_required_title">Download on Wi-Fi only</string>
|
||||||
<string name="song_details.all">%1$s%2$s</string>
|
<string name="song_details.all">%1$s%2$s</string>
|
||||||
<string name="song_details.kbps">%d kbps</string>
|
<string name="song_details.kbps">%d kbps</string>
|
||||||
|
<string name="song_details.nowplaying">%1$s  •  %2$d  •  %3$d kbps %4$s</string>
|
||||||
<string name="util.bytes_format.byte">0 B</string>
|
<string name="util.bytes_format.byte">0 B</string>
|
||||||
<string name="util.bytes_format.gigabyte">0.00 GB</string>
|
<string name="util.bytes_format.gigabyte">0.00 GB</string>
|
||||||
<string name="util.bytes_format.kilobyte">0 KB</string>
|
<string name="util.bytes_format.kilobyte">0 KB</string>
|
||||||
|
@ -468,7 +471,6 @@
|
||||||
<!-- Subsonic features -->
|
<!-- Subsonic features -->
|
||||||
<string name="settings.features_title">Features</string>
|
<string name="settings.features_title">Features</string>
|
||||||
<string name="settings.five_star_rating_title">Use five star rating for songs</string>
|
<string name="settings.five_star_rating_title">Use five star rating for songs</string>
|
||||||
<string name="settings.five_star_rating_description">Use five star rating system for songs instead of simply starring/unstarring items.
|
<string name="settings.five_star_rating_description">Use five star rating system for songs instead of simply starring/unstarring items.</string>
|
||||||
</string>
|
|
||||||
|
|
||||||
</resources>
|
</resources>
|
||||||
|
|
|
@ -53,6 +53,12 @@
|
||||||
a:title="@string/settings.playback_control_title"
|
a:title="@string/settings.playback_control_title"
|
||||||
a:key="playbackControlSettings"
|
a:key="playbackControlSettings"
|
||||||
app:iconSpaceReserved="false">
|
app:iconSpaceReserved="false">
|
||||||
|
<CheckBoxPreference
|
||||||
|
a:defaultValue="false"
|
||||||
|
a:key="showNowPlayingDetails"
|
||||||
|
a:summary="@string/settings.show_now_playing_details_summary"
|
||||||
|
a:title="@string/settings.show_now_playing_details"
|
||||||
|
app:iconSpaceReserved="false"/>
|
||||||
<CheckBoxPreference
|
<CheckBoxPreference
|
||||||
a:defaultValue="true"
|
a:defaultValue="true"
|
||||||
a:key="useId3Tags"
|
a:key="useId3Tags"
|
||||||
|
|
Loading…
Reference in New Issue