diff --git a/ultrasonic/src/main/java/org/moire/ultrasonic/util/MergeAdapter.java b/ultrasonic/src/main/java/org/moire/ultrasonic/util/MergeAdapter.java
deleted file mode 100644
index 7d8880be..00000000
--- a/ultrasonic/src/main/java/org/moire/ultrasonic/util/MergeAdapter.java
+++ /dev/null
@@ -1,316 +0,0 @@
-/**
- Copyright (c) 2008-2009 CommonsWare, LLC
- Portions (c) 2009 Google, Inc.
-
- Licensed under the Apache License, Version 2.0 (the "License"); you may
- not use this file except in compliance with the License. You may obtain
- a copy of the License at
- http://www.apache.org/licenses/LICENSE-2.0
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
- */
-
-package org.moire.ultrasonic.util;
-
-import android.database.DataSetObserver;
-import android.view.View;
-import android.view.ViewGroup;
-import android.widget.BaseAdapter;
-import android.widget.ListAdapter;
-
-import java.util.AbstractList;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.List;
-
-/**
- * Adapter that merges multiple child adapters and views
- * into a single contiguous whole.
- *
- * Adapters used as pieces within MergeAdapter must
- * have view type IDs monotonically increasing from 0. Ideally,
- * adapters also have distinct ranges for their row ids, as
- * returned by getItemId().
- */
-public class MergeAdapter extends BaseAdapter
-{
- private final CascadeDataSetObserver observer = new CascadeDataSetObserver();
- private final AbstractList pieces = new ArrayList();
-
- /**
- * Adds a new adapter to the roster of things to appear
- * in the aggregate list.
- *
- * @param adapter Source for row views for this section
- */
- public void addAdapter(ListAdapter adapter)
- {
- pieces.add(adapter);
- adapter.registerDataSetObserver(observer);
- }
-
- public void removeAdapter(ListAdapter adapter)
- {
- adapter.unregisterDataSetObserver(observer);
- pieces.remove(adapter);
- }
-
- /**
- * Adds a new View to the roster of things to appear
- * in the aggregate list.
- *
- * @param view Single view to add
- */
- public ListAdapter addView(View view)
- {
- return addView(view, false);
- }
-
- /**
- * Adds a new View to the roster of things to appear
- * in the aggregate list.
- *
- * @param view Single view to add
- * @param enabled false if views are disabled, true if enabled
- */
- public ListAdapter addView(View view, boolean enabled)
- {
- return addViews(Collections.singletonList(view), enabled);
- }
-
- /**
- * Adds a list of views to the roster of things to appear
- * in the aggregate list.
- *
- * @param views List of views to add
- */
- public ListAdapter addViews(List views)
- {
- return addViews(views, false);
- }
-
- /**
- * Adds a list of views to the roster of things to appear
- * in the aggregate list.
- *
- * @param views List of views to add
- * @param enabled false if views are disabled, true if enabled
- */
- public ListAdapter addViews(List views, boolean enabled)
- {
- ListAdapter adapter = enabled ? new EnabledSackAdapter(views) : new SackOfViewsAdapter(views);
- addAdapter(adapter);
- return adapter;
- }
-
- /**
- * Get the data item associated with the specified
- * position in the data set.
- *
- * @param position Position of the item whose data we want
- */
- @Override
- public Object getItem(int position)
- {
- for (ListAdapter piece : pieces)
- {
- int size = piece.getCount();
-
- if (position < size)
- {
- return (piece.getItem(position));
- }
-
- position -= size;
- }
-
- return (null);
- }
-
- /**
- * How many items are in the data set represented by this
- * Adapter.
- */
- @Override
- public int getCount()
- {
- int total = 0;
-
- for (ListAdapter piece : pieces)
- {
- total += piece.getCount();
- }
-
- return (total);
- }
-
- /**
- * Returns the number of types of Views that will be
- * created by getView().
- */
- @Override
- public int getViewTypeCount()
- {
- int total = 0;
-
- for (ListAdapter piece : pieces)
- {
- total += piece.getViewTypeCount();
- }
-
- return (Math.max(total, 1)); // needed for setListAdapter() before content add'
- }
-
- /**
- * Get the type of View that will be created by getView()
- * for the specified item.
- *
- * @param position Position of the item whose data we want
- */
- @Override
- public int getItemViewType(int position)
- {
- int typeOffset = 0;
- int result = -1;
-
- for (ListAdapter piece : pieces)
- {
- int size = piece.getCount();
-
- if (position < size)
- {
- result = typeOffset + piece.getItemViewType(position);
- break;
- }
-
- position -= size;
- typeOffset += piece.getViewTypeCount();
- }
-
- return (result);
- }
-
- /**
- * Are all items in this ListAdapter enabled? If yes it
- * means all items are selectable and clickable.
- */
- @Override
- public boolean areAllItemsEnabled()
- {
- return (false);
- }
-
- /**
- * Returns true if the item at the specified position is
- * not a separator.
- *
- * @param position Position of the item whose data we want
- */
- @Override
- public boolean isEnabled(int position)
- {
- for (ListAdapter piece : pieces)
- {
- int size = piece.getCount();
-
- if (position < size)
- {
- return (piece.isEnabled(position));
- }
-
- position -= size;
- }
-
- return (false);
- }
-
- /**
- * Get a View that displays the data at the specified
- * position in the data set.
- *
- * @param position Position of the item whose data we want
- * @param convertView View to recycle, if not null
- * @param parent ViewGroup containing the returned View
- */
- @Override
- public View getView(int position, View convertView, ViewGroup parent)
- {
- for (ListAdapter piece : pieces)
- {
- int size = piece.getCount();
-
- if (position < size)
- {
-
- return (piece.getView(position, convertView, parent));
- }
-
- position -= size;
- }
-
- return (null);
- }
-
- /**
- * Get the row id associated with the specified position
- * in the list.
- *
- * @param position Position of the item whose data we want
- */
- @Override
- public long getItemId(int position)
- {
- for (ListAdapter piece : pieces)
- {
- int size = piece.getCount();
-
- if (position < size)
- {
- return (piece.getItemId(position));
- }
-
- position -= size;
- }
-
- return (-1);
- }
-
- private static class EnabledSackAdapter extends SackOfViewsAdapter
- {
- public EnabledSackAdapter(List views)
- {
- super(views);
- }
-
- @Override
- public boolean areAllItemsEnabled()
- {
- return (true);
- }
-
- @Override
- public boolean isEnabled(int position)
- {
- return (true);
- }
- }
-
- private class CascadeDataSetObserver extends DataSetObserver
- {
- @Override
- public void onChanged()
- {
- notifyDataSetChanged();
- }
-
- @Override
- public void onInvalidated()
- {
- notifyDataSetInvalidated();
- }
- }
-}
-
diff --git a/ultrasonic/src/main/java/org/moire/ultrasonic/util/SackOfViewsAdapter.java b/ultrasonic/src/main/java/org/moire/ultrasonic/util/SackOfViewsAdapter.java
deleted file mode 100644
index 080e1430..00000000
--- a/ultrasonic/src/main/java/org/moire/ultrasonic/util/SackOfViewsAdapter.java
+++ /dev/null
@@ -1,195 +0,0 @@
-/**
- Copyright (c) 2008-2009 CommonsWare, LLC
- Portions (c) 2009 Google, Inc.
-
- Licensed under the Apache License, Version 2.0 (the "License"); you may
- not use this file except in compliance with the License. You may obtain
- a copy of the License at
- http://www.apache.org/licenses/LICENSE-2.0
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
- */
-package org.moire.ultrasonic.util;
-
-import android.view.View;
-import android.view.ViewGroup;
-import android.widget.BaseAdapter;
-import android.widget.ListView;
-
-import java.util.ArrayList;
-import java.util.List;
-
-/**
- * Adapter that simply returns row views from a list.
- *
- * If you supply a size, you must implement newView(), to
- * create a required view. The adapter will then cache these
- * views.
- *
- * If you supply a list of views in the constructor, that
- * list will be used directly. If any elements in the list
- * are null, then newView() will be called just for those
- * slots.
- *
- * Subclasses may also wish to override areAllItemsEnabled()
- * (default: false) and isEnabled() (default: false), if some
- * of their rows should be selectable.
- *
- * It is assumed each view is unique, and therefore will not
- * get recycled.
- *
- * Note that this adapter is not designed for long lists. It
- * is more for screens that should behave like a list. This
- * is particularly useful if you combine this with other
- * adapters (e.g., SectionedAdapter) that might have an
- * arbitrary number of rows, so it all appears seamless.
- */
-public class SackOfViewsAdapter extends BaseAdapter
-{
- private List views;
-
- /**
- * Constructor creating an empty list of views, but with
- * a specified count. Subclasses must override newView().
- */
- public SackOfViewsAdapter(int count)
- {
- super();
-
- views = new ArrayList(count);
-
- for (int i = 0; i < count; i++)
- {
- views.add(null);
- }
- }
-
- /**
- * Constructor wrapping a supplied list of views.
- * Subclasses must override newView() if any of the elements
- * in the list are null.
- */
- public SackOfViewsAdapter(List views)
- {
- for (View view : views)
- {
- view.setLayoutParams(new ListView.LayoutParams(ViewGroup.LayoutParams.FILL_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT));
- }
- this.views = views;
- }
-
- /**
- * Get the data item associated with the specified
- * position in the data set.
- *
- * @param position Position of the item whose data we want
- */
- @Override
- public Object getItem(int position)
- {
- return (views.get(position));
- }
-
- /**
- * How many items are in the data set represented by this
- * Adapter.
- */
- @Override
- public int getCount()
- {
- return (views.size());
- }
-
- /**
- * Returns the number of types of Views that will be
- * created by getView().
- */
- @Override
- public int getViewTypeCount()
- {
- return (getCount());
- }
-
- /**
- * Get the type of View that will be created by getView()
- * for the specified item.
- *
- * @param position Position of the item whose data we want
- */
- @Override
- public int getItemViewType(int position)
- {
- return (position);
- }
-
- /**
- * Are all items in this ListAdapter enabled? If yes it
- * means all items are selectable and clickable.
- */
- @Override
- public boolean areAllItemsEnabled()
- {
- return (false);
- }
-
- /**
- * Returns true if the item at the specified position is
- * not a separator.
- *
- * @param position Position of the item whose data we want
- */
- @Override
- public boolean isEnabled(int position)
- {
- return (false);
- }
-
- /**
- * Get a View that displays the data at the specified
- * position in the data set.
- *
- * @param position Position of the item whose data we want
- * @param convertView View to recycle, if not null
- * @param parent ViewGroup containing the returned View
- */
- @Override
- public View getView(int position, View convertView, ViewGroup parent)
- {
- View result = views.get(position);
-
- if (result == null)
- {
- result = newView(position, parent);
- views.set(position, result);
- }
-
- return (result);
- }
-
- /**
- * Get the row id associated with the specified position
- * in the list.
- *
- * @param position Position of the item whose data we want
- */
- @Override
- public long getItemId(int position)
- {
- return (position);
- }
-
- /**
- * Create a new View to go into the list at the specified
- * position.
- *
- * @param position Position of the item whose data we want
- * @param parent ViewGroup containing the returned View
- */
- protected static View newView(int position, ViewGroup parent)
- {
- throw new RuntimeException("You must override newView()!");
- }
-}
diff --git a/ultrasonic/src/main/kotlin/org/moire/ultrasonic/activity/NavigationActivity.kt b/ultrasonic/src/main/kotlin/org/moire/ultrasonic/activity/NavigationActivity.kt
index 44b67078..2a915be3 100644
--- a/ultrasonic/src/main/kotlin/org/moire/ultrasonic/activity/NavigationActivity.kt
+++ b/ultrasonic/src/main/kotlin/org/moire/ultrasonic/activity/NavigationActivity.kt
@@ -158,6 +158,12 @@ class NavigationActivity : AppCompatActivity() {
var showWelcomeScreen = Util.isFirstRun()
val areServersMigrated: Boolean = serverSettingsModel.migrateFromPreferences()
+ // Migrate Feature storage if needed
+ // TODO: Remove in December 2022
+ if (!Settings.hasKey(Constants.PREFERENCES_KEY_USE_FIVE_STAR_RATING)) {
+ Settings.migrateFeatureStorage()
+ }
+
// If there are any servers in the DB, do not show the welcome screen
showWelcomeScreen = showWelcomeScreen and !areServersMigrated
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 6c58d85a..2ec56ddb 100644
--- a/ultrasonic/src/main/kotlin/org/moire/ultrasonic/adapters/TrackViewHolder.kt
+++ b/ultrasonic/src/main/kotlin/org/moire/ultrasonic/adapters/TrackViewHolder.kt
@@ -13,12 +13,9 @@ import androidx.lifecycle.MutableLiveData
import androidx.recyclerview.widget.RecyclerView
import io.reactivex.rxjava3.disposables.Disposable
import org.koin.core.component.KoinComponent
-import org.koin.core.component.get
import org.moire.ultrasonic.R
import org.moire.ultrasonic.data.ActiveServerProvider
import org.moire.ultrasonic.domain.MusicDirectory
-import org.moire.ultrasonic.featureflags.Feature
-import org.moire.ultrasonic.featureflags.FeatureStorage
import org.moire.ultrasonic.service.DownloadFile
import org.moire.ultrasonic.service.DownloadStatus
import org.moire.ultrasonic.service.MusicServiceFactory
@@ -61,11 +58,6 @@ class TrackViewHolder(val view: View) : RecyclerView.ViewHolder(view), Checkable
var observableChecked = MutableLiveData(false)
- private val useFiveStarRating: Boolean by lazy {
- val features: FeatureStorage = get()
- features.isFeatureEnabled(Feature.FIVE_STAR_RATING)
- }
-
lateinit var imageHelper: Utils.ImageHelper
fun setSong(
@@ -74,6 +66,7 @@ class TrackViewHolder(val view: View) : RecyclerView.ViewHolder(view), Checkable
draggable: Boolean,
isSelected: Boolean = false
) {
+ val useFiveStarRating = Settings.useFiveStarRating
val song = file.song
downloadFile = file
entry = song
@@ -98,7 +91,7 @@ class TrackViewHolder(val view: View) : RecyclerView.ViewHolder(view), Checkable
star.isVisible = false
rating.isVisible = false
} else {
- setupStarButtons(song)
+ setupStarButtons(song, useFiveStarRating)
}
updateProgress(downloadFile!!.progress.value!!)
@@ -138,7 +131,7 @@ class TrackViewHolder(val view: View) : RecyclerView.ViewHolder(view), Checkable
}
}
- private fun setupStarButtons(song: MusicDirectory.Entry) {
+ private fun setupStarButtons(song: MusicDirectory.Entry, useFiveStarRating: Boolean) {
if (useFiveStarRating) {
// Hide single star
star.isVisible = false
diff --git a/ultrasonic/src/main/kotlin/org/moire/ultrasonic/app/UApp.kt b/ultrasonic/src/main/kotlin/org/moire/ultrasonic/app/UApp.kt
index 36eb3786..2096928f 100644
--- a/ultrasonic/src/main/kotlin/org/moire/ultrasonic/app/UApp.kt
+++ b/ultrasonic/src/main/kotlin/org/moire/ultrasonic/app/UApp.kt
@@ -9,7 +9,6 @@ import org.moire.ultrasonic.BuildConfig
import org.moire.ultrasonic.di.appPermanentStorage
import org.moire.ultrasonic.di.applicationModule
import org.moire.ultrasonic.di.baseNetworkModule
-import org.moire.ultrasonic.di.featureFlagsModule
import org.moire.ultrasonic.di.mediaPlayerModule
import org.moire.ultrasonic.di.musicServiceModule
import org.moire.ultrasonic.log.FileLoggerTree
@@ -47,7 +46,6 @@ class UApp : MultiDexApplication() {
applicationModule,
appPermanentStorage,
baseNetworkModule,
- featureFlagsModule,
musicServiceModule,
mediaPlayerModule
)
diff --git a/ultrasonic/src/main/kotlin/org/moire/ultrasonic/di/FeatureFlagsModule.kt b/ultrasonic/src/main/kotlin/org/moire/ultrasonic/di/FeatureFlagsModule.kt
deleted file mode 100644
index 303f058a..00000000
--- a/ultrasonic/src/main/kotlin/org/moire/ultrasonic/di/FeatureFlagsModule.kt
+++ /dev/null
@@ -1,12 +0,0 @@
-package org.moire.ultrasonic.di
-
-import org.koin.android.ext.koin.androidContext
-import org.koin.dsl.module
-import org.moire.ultrasonic.featureflags.FeatureStorage
-
-/**
- * This Koin module contains the registration for the Feature Flags
- */
-val featureFlagsModule = module {
- factory { FeatureStorage(androidContext()) }
-}
diff --git a/ultrasonic/src/main/kotlin/org/moire/ultrasonic/featureflags/Feature.kt b/ultrasonic/src/main/kotlin/org/moire/ultrasonic/featureflags/Feature.kt
deleted file mode 100644
index a92edbc4..00000000
--- a/ultrasonic/src/main/kotlin/org/moire/ultrasonic/featureflags/Feature.kt
+++ /dev/null
@@ -1,18 +0,0 @@
-package org.moire.ultrasonic.featureflags
-
-/**
- * Contains a list of new features/implementations that are not yet finished,
- * but possible to try it out.
- */
-enum class Feature(
- val defaultValue: Boolean
-) {
- /**
- * Enables new image downloader implementation.
- */
- NEW_IMAGE_DOWNLOADER(false),
- /**
- * Enables five star rating system.
- */
- FIVE_STAR_RATING(false)
-}
diff --git a/ultrasonic/src/main/kotlin/org/moire/ultrasonic/featureflags/FeatureStorage.kt b/ultrasonic/src/main/kotlin/org/moire/ultrasonic/featureflags/FeatureStorage.kt
deleted file mode 100644
index dca9bb4f..00000000
--- a/ultrasonic/src/main/kotlin/org/moire/ultrasonic/featureflags/FeatureStorage.kt
+++ /dev/null
@@ -1,31 +0,0 @@
-package org.moire.ultrasonic.featureflags
-
-import android.content.Context
-
-private const val SP_NAME = "feature_flags"
-
-/**
- * Provides storage for current feature flag state.
- */
-class FeatureStorage(
- context: Context
-) {
- private val sp = context.getSharedPreferences(SP_NAME, Context.MODE_PRIVATE)
-
- /**
- * Get [feature] current enabled state.
- */
- fun isFeatureEnabled(feature: Feature): Boolean {
- return sp.getBoolean(feature.name, feature.defaultValue)
- }
-
- /**
- * Update [feature] enabled state to [isEnabled].
- */
- fun changeFeatureFlag(
- feature: Feature,
- isEnabled: Boolean
- ) {
- sp.edit().putBoolean(feature.name, isEnabled).apply()
- }
-}
diff --git a/ultrasonic/src/main/kotlin/org/moire/ultrasonic/fragment/MainFragment.kt b/ultrasonic/src/main/kotlin/org/moire/ultrasonic/fragment/MainFragment.kt
index 940fb1b5..6969a47f 100644
--- a/ultrasonic/src/main/kotlin/org/moire/ultrasonic/fragment/MainFragment.kt
+++ b/ultrasonic/src/main/kotlin/org/moire/ultrasonic/fragment/MainFragment.kt
@@ -4,16 +4,15 @@ import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
-import android.widget.AdapterView
-import android.widget.AdapterView.OnItemClickListener
-import android.widget.ListView
+import android.widget.LinearLayout
+import android.widget.TextView
+import androidx.core.view.isVisible
import androidx.fragment.app.Fragment
import androidx.navigation.Navigation
import org.koin.core.component.KoinComponent
import org.moire.ultrasonic.R
import org.moire.ultrasonic.data.ActiveServerProvider.Companion.isOffline
import org.moire.ultrasonic.util.Constants
-import org.moire.ultrasonic.util.MergeAdapter
import org.moire.ultrasonic.util.Settings
import org.moire.ultrasonic.util.Util
@@ -21,26 +20,26 @@ import org.moire.ultrasonic.util.Util
* Displays the Main screen of Ultrasonic, where the music library can be browsed
*/
class MainFragment : Fragment(), KoinComponent {
- private var list: ListView? = null
- private lateinit var musicTitle: View
- private lateinit var artistsButton: View
- private lateinit var albumsButton: View
- private lateinit var genresButton: View
- private lateinit var videosTitle: View
- private lateinit var songsTitle: View
- private lateinit var randomSongsButton: View
- private lateinit var songsStarredButton: View
- private lateinit var albumsTitle: View
- private lateinit var albumsNewestButton: View
- private lateinit var albumsRandomButton: View
- private lateinit var albumsHighestButton: View
- private lateinit var albumsStarredButton: View
- private lateinit var albumsRecentButton: View
- private lateinit var albumsFrequentButton: View
- private lateinit var albumsAlphaByNameButton: View
- private lateinit var albumsAlphaByArtistButton: View
- private lateinit var videosButton: View
+ private lateinit var list: LinearLayout
+ private lateinit var musicTitle: TextView
+ private lateinit var artistsButton: TextView
+ private lateinit var albumsButton: TextView
+ private lateinit var genresButton: TextView
+ private lateinit var videosTitle: TextView
+ private lateinit var songsTitle: TextView
+ private lateinit var randomSongsButton: TextView
+ private lateinit var songsStarredButton: TextView
+ private lateinit var albumsTitle: TextView
+ private lateinit var albumsNewestButton: TextView
+ private lateinit var albumsRandomButton: TextView
+ private lateinit var albumsHighestButton: TextView
+ private lateinit var albumsStarredButton: TextView
+ private lateinit var albumsRecentButton: TextView
+ private lateinit var albumsFrequentButton: TextView
+ private lateinit var albumsAlphaByNameButton: TextView
+ private lateinit var albumsAlphaByArtistButton: TextView
+ private lateinit var videosButton: TextView
override fun onCreate(savedInstanceState: Bundle?) {
Util.applyTheme(this.context)
@@ -59,8 +58,8 @@ class MainFragment : Fragment(), KoinComponent {
list = view.findViewById(R.id.main_list)
setupButtons()
-
- if (list != null) setupMenuList(list!!)
+ setupClickListener()
+ setupItemVisibility()
super.onViewCreated(view, savedInstanceState)
}
@@ -71,134 +70,128 @@ class MainFragment : Fragment(), KoinComponent {
val currentId3Setting = Settings.shouldUseId3Tags
// If setting has changed...
- if (currentId3Setting != shouldUseId3) {
- shouldUseId3 = currentId3Setting
+ if (currentId3Setting != cachedId3Setting) {
+ cachedId3Setting = currentId3Setting
shouldRestart = true
}
// then setup the list anew.
if (shouldRestart) {
- if (list != null) setupMenuList(list!!)
+ setupItemVisibility()
}
}
private fun setupButtons() {
- val buttons = layoutInflater.inflate(R.layout.main_buttons, list, false)
- musicTitle = buttons.findViewById(R.id.main_music)
- artistsButton = buttons.findViewById(R.id.main_artists_button)
- albumsButton = buttons.findViewById(R.id.main_albums_button)
- genresButton = buttons.findViewById(R.id.main_genres_button)
- videosTitle = buttons.findViewById(R.id.main_videos_title)
- songsTitle = buttons.findViewById(R.id.main_songs)
- randomSongsButton = buttons.findViewById(R.id.main_songs_button)
- songsStarredButton = buttons.findViewById(R.id.main_songs_starred)
- albumsTitle = buttons.findViewById(R.id.main_albums)
- albumsNewestButton = buttons.findViewById(R.id.main_albums_newest)
- albumsRandomButton = buttons.findViewById(R.id.main_albums_random)
- albumsHighestButton = buttons.findViewById(R.id.main_albums_highest)
- albumsStarredButton = buttons.findViewById(R.id.main_albums_starred)
- albumsRecentButton = buttons.findViewById(R.id.main_albums_recent)
- albumsFrequentButton = buttons.findViewById(R.id.main_albums_frequent)
- albumsAlphaByNameButton = buttons.findViewById(R.id.main_albums_alphaByName)
- albumsAlphaByArtistButton = buttons.findViewById(R.id.main_albums_alphaByArtist)
- videosButton = buttons.findViewById(R.id.main_videos)
+ musicTitle = list.findViewById(R.id.main_music)
+ artistsButton = list.findViewById(R.id.main_artists_button)
+ albumsButton = list.findViewById(R.id.main_albums_button)
+ genresButton = list.findViewById(R.id.main_genres_button)
+ videosTitle = list.findViewById(R.id.main_videos_title)
+ songsTitle = list.findViewById(R.id.main_songs)
+ randomSongsButton = list.findViewById(R.id.main_songs_button)
+ songsStarredButton = list.findViewById(R.id.main_songs_starred)
+ albumsTitle = list.findViewById(R.id.main_albums)
+ albumsNewestButton = list.findViewById(R.id.main_albums_newest)
+ albumsRandomButton = list.findViewById(R.id.main_albums_random)
+ albumsHighestButton = list.findViewById(R.id.main_albums_highest)
+ albumsStarredButton = list.findViewById(R.id.main_albums_starred)
+ albumsRecentButton = list.findViewById(R.id.main_albums_recent)
+ albumsFrequentButton = list.findViewById(R.id.main_albums_frequent)
+ albumsAlphaByNameButton = list.findViewById(R.id.main_albums_alphaByName)
+ albumsAlphaByArtistButton = list.findViewById(R.id.main_albums_alphaByArtist)
+ videosButton = list.findViewById(R.id.main_videos)
}
- private fun setupMenuList(list: ListView) {
+ private fun setupItemVisibility() {
+ // Cache some values
+ cachedId3Setting = Settings.shouldUseId3Tags
+ val isOnline = !isOffline()
- // TODO: Should use RecyclerView
- val adapter = MergeAdapter()
+ // Music
+ musicTitle.isVisible = true
+ artistsButton.isVisible = true
+ albumsButton.isVisible = isOnline
+ genresButton.isVisible = true
- shouldUseId3 = Settings.shouldUseId3Tags
+ // Songs
+ songsTitle.isVisible = isOnline
+ randomSongsButton.isVisible = true
+ songsStarredButton.isVisible = isOnline
- if (!isOffline()) {
- adapter.addView(musicTitle, false)
- adapter.addViews(listOf(artistsButton, albumsButton, genresButton), true)
- adapter.addView(songsTitle, false)
- adapter.addViews(listOf(randomSongsButton, songsStarredButton), true)
- adapter.addView(albumsTitle, false)
- adapter.addViews(
- listOf(
- albumsNewestButton,
- albumsRecentButton,
- albumsFrequentButton
- ),
- true
- )
- if (!shouldUseId3) {
- adapter.addView(albumsHighestButton, true)
- }
- adapter.addViews(
- listOf(
- albumsRandomButton,
- albumsStarredButton,
- albumsAlphaByNameButton,
- albumsAlphaByArtistButton
- ),
- true
- )
- adapter.addView(videosTitle, false)
- adapter.addViews(listOf(videosButton), true)
- } else {
- // Offline supported calls
- adapter.addView(musicTitle, false)
- adapter.addViews(listOf(artistsButton, genresButton), true)
- adapter.addView(songsTitle, false)
- adapter.addView(randomSongsButton, true)
- }
+ // Albums
+ albumsTitle.isVisible = isOnline
+ albumsNewestButton.isVisible = isOnline
+ albumsRecentButton.isVisible = isOnline
+ albumsFrequentButton.isVisible = isOnline
+ albumsHighestButton.isVisible = isOnline && !cachedId3Setting
+ albumsRandomButton.isVisible = isOnline
+ albumsStarredButton.isVisible = isOnline
+ albumsAlphaByNameButton.isVisible = isOnline
+ albumsAlphaByArtistButton.isVisible = isOnline
- list.adapter = adapter
- list.onItemClickListener = listListener
+ // Videos
+ videosTitle.isVisible = isOnline
+ videosButton.isVisible = isOnline
}
- private val listListener =
- OnItemClickListener { _: AdapterView<*>?, view: View, _: Int, _: Long ->
- when {
- view === albumsNewestButton -> {
- showAlbumList("newest", R.string.main_albums_newest)
- }
- view === albumsRandomButton -> {
- showAlbumList("random", R.string.main_albums_random)
- }
- view === albumsHighestButton -> {
- showAlbumList("highest", R.string.main_albums_highest)
- }
- view === albumsRecentButton -> {
- showAlbumList("recent", R.string.main_albums_recent)
- }
- view === albumsFrequentButton -> {
- showAlbumList("frequent", R.string.main_albums_frequent)
- }
- view === albumsStarredButton -> {
- showAlbumList(Constants.STARRED, R.string.main_albums_starred)
- }
- view === albumsAlphaByNameButton -> {
- showAlbumList(Constants.ALPHABETICAL_BY_NAME, R.string.main_albums_alphaByName)
- }
- view === albumsAlphaByArtistButton -> {
- showAlbumList("alphabeticalByArtist", R.string.main_albums_alphaByArtist)
- }
- view === songsStarredButton -> {
- showStarredSongs()
- }
- view === artistsButton -> {
- showArtists()
- }
- view === albumsButton -> {
- showAlbumList(Constants.ALPHABETICAL_BY_NAME, R.string.main_albums_title)
- }
- view === randomSongsButton -> {
- showRandomSongs()
- }
- view === genresButton -> {
- showGenres()
- }
- view === videosButton -> {
- showVideos()
- }
- }
+ private fun setupClickListener() {
+ albumsNewestButton.setOnClickListener {
+ showAlbumList("newest", R.string.main_albums_newest)
}
+ albumsRandomButton.setOnClickListener {
+ showAlbumList("random", R.string.main_albums_random)
+ }
+
+ albumsHighestButton.setOnClickListener {
+ showAlbumList("highest", R.string.main_albums_highest)
+ }
+
+ albumsRecentButton.setOnClickListener {
+ showAlbumList("recent", R.string.main_albums_recent)
+ }
+
+ albumsFrequentButton.setOnClickListener {
+ showAlbumList("frequent", R.string.main_albums_frequent)
+ }
+
+ albumsStarredButton.setOnClickListener {
+ showAlbumList(Constants.STARRED, R.string.main_albums_starred)
+ }
+
+ albumsAlphaByNameButton.setOnClickListener {
+ showAlbumList(Constants.ALPHABETICAL_BY_NAME, R.string.main_albums_alphaByName)
+ }
+
+ albumsAlphaByArtistButton.setOnClickListener {
+ showAlbumList("alphabeticalByArtist", R.string.main_albums_alphaByArtist)
+ }
+
+ songsStarredButton.setOnClickListener {
+ showStarredSongs()
+ }
+
+ artistsButton.setOnClickListener {
+ showArtists()
+ }
+
+ albumsButton.setOnClickListener {
+ showAlbumList(Constants.ALPHABETICAL_BY_NAME, R.string.main_albums_title)
+ }
+
+ randomSongsButton.setOnClickListener {
+ showRandomSongs()
+ }
+
+ genresButton.setOnClickListener {
+ showGenres()
+ }
+
+ videosButton.setOnClickListener {
+ showVideos()
+ }
+ }
+
private fun showStarredSongs() {
val bundle = Bundle()
bundle.putInt(Constants.INTENT_STARRED, 1)
@@ -242,6 +235,6 @@ class MainFragment : Fragment(), KoinComponent {
}
companion object {
- private var shouldUseId3 = false
+ private var cachedId3Setting = false
}
}
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 04f9c2d3..e1a145ae 100644
--- a/ultrasonic/src/main/kotlin/org/moire/ultrasonic/fragment/PlayerFragment.kt
+++ b/ultrasonic/src/main/kotlin/org/moire/ultrasonic/fragment/PlayerFragment.kt
@@ -70,8 +70,6 @@ import org.moire.ultrasonic.domain.Identifiable
import org.moire.ultrasonic.domain.MusicDirectory
import org.moire.ultrasonic.domain.PlayerState
import org.moire.ultrasonic.domain.RepeatMode
-import org.moire.ultrasonic.featureflags.Feature
-import org.moire.ultrasonic.featureflags.FeatureStorage
import org.moire.ultrasonic.fragment.FragmentTitle.Companion.setTitle
import org.moire.ultrasonic.service.DownloadFile
import org.moire.ultrasonic.service.LocalMediaPlayer
@@ -210,7 +208,7 @@ class PlayerFragment :
val width = size.x
val height = size.y
setHasOptionsMenu(true)
- useFiveStarRating = get().isFeatureEnabled(Feature.FIVE_STAR_RATING)
+ useFiveStarRating = Settings.useFiveStarRating
swipeDistance = (width + height) * PERCENTAGE_OF_SCREEN_FOR_SWIPE / 100
swipeVelocity = swipeDistance
gestureScanner = GestureDetector(context, this)
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 e49a79fd..b551fd29 100644
--- a/ultrasonic/src/main/kotlin/org/moire/ultrasonic/fragment/SettingsFragment.kt
+++ b/ultrasonic/src/main/kotlin/org/moire/ultrasonic/fragment/SettingsFragment.kt
@@ -23,12 +23,9 @@ import androidx.preference.PreferenceFragmentCompat
import java.io.File
import kotlin.math.ceil
import org.koin.core.component.KoinComponent
-import org.koin.java.KoinJavaComponent.get
import org.koin.java.KoinJavaComponent.inject
import org.moire.ultrasonic.R
import org.moire.ultrasonic.app.UApp
-import org.moire.ultrasonic.featureflags.Feature
-import org.moire.ultrasonic.featureflags.FeatureStorage
import org.moire.ultrasonic.fragment.FragmentTitle.Companion.setTitle
import org.moire.ultrasonic.log.FileLoggerTree
import org.moire.ultrasonic.log.FileLoggerTree.Companion.deleteLogFiles
@@ -144,7 +141,6 @@ class SettingsFragment :
sharingDefaultGreeting!!.text = shareGreeting
setupClearSearchPreference()
- setupFeatureFlagsPreferences()
setupCacheLocationPreference()
setupBluetoothDevicePreferences()
@@ -377,21 +373,6 @@ class SettingsFragment :
}
}
- private fun setupFeatureFlagsPreferences() {
- val featureStorage = get(FeatureStorage::class.java)
- val useFiveStarRating = findPreference(
- Constants.PREFERENCES_KEY_USE_FIVE_STAR_RATING
- ) as CheckBoxPreference?
- if (useFiveStarRating != null) {
- useFiveStarRating.isChecked = featureStorage.isFeatureEnabled(Feature.FIVE_STAR_RATING)
- useFiveStarRating.onPreferenceChangeListener =
- Preference.OnPreferenceChangeListener { _: Preference?, o: Any? ->
- featureStorage.changeFeatureFlag(Feature.FIVE_STAR_RATING, (o as Boolean?)!!)
- true
- }
- }
- }
-
private fun update() {
theme!!.summary = theme!!.entry
maxBitrateWifi!!.summary = maxBitrateWifi!!.entry
diff --git a/ultrasonic/src/main/kotlin/org/moire/ultrasonic/service/MediaPlayerController.kt b/ultrasonic/src/main/kotlin/org/moire/ultrasonic/service/MediaPlayerController.kt
index 55bffc4c..55cf2796 100644
--- a/ultrasonic/src/main/kotlin/org/moire/ultrasonic/service/MediaPlayerController.kt
+++ b/ultrasonic/src/main/kotlin/org/moire/ultrasonic/service/MediaPlayerController.kt
@@ -8,15 +8,12 @@ package org.moire.ultrasonic.service
import android.content.Intent
import org.koin.core.component.KoinComponent
-import org.koin.core.component.get
import org.koin.core.component.inject
import org.moire.ultrasonic.app.UApp
import org.moire.ultrasonic.data.ActiveServerProvider
import org.moire.ultrasonic.domain.MusicDirectory
import org.moire.ultrasonic.domain.PlayerState
import org.moire.ultrasonic.domain.RepeatMode
-import org.moire.ultrasonic.featureflags.Feature
-import org.moire.ultrasonic.featureflags.FeatureStorage
import org.moire.ultrasonic.service.MediaPlayerService.Companion.executeOnStartedMediaPlayerService
import org.moire.ultrasonic.service.MediaPlayerService.Companion.getInstance
import org.moire.ultrasonic.service.MediaPlayerService.Companion.runningInstance
@@ -473,8 +470,7 @@ class MediaPlayerController(
@Suppress("TooGenericExceptionCaught") // The interface throws only generic exceptions
fun setSongRating(rating: Int) {
- val features: FeatureStorage = get()
- if (!features.isFeatureEnabled(Feature.FIVE_STAR_RATING)) return
+ if (!Settings.useFiveStarRating) return
if (localMediaPlayer.currentPlaying == null) return
val song = localMediaPlayer.currentPlaying!!.song
song.userRating = rating
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 29c13b18..e5240e33 100644
--- a/ultrasonic/src/main/kotlin/org/moire/ultrasonic/util/Settings.kt
+++ b/ultrasonic/src/main/kotlin/org/moire/ultrasonic/util/Settings.kt
@@ -297,11 +297,6 @@ object Settings {
return 0
}
- var shouldShowAllSongsByArtist by BooleanSetting(
- Constants.PREFERENCES_KEY_SHOW_ALL_SONGS_BY_ARTIST,
- false
- )
-
@JvmStatic
var resumeOnBluetoothDevice by IntSetting(
Constants.PREFERENCES_KEY_RESUME_ON_BLUETOOTH_DEVICE,
@@ -320,6 +315,18 @@ object Settings {
val preferences: SharedPreferences
get() = PreferenceManager.getDefaultSharedPreferences(Util.appContext())
+ var useFiveStarRating by BooleanSetting(Constants.PREFERENCES_KEY_USE_FIVE_STAR_RATING, false)
+
+ // TODO: Remove in December 2022
+ fun migrateFeatureStorage() {
+ val sp = appContext.getSharedPreferences("feature_flags", Context.MODE_PRIVATE)
+ useFiveStarRating = sp.getBoolean("FIVE_STAR_RATING", false)
+ }
+
+ fun hasKey(key: String): Boolean {
+ return preferences.contains(key)
+ }
+
private val appContext: Context
get() {
return UApp.applicationContext()
diff --git a/ultrasonic/src/main/res/layout/main.xml b/ultrasonic/src/main/res/layout/main.xml
index dcd8fbd0..e6763155 100644
--- a/ultrasonic/src/main/res/layout/main.xml
+++ b/ultrasonic/src/main/res/layout/main.xml
@@ -1,18 +1,211 @@
+ a:orientation="vertical">
-
+ a:layout_height="wrap_content"
+ a:gravity="center_vertical"
+ a:paddingStart="6dp"
+ a:text="@string/main.music"
+ a:textAllCaps="true"
+ a:textAppearance="?android:attr/textAppearanceSmall"
+ a:textColor="@color/cyan"
+ a:textStyle="bold" />
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
\ No newline at end of file
diff --git a/ultrasonic/src/main/res/layout/main_buttons.xml b/ultrasonic/src/main/res/layout/main_buttons.xml
deleted file mode 100644
index ef1395c7..00000000
--- a/ultrasonic/src/main/res/layout/main_buttons.xml
+++ /dev/null
@@ -1,100 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/ultrasonic/src/main/res/values-cs/strings.xml b/ultrasonic/src/main/res/values-cs/strings.xml
index d4819465..034a12f0 100644
--- a/ultrasonic/src/main/res/values-cs/strings.xml
+++ b/ultrasonic/src/main/res/values-cs/strings.xml
@@ -428,10 +428,10 @@
Nekompatibilní verze. Aktualizujte prosím Ultrasonic Android aplikaci.
Nekompatibilní verze. Aktualizujte prosím Subsonic server.
-
- Příznaky funkcí
- Používat pět hvězdiček pro hodnocení skladeb
- Používat pět hvězdiček pro hodnocení skladeb
+
+ Příznaky funkcí
+ Používat pět hvězdiček pro hodnocení skladeb
+ Používat pět hvězdiček pro hodnocení skladeb
namísto jednoduchého jednohvězdičkového hodnocení.
diff --git a/ultrasonic/src/main/res/values-de/strings.xml b/ultrasonic/src/main/res/values-de/strings.xml
index 03b7b4a1..32fedc2a 100644
--- a/ultrasonic/src/main/res/values-de/strings.xml
+++ b/ultrasonic/src/main/res/values-de/strings.xml
@@ -360,10 +360,10 @@
Inkompatible Versionen. Bitte die Ultrasonic App aktualisieren.
Inkompatible Versionen. Bitte den subsonic Server aktualisieren.
-
- Funktionseinstellungem
- Verwenden Sie Fünf-Sterne-Bewertung für Songs
- Verwenden Sie Fünf-Sterne-Bewertungssystem für Songs
+
+ Funktionseinstellungem
+ Verwenden Sie Fünf-Sterne-Bewertung für Songs
+ Verwenden Sie Fünf-Sterne-Bewertungssystem für Songs
anstatt einfach Elemente zu markieren / zu entfernen.
diff --git a/ultrasonic/src/main/res/values-es/strings.xml b/ultrasonic/src/main/res/values-es/strings.xml
index 75ef533d..c3010b41 100644
--- a/ultrasonic/src/main/res/values-es/strings.xml
+++ b/ultrasonic/src/main/res/values-es/strings.xml
@@ -450,10 +450,10 @@
Versiones incompatibles. Por favor actualiza la aplicación de Android Ultrasonic.
Versiones incompatibles. Por favor actualiza el servidor de Subsonic.
-
- Funciones experimentales
- Use cinco estrellas para las canciones
- Utilice el sistema de calificación de cinco estrellas para canciones
+
+ Funciones experimentales
+ Use cinco estrellas para las canciones
+ Utilice el sistema de calificación de cinco estrellas para canciones
en lugar de simplemente destacar / desestimar elementos.
diff --git a/ultrasonic/src/main/res/values-fr/strings.xml b/ultrasonic/src/main/res/values-fr/strings.xml
index d59744f2..c538e37a 100644
--- a/ultrasonic/src/main/res/values-fr/strings.xml
+++ b/ultrasonic/src/main/res/values-fr/strings.xml
@@ -439,10 +439,10 @@
Versions incompatibles. Veuillez mette à jour l\'application Android Ultrasonic.
Versions incompatibles. Veuillez mette à jour le serveur Subsonic.
-
- Drapeaux des fonctionnalités
- Utiliser les étoiles pour noter les morceaux
- Utiliser un système de notation à base d\'étoiles pour les morceaux
+
+ Drapeaux des fonctionnalités
+ Utiliser les étoiles pour noter les morceaux
+ Utiliser un système de notation à base d\'étoiles pour les morceaux
au lieu de simplement mettre en avant les morceaux.
diff --git a/ultrasonic/src/main/res/values-hu/strings.xml b/ultrasonic/src/main/res/values-hu/strings.xml
index d8f35055..efa3dcd0 100644
--- a/ultrasonic/src/main/res/values-hu/strings.xml
+++ b/ultrasonic/src/main/res/values-hu/strings.xml
@@ -434,10 +434,10 @@
Nem kompatibilis verzió. Kérjük, frissítse az Ultrasonic Android alkalmazást!
Nem kompatibilis verzió. Kérjük, frissítse a Subsonic kiszolgálót!
-
- Jellemzők Zászlók
- Öt csillagos értékelés használata a dalokhoz
- Öt csillag használata az értékeléshez az egyszerű
+
+ Jellemzők Zászlók
+ Öt csillagos értékelés használata a dalokhoz
+ Öt csillag használata az értékeléshez az egyszerű
csillaggal jelölés helyett.
diff --git a/ultrasonic/src/main/res/values-nl/strings.xml b/ultrasonic/src/main/res/values-nl/strings.xml
index 5478b41b..194afb24 100644
--- a/ultrasonic/src/main/res/values-nl/strings.xml
+++ b/ultrasonic/src/main/res/values-nl/strings.xml
@@ -450,10 +450,10 @@
Incompatibele versies. Werk de Ultrasonic Android-app bij.
Incompatibele versies. Werk je Subsonic-server bij.
-
- Experimentele functies
- Gebruik vijf sterren voor nummers
- Gebruik vijf sterren ratingsysteem voor liedjes
+
+ Experimentele functies
+ Gebruik vijf sterren voor nummers
+ Gebruik vijf sterren ratingsysteem voor liedjes
in plaats van items simpelweg in de hoofdrol te zetten / niet te verwijderen.
diff --git a/ultrasonic/src/main/res/values-pl/strings.xml b/ultrasonic/src/main/res/values-pl/strings.xml
index 1651e37e..8832e780 100644
--- a/ultrasonic/src/main/res/values-pl/strings.xml
+++ b/ultrasonic/src/main/res/values-pl/strings.xml
@@ -404,10 +404,10 @@ ponieważ api Subsonic nie wspiera nowego sposobu autoryzacji dla użytkowników
Brak zgodności wersji. Uaktualnij aplikację Ultrasonic na Androida.
Brak zgodności wersji. Uaktualnij serwer Subsonic.
-
- Flagi funkcji
- Użyj pięciu gwiazdek dla utworów
- W przypadku utworów użyj systemu pięciu gwiazdek
+
+ Flagi funkcji
+ Użyj pięciu gwiazdek dla utworów
+ W przypadku utworów użyj systemu pięciu gwiazdek
zamiast po prostu grać gwiazdkami / bez gwiazd.
diff --git a/ultrasonic/src/main/res/values-pt-rBR/strings.xml b/ultrasonic/src/main/res/values-pt-rBR/strings.xml
index 781e6ec3..5fd380a2 100644
--- a/ultrasonic/src/main/res/values-pt-rBR/strings.xml
+++ b/ultrasonic/src/main/res/values-pt-rBR/strings.xml
@@ -443,10 +443,10 @@
Versões incompativeis. Atualize o aplicativo Ultrasonic para Android.
Versões incompativeis. Atualize o servidor Ultrasonic.
-
- Sinalização de Recursos
- Usar Classif. 5 Estrelas para Músicas
- Usar o sistema de classificação de 5 estrelas para músicas
+
+ Sinalização de Recursos
+ Usar Classif. 5 Estrelas para Músicas
+ Usar o sistema de classificação de 5 estrelas para músicas
em vez de simplesmente estrelar/não estrelar itens
diff --git a/ultrasonic/src/main/res/values-pt/strings.xml b/ultrasonic/src/main/res/values-pt/strings.xml
index 21d56dae..1a277b2d 100644
--- a/ultrasonic/src/main/res/values-pt/strings.xml
+++ b/ultrasonic/src/main/res/values-pt/strings.xml
@@ -389,10 +389,10 @@
Versões incompativeis. Atualize o aplicativo Ultrasonic para Android.
Versões incompativeis. Atualize o servidor Ultrasonic.
-
- Bandeiras de recursos
- Use classificação de cinco estrelas para músicas
- Use o sistema de classificação de cinco estrelas para músicas
+
+ Bandeiras de recursos
+ Use classificação de cinco estrelas para músicas
+ Use o sistema de classificação de cinco estrelas para músicas
em vez de simplesmente estrelar / não estrelar itens.
diff --git a/ultrasonic/src/main/res/values-ru/strings.xml b/ultrasonic/src/main/res/values-ru/strings.xml
index 9be7d70b..28c81902 100644
--- a/ultrasonic/src/main/res/values-ru/strings.xml
+++ b/ultrasonic/src/main/res/values-ru/strings.xml
@@ -453,10 +453,10 @@
Несовместимые версии. Пожалуйста, обновите приложение Ultrasonic для Android.
Несовместимые версии. Пожалуйста, обновите Subsonic сервер.
-
- Флаги
- Использовать пятизвездочный рейтинг для песен
- Использовать пятизвездочную систему рейтинга для песен
+
+ Флаги
+ Использовать пятизвездочный рейтинг для песен
+ Использовать пятизвездочную систему рейтинга для песен
вместо того, чтобы просто ставить/не ставить звезды.
diff --git a/ultrasonic/src/main/res/values-zh-rCN/strings.xml b/ultrasonic/src/main/res/values-zh-rCN/strings.xml
index 7e4a1e04..97927f41 100644
--- a/ultrasonic/src/main/res/values-zh-rCN/strings.xml
+++ b/ultrasonic/src/main/res/values-zh-rCN/strings.xml
@@ -432,10 +432,10 @@
版本不兼容,请升级 Ultrasonic 应用。
不兼容的版本。请升级Subsonic 服务。
-
- 特性标志
- 为歌曲使用五星评分
- 对歌曲使用五星级评级系统
+
+ 特性标志
+ 为歌曲使用五星评分
+ 对歌曲使用五星级评级系统
而不是简单地为项目加星标/取消星标。
diff --git a/ultrasonic/src/main/res/values/strings.xml b/ultrasonic/src/main/res/values/strings.xml
index 1e744543..04bbc31f 100644
--- a/ultrasonic/src/main/res/values/strings.xml
+++ b/ultrasonic/src/main/res/values/strings.xml
@@ -461,10 +461,10 @@
Incompatible versions. Please upgrade Ultrasonic Android app.
Incompatible versions. Please upgrade Subsonic server.
-
- Feature Flags
- Use five star rating for songs
- Use five star rating system for songs
+
+ Features
+ Use five star rating for songs
+ Use five star rating system for songs
instead of simply starring/unstarring items.
diff --git a/ultrasonic/src/main/res/xml/settings.xml b/ultrasonic/src/main/res/xml/settings.xml
index 73c611f6..5f96a81b 100644
--- a/ultrasonic/src/main/res/xml/settings.xml
+++ b/ultrasonic/src/main/res/xml/settings.xml
@@ -345,14 +345,14 @@
app:iconSpaceReserved="false"/>
+ a:summary="@string/settings.five_star_rating_description"
+ a:title="@string/settings.five_star_rating_title"
+ app:iconSpaceReserved="false" />