diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index fa541152..39edabbe 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -1,5 +1,5 @@
default:
- image: registry.gitlab.com/ultrasonic/ci-android:1.1.0
+ image: registry.gitlab.com/ultrasonic/ci-android:1.2.0
cache: &global_cache
key:
files:
diff --git a/.idea/compiler.xml b/.idea/compiler.xml
index b589d56e..b86273d9 100644
--- a/.idea/compiler.xml
+++ b/.idea/compiler.xml
@@ -1,6 +1,6 @@
-
+
\ No newline at end of file
diff --git a/build.gradle b/build.gradle
index 1797e96b..ebc6fa8b 100644
--- a/build.gradle
+++ b/build.gradle
@@ -43,7 +43,7 @@ allprojects {
// Set Kotlin JVM target to the same for all subprojects
tasks.withType(KotlinCompile).configureEach {
kotlinOptions {
- jvmTarget = "17"
+ jvmTarget = "21"
}
}
diff --git a/core/domain/build.gradle b/core/domain/build.gradle
index 069c9605..75b14dc5 100644
--- a/core/domain/build.gradle
+++ b/core/domain/build.gradle
@@ -13,4 +13,8 @@ dependencies {
android {
namespace 'org.moire.ultrasonic.subsonic.domain'
+ compileOptions {
+ sourceCompatibility JavaVersion.VERSION_21
+ targetCompatibility JavaVersion.VERSION_21
+ }
}
diff --git a/core/subsonic-api/build.gradle b/core/subsonic-api/build.gradle
index 034da1e2..47428b10 100644
--- a/core/subsonic-api/build.gradle
+++ b/core/subsonic-api/build.gradle
@@ -4,6 +4,11 @@ plugins {
apply from: bootstrap.kotlinModule
+java {
+ sourceCompatibility = JavaVersion.VERSION_21
+ targetCompatibility = JavaVersion.VERSION_21
+}
+
dependencies {
api libs.retrofit
api libs.jacksonConverter
diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml
index 2e9701fc..b4794985 100644
--- a/gradle/libs.versions.toml
+++ b/gradle/libs.versions.toml
@@ -1,27 +1,27 @@
[versions]
# You need to run ./gradlew wrapper after updating the version
-gradle = "8.1.1"
+gradle = "8.11.1"
-navigation = "2.7.5"
-gradlePlugin = "8.2.0"
-androidxcar = "1.2.0"
-androidxcore = "1.12.0"
+navigation = "2.8.9"
+gradlePlugin = "8.9.1"
+androidxcar = "1.4.0"
+androidxcore = "1.15.0"
ktlint = "1.0.1"
ktlintGradle = "12.0.2"
detekt = "1.23.4"
preferences = "1.2.1"
-media3 = "1.2.0"
+media3 = "1.6.0"
-androidSupport = "1.7.0"
-materialDesign = "1.10.0"
-constraintLayout = "2.1.4"
-activity = "1.8.1"
+androidSupport = "1.9.1"
+materialDesign = "1.12.0"
+constraintLayout = "2.2.1"
+activity = "1.10.1"
multidex = "2.0.1"
room = "2.6.1"
-kotlin = "1.9.21"
-ksp = "1.9.21-1.0.15"
+kotlin = "2.1.20"
+ksp = "2.1.20-1.0.32"
kotlinxCoroutines = "1.7.3"
-viewModelKtx = "2.6.2"
+viewModelKtx = "2.8.7"
swipeRefresh = "1.1.0"
retrofit = "2.9.0"
diff --git a/gradle/versions.gradle b/gradle/versions.gradle
index 3b8d8617..799d9bc9 100644
--- a/gradle/versions.gradle
+++ b/gradle/versions.gradle
@@ -1,5 +1,5 @@
ext.versions = [
minSdk : 21,
targetSdk : 33,
- compileSdk : 34,
+ compileSdk : 35,
]
diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties
index e6aba251..c1d5e018 100644
--- a/gradle/wrapper/gradle-wrapper.properties
+++ b/gradle/wrapper/gradle-wrapper.properties
@@ -1,6 +1,6 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-8.5-all.zip
+distributionUrl=https\://services.gradle.org/distributions/gradle-8.11.1-all.zip
networkTimeout=10000
validateDistributionUrl=true
zipStoreBase=GRADLE_USER_HOME
diff --git a/ultrasonic/build.gradle b/ultrasonic/build.gradle
index 15f1f6d7..a92a3928 100644
--- a/ultrasonic/build.gradle
+++ b/ultrasonic/build.gradle
@@ -53,7 +53,7 @@ android {
}
kotlinOptions {
- jvmTarget = "17"
+ jvmTarget = "21"
}
buildFeatures {
@@ -63,8 +63,8 @@ android {
}
compileOptions {
- sourceCompatibility JavaVersion.VERSION_17
- targetCompatibility JavaVersion.VERSION_17
+ sourceCompatibility JavaVersion.VERSION_21
+ targetCompatibility JavaVersion.VERSION_21
}
ksp {
diff --git a/ultrasonic/src/main/kotlin/org/moire/ultrasonic/adapters/AlbumRowDelegate.kt b/ultrasonic/src/main/kotlin/org/moire/ultrasonic/adapters/AlbumRowDelegate.kt
index e7d79cbb..5e3154e4 100644
--- a/ultrasonic/src/main/kotlin/org/moire/ultrasonic/adapters/AlbumRowDelegate.kt
+++ b/ultrasonic/src/main/kotlin/org/moire/ultrasonic/adapters/AlbumRowDelegate.kt
@@ -35,8 +35,8 @@ open class AlbumRowDelegate(
open val onContextMenuClick: (MenuItem, Album) -> Boolean
) : ItemViewDelegate(), KoinComponent {
- private val starDrawable: Int = R.drawable.ic_star_full
- private val starHollowDrawable: Int = R.drawable.ic_star_hollow
+ private val starDrawable: Int = R.drawable.rating_star_full
+ private val starHollowDrawable: Int = R.drawable.rating_star_hollow
open var layoutType = LayoutType.LIST
diff --git a/ultrasonic/src/main/kotlin/org/moire/ultrasonic/adapters/TrackViewHolder.kt b/ultrasonic/src/main/kotlin/org/moire/ultrasonic/adapters/TrackViewHolder.kt
index ad415dce..436f8d23 100644
--- a/ultrasonic/src/main/kotlin/org/moire/ultrasonic/adapters/TrackViewHolder.kt
+++ b/ultrasonic/src/main/kotlin/org/moire/ultrasonic/adapters/TrackViewHolder.kt
@@ -1,13 +1,18 @@
package org.moire.ultrasonic.adapters
import android.graphics.Color
+import android.graphics.drawable.LayerDrawable
+import android.os.Build
+import android.view.MenuInflater
import android.view.View
import android.widget.Checkable
import android.widget.CheckedTextView
import android.widget.ImageView
import android.widget.LinearLayout
+import android.widget.PopupMenu
import android.widget.TextView
import androidx.core.content.ContextCompat
+import androidx.core.content.res.ResourcesCompat
import androidx.core.view.isGone
import androidx.core.view.isVisible
import androidx.lifecycle.MutableLiveData
@@ -31,6 +36,7 @@ import org.moire.ultrasonic.service.RxBus
import org.moire.ultrasonic.service.plusAssign
import org.moire.ultrasonic.util.Settings
import org.moire.ultrasonic.util.Util
+import org.moire.ultrasonic.util.Util.themeColor
const val INDICATOR_THICKNESS_INDEFINITE = 5
const val INDICATOR_THICKNESS_DEFINITE = 10
@@ -50,17 +56,12 @@ class TrackViewHolder(val view: View) :
var entry: Track? = null
private set
- var songLayout: LinearLayout = view.findViewById(R.id.song_layout)
+ private var songLayout: LinearLayout = view.findViewById(R.id.song_layout)
+
var check: CheckedTextView = view.findViewById(R.id.song_check)
var drag: ImageView = view.findViewById(R.id.song_drag)
var observableChecked = MutableLiveData(false)
- private var rating: LinearLayout = view.findViewById(R.id.song_rating)
- private var fiveStar1: ImageView = view.findViewById(R.id.song_five_star_1)
- private var fiveStar2: ImageView = view.findViewById(R.id.song_five_star_2)
- private var fiveStar3: ImageView = view.findViewById(R.id.song_five_star_3)
- private var fiveStar4: ImageView = view.findViewById(R.id.song_five_star_4)
- private var fiveStar5: ImageView = view.findViewById(R.id.song_five_star_5)
private var star: ImageView = view.findViewById(R.id.song_star)
private var track: TextView = view.findViewById(R.id.song_track)
private var title: TextView = view.findViewById(R.id.song_title)
@@ -80,7 +81,6 @@ class TrackViewHolder(val view: View) :
@Suppress("ComplexMethod")
fun setSong(song: Track, checkable: Boolean, draggable: Boolean, isSelected: Boolean = false) {
- val useFiveStarRating = Settings.useFiveStarRating
entry = song
val entryDescription = Util.readableEntryDescription(song)
@@ -103,7 +103,7 @@ class TrackViewHolder(val view: View) :
if (ActiveServerProvider.isOffline()) {
star.isGone = true
} else {
- setupStarButtons(song, useFiveStarRating)
+ setupRating(song)
}
// Instead of blocking the UI thread while looking up the current state,
@@ -115,11 +115,7 @@ class TrackViewHolder(val view: View) :
)
}
- if (useFiveStarRating) {
- updateFiveStars(entry?.userRating ?: 0)
- } else {
- updateSingleStar(entry!!.starred)
- }
+ updateRatingDisplay(entry!!.userRating, entry!!.starred)
if (song.isVideo) {
artist.isGone = true
@@ -144,9 +140,9 @@ class TrackViewHolder(val view: View) :
if (it.id != song.id) return@launch
if (it.rating is HeartRating) {
- updateSingleStar(it.rating.isHeart)
+ updateRatingDisplay(song.userRating, it.rating.isHeart)
} else if (it.rating is StarRating) {
- updateFiveStars(it.rating.starRating.toInt())
+ updateRatingDisplay(it.rating.starRating.toInt(), song.starred)
}
}
}
@@ -187,55 +183,88 @@ class TrackViewHolder(val view: View) :
}
}
- private fun setupStarButtons(track: Track, useFiveStarRating: Boolean) {
- if (useFiveStarRating) {
- // Hide single star
- star.isGone = true
- rating.isVisible = true
- val rating = if (track.userRating == null) 0 else track.userRating!!
- updateFiveStars(rating)
+ private fun setupRating(track: Track) {
+ star.isVisible = true
+ updateRatingDisplay(track.userRating, track.starred)
- // Five star rating has no click handler because in the
- // track view theres not enough space
- } else {
- star.isVisible = true
- rating.isGone = true
- updateSingleStar(track.starred)
- star.setOnClickListener {
- track.starred = !track.starred
- updateSingleStar(track.starred)
- RxBus.ratingSubmitter.onNext(
- RatingUpdate(track.id, HeartRating(track.starred))
- )
- }
- }
+ star.setOnClickListener { toggleHeart(track) }
+ star.setOnLongClickListener { view -> showRatingPopup(view, track) }
+ }
+
+ private fun toggleHeart(track: Track) {
+ track.starred = !track.starred
+ updateRatingDisplay(track.userRating, track.starred)
+ RxBus.ratingSubmitter.onNext(
+ RatingUpdate(track.id, HeartRating(track.starred))
+ )
}
@Suppress("MagicNumber")
- private fun updateFiveStars(rating: Int) {
- fiveStar1.setImageResource(
- if (rating > 0) R.drawable.ic_star_full else R.drawable.ic_star_hollow
- )
- fiveStar2.setImageResource(
- if (rating > 1) R.drawable.ic_star_full else R.drawable.ic_star_hollow
- )
- fiveStar3.setImageResource(
- if (rating > 2) R.drawable.ic_star_full else R.drawable.ic_star_hollow
- )
- fiveStar4.setImageResource(
- if (rating > 3) R.drawable.ic_star_full else R.drawable.ic_star_hollow
- )
- fiveStar5.setImageResource(
- if (rating > 4) R.drawable.ic_star_full else R.drawable.ic_star_hollow
- )
+ private fun showRatingPopup(view: View, track: Track): Boolean {
+ val popup = PopupMenu(view.context, view)
+ val inflater: MenuInflater = popup.menuInflater
+ inflater.inflate(R.menu.rating, popup.menu)
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) popup.setForceShowIcon(true)
+
+ popup.setOnMenuItemClickListener {
+ val rating = when (it.itemId) {
+ R.id.popup_rate_1 -> 1
+ R.id.popup_rate_2 -> 2
+ R.id.popup_rate_3 -> 3
+ R.id.popup_rate_4 -> 4
+ R.id.popup_rate_5 -> 5
+ else -> 0
+ }
+ track.userRating = rating
+ updateRatingDisplay(track.userRating, track.starred)
+ RxBus.ratingSubmitter.onNext(
+ RatingUpdate(track.id, StarRating(5, rating.toFloat()))
+ )
+ true
+ }
+ popup.show()
+ return true
}
- private fun updateSingleStar(starred: Boolean) {
- if (starred) {
- star.setImageResource(R.drawable.ic_star_full)
- } else {
- star.setImageResource(R.drawable.ic_star_hollow)
+ @Suppress("MagicNumber")
+ private fun updateRatingDisplay(rating: Int?, starred: Boolean) {
+ val ratingDrawable = when (rating) {
+ 1 -> R.drawable.rating_star_1
+ 2 -> R.drawable.rating_star_2
+ 3 -> R.drawable.rating_star_3
+ 4 -> R.drawable.rating_star_4
+ 5 -> R.drawable.rating_star_5
+ else -> {
+ R.drawable.rating_star_0
+ }
}
+
+ val layers = if (starred) {
+ arrayOf(
+ ResourcesCompat.getDrawable(view.resources, ratingDrawable, null)!!,
+ ResourcesCompat.getDrawable(
+ view.resources,
+ R.drawable.rating_heart_mini_overlay,
+ null
+ )!!
+ )
+ } else {
+ arrayOf(
+ ResourcesCompat.getDrawable(view.resources, ratingDrawable, null)!!
+ )
+ }
+
+ val ratingDisplay = LayerDrawable(layers)
+ ratingDisplay.getDrawable(0).setTint(
+ view.context.themeColor(com.google.android.material.R.attr.colorOnBackground)
+ )
+ if (starred) {
+ ratingDisplay.getDrawable(1).setTint(
+ view.context.themeColor(com.google.android.material.R.attr.colorTertiary)
+ )
+ }
+
+ star.setImageDrawable(ratingDisplay)
}
private fun updateStatus(status: DownloadState, progress: Int?) {
diff --git a/ultrasonic/src/main/kotlin/org/moire/ultrasonic/fragment/AboutFragment.kt b/ultrasonic/src/main/kotlin/org/moire/ultrasonic/fragment/AboutFragment.kt
index d35d8526..ad8003b9 100644
--- a/ultrasonic/src/main/kotlin/org/moire/ultrasonic/fragment/AboutFragment.kt
+++ b/ultrasonic/src/main/kotlin/org/moire/ultrasonic/fragment/AboutFragment.kt
@@ -8,13 +8,13 @@
package org.moire.ultrasonic.fragment
import android.content.Intent
-import android.net.Uri
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.Button
import android.widget.TextView
+import androidx.core.net.toUri
import androidx.fragment.app.Fragment
import java.util.Locale
import org.moire.ultrasonic.R
@@ -60,13 +60,13 @@ class AboutFragment : Fragment() {
webPageButton?.setOnClickListener {
startActivity(
- Intent(Intent.ACTION_VIEW, Uri.parse(getString(R.string.about_webpage_url)))
+ Intent(Intent.ACTION_VIEW, getString(R.string.about_webpage_url).toUri())
)
}
reportBugButton?.setOnClickListener {
startActivity(
- Intent(Intent.ACTION_VIEW, Uri.parse(getString(R.string.about_report_url)))
+ Intent(Intent.ACTION_VIEW, getString(R.string.about_report_url).toUri())
)
}
}
diff --git a/ultrasonic/src/main/kotlin/org/moire/ultrasonic/fragment/PlayerFragment.kt b/ultrasonic/src/main/kotlin/org/moire/ultrasonic/fragment/PlayerFragment.kt
index 03bd5e9a..61e77030 100644
--- a/ultrasonic/src/main/kotlin/org/moire/ultrasonic/fragment/PlayerFragment.kt
+++ b/ultrasonic/src/main/kotlin/org/moire/ultrasonic/fragment/PlayerFragment.kt
@@ -8,7 +8,6 @@
package org.moire.ultrasonic.fragment
import android.annotation.SuppressLint
-import android.content.Context
import android.graphics.Canvas
import android.graphics.Color.argb
import android.graphics.Point
@@ -18,7 +17,6 @@ import android.os.Build
import android.os.Bundle
import android.os.Handler
import android.os.Looper
-import android.util.TypedValue
import android.view.GestureDetector
import android.view.LayoutInflater
import android.view.Menu
@@ -31,15 +29,12 @@ import android.view.WindowManager
import android.view.animation.AnimationUtils
import android.widget.EditText
import android.widget.ImageView
-import android.widget.LinearLayout
import android.widget.PopupMenu
import android.widget.SeekBar
import android.widget.SeekBar.OnSeekBarChangeListener
import android.widget.TextView
import android.widget.Toast
import android.widget.ViewFlipper
-import androidx.annotation.AttrRes
-import androidx.annotation.ColorInt
import androidx.constraintlayout.widget.ConstraintLayout
import androidx.core.content.res.ResourcesCompat
import androidx.core.view.MenuHost
@@ -105,6 +100,7 @@ import org.moire.ultrasonic.util.CommunicationError
import org.moire.ultrasonic.util.ConfirmationDialog
import org.moire.ultrasonic.util.Settings
import org.moire.ultrasonic.util.Util
+import org.moire.ultrasonic.util.Util.themeColor
import org.moire.ultrasonic.util.Util.toast
import org.moire.ultrasonic.util.toTrack
import org.moire.ultrasonic.view.AutoRepeatButton
@@ -125,7 +121,6 @@ class PlayerFragment :
private var swipeDistance = 0
private var swipeVelocity = 0
private var jukeboxAvailable = false
- private var useFiveStarRating = false
private var isEqualizerAvailable = false
// Detectors & Callbacks
@@ -151,6 +146,7 @@ class PlayerFragment :
private lateinit var fiveStar3ImageView: ImageView
private lateinit var fiveStar4ImageView: ImageView
private lateinit var fiveStar5ImageView: ImageView
+ private lateinit var heartRatingImageView: ImageView
private lateinit var playlistFlipper: ViewFlipper
private lateinit var emptyTextView: TextView
private lateinit var emptyView: ConstraintLayout
@@ -174,10 +170,15 @@ class PlayerFragment :
private lateinit var repeatButton: MaterialButton
private lateinit var progressBar: SeekBar
private lateinit var progressIndicator: CircularProgressIndicator
- private val hollowStar = R.drawable.star_hollow_outline
- private val fullStar = R.drawable.star_full_outline
+
+ private val hollowStar = R.drawable.rating_star_hollow_layered
+ private val fullStar = R.drawable.rating_star_full_layered
+ private val hollowHeart = R.drawable.rating_heart_hollow_layered
+ private val fullHeart = R.drawable.rating_heart_full_layered
private lateinit var hollowStarDrawable: Drawable
private lateinit var fullStarDrawable: Drawable
+ private lateinit var hollowHeartDrawable: Drawable
+ private lateinit var fullHeartDrawable: Drawable
private var _binding: CurrentPlayingBinding? = null
@@ -233,6 +234,7 @@ class PlayerFragment :
fiveStar3ImageView = view.findViewById(R.id.song_five_star_3)
fiveStar4ImageView = view.findViewById(R.id.song_five_star_4)
fiveStar5ImageView = view.findViewById(R.id.song_five_star_5)
+ heartRatingImageView = view.findViewById(R.id.song_rating_heart)
}
@Suppress("LongMethod")
@@ -265,7 +267,6 @@ class PlayerFragment :
Lifecycle.State.RESUMED
)
- useFiveStarRating = Settings.useFiveStarRating
swipeDistance = (width + height) * PERCENTAGE_OF_SCREEN_FOR_SWIPE / 100
swipeVelocity = swipeDistance
gestureScanner = GestureDetector(context, this)
@@ -277,19 +278,26 @@ class PlayerFragment :
updateShuffleButtonState(mediaPlayerManager.isShufflePlayEnabled)
updateRepeatButtonState(mediaPlayerManager.repeatMode)
- val ratingLinearLayout = view.findViewById(R.id.song_rating)
- if (!useFiveStarRating) ratingLinearLayout.isVisible = false
-
hollowStarDrawable = ResourcesCompat.getDrawable(resources, hollowStar, null)!!
fullStarDrawable = ResourcesCompat.getDrawable(resources, fullStar, null)!!
setLayerDrawableColors(hollowStarDrawable as LayerDrawable)
setLayerDrawableColors(fullStarDrawable as LayerDrawable)
+ hollowHeartDrawable = ResourcesCompat.getDrawable(resources, hollowHeart, null)!!
+ fullHeartDrawable = ResourcesCompat.getDrawable(resources, fullHeart, null)!!
+ setLayerDrawableColors(hollowHeartDrawable as LayerDrawable)
+ setLayerDrawableColors(
+ fullHeartDrawable as LayerDrawable,
+ RM.attr.colorAccent,
+ RM.attr.colorSurface
+ )
+
fiveStar1ImageView.setOnClickListener { setSongRating(1) }
fiveStar2ImageView.setOnClickListener { setSongRating(2) }
fiveStar3ImageView.setOnClickListener { setSongRating(3) }
fiveStar4ImageView.setOnClickListener { setSongRating(4) }
fiveStar5ImageView.setOnClickListener { setSongRating(5) }
+ heartRatingImageView.setOnClickListener { setSongHeartRating() }
albumArtImageView.setOnTouchListener { _, me ->
gestureScanner.onTouchEvent(me)
@@ -409,6 +417,21 @@ class PlayerFragment :
updateButtonStates(it.state)
}
+ rxBusSubscription += RxBus.ratingPublishedObservable.subscribe { update ->
+
+ // Ignore updates which are not for the current song
+ if (update.id != currentSong?.id) return@subscribe
+ // Ensure UI thread
+ launch {
+ if (update.success == false) {
+ Toast.makeText(context, "Setting rating failed", Toast.LENGTH_SHORT)
+ .show()
+ } else {
+ updateSongRatingDisplay()
+ }
+ }
+ }
+
// Query the Jukebox state in an IO Context
ioScope.launch(CommunicationError.getHandler(context)) {
try {
@@ -537,38 +560,13 @@ class PlayerFragment :
val equalizerMenuItem = menu.findItem(R.id.menu_item_equalizer)
val shareMenuItem = menu.findItem(R.id.menu_item_share)
val shareSongMenuItem = menu.findItem(R.id.menu_item_share_song)
- val starMenuItem = menu.findItem(R.id.menu_item_star)
val bookmarkMenuItem = menu.findItem(R.id.menu_item_bookmark_set)
val bookmarkRemoveMenuItem = menu.findItem(R.id.menu_item_bookmark_delete)
- // Listen to rating changes and update the UI
- rxBusSubscription += RxBus.ratingPublishedObservable.subscribe { update ->
-
- // Ignore updates which are not for the current song
- if (update.id != currentSong?.id) return@subscribe
-
- // Ensure UI thread
- launch {
- if (update.success == true && update.rating is HeartRating) {
- if (update.rating.isHeart) {
- starMenuItem.setIcon(fullStar)
- starMenuItem.setTitle(R.string.download_menu_unstar)
- } else {
- starMenuItem.setIcon(hollowStar)
- starMenuItem.setTitle(R.string.download_menu_star)
- }
- } else if (update.success == false) {
- Toast.makeText(context, "Setting rating failed", Toast.LENGTH_SHORT)
- .show()
- }
- }
- }
-
if (isOffline()) {
if (shareMenuItem != null) {
shareMenuItem.isVisible = false
}
- starMenuItem.isVisible = false
if (bookmarkMenuItem != null) {
bookmarkMenuItem.isVisible = false
}
@@ -587,15 +585,11 @@ class PlayerFragment :
currentSong = track
}
- if (useFiveStarRating) starMenuItem.isVisible = false
-
if (currentSong != null) {
- starMenuItem.setIcon(if (currentSong!!.starred) fullStar else hollowStar)
shareSongMenuItem.isVisible = true
goToAlbum.isVisible = true
goToArtist.isVisible = true
} else {
- starMenuItem.setIcon(hollowStar)
shareSongMenuItem.isVisible = false
goToAlbum.isVisible = false
goToArtist.isVisible = false
@@ -731,16 +725,6 @@ class PlayerFragment :
}
return true
}
- R.id.menu_item_star -> {
- if (track == null) return true
- track.starred = !track.starred
-
- RxBus.ratingSubmitter.onNext(
- RatingUpdate(track.id, HeartRating(track.starred))
- )
-
- return true
- }
R.id.menu_item_bookmark_set -> {
if (track == null) return true
@@ -1288,30 +1272,36 @@ class PlayerFragment :
private fun updateSongRatingDisplay() {
val rating = currentSong?.userRating ?: 0
+ val isHeartSet = currentSong?.starred ?: false
fiveStar1ImageView.setImageDrawable(getStarForRating(rating, 0))
fiveStar2ImageView.setImageDrawable(getStarForRating(rating, 1))
fiveStar3ImageView.setImageDrawable(getStarForRating(rating, 2))
fiveStar4ImageView.setImageDrawable(getStarForRating(rating, 3))
fiveStar5ImageView.setImageDrawable(getStarForRating(rating, 4))
+
+ if (isHeartSet) {
+ heartRatingImageView.setImageDrawable(fullHeartDrawable)
+ } else {
+ heartRatingImageView.setImageDrawable(hollowHeartDrawable)
+ }
}
private fun getStarForRating(rating: Int, position: Int): Drawable {
return if (rating > position) fullStarDrawable else hollowStarDrawable
}
- private fun setLayerDrawableColors(drawable: LayerDrawable) {
+ private fun setLayerDrawableColors(
+ drawable: LayerDrawable,
+ innerColor: Int = RM.attr.colorSurface,
+ borderColor: Int = RM.attr.colorAccent
+ ) {
drawable.apply {
- getDrawable(0).setTint(requireContext().themeColor(RM.attr.colorSurface))
- getDrawable(1).setTint(requireContext().themeColor(RM.attr.colorAccent))
+ getDrawable(0).setTint(requireContext().themeColor(innerColor))
+ getDrawable(1).setTint(requireContext().themeColor(borderColor))
}
}
- @ColorInt
- fun Context.themeColor(@AttrRes attrRes: Int): Int = TypedValue()
- .apply { theme.resolveAttribute(attrRes, this, true) }
- .data
-
private fun setSongRating(rating: Int) {
if (currentSong == null) return
currentSong?.userRating = rating
@@ -1325,6 +1315,19 @@ class PlayerFragment :
)
}
+ private fun setSongHeartRating() {
+ if (currentSong == null) return
+ currentSong?.starred = !(currentSong?.starred ?: true)
+ updateSongRatingDisplay()
+
+ RxBus.ratingSubmitter.onNext(
+ RatingUpdate(
+ currentSong!!.id,
+ HeartRating(currentSong?.starred ?: false)
+ )
+ )
+ }
+
@SuppressLint("InflateParams")
private fun showSavePlaylistDialog() {
val layout = LayoutInflater.from(this.context)
diff --git a/ultrasonic/src/main/kotlin/org/moire/ultrasonic/fragment/SettingsFragment.kt b/ultrasonic/src/main/kotlin/org/moire/ultrasonic/fragment/SettingsFragment.kt
index 2c574512..d3cccb8b 100644
--- a/ultrasonic/src/main/kotlin/org/moire/ultrasonic/fragment/SettingsFragment.kt
+++ b/ultrasonic/src/main/kotlin/org/moire/ultrasonic/fragment/SettingsFragment.kt
@@ -11,11 +11,11 @@ import android.content.DialogInterface
import android.content.Intent
import android.content.SharedPreferences
import android.content.SharedPreferences.OnSharedPreferenceChangeListener
-import android.net.Uri
import android.os.Bundle
import android.provider.SearchRecentSuggestions
import android.view.View
import androidx.annotation.StringRes
+import androidx.core.net.toUri
import androidx.preference.CheckBoxPreference
import androidx.preference.EditTextPreference
import androidx.preference.ListPreference
@@ -194,7 +194,7 @@ class SettingsFragment :
}
cacheLocation?.isVisible = true
- val uri = Uri.parse(Settings.cacheLocationUri)
+ val uri = Settings.cacheLocationUri.toUri()
cacheLocation!!.summary = uri.path
cacheLocation!!.onPreferenceClickListener = Preference.OnPreferenceClickListener {
selectCacheLocation()
@@ -342,7 +342,7 @@ class SettingsFragment :
private fun setCacheLocation(path: String) {
if (path != "") {
- val uri = Uri.parse(path)
+ val uri = path.toUri()
cacheLocation!!.summary = uri.path ?: ""
}
diff --git a/ultrasonic/src/main/kotlin/org/moire/ultrasonic/imageloader/ArtworkBitmapLoader.kt b/ultrasonic/src/main/kotlin/org/moire/ultrasonic/imageloader/ArtworkBitmapLoader.kt
index c0e4c16c..a264e2af 100644
--- a/ultrasonic/src/main/kotlin/org/moire/ultrasonic/imageloader/ArtworkBitmapLoader.kt
+++ b/ultrasonic/src/main/kotlin/org/moire/ultrasonic/imageloader/ArtworkBitmapLoader.kt
@@ -32,6 +32,11 @@ class ArtworkBitmapLoader : BitmapLoader, KoinComponent {
)
}
+ override fun supportsMimeType(mimeType: String): Boolean {
+ // TODO: Implement?
+ return true
+ }
+
override fun decodeBitmap(data: ByteArray): ListenableFuture {
return executorService.submit {
decode(
@@ -46,10 +51,6 @@ class ArtworkBitmapLoader : BitmapLoader, KoinComponent {
}
}
- override fun loadBitmap(uri: Uri, options: BitmapFactory.Options?): ListenableFuture {
- return loadBitmap(uri)
- }
-
private fun decode(data: ByteArray): Bitmap {
val bitmap = BitmapFactory.decodeByteArray(data, 0, data.size)
return bitmap ?: throw IllegalArgumentException("Could not decode bitmap")
diff --git a/ultrasonic/src/main/kotlin/org/moire/ultrasonic/service/JukeboxUnimplementedFunctions.kt b/ultrasonic/src/main/kotlin/org/moire/ultrasonic/service/JukeboxUnimplementedFunctions.kt
index 95dcc4cb..9c2b9fc7 100644
--- a/ultrasonic/src/main/kotlin/org/moire/ultrasonic/service/JukeboxUnimplementedFunctions.kt
+++ b/ultrasonic/src/main/kotlin/org/moire/ultrasonic/service/JukeboxUnimplementedFunctions.kt
@@ -96,25 +96,10 @@ abstract class JukeboxUnimplementedFunctions : Player {
TODO("Not yet implemented")
}
- @Deprecated("Deprecated in Java")
- override fun hasPrevious(): Boolean {
- TODO("Not yet implemented")
- }
-
- @Deprecated("Deprecated in Java")
- override fun hasPreviousWindow(): Boolean {
- TODO("Not yet implemented")
- }
-
override fun hasPreviousMediaItem(): Boolean {
TODO("Not yet implemented")
}
- @Deprecated("Deprecated in Java")
- override fun previous() {
- TODO("Not yet implemented")
- }
-
@Deprecated("Deprecated in Java")
override fun seekToPreviousWindow() {
TODO("Not yet implemented")
diff --git a/ultrasonic/src/main/kotlin/org/moire/ultrasonic/service/MediaLibrarySessionCallback.kt b/ultrasonic/src/main/kotlin/org/moire/ultrasonic/service/MediaLibrarySessionCallback.kt
index c2011004..fbe2b37c 100644
--- a/ultrasonic/src/main/kotlin/org/moire/ultrasonic/service/MediaLibrarySessionCallback.kt
+++ b/ultrasonic/src/main/kotlin/org/moire/ultrasonic/service/MediaLibrarySessionCallback.kt
@@ -9,6 +9,7 @@ package org.moire.ultrasonic.service
import android.os.Build
import android.os.Bundle
+import androidx.annotation.OptIn
import androidx.car.app.connection.CarConnection
import androidx.media3.common.HeartRating
import androidx.media3.common.MediaItem
@@ -21,11 +22,13 @@ import androidx.media3.common.MediaMetadata.MEDIA_TYPE_PLAYLIST
import androidx.media3.common.Player
import androidx.media3.common.Rating
import androidx.media3.common.StarRating
+import androidx.media3.common.util.UnstableApi
import androidx.media3.session.CommandButton
import androidx.media3.session.LibraryResult
import androidx.media3.session.MediaLibraryService
import androidx.media3.session.MediaSession
import androidx.media3.session.SessionCommand
+import androidx.media3.session.SessionError
import androidx.media3.session.SessionResult
import androidx.media3.session.SessionResult.RESULT_SUCCESS
import com.google.common.collect.ImmutableList
@@ -323,9 +326,9 @@ class MediaLibrarySessionCallback :
)
.setIconResId(
if (willHeart) {
- R.drawable.ic_star_hollow
+ R.drawable.rating_star_hollow
} else {
- R.drawable.ic_star_full
+ R.drawable.rating_star_full
}
)
.setSessionCommand(sessionCommand)
@@ -371,6 +374,7 @@ class MediaLibrarySessionCallback :
.setEnabled(true)
.build()
+ @OptIn(UnstableApi::class)
override fun onGetItem(
session: MediaLibraryService.MediaLibrarySession,
browser: MediaSession.ControllerInfo,
@@ -390,7 +394,7 @@ class MediaLibrarySessionCallback :
)
} else {
Futures.immediateFuture(
- LibraryResult.ofError(LibraryResult.RESULT_ERROR_BAD_VALUE)
+ LibraryResult.ofError(SessionError.ERROR_BAD_VALUE)
)
}
}
diff --git a/ultrasonic/src/main/kotlin/org/moire/ultrasonic/service/MediaPlayerManager.kt b/ultrasonic/src/main/kotlin/org/moire/ultrasonic/service/MediaPlayerManager.kt
index 41c2f817..329538c6 100644
--- a/ultrasonic/src/main/kotlin/org/moire/ultrasonic/service/MediaPlayerManager.kt
+++ b/ultrasonic/src/main/kotlin/org/moire/ultrasonic/service/MediaPlayerManager.kt
@@ -42,7 +42,10 @@ import org.moire.ultrasonic.util.Settings
import org.moire.ultrasonic.util.Util
import org.moire.ultrasonic.util.Util.navigateToCurrent
import org.moire.ultrasonic.util.Util.toast
+import org.moire.ultrasonic.util.getTrackId
import org.moire.ultrasonic.util.launchWithToast
+import org.moire.ultrasonic.util.setRating
+import org.moire.ultrasonic.util.setStarred
import org.moire.ultrasonic.util.toMediaItem
import org.moire.ultrasonic.util.toTrack
import timber.log.Timber
@@ -235,9 +238,15 @@ class MediaPlayerManager(
rxBusSubscription += RxBus.ratingSubmitterObservable.subscribe {
// Ensure correct thread
mainScope.launch {
- // This deals only with the current track!
- if (it.id != currentMediaItem?.toTrack()?.id) return@launch
- setRating(it.rating)
+ val mediaItem =
+ playlist.firstOrNull { item -> item.getTrackId() == it.id } ?: return@launch
+ if (it.rating is HeartRating) {
+ mediaItem.setStarred(it.rating.isHeart)
+ }
+ if (it.rating is StarRating) {
+ mediaItem.setRating(it.rating.starRating.toInt())
+ }
+ mediaItem.toTrack() // Update item in Converter cache
}
}
diff --git a/ultrasonic/src/main/kotlin/org/moire/ultrasonic/service/PlaybackService.kt b/ultrasonic/src/main/kotlin/org/moire/ultrasonic/service/PlaybackService.kt
index c7d28e73..277184a5 100644
--- a/ultrasonic/src/main/kotlin/org/moire/ultrasonic/service/PlaybackService.kt
+++ b/ultrasonic/src/main/kotlin/org/moire/ultrasonic/service/PlaybackService.kt
@@ -323,7 +323,11 @@ class PlaybackService :
player.shuffleModeEnabled,
player.currentMediaItemIndex,
Settings.preloadCount
- ).map { it.toTrack() }
+ ).map {
+ // These items should skip the MediaItemConverter cache.
+ // The cache contains the controller's items, which may be modified (e.g. their rating)
+ it.toTrack(false)
+ }
launch {
DownloadService.download(nextSongs, isHighPriority = true)
diff --git a/ultrasonic/src/main/kotlin/org/moire/ultrasonic/subsonic/ShareHandler.kt b/ultrasonic/src/main/kotlin/org/moire/ultrasonic/subsonic/ShareHandler.kt
index c2478539..52ea6857 100644
--- a/ultrasonic/src/main/kotlin/org/moire/ultrasonic/subsonic/ShareHandler.kt
+++ b/ultrasonic/src/main/kotlin/org/moire/ultrasonic/subsonic/ShareHandler.kt
@@ -254,7 +254,7 @@ class ShareHandler {
val timeSpanAmount: Int = timeSpanPicker!!.timeSpanAmount
Settings.defaultShareExpiration =
if (!noExpirationCheckBox!!.isChecked && timeSpanAmount > 0) {
- String.format("%d:%s", timeSpanAmount, timeSpanType)
+ String.format(Locale.ROOT, "%d:%s", timeSpanAmount, timeSpanType)
} else {
""
}
diff --git a/ultrasonic/src/main/kotlin/org/moire/ultrasonic/subsonic/VideoPlayer.kt b/ultrasonic/src/main/kotlin/org/moire/ultrasonic/subsonic/VideoPlayer.kt
index fa97f749..7f051111 100644
--- a/ultrasonic/src/main/kotlin/org/moire/ultrasonic/subsonic/VideoPlayer.kt
+++ b/ultrasonic/src/main/kotlin/org/moire/ultrasonic/subsonic/VideoPlayer.kt
@@ -2,7 +2,7 @@ package org.moire.ultrasonic.subsonic
import android.content.Context
import android.content.Intent
-import android.net.Uri
+import androidx.core.net.toUri
import org.moire.ultrasonic.R
import org.moire.ultrasonic.domain.Track
import org.moire.ultrasonic.service.MusicServiceFactory
@@ -27,7 +27,7 @@ class VideoPlayer {
format = "raw"
)
intent.setDataAndType(
- Uri.parse(url),
+ url?.toUri(),
"video/*"
)
context.startActivity(intent)
diff --git a/ultrasonic/src/main/kotlin/org/moire/ultrasonic/util/LocaleHelper.kt b/ultrasonic/src/main/kotlin/org/moire/ultrasonic/util/LocaleHelper.kt
index 8c2e55ba..01bb3b74 100644
--- a/ultrasonic/src/main/kotlin/org/moire/ultrasonic/util/LocaleHelper.kt
+++ b/ultrasonic/src/main/kotlin/org/moire/ultrasonic/util/LocaleHelper.kt
@@ -7,11 +7,11 @@
package org.moire.ultrasonic.util
-import android.annotation.TargetApi
import android.content.Context
import android.content.ContextWrapper
import android.content.res.Configuration
import android.os.Build
+import androidx.annotation.RequiresApi
import java.util.Locale
/**
@@ -42,7 +42,7 @@ class LocaleHelper(base: Context?) : ContextWrapper(base) {
config.locale = locale
}
- @TargetApi(Build.VERSION_CODES.N)
+ @RequiresApi(Build.VERSION_CODES.N)
fun setSystemLocale(config: Configuration, locale: Locale?) {
config.setLocale(locale)
}
diff --git a/ultrasonic/src/main/kotlin/org/moire/ultrasonic/util/MediaItemConverter.kt b/ultrasonic/src/main/kotlin/org/moire/ultrasonic/util/MediaItemConverter.kt
index bf03e09e..72e5fd4a 100644
--- a/ultrasonic/src/main/kotlin/org/moire/ultrasonic/util/MediaItemConverter.kt
+++ b/ultrasonic/src/main/kotlin/org/moire/ultrasonic/util/MediaItemConverter.kt
@@ -139,11 +139,36 @@ fun Track.toMediaItem(mediaId: String = id): MediaItem {
return item
}
+/**
+ * Convenience function to get the Track Id of the MediaItem
+ */
+fun MediaItem.getTrackId(): String {
+ return mediaId
+}
+
+/**
+ * Updates the "starred" metadata of the MediaItem
+ */
+fun MediaItem.setStarred(starred: Boolean) {
+ mediaMetadata.extras?.putBoolean("starred", starred)
+ MediaItemConverter.trackCache[mediaId]?.clear()
+ MediaItemConverter.mediaItemCache[mediaId]?.clear()
+}
+
+/**
+ * Updates the "userRating" metadata of the MediaItem
+ */
+fun MediaItem.setRating(rating: Int) {
+ mediaMetadata.extras?.putInt("userRating", rating)
+ MediaItemConverter.trackCache[mediaId]?.clear()
+ MediaItemConverter.mediaItemCache[mediaId]?.clear()
+}
+
/**
* Extension function to convert a MediaItem to a Track, using the cache if possible
*/
-@Suppress("ComplexMethod")
-fun MediaItem.toTrack(): Track {
+@Suppress("ComplexMethod", "LongMethod")
+fun MediaItem.toTrack(cacheResult: Boolean = true): Track {
// Check Cache
val cachedTrack = MediaItemConverter.trackCache[mediaId]?.get()
if (cachedTrack != null) return cachedTrack
@@ -202,9 +227,11 @@ fun MediaItem.toTrack(): Track {
track.starred = (mediaMetadata.userRating as HeartRating).isHeart
}
- // Add MediaItem and Track to the cache
- MediaItemConverter.addToCache(mediaId, track)
- MediaItemConverter.addToCache(mediaId, this)
+ if (cacheResult) {
+ // Add MediaItem and Track to the cache
+ MediaItemConverter.addToCache(mediaId, track)
+ MediaItemConverter.addToCache(mediaId, this)
+ }
return track
}
diff --git a/ultrasonic/src/main/kotlin/org/moire/ultrasonic/util/Settings.kt b/ultrasonic/src/main/kotlin/org/moire/ultrasonic/util/Settings.kt
index c184b916..e82ca05e 100644
--- a/ultrasonic/src/main/kotlin/org/moire/ultrasonic/util/Settings.kt
+++ b/ultrasonic/src/main/kotlin/org/moire/ultrasonic/util/Settings.kt
@@ -246,11 +246,6 @@ object Settings {
@JvmStatic
val overrideLanguage by StringSetting(getKey(R.string.setting_key_override_language), "")
- var useFiveStarRating by BooleanSetting(
- getKey(R.string.setting_key_use_five_star_rating),
- false
- )
-
var useHwOffload by BooleanSetting(getKey(R.string.setting_key_hardware_offload), false)
@JvmStatic
diff --git a/ultrasonic/src/main/kotlin/org/moire/ultrasonic/util/Storage.kt b/ultrasonic/src/main/kotlin/org/moire/ultrasonic/util/Storage.kt
index a777605d..6511b8a9 100644
--- a/ultrasonic/src/main/kotlin/org/moire/ultrasonic/util/Storage.kt
+++ b/ultrasonic/src/main/kotlin/org/moire/ultrasonic/util/Storage.kt
@@ -7,7 +7,7 @@
package org.moire.ultrasonic.util
-import android.net.Uri
+import androidx.core.net.toUri
import androidx.documentfile.provider.DocumentFile
import java.io.File
import org.moire.ultrasonic.R
@@ -107,7 +107,7 @@ object Storage {
if (Settings.cacheLocationUri.isBlank()) return Pair(getDefaultRoot(), true)
val documentFile = DocumentFile.fromTreeUri(
UApp.applicationContext(),
- Uri.parse(Settings.cacheLocationUri)
+ Settings.cacheLocationUri.toUri()
) ?: return Pair(getDefaultRoot(), true)
if (!documentFile.exists()) return Pair(getDefaultRoot(), true)
Pair(
diff --git a/ultrasonic/src/main/kotlin/org/moire/ultrasonic/util/TimeSpanPreferenceDialogFragmentCompat.kt b/ultrasonic/src/main/kotlin/org/moire/ultrasonic/util/TimeSpanPreferenceDialogFragmentCompat.kt
index 1ac4c895..e89d5e71 100644
--- a/ultrasonic/src/main/kotlin/org/moire/ultrasonic/util/TimeSpanPreferenceDialogFragmentCompat.kt
+++ b/ultrasonic/src/main/kotlin/org/moire/ultrasonic/util/TimeSpanPreferenceDialogFragmentCompat.kt
@@ -9,6 +9,7 @@ package org.moire.ultrasonic.util
import android.content.Context
import android.view.View
+import androidx.core.content.edit
import androidx.preference.DialogPreference.TargetFragment
import androidx.preference.Preference
import androidx.preference.PreferenceDialogFragmentCompat
@@ -49,7 +50,7 @@ class TimeSpanPreferenceDialogFragmentCompat : PreferenceDialogFragmentCompat(),
}
}
val preference: Preference = preference
- preference.sharedPreferences!!.edit().putString(preference.key, persisted).apply()
+ preference.sharedPreferences!!.edit { putString(preference.key, persisted) }
}
@Suppress("UNCHECKED_CAST")
diff --git a/ultrasonic/src/main/kotlin/org/moire/ultrasonic/util/Util.kt b/ultrasonic/src/main/kotlin/org/moire/ultrasonic/util/Util.kt
index 68d576e9..227871b3 100644
--- a/ultrasonic/src/main/kotlin/org/moire/ultrasonic/util/Util.kt
+++ b/ultrasonic/src/main/kotlin/org/moire/ultrasonic/util/Util.kt
@@ -30,14 +30,18 @@ import android.os.Build
import android.os.Environment
import android.text.TextUtils
import android.util.DisplayMetrics
+import android.util.TypedValue
import android.view.inputmethod.InputMethodManager
import android.widget.Toast
import androidx.activity.ComponentActivity
import androidx.activity.result.contract.ActivityResultContracts
import androidx.annotation.AnyRes
+import androidx.annotation.AttrRes
+import androidx.annotation.ColorInt
import androidx.annotation.StringRes
import androidx.core.app.NotificationManagerCompat
import androidx.core.content.ContextCompat
+import androidx.core.net.toUri
import androidx.fragment.app.Fragment
import androidx.media3.common.C
import androidx.media3.common.MediaItem
@@ -614,12 +618,12 @@ object Util {
}
fun getUriToDrawable(context: Context, @AnyRes drawableId: Int): Uri {
- return Uri.parse(
+ return (
ContentResolver.SCHEME_ANDROID_RESOURCE +
"://" + context.resources.getResourcePackageName(drawableId) +
'/' + context.resources.getResourceTypeName(drawableId) +
'/' + context.resources.getResourceEntryName(drawableId)
- )
+ ).toUri()
}
data class ReadableEntryDescription(
@@ -823,6 +827,11 @@ object Util {
}
}
+ @ColorInt
+ fun Context.themeColor(@AttrRes attrRes: Int): Int = TypedValue()
+ .apply { theme.resolveAttribute(attrRes, this, true) }
+ .data
+
fun Fragment.navigateToCurrent() {
if (Settings.shouldTransitionOnPlayback) {
findNavController().popBackStack(R.id.playerFragment, true)
diff --git a/ultrasonic/src/main/res/drawable/rating_heart_full.xml b/ultrasonic/src/main/res/drawable/rating_heart_full.xml
new file mode 100644
index 00000000..7b677590
--- /dev/null
+++ b/ultrasonic/src/main/res/drawable/rating_heart_full.xml
@@ -0,0 +1,11 @@
+
+
+
diff --git a/ultrasonic/src/main/res/drawable/rating_heart_full_layered.xml b/ultrasonic/src/main/res/drawable/rating_heart_full_layered.xml
new file mode 100644
index 00000000..8645f0b9
--- /dev/null
+++ b/ultrasonic/src/main/res/drawable/rating_heart_full_layered.xml
@@ -0,0 +1,5 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/ultrasonic/src/main/res/drawable/rating_heart_full_outline.xml b/ultrasonic/src/main/res/drawable/rating_heart_full_outline.xml
new file mode 100644
index 00000000..40464f40
--- /dev/null
+++ b/ultrasonic/src/main/res/drawable/rating_heart_full_outline.xml
@@ -0,0 +1,10 @@
+
+
+
diff --git a/ultrasonic/src/main/res/drawable/rating_heart_hollow.xml b/ultrasonic/src/main/res/drawable/rating_heart_hollow.xml
new file mode 100644
index 00000000..c5a40143
--- /dev/null
+++ b/ultrasonic/src/main/res/drawable/rating_heart_hollow.xml
@@ -0,0 +1,10 @@
+
+
+
diff --git a/ultrasonic/src/main/res/drawable/rating_heart_hollow_layered.xml b/ultrasonic/src/main/res/drawable/rating_heart_hollow_layered.xml
new file mode 100644
index 00000000..a21dd8a1
--- /dev/null
+++ b/ultrasonic/src/main/res/drawable/rating_heart_hollow_layered.xml
@@ -0,0 +1,5 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/ultrasonic/src/main/res/drawable/rating_heart_hollow_outline.xml b/ultrasonic/src/main/res/drawable/rating_heart_hollow_outline.xml
new file mode 100644
index 00000000..1bacd950
--- /dev/null
+++ b/ultrasonic/src/main/res/drawable/rating_heart_hollow_outline.xml
@@ -0,0 +1,10 @@
+
+
+
diff --git a/ultrasonic/src/main/res/drawable/rating_heart_mini_overlay.xml b/ultrasonic/src/main/res/drawable/rating_heart_mini_overlay.xml
new file mode 100644
index 00000000..994358e6
--- /dev/null
+++ b/ultrasonic/src/main/res/drawable/rating_heart_mini_overlay.xml
@@ -0,0 +1,11 @@
+
+
+
diff --git a/ultrasonic/src/main/res/drawable/rating_star_0.xml b/ultrasonic/src/main/res/drawable/rating_star_0.xml
new file mode 100644
index 00000000..0690ffe7
--- /dev/null
+++ b/ultrasonic/src/main/res/drawable/rating_star_0.xml
@@ -0,0 +1,11 @@
+
+
+
diff --git a/ultrasonic/src/main/res/drawable/rating_star_1.xml b/ultrasonic/src/main/res/drawable/rating_star_1.xml
new file mode 100644
index 00000000..ca0cc12d
--- /dev/null
+++ b/ultrasonic/src/main/res/drawable/rating_star_1.xml
@@ -0,0 +1,11 @@
+
+
+
diff --git a/ultrasonic/src/main/res/drawable/rating_star_2.xml b/ultrasonic/src/main/res/drawable/rating_star_2.xml
new file mode 100644
index 00000000..dbbca321
--- /dev/null
+++ b/ultrasonic/src/main/res/drawable/rating_star_2.xml
@@ -0,0 +1,11 @@
+
+
+
diff --git a/ultrasonic/src/main/res/drawable/rating_star_3.xml b/ultrasonic/src/main/res/drawable/rating_star_3.xml
new file mode 100644
index 00000000..99a5c447
--- /dev/null
+++ b/ultrasonic/src/main/res/drawable/rating_star_3.xml
@@ -0,0 +1,11 @@
+
+
+
diff --git a/ultrasonic/src/main/res/drawable/rating_star_4.xml b/ultrasonic/src/main/res/drawable/rating_star_4.xml
new file mode 100644
index 00000000..c61791e9
--- /dev/null
+++ b/ultrasonic/src/main/res/drawable/rating_star_4.xml
@@ -0,0 +1,11 @@
+
+
+
diff --git a/ultrasonic/src/main/res/drawable/rating_star_5.xml b/ultrasonic/src/main/res/drawable/rating_star_5.xml
new file mode 100644
index 00000000..c32a85f5
--- /dev/null
+++ b/ultrasonic/src/main/res/drawable/rating_star_5.xml
@@ -0,0 +1,11 @@
+
+
+
diff --git a/ultrasonic/src/main/res/drawable/ic_star_full.xml b/ultrasonic/src/main/res/drawable/rating_star_full.xml
similarity index 100%
rename from ultrasonic/src/main/res/drawable/ic_star_full.xml
rename to ultrasonic/src/main/res/drawable/rating_star_full.xml
diff --git a/ultrasonic/src/main/res/drawable/rating_star_full_layered.xml b/ultrasonic/src/main/res/drawable/rating_star_full_layered.xml
new file mode 100644
index 00000000..f17c7d64
--- /dev/null
+++ b/ultrasonic/src/main/res/drawable/rating_star_full_layered.xml
@@ -0,0 +1,5 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/ultrasonic/src/main/res/drawable/ic_star_full_outline.xml b/ultrasonic/src/main/res/drawable/rating_star_full_outline.xml
similarity index 100%
rename from ultrasonic/src/main/res/drawable/ic_star_full_outline.xml
rename to ultrasonic/src/main/res/drawable/rating_star_full_outline.xml
diff --git a/ultrasonic/src/main/res/drawable/ic_star_hollow.xml b/ultrasonic/src/main/res/drawable/rating_star_hollow.xml
similarity index 100%
rename from ultrasonic/src/main/res/drawable/ic_star_hollow.xml
rename to ultrasonic/src/main/res/drawable/rating_star_hollow.xml
diff --git a/ultrasonic/src/main/res/drawable/rating_star_hollow_layered.xml b/ultrasonic/src/main/res/drawable/rating_star_hollow_layered.xml
new file mode 100644
index 00000000..97420c6e
--- /dev/null
+++ b/ultrasonic/src/main/res/drawable/rating_star_hollow_layered.xml
@@ -0,0 +1,5 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/ultrasonic/src/main/res/drawable/ic_star_hollow_outline.xml b/ultrasonic/src/main/res/drawable/rating_star_hollow_outline.xml
similarity index 100%
rename from ultrasonic/src/main/res/drawable/ic_star_hollow_outline.xml
rename to ultrasonic/src/main/res/drawable/rating_star_hollow_outline.xml
diff --git a/ultrasonic/src/main/res/drawable/star_full_outline.xml b/ultrasonic/src/main/res/drawable/star_full_outline.xml
deleted file mode 100644
index 5932d246..00000000
--- a/ultrasonic/src/main/res/drawable/star_full_outline.xml
+++ /dev/null
@@ -1,5 +0,0 @@
-
-
-
-
-
\ No newline at end of file
diff --git a/ultrasonic/src/main/res/drawable/star_hollow_outline.xml b/ultrasonic/src/main/res/drawable/star_hollow_outline.xml
deleted file mode 100644
index ab2c6c3e..00000000
--- a/ultrasonic/src/main/res/drawable/star_hollow_outline.xml
+++ /dev/null
@@ -1,5 +0,0 @@
-
-
-
-
-
\ No newline at end of file
diff --git a/ultrasonic/src/main/res/layout-land/current_playing.xml b/ultrasonic/src/main/res/layout-land/current_playing.xml
index af77ad49..df5f07e2 100644
--- a/ultrasonic/src/main/res/layout-land/current_playing.xml
+++ b/ultrasonic/src/main/res/layout-land/current_playing.xml
@@ -42,7 +42,8 @@
a:layout_width="match_parent"
a:layout_height="60dip"
a:layout_gravity="center"
- a:layout_margin="10dip"
+ a:layout_marginHorizontal="60dip"
+ a:layout_marginVertical="10dip"
a:orientation="horizontal">
+ a:src="@drawable/rating_star_hollow_layered" />
+ a:src="@drawable/rating_star_hollow_layered" />
+ a:src="@drawable/rating_star_hollow_layered" />
+ a:src="@drawable/rating_star_hollow_layered" />
+ a:src="@drawable/rating_star_hollow_layered" />
+
+
diff --git a/ultrasonic/src/main/res/layout/current_playing.xml b/ultrasonic/src/main/res/layout/current_playing.xml
index 7b674824..055c0eef 100644
--- a/ultrasonic/src/main/res/layout/current_playing.xml
+++ b/ultrasonic/src/main/res/layout/current_playing.xml
@@ -52,9 +52,8 @@
a:focusable="false"
a:gravity="center_vertical"
a:importantForAccessibility="no"
- a:padding="5dip"
a:scaleType="fitCenter"
- a:src="@drawable/star_hollow_outline" />
+ a:src="@drawable/rating_star_hollow_layered" />
+ a:src="@drawable/rating_star_hollow_layered" />
+ a:src="@drawable/rating_star_hollow_layered" />
+ a:src="@drawable/rating_star_hollow_layered" />
+ a:src="@drawable/rating_star_hollow_layered" />
+
+
diff --git a/ultrasonic/src/main/res/layout/grid_item_album.xml b/ultrasonic/src/main/res/layout/grid_item_album.xml
index 59b061d5..27fd5490 100644
--- a/ultrasonic/src/main/res/layout/grid_item_album.xml
+++ b/ultrasonic/src/main/res/layout/grid_item_album.xml
@@ -67,7 +67,7 @@
a:contentDescription="@string/download.menu_star"
a:gravity="center_horizontal"
a:padding="4dp"
- a:src="@drawable/ic_star_hollow"
+ a:src="@drawable/rating_star_hollow"
app:layout_constraintBottom_toBottomOf="@+id/cover_art"
app:layout_constraintEnd_toEndOf="@+id/cover_art" />
diff --git a/ultrasonic/src/main/res/layout/list_item_album.xml b/ultrasonic/src/main/res/layout/list_item_album.xml
index 9d5e0265..14ac400c 100644
--- a/ultrasonic/src/main/res/layout/list_item_album.xml
+++ b/ultrasonic/src/main/res/layout/list_item_album.xml
@@ -68,7 +68,7 @@
a:layout_marginEnd="20dp"
a:background="@android:color/transparent"
a:gravity="center_horizontal"
- a:src="@drawable/ic_star_hollow"
+ a:src="@drawable/rating_star_hollow"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintLeft_toRightOf="@+id/row_album_details"
app:layout_constraintStart_toEndOf="@+id/row_album_details"
diff --git a/ultrasonic/src/main/res/layout/list_item_track.xml b/ultrasonic/src/main/res/layout/list_item_track.xml
index ab3cce4b..1c484580 100644
--- a/ultrasonic/src/main/res/layout/list_item_track.xml
+++ b/ultrasonic/src/main/res/layout/list_item_track.xml
@@ -1,6 +1,7 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
+ a:paddingEnd="5dip"
+ a:src="@drawable/rating_star_5" />
\ No newline at end of file
diff --git a/ultrasonic/src/main/res/menu-v26/rating.xml b/ultrasonic/src/main/res/menu-v26/rating.xml
new file mode 100644
index 00000000..9efb8af0
--- /dev/null
+++ b/ultrasonic/src/main/res/menu-v26/rating.xml
@@ -0,0 +1,48 @@
+
+
+
\ No newline at end of file
diff --git a/ultrasonic/src/main/res/menu/nowplaying.xml b/ultrasonic/src/main/res/menu/nowplaying.xml
index d3bc8b59..ffd26c36 100644
--- a/ultrasonic/src/main/res/menu/nowplaying.xml
+++ b/ultrasonic/src/main/res/menu/nowplaying.xml
@@ -9,11 +9,6 @@
a:icon="@drawable/media_toggle_list"
app:showAsAction="always"
a:title="@string/download.toggle_playlist"/>
-
-
+
+
\ No newline at end of file
diff --git a/ultrasonic/src/main/res/values-cs/strings.xml b/ultrasonic/src/main/res/values-cs/strings.xml
index 3be9153f..26a16172 100644
--- a/ultrasonic/src/main/res/values-cs/strings.xml
+++ b/ultrasonic/src/main/res/values-cs/strings.xml
@@ -329,5 +329,4 @@
Nekompatibilní verze. Aktualizujte prosím Subsonic server.
- Používat pět hvězdiček pro hodnocení skladeb
diff --git a/ultrasonic/src/main/res/values-de/strings.xml b/ultrasonic/src/main/res/values-de/strings.xml
index a94a15e0..505ae394 100644
--- a/ultrasonic/src/main/res/values-de/strings.xml
+++ b/ultrasonic/src/main/res/values-de/strings.xml
@@ -415,8 +415,6 @@
Inkompatible Versionen. Bitte die Ultrasonic App aktualisieren.
Inkompatible Versionen. Bitte den Subsonic Server aktualisieren.
- Fünf-Stern Bewertung
- Benutze Bewertungssystem mit fünf Sternen, anstatt Lieder mit nur mit einem Stern zu markieren.
Ultrasonic ist ein kostenloser und quelloffener Android-Musikstreaming-Client für Subsonic API (Version 1.7.0 oder höher) kompatible Server.
\n
\nMit Ultrasonic können Sie mit Ihrem Subsonic-kompatiblen Medienserver ganz einfach Musik von Ihrem Heimcomputer auf Ihr Android-Telefon streamen oder herunterladen. Die Subsonic-Server-Software erfordert eine zusätzliche, von Ultrasonic unabhängige Konfiguration.
diff --git a/ultrasonic/src/main/res/values-es/strings.xml b/ultrasonic/src/main/res/values-es/strings.xml
index 100b01c7..dfcb6434 100644
--- a/ultrasonic/src/main/res/values-es/strings.xml
+++ b/ultrasonic/src/main/res/values-es/strings.xml
@@ -429,8 +429,6 @@
Versiones incompatibles. Por favor actualiza la aplicación de Android Ultrasonic.
Versiones incompatibles. Por favor actualiza el servidor de Subsonic.
- Use cinco estrellas para las canciones
- Utilice el sistema de calificación de cinco estrellas para canciones en lugar de simplemente marcar / desmarcar elementos.
Utilizar la reproducción por hardware (experimental)
Intenta reproducir los medios usando el procesador decodificador de los medios en tu teléfono. Esto puede mejorar el uso de la batería. ¡Algunos usuarios informan de fallos en la reproducción cuando activan esta opción!
Lista
@@ -446,7 +444,6 @@
Tasa de bits máxima: al fijar una canción de forma permanente
Canciones aleatorias
Reproducir las canciones aleatoriamente
- No me gusta
- %d canción añadida a la cola de reproducción
- %d canciones añadidas a la cola de reproducción
diff --git a/ultrasonic/src/main/res/values-fr/strings.xml b/ultrasonic/src/main/res/values-fr/strings.xml
index 31914406..9cfd7bf7 100644
--- a/ultrasonic/src/main/res/values-fr/strings.xml
+++ b/ultrasonic/src/main/res/values-fr/strings.xml
@@ -381,7 +381,6 @@
Versions incompatibles. Veuillez mette à jour l\'application Android Ultrasonic.
Versions incompatibles. Veuillez mette à jour le serveur Subsonic.
- Utiliser les étoiles pour noter les morceaux
Chronologique
Couverture
1000 morceaux
@@ -408,7 +407,6 @@
Si vous activez ce paramètre, il n\'affichera que la musique que vous avez téléchargée avec Ultrasonic 4.0 ou une version ultérieure. Les téléchargements antérieurs n\'ont pas les métadonnées nécessaires téléchargées. Vous pouvez basculer entre le mode Épingler et le mode Enregistrer pour déclencher le téléchargement des métadonnées manquantes.
Afficher le dialogue de confirmation
Les notifications sont nécessaires pour la lecture des médias. Vous pouvez accorder cette autorisation à tout moment dans les paramètres Android.
- Utiliser un système de notation à cinq étoiles pour les chansons au lieu d\'attribuer des étoiles ou de ne pas en attribuer à certains éléments.
Essayez de lire le média à l\'aide de la puce de décodage média de votre téléphone. Ceci peut améliorer l\'utilisation de la batterie.
Fonctionnalités prises en charge
Utiliser la lecture matérielle (expérimental)
diff --git a/ultrasonic/src/main/res/values-hu/strings.xml b/ultrasonic/src/main/res/values-hu/strings.xml
index 28efc2c8..277337c3 100644
--- a/ultrasonic/src/main/res/values-hu/strings.xml
+++ b/ultrasonic/src/main/res/values-hu/strings.xml
@@ -335,5 +335,4 @@
Nem kompatibilis verzió. Kérjük, frissítse a Subsonic kiszolgálót!
- Öt csillagos értékelés használata a dalokhoz
diff --git a/ultrasonic/src/main/res/values-ja/strings.xml b/ultrasonic/src/main/res/values-ja/strings.xml
index abb4cc52..b51c3a2b 100644
--- a/ultrasonic/src/main/res/values-ja/strings.xml
+++ b/ultrasonic/src/main/res/values-ja/strings.xml
@@ -325,8 +325,6 @@
要求されたデータが見つかりませんでした。
互換性のないバージョンです。UltrasonicのAndroidアプリをバージョンアップしてください。
互換性のないバージョンです。Subsonicサーバーをバージョンアップしてください。
- 曲に五つ星評価を利用
- 楽曲の評価を、スターあり/なし ではなく、5つの星を付ける方式にします。
リスト
カバー
サポートされている機能
diff --git a/ultrasonic/src/main/res/values-nb-rNO/strings.xml b/ultrasonic/src/main/res/values-nb-rNO/strings.xml
index 0bd99046..62b20a79 100644
--- a/ultrasonic/src/main/res/values-nb-rNO/strings.xml
+++ b/ultrasonic/src/main/res/values-nb-rNO/strings.xml
@@ -430,10 +430,8 @@
Prøveperioden er over.
Ukompatible versjoner. Oppgrader Ultrasonic-programmet for Android.
Ukompatible versjoner. Oppgrader Subsonic-tjeneren.
- Bruk femstjerners vurdering for spor
Liste
Ikke identitetsbekreftet. Sjekk brukertilganger på Subsonic-tjeneren.
- Bruk femstjerners vurderingssystem for spor istedenfor enkel stjernemerking/opphevelse av stjernemerking av elementer.
Bruk maskinvarebasert avspilling (eksperimentelt)
Omslag
Støttede funksjoner
diff --git a/ultrasonic/src/main/res/values-night/themes.xml b/ultrasonic/src/main/res/values-night/themes.xml
index ebb3ed2f..cafab5d0 100644
--- a/ultrasonic/src/main/res/values-night/themes.xml
+++ b/ultrasonic/src/main/res/values-night/themes.xml
@@ -4,5 +4,6 @@
- ?attr/colorSurface
- ?attr/colorOnSurface
- ?attr/colorSecondary
+ - @color/tertiary
\ No newline at end of file
diff --git a/ultrasonic/src/main/res/values-nl/strings.xml b/ultrasonic/src/main/res/values-nl/strings.xml
index ca71f450..b9c995d6 100644
--- a/ultrasonic/src/main/res/values-nl/strings.xml
+++ b/ultrasonic/src/main/res/values-nl/strings.xml
@@ -425,9 +425,6 @@
Incompatibele versies. Werk je Subsonic-server bij.
- Vijf sterren gebruiken voor nummers
- Toon vijf sterren om nummers te beoordelen in plaats van items toe te voegen aan of te verwijderen uit de favorieten.
-
Hardwarematig afspelen (experimenteel)
Probeer media af te spelen met behulp van de mediadecoder op je telefoon. Let op: hierdoor kan het accuverbruik toenemen.
Lijst
diff --git a/ultrasonic/src/main/res/values-pl/strings.xml b/ultrasonic/src/main/res/values-pl/strings.xml
index f7392c5c..055755e0 100644
--- a/ultrasonic/src/main/res/values-pl/strings.xml
+++ b/ultrasonic/src/main/res/values-pl/strings.xml
@@ -317,7 +317,6 @@
Brak zgodności wersji. Uaktualnij aplikację Ultrasonic na Androida.
Brak zgodności wersji. Uaktualnij serwer Subsonic.
- 5-gwiazdkowy system ocen utworów
Pokaż okno potwierdzające usunięcie lub odpięcie utworów
Angielski
Pamiętaj o ustawieniu nazwy użytkownika i hasła do usługi Scrobble na serwerze
@@ -434,7 +433,6 @@
Jedna lub więcej funkcji zostało wyłączonych ponieważ serwer ich nie obsługiwał.
\nMożesz uruchomić ten test ponownie kiedykolwiek.
Serwer demonstracyjny
- Używaj 5-gwiazdkowego systemu ocen utworów zamiast zwykłego oznaczania/odznaczania utworów gwiazdką.
Lista
Okładka
Spróbuj odtworzyć pliki multimedialne za pomocą układu dekodującego w telefonie. Może to zmniejszyć zużycie baterii!
diff --git a/ultrasonic/src/main/res/values-pt-rBR/strings.xml b/ultrasonic/src/main/res/values-pt-rBR/strings.xml
index 47dfc729..6aa187ef 100644
--- a/ultrasonic/src/main/res/values-pt-rBR/strings.xml
+++ b/ultrasonic/src/main/res/values-pt-rBR/strings.xml
@@ -425,12 +425,9 @@
Versões incompativeis. Atualize o aplicativo Ultrasonic para Android.
Versões incompativeis. Atualize o servidor Ultrasonic.
- Avaliar Músicas com Estrelas
- Usar o sistema de classificação de 5 estrelas em vez de estrelar/não estrelar itens.
Usar Reprodução por Hardware (experimental)
Tenta reproduzir a mídia usando o chip decodificador de mídia do telefone. Isso pode melhorar o uso da bateria. Alguns usuários relatam falhas na reprodução ao ativar esta opção!
Jukebox
- Desfavoritar
1000 músicas
Opções
Se você ativar esta configuração, ela mostrará apenas as músicas que você baixou com o Ultrasonic 4.0 ou posterior. Os downloads anteriores não têm os metadados necessários baixados. Você pode alternar entre os modos Fixar e Salvar para acionar o download dos metadados ausentes.
diff --git a/ultrasonic/src/main/res/values-pt/strings.xml b/ultrasonic/src/main/res/values-pt/strings.xml
index bc63daad..23fc4861 100644
--- a/ultrasonic/src/main/res/values-pt/strings.xml
+++ b/ultrasonic/src/main/res/values-pt/strings.xml
@@ -316,7 +316,6 @@
Versões incompativeis. Atualize o aplicativo Ultrasonic para Android.
Versões incompativeis. Atualize o servidor Ultrasonic.
- Use classificação de cinco estrelas para músicas
Um ou mais recursos foram desativados porque o servidor não os suporta.
\nPode executar este teste novamente a qualquer momento.
Servidor Demonstração
@@ -347,7 +346,6 @@
Repetir
Parar
Próxima
- Usar o sistema de classificação de 5 estrelas em vez de estrelar/não estrelar itens.
Cápa
Lista
Recursos suportados
diff --git a/ultrasonic/src/main/res/values-ru/strings.xml b/ultrasonic/src/main/res/values-ru/strings.xml
index da167d66..96c66bec 100644
--- a/ultrasonic/src/main/res/values-ru/strings.xml
+++ b/ultrasonic/src/main/res/values-ru/strings.xml
@@ -358,5 +358,4 @@
Несовместимые версии. Пожалуйста, обновите Subsonic сервер.
- Использовать пятизвездочный рейтинг для песен
diff --git a/ultrasonic/src/main/res/values-zh-rCN/strings.xml b/ultrasonic/src/main/res/values-zh-rCN/strings.xml
index 0e0ecbb0..ca17cbe9 100644
--- a/ultrasonic/src/main/res/values-zh-rCN/strings.xml
+++ b/ultrasonic/src/main/res/values-zh-rCN/strings.xml
@@ -393,7 +393,6 @@
版本不兼容,请升级 Ultrasonic 应用。
版本不兼容,请升级 Subsonic 服务器。
- 为歌曲使用五星评分
500 首歌
如果您启用此设置,它将只显示您使用 Ultrasonic 4.0 或更高版本下载的音乐。较早的下载没有下载必要的元数据。您可以在固定和保存模式之间切换,以触发缺失元数据的下载。
如果媒体通知仍然存在,请按媒体通知中的播放按钮;否则请打开应用程序开始播放,并重新连接会话到控制器
@@ -420,7 +419,6 @@
专辑封面
展示确认对话框
需要通知权限才能进行媒体播放。您可以随时在 Android 设置中授予权限。
- 对歌曲使用五星评级系统,而不是简单的星标/取消星标。
使用硬件回放(实验性)
尝试使用手机上的媒体解码器芯片来播放媒体。这可以改善电池使用情况。部分用户报告启用该选项后播放会有问题!
列表
diff --git a/ultrasonic/src/main/res/values/colors.xml b/ultrasonic/src/main/res/values/colors.xml
index 251f0555..80e88438 100644
--- a/ultrasonic/src/main/res/values/colors.xml
+++ b/ultrasonic/src/main/res/values/colors.xml
@@ -3,4 +3,5 @@
#000000
#F3F3F3
#000000
+ #ec407a
\ No newline at end of file
diff --git a/ultrasonic/src/main/res/values/setting_keys.xml b/ultrasonic/src/main/res/values/setting_keys.xml
index 20356d83..26df67dd 100644
--- a/ultrasonic/src/main/res/values/setting_keys.xml
+++ b/ultrasonic/src/main/res/values/setting_keys.xml
@@ -46,7 +46,6 @@
sharingDefaultGreeting
sharingCreateOnServer
sharingDefaultExpiration
- use_five_star_rating
use_hw_offload
firstRunExecuted
resumeOnBluetoothDevice
diff --git a/ultrasonic/src/main/res/values/strings.xml b/ultrasonic/src/main/res/values/strings.xml
index a4e457a7..6d27f0ab 100644
--- a/ultrasonic/src/main/res/values/strings.xml
+++ b/ultrasonic/src/main/res/values/strings.xml
@@ -132,6 +132,12 @@
Exit
Settings
Refresh
+ No Rating
+ 1 Star
+ 2 Stars
+ 3 Stars
+ 4 Stars
+ 5 Stars
Media Library
Offline Media
Playlists
@@ -338,7 +344,6 @@
Set Bookmark
Delete Bookmark
Star
- Unstar
Clear Playlist
Shares
No shares available on server
@@ -441,8 +446,6 @@
Incompatible versions. Please upgrade Subsonic server.
- Use five star rating for songs
- Use five star rating system for songs instead of simply starring/unstarring items.
Use hardware playback (experimental)
Try to play the media using the media decoder chip on your phone. This can improve battery usage. Some users report glitches in playback when they activate this option!
List
diff --git a/ultrasonic/src/main/res/values/themes.xml b/ultrasonic/src/main/res/values/themes.xml
index bb470b01..274b9bd4 100644
--- a/ultrasonic/src/main/res/values/themes.xml
+++ b/ultrasonic/src/main/res/values/themes.xml
@@ -19,23 +19,27 @@
\ No newline at end of file
diff --git a/ultrasonic/src/main/res/xml/settings.xml b/ultrasonic/src/main/res/xml/settings.xml
index bb5d6fdd..30ef87a0 100644
--- a/ultrasonic/src/main/res/xml/settings.xml
+++ b/ultrasonic/src/main/res/xml/settings.xml
@@ -105,12 +105,6 @@
a:key="@string/setting_key.pause_on_bluetooth_device"
a:title="@string/settings.playback.pause_on_bluetooth_device"
app:iconSpaceReserved="false"/>
-