Merge pull request #585 from nitehu/fix/avrcp_compatibility

Added setting to disable Now Playing List sending for incompatible bluetooth devices
This commit is contained in:
Nite 2021-09-24 20:29:43 +02:00 committed by GitHub
commit 2237b476dc
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
44 changed files with 655 additions and 538 deletions

View File

@ -30,6 +30,7 @@ import org.moire.ultrasonic.service.MusicServiceFactory;
import org.moire.ultrasonic.util.BackgroundTask;
import org.moire.ultrasonic.util.CancellationToken;
import org.moire.ultrasonic.util.FragmentBackgroundTask;
import org.moire.ultrasonic.util.Settings;
import org.moire.ultrasonic.util.Util;
import org.moire.ultrasonic.view.ChatAdapter;
@ -202,7 +203,7 @@ public class ChatFragment extends Fragment {
private void timerMethod()
{
int refreshInterval = Util.getChatRefreshInterval();
int refreshInterval = Settings.getChatRefreshInterval();
if (refreshInterval > 0)
{

View File

@ -18,10 +18,8 @@ import org.moire.ultrasonic.data.ActiveServerProvider
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.Util.applyTheme
import org.moire.ultrasonic.util.Util.getMaxAlbums
import org.moire.ultrasonic.util.Util.getMaxSongs
import org.moire.ultrasonic.util.Util.getShouldUseId3Tags
import org.moire.ultrasonic.util.Settings
import org.moire.ultrasonic.util.Util
/**
* Displays the Main screen of Ultrasonic, where the music library can be browsed
@ -53,7 +51,7 @@ class MainFragment : Fragment(), KoinComponent {
private val activeServerProvider: ActiveServerProvider by inject()
override fun onCreate(savedInstanceState: Bundle?) {
applyTheme(this.context)
Util.applyTheme(this.context)
super.onCreate(savedInstanceState)
}
@ -79,7 +77,7 @@ class MainFragment : Fragment(), KoinComponent {
override fun onResume() {
super.onResume()
var shouldRestart = false
val currentId3Setting = getShouldUseId3Tags()
val currentId3Setting = Settings.shouldUseId3Tags
val currentActiveServerProperties = getActiveServerProperties()
// If setting has changed...
@ -134,7 +132,7 @@ class MainFragment : Fragment(), KoinComponent {
adapter.addView(serverButton, true)
shouldUseId3 = getShouldUseId3Tags()
shouldUseId3 = Settings.shouldUseId3Tags
if (!isOffline()) {
adapter.addView(musicTitle, false)
@ -250,7 +248,7 @@ class MainFragment : Fragment(), KoinComponent {
private fun showRandomSongs() {
val bundle = Bundle()
bundle.putInt(Constants.INTENT_EXTRA_NAME_RANDOM, 1)
bundle.putInt(Constants.INTENT_EXTRA_NAME_ALBUM_LIST_SIZE, getMaxSongs())
bundle.putInt(Constants.INTENT_EXTRA_NAME_ALBUM_LIST_SIZE, Settings.maxSongs)
Navigation.findNavController(requireView()).navigate(R.id.mainToTrackCollection, bundle)
}
@ -268,7 +266,7 @@ class MainFragment : Fragment(), KoinComponent {
val title = requireContext().resources.getString(titleIndex, "")
bundle.putString(Constants.INTENT_EXTRA_NAME_ALBUM_LIST_TYPE, type)
bundle.putString(Constants.INTENT_EXTRA_NAME_ALBUM_LIST_TITLE, title)
bundle.putInt(Constants.INTENT_EXTRA_NAME_ALBUM_LIST_SIZE, getMaxAlbums())
bundle.putInt(Constants.INTENT_EXTRA_NAME_ALBUM_LIST_SIZE, Settings.maxAlbums)
bundle.putInt(Constants.INTENT_EXTRA_NAME_ALBUM_LIST_OFFSET, 0)
Navigation.findNavController(requireView()).navigate(R.id.mainToAlbumList, bundle)
}

View File

@ -22,6 +22,7 @@ import org.moire.ultrasonic.subsonic.ImageLoaderProvider;
import org.moire.ultrasonic.util.Constants;
import org.moire.ultrasonic.util.NowPlayingEventDistributor;
import org.moire.ultrasonic.util.NowPlayingEventListener;
import org.moire.ultrasonic.util.Settings;
import org.moire.ultrasonic.util.Util;
import kotlin.Lazy;
@ -115,7 +116,7 @@ public class NowPlayingFragment extends Fragment {
nowPlayingAlbumArtImage.setOnClickListener(v -> {
Bundle bundle = new Bundle();
if (Util.getShouldUseId3Tags()) {
if (Settings.getShouldUseId3Tags()) {
bundle.putBoolean(Constants.INTENT_EXTRA_NAME_IS_ALBUM, true);
bundle.putString(Constants.INTENT_EXTRA_NAME_ID, song.getAlbumId());
} else {

View File

@ -44,6 +44,7 @@ import org.moire.ultrasonic.util.CancellationToken;
import org.moire.ultrasonic.util.Constants;
import org.moire.ultrasonic.util.MergeAdapter;
import org.moire.ultrasonic.util.FragmentBackgroundTask;
import org.moire.ultrasonic.util.Settings;
import org.moire.ultrasonic.util.Util;
import org.moire.ultrasonic.view.ArtistAdapter;
import org.moire.ultrasonic.view.EntryAdapter;
@ -112,9 +113,9 @@ public class SearchFragment extends Fragment {
FragmentTitle.Companion.setTitle(this, R.string.search_title);
setHasOptionsMenu(true);
DEFAULT_ARTISTS = Util.getDefaultArtists();
DEFAULT_ALBUMS = Util.getDefaultAlbums();
DEFAULT_SONGS = Util.getDefaultSongs();
DEFAULT_ARTISTS = Settings.getDefaultArtists();
DEFAULT_ALBUMS = Settings.getDefaultAlbums();
DEFAULT_SONGS = Settings.getDefaultSongs();
View buttons = LayoutInflater.from(getContext()).inflate(R.layout.search_buttons, list, false);
@ -409,9 +410,9 @@ public class SearchFragment extends Fragment {
private void search(final String query, final boolean autoplay)
{
final int maxArtists = Util.getMaxArtists();
final int maxAlbums = Util.getMaxAlbums();
final int maxSongs = Util.getMaxSongs();
final int maxArtists = Settings.getMaxArtists();
final int maxAlbums = Settings.getMaxAlbums();
final int maxSongs = Settings.getMaxSongs();
BackgroundTask<SearchResult> task = new FragmentBackgroundTask<SearchResult>(getActivity(), true, searchRefresh, cancellationToken)
{

View File

@ -21,6 +21,7 @@ import org.moire.ultrasonic.util.BackgroundTask;
import org.moire.ultrasonic.util.CancellationToken;
import org.moire.ultrasonic.util.Constants;
import org.moire.ultrasonic.util.FragmentBackgroundTask;
import org.moire.ultrasonic.util.Settings;
import org.moire.ultrasonic.util.Util;
import org.moire.ultrasonic.view.GenreAdapter;
@ -75,7 +76,7 @@ public class SelectGenreFragment extends Fragment {
{
Bundle bundle = new Bundle();
bundle.putString(Constants.INTENT_EXTRA_NAME_GENRE_NAME, genre.getName());
bundle.putInt(Constants.INTENT_EXTRA_NAME_ALBUM_LIST_SIZE, Util.getMaxSongs());
bundle.putInt(Constants.INTENT_EXTRA_NAME_ALBUM_LIST_SIZE, Settings.getMaxSongs());
bundle.putInt(Constants.INTENT_EXTRA_NAME_ALBUM_LIST_OFFSET, 0);
Navigation.findNavController(view).navigate(R.id.trackCollectionFragment, bundle);
}

View File

@ -35,6 +35,7 @@ import org.moire.ultrasonic.util.Constants;
import org.moire.ultrasonic.util.FileUtil;
import org.moire.ultrasonic.util.MediaSessionHandler;
import org.moire.ultrasonic.util.PermissionUtil;
import org.moire.ultrasonic.util.Settings;
import org.moire.ultrasonic.util.ThemeChangedEventDistributor;
import org.moire.ultrasonic.util.TimeSpanPreference;
import org.moire.ultrasonic.util.TimeSpanPreferenceDialogFragmentCompat;
@ -141,7 +142,7 @@ public class SettingsFragment extends PreferenceFragmentCompat
showArtistPicture = findPreference(Constants.PREFERENCES_KEY_SHOW_ARTIST_PICTURE);
setupServersCategory();
sharingDefaultGreeting.setText(Util.getShareGreeting());
sharingDefaultGreeting.setText(Settings.getShareGreeting());
setupClearSearchPreference();
setupGaplessControlSettingsV14();
setupFeatureFlagsPreferences();
@ -168,14 +169,14 @@ public class SettingsFragment extends PreferenceFragmentCompat
@Override
public void onResume() {
super.onResume();
SharedPreferences preferences = Util.getPreferences();
SharedPreferences preferences = Settings.getPreferences();
preferences.registerOnSharedPreferenceChangeListener(this);
}
@Override
public void onPause() {
super.onPause();
SharedPreferences prefs = Util.getPreferences();
SharedPreferences prefs = Settings.getPreferences();
prefs.unregisterOnSharedPreferenceChangeListener(this);
}
@ -257,8 +258,8 @@ public class SettingsFragment extends PreferenceFragmentCompat
}
private void setupBluetoothDevicePreferences() {
final int resumeSetting = Util.getResumeOnBluetoothDevice();
final int pauseSetting = Util.getPauseOnBluetoothDevice();
final int resumeSetting = Settings.getResumeOnBluetoothDevice();
final int pauseSetting = Settings.getPauseOnBluetoothDevice();
resumeOnBluetoothDevice.setSummary(bluetoothDevicePreferenceToString(resumeSetting));
pauseOnBluetoothDevice.setSummary(bluetoothDevicePreferenceToString(pauseSetting));
@ -268,7 +269,7 @@ public class SettingsFragment extends PreferenceFragmentCompat
public boolean onPreferenceClick(Preference preference) {
showBluetoothDevicePreferenceDialog(
R.string.settings_playback_resume_on_bluetooth_device,
Util.getResumeOnBluetoothDevice(),
Settings.getResumeOnBluetoothDevice(),
new Consumer<Integer>() {
@Override
public void accept(Integer choice) {
@ -287,7 +288,7 @@ public class SettingsFragment extends PreferenceFragmentCompat
public boolean onPreferenceClick(Preference preference) {
showBluetoothDevicePreferenceDialog(
R.string.settings_playback_pause_on_bluetooth_device,
Util.getPauseOnBluetoothDevice(),
Settings.getPauseOnBluetoothDevice(),
new Consumer<Integer>() {
@Override
public void accept(Integer choice) {
@ -450,7 +451,7 @@ public class SettingsFragment extends PreferenceFragmentCompat
debugLogToFile.setSummary("");
}
showArtistPicture.setEnabled(Util.getShouldUseId3Tags());
showArtistPicture.setEnabled(Settings.getShouldUseId3Tags());
}

View File

@ -26,6 +26,7 @@ import android.content.Intent;
import timber.log.Timber;
import org.moire.ultrasonic.util.Constants;
import org.moire.ultrasonic.util.Settings;
import org.moire.ultrasonic.util.Util;
/**
@ -66,7 +67,7 @@ public class BluetoothIntentReceiver extends BroadcastReceiver
boolean resume = false;
boolean pause = false;
switch (Util.getResumeOnBluetoothDevice())
switch (Settings.getResumeOnBluetoothDevice())
{
case Constants.PREFERENCE_VALUE_ALL: resume = actionA2dpConnected || actionBluetoothDeviceConnected;
break;
@ -74,7 +75,7 @@ public class BluetoothIntentReceiver extends BroadcastReceiver
break;
}
switch (Util.getPauseOnBluetoothDevice())
switch (Settings.getPauseOnBluetoothDevice())
{
case Constants.PREFERENCE_VALUE_ALL: pause = actionA2dpDisconnected || actionBluetoothDeviceDisconnected;
break;

View File

@ -27,6 +27,7 @@ import timber.log.Timber;
import org.moire.ultrasonic.service.MediaPlayerLifecycleSupport;
import org.moire.ultrasonic.util.Constants;
import org.moire.ultrasonic.util.Settings;
import org.moire.ultrasonic.util.Util;
import kotlin.Lazy;
@ -46,7 +47,7 @@ public class MediaButtonIntentReceiver extends BroadcastReceiver
String intentAction = intent.getAction();
// If media button are turned off and we received a media button, exit
if (!Util.getMediaButtonsEnabled() && Intent.ACTION_MEDIA_BUTTON.equals(intentAction))
if (!Settings.getMediaButtonsEnabled() && Intent.ACTION_MEDIA_BUTTON.equals(intentAction))
return;
// Only process media buttons and CMD_PROCESS_KEYCODE, which is received from the widgets

View File

@ -10,11 +10,9 @@ import org.koin.core.component.inject
import org.moire.ultrasonic.domain.MusicDirectory
import org.moire.ultrasonic.domain.PlayerState
import org.moire.ultrasonic.util.LRUCache
import org.moire.ultrasonic.util.Settings
import org.moire.ultrasonic.util.ShufflePlayBuffer
import org.moire.ultrasonic.util.Util.getMaxSongs
import org.moire.ultrasonic.util.Util.getPreloadCount
import org.moire.ultrasonic.util.Util.isExternalStoragePresent
import org.moire.ultrasonic.util.Util.isNetworkConnected
import org.moire.ultrasonic.util.Util
import timber.log.Timber
/**
@ -78,13 +76,16 @@ class Downloader(
@Synchronized
fun checkDownloadsInternal() {
if (!isExternalStoragePresent() || !externalStorageMonitor.isExternalStorageAvailable) {
if (
!Util.isExternalStoragePresent() ||
!externalStorageMonitor.isExternalStorageAvailable
) {
return
}
if (shufflePlayBuffer.isEnabled) {
checkShufflePlay()
}
if (jukeboxMediaPlayer.isEnabled || !isNetworkConnected()) {
if (jukeboxMediaPlayer.isEnabled || !Util.isNetworkConnected()) {
return
}
@ -92,7 +93,7 @@ class Downloader(
cleanupActiveDownloads()
// Check if need to preload more from playlist
val preloadCount = getPreloadCount()
val preloadCount = Settings.preloadCount
// Start preloading at the current playing song
var start = currentPlayingIndex
@ -307,7 +308,7 @@ class Downloader(
@Synchronized
private fun checkShufflePlay() {
// Get users desired random playlist size
val listSize = getMaxSongs()
val listSize = Settings.maxSongs
val wasEmpty = playlist.isEmpty()
val revisionBefore = playlistUpdateRevision

View File

@ -70,7 +70,7 @@ public class AlbumHeader
if (!entry.isDirectory())
{
if (Util.shouldUseFolderForArtistName())
if (Settings.getShouldUseFolderForArtistName())
{
albumHeader.processGrandParents(entry);
}

View File

@ -109,7 +109,7 @@ public class CacheCleaner
return 0L;
}
long cacheSizeBytes = Util.getCacheSizeMB() * 1024L * 1024L;
long cacheSizeBytes = Settings.getCacheSizeMB() * 1024L * 1024L;
long bytesUsedBySubsonic = 0L;
for (File file : files)

View File

@ -119,6 +119,7 @@ public final class Constants
public static final String PREFERENCES_KEY_DISC_SORT = "discAndTrackSort";
public static final String PREFERENCES_KEY_SEND_BLUETOOTH_NOTIFICATIONS = "sendBluetoothNotifications";
public static final String PREFERENCES_KEY_SEND_BLUETOOTH_ALBUM_ART = "sendBluetoothAlbumArt";
public static final String PREFERENCES_KEY_DISABLE_SEND_NOW_PLAYING_LIST = "disableNowPlayingListSending";
public static final String PREFERENCES_KEY_VIEW_REFRESH = "viewRefresh";
public static final String PREFERENCES_KEY_ASK_FOR_SHARE_DETAILS = "sharingAlwaysAskForDetails";
public static final String PREFERENCES_KEY_DEFAULT_SHARE_DESCRIPTION = "sharingDefaultDescription";

View File

@ -289,7 +289,7 @@ public class FileUtil
public static File getMusicDirectory()
{
File defaultMusicDirectory = getDefaultMusicDirectory();
String path = Util.getPreferences().getString(Constants.PREFERENCES_KEY_CACHE_LOCATION, defaultMusicDirectory.getPath());
String path = Settings.getPreferences().getString(Constants.PREFERENCES_KEY_CACHE_LOCATION, defaultMusicDirectory.getPath());
File dir = new File(path);
boolean hasAccess = ensureDirectoryExistsAndIsReadWritable(dir);

View File

@ -60,7 +60,7 @@ public class PermissionUtil {
* @param callback callback function to execute after the permission request is finished
*/
public void handlePermissionFailed(final PermissionRequestFinishedCallback callback) {
String currentCachePath = Util.getPreferences().getString(Constants.PREFERENCES_KEY_CACHE_LOCATION, FileUtil.getDefaultMusicDirectory().getPath());
String currentCachePath = Settings.getPreferences().getString(Constants.PREFERENCES_KEY_CACHE_LOCATION, FileUtil.getDefaultMusicDirectory().getPath());
String defaultCachePath = FileUtil.getDefaultMusicDirectory().getPath();
// Ultrasonic can do nothing about this error when the Music Directory is already set to the default.
@ -136,7 +136,7 @@ public class PermissionUtil {
}
private static void setCacheLocation(Context context, String cacheLocation) {
Util.getPreferences().edit()
Settings.getPreferences().edit()
.putString(Constants.PREFERENCES_KEY_CACHE_LOCATION, cacheLocation)
.apply();
}

View File

@ -29,6 +29,7 @@ import org.moire.ultrasonic.domain.MusicDirectory;
import org.moire.ultrasonic.service.MusicService;
import org.moire.ultrasonic.service.MusicServiceFactory;
import org.moire.ultrasonic.imageloader.ImageLoader;
import org.moire.ultrasonic.util.Settings;
import org.moire.ultrasonic.util.Util;
/**
@ -54,7 +55,7 @@ public class AlbumView extends UpdateView
this.context = context;
this.imageLoader = imageLoader;
String theme = Util.getTheme();
String theme = Settings.getTheme();
boolean themesMatch = theme.equals(AlbumView.theme);
AlbumView.theme = theme;
@ -152,7 +153,7 @@ public class AlbumView extends UpdateView
@Override
public void run()
{
boolean useId3 = Util.getShouldUseId3Tags();
boolean useId3 = Settings.getShouldUseId3Tags();
try
{

View File

@ -7,6 +7,7 @@ import android.view.ViewGroup;
import android.widget.AbsListView;
import android.widget.LinearLayout;
import org.moire.ultrasonic.util.Settings;
import org.moire.ultrasonic.util.Util;
import java.util.ArrayList;
@ -115,7 +116,7 @@ public class UpdateView extends LinearLayout
Timber.w(x, "Error when updating song views.");
}
uiHandler.postDelayed(updateRunnable, Util.getViewRefreshInterval());
uiHandler.postDelayed(updateRunnable, Settings.getViewRefreshInterval());
}
};

View File

@ -45,6 +45,7 @@ import org.moire.ultrasonic.util.FileUtil
import org.moire.ultrasonic.util.NowPlayingEventDistributor
import org.moire.ultrasonic.util.NowPlayingEventListener
import org.moire.ultrasonic.util.PermissionUtil
import org.moire.ultrasonic.util.Settings
import org.moire.ultrasonic.util.SubsonicUncaughtExceptionHandler
import org.moire.ultrasonic.util.ThemeChangedEventDistributor
import org.moire.ultrasonic.util.ThemeChangedEventListener
@ -301,7 +302,7 @@ class NavigationActivity : AppCompatActivity() {
private fun loadSettings() {
PreferenceManager.setDefaultValues(this, R.xml.settings, false)
val preferences = Util.getPreferences()
val preferences = Settings.preferences
if (!preferences.contains(Constants.PREFERENCES_KEY_CACHE_LOCATION)) {
val editor = preferences.edit()
editor.putString(
@ -349,7 +350,7 @@ class NavigationActivity : AppCompatActivity() {
}
private fun showNowPlaying() {
if (!Util.getShowNowPlayingPreference()) {
if (!Settings.showNowPlaying) {
hideNowPlaying()
return
}

View File

@ -14,7 +14,7 @@ import org.moire.ultrasonic.di.mediaPlayerModule
import org.moire.ultrasonic.di.musicServiceModule
import org.moire.ultrasonic.log.FileLoggerTree
import org.moire.ultrasonic.log.TimberKoinLogger
import org.moire.ultrasonic.util.Util
import org.moire.ultrasonic.util.Settings
import timber.log.Timber
import timber.log.Timber.DebugTree
@ -34,7 +34,7 @@ class UApp : MultiDexApplication() {
if (BuildConfig.DEBUG) {
Timber.plant(DebugTree())
}
if (Util.getDebugLogToFile()) {
if (Settings.debugLogToFile) {
FileLoggerTree.plantToTimberForest()
}

View File

@ -11,6 +11,7 @@ import org.moire.ultrasonic.app.UApp
import org.moire.ultrasonic.di.DB_FILENAME
import org.moire.ultrasonic.service.MusicServiceFactory.resetMusicService
import org.moire.ultrasonic.util.Constants
import org.moire.ultrasonic.util.Settings
import org.moire.ultrasonic.util.Util
import timber.log.Timber
@ -176,7 +177,7 @@ class ActiveServerProvider(
* Queries the Id of the Active Server
*/
fun getActiveServerId(): Int {
val preferences = Util.getPreferences()
val preferences = Settings.preferences
return preferences.getInt(Constants.PREFERENCES_KEY_SERVER_INSTANCE, -1)
}
@ -186,7 +187,7 @@ class ActiveServerProvider(
fun setActiveServerId(serverId: Int) {
resetMusicService()
val preferences = Util.getPreferences()
val preferences = Settings.preferences
val editor = preferences.edit()
editor.putInt(Constants.PREFERENCES_KEY_SERVER_INSTANCE, serverId)
editor.apply()
@ -199,7 +200,7 @@ class ActiveServerProvider(
if (isOffline()) {
return false
}
val preferences = Util.getPreferences()
val preferences = Settings.preferences
return preferences.getBoolean(Constants.PREFERENCES_KEY_SCROBBLE, false)
}
@ -210,7 +211,7 @@ class ActiveServerProvider(
if (isOffline()) {
return false
}
val preferences = Util.getPreferences()
val preferences = Settings.preferences
return preferences.getBoolean(Constants.PREFERENCES_KEY_SERVER_SCALING, false)
}
}

View File

@ -9,7 +9,7 @@ import org.moire.ultrasonic.data.AppDatabase
import org.moire.ultrasonic.data.MIGRATION_1_2
import org.moire.ultrasonic.data.MIGRATION_2_3
import org.moire.ultrasonic.fragment.ServerSettingsModel
import org.moire.ultrasonic.util.Util
import org.moire.ultrasonic.util.Settings
const val SP_NAME = "Default_SP"
const val DB_FILENAME = "ultrasonic-database"
@ -18,7 +18,7 @@ const val DB_FILENAME = "ultrasonic-database"
* This Koin module contains registration of classes related to permanent storage
*/
val appPermanentStorage = module {
single(named(SP_NAME)) { Util.getPreferences() }
single(named(SP_NAME)) { Settings.preferences }
single {
Room.databaseBuilder(

View File

@ -9,7 +9,7 @@ import org.moire.ultrasonic.api.subsonic.models.AlbumListType
import org.moire.ultrasonic.domain.MusicDirectory
import org.moire.ultrasonic.service.MusicService
import org.moire.ultrasonic.util.Constants
import org.moire.ultrasonic.util.Util
import org.moire.ultrasonic.util.Settings
class AlbumListModel(application: Application) : GenericListModel(application) {
@ -92,7 +92,7 @@ class AlbumListModel(application: Application) : GenericListModel(application) {
val isAlphabetical = (albumListType == AlbumListType.SORTED_BY_NAME.toString()) ||
(albumListType == AlbumListType.SORTED_BY_ARTIST.toString())
return !isOffline() && !Util.getShouldUseId3Tags() && isAlphabetical
return !isOffline() && !Settings.shouldUseId3Tags && isAlphabetical
}
private fun isCollectionSortable(albumListType: String): Boolean {

View File

@ -16,7 +16,7 @@ import org.moire.ultrasonic.R
import org.moire.ultrasonic.domain.ArtistOrIndex
import org.moire.ultrasonic.domain.MusicDirectory
import org.moire.ultrasonic.imageloader.ImageLoader
import org.moire.ultrasonic.util.Util
import org.moire.ultrasonic.util.Settings
/**
* Creates a Row in a RecyclerView which contains the details of an Artist
@ -57,7 +57,7 @@ class ArtistRowAdapter(
holder.layout.setOnLongClickListener { view -> createPopupMenu(view, listPosition) }
holder.coverArtId = itemList[listPosition].coverArt
if (Util.getShouldShowArtistPicture()) {
if (Settings.shouldShowArtistPicture) {
holder.coverArt.visibility = View.VISIBLE
imageLoader.loadImage(
holder.coverArt,

View File

@ -22,6 +22,7 @@ import org.moire.ultrasonic.domain.MusicFolder
import org.moire.ultrasonic.subsonic.DownloadHandler
import org.moire.ultrasonic.subsonic.ImageLoaderProvider
import org.moire.ultrasonic.util.Constants
import org.moire.ultrasonic.util.Settings
import org.moire.ultrasonic.util.Util
import org.moire.ultrasonic.view.SelectMusicFolderView
@ -110,7 +111,7 @@ abstract class GenericListFragment<T : GenericEntry, TA : GenericRowAdapter<T>>
*/
fun showFolderHeader(): Boolean {
return listModel.showSelectFolderHeader(arguments) &&
!listModel.isOffline() && !Util.getShouldUseId3Tags()
!listModel.isOffline() && !Settings.shouldUseId3Tags
}
fun setTitle(title: String?) {

View File

@ -21,7 +21,7 @@ import org.moire.ultrasonic.domain.MusicFolder
import org.moire.ultrasonic.service.CommunicationErrorHandler
import org.moire.ultrasonic.service.MusicService
import org.moire.ultrasonic.service.MusicServiceFactory
import org.moire.ultrasonic.util.Util
import org.moire.ultrasonic.util.Settings
/**
* An abstract Model, which can be extended to retrieve a list of items from the API
@ -83,7 +83,7 @@ open class GenericListModel(application: Application) :
withContext(Dispatchers.IO) {
val musicService = MusicServiceFactory.getMusicService()
val isOffline = ActiveServerProvider.isOffline()
val useId3Tags = Util.getShouldUseId3Tags()
val useId3Tags = Settings.shouldUseId3Tags
try {
load(isOffline, useId3Tags, musicService, refresh, bundle)

View File

@ -70,6 +70,7 @@ import org.moire.ultrasonic.subsonic.NetworkAndStorageChecker
import org.moire.ultrasonic.subsonic.ShareHandler
import org.moire.ultrasonic.util.CancellationToken
import org.moire.ultrasonic.util.Constants
import org.moire.ultrasonic.util.Settings
import org.moire.ultrasonic.util.SilentBackgroundTask
import org.moire.ultrasonic.util.Util
import org.moire.ultrasonic.view.AutoRepeatButton
@ -242,7 +243,7 @@ class PlayerFragment : Fragment(), GestureDetector.OnGestureListener, KoinCompon
}
previousButton.setOnRepeatListener {
val incrementTime = Util.getIncrementTime()
val incrementTime = Settings.incrementTime
changeProgress(-incrementTime)
}
@ -264,7 +265,7 @@ class PlayerFragment : Fragment(), GestureDetector.OnGestureListener, KoinCompon
}
nextButton.setOnRepeatListener {
val incrementTime = Util.getIncrementTime()
val incrementTime = Settings.incrementTime
changeProgress(incrementTime)
}
pauseButton.setOnClickListener {
@ -565,7 +566,7 @@ class PlayerFragment : Fragment(), GestureDetector.OnGestureListener, KoinCompon
}
}
if (isOffline() || !Util.getShouldUseId3Tags()) {
if (isOffline() || !Settings.shouldUseId3Tags) {
menu.findItem(R.id.menu_show_artist)?.isVisible = false
}
@ -600,7 +601,7 @@ class PlayerFragment : Fragment(), GestureDetector.OnGestureListener, KoinCompon
if (entry == null) {
return false
}
if (Util.getShouldUseId3Tags()) {
if (Settings.shouldUseId3Tags) {
bundle = Bundle()
bundle.putString(Constants.INTENT_EXTRA_NAME_ID, entry.artistId)
bundle.putString(Constants.INTENT_EXTRA_NAME_NAME, entry.artist)
@ -615,7 +616,7 @@ class PlayerFragment : Fragment(), GestureDetector.OnGestureListener, KoinCompon
if (entry == null) {
return false
}
val albumId = if (Util.getShouldUseId3Tags()) entry.albumId else entry.parent
val albumId = if (Settings.shouldUseId3Tags) entry.albumId else entry.parent
bundle = Bundle()
bundle.putString(Constants.INTENT_EXTRA_NAME_ID, albumId)
bundle.putString(Constants.INTENT_EXTRA_NAME_NAME, entry.album)

View File

@ -49,6 +49,7 @@ import org.moire.ultrasonic.util.AlbumHeader
import org.moire.ultrasonic.util.CancellationToken
import org.moire.ultrasonic.util.Constants
import org.moire.ultrasonic.util.EntryByDiscAndTrackComparator
import org.moire.ultrasonic.util.Settings
import org.moire.ultrasonic.util.Util
import org.moire.ultrasonic.view.AlbumView
import org.moire.ultrasonic.view.EntryAdapter
@ -276,7 +277,7 @@ class TrackCollectionFragment : Fragment() {
model.getRandom(albumListSize)
} else {
setTitle(name)
if (!isOffline() && Util.getShouldUseId3Tags()) {
if (!isOffline() && Settings.shouldUseId3Tags) {
if (isAlbum) {
model.getAlbum(refresh, id!!, name, parentId)
} else {
@ -635,7 +636,7 @@ class TrackCollectionFragment : Fragment() {
private fun updateInterfaceWithEntries(musicDirectory: MusicDirectory) {
val entries = musicDirectory.getChildren()
if (model.currentListIsSortable && Util.getShouldSortByDisc()) {
if (model.currentListIsSortable && Settings.shouldSortByDisc) {
Collections.sort(entries, EntryByDiscAndTrackComparator())
}

View File

@ -17,6 +17,7 @@ import org.moire.ultrasonic.R
import org.moire.ultrasonic.domain.MusicDirectory
import org.moire.ultrasonic.service.MusicService
import org.moire.ultrasonic.service.MusicServiceFactory
import org.moire.ultrasonic.util.Settings
import org.moire.ultrasonic.util.Util
/*
@ -67,7 +68,7 @@ class TrackCollectionModel(application: Application) : GenericListModel(applicat
} else {
val musicDirectory = service.getMusicDirectory(id, name, refresh)
if (Util.getShouldShowAllSongsByArtist() &&
if (Settings.shouldShowAllSongsByArtist &&
musicDirectory.findChild(allSongsId) == null &&
hasOnlyFolders(musicDirectory)
) {
@ -128,7 +129,7 @@ class TrackCollectionModel(application: Application) : GenericListModel(applicat
val musicDirectory = service.getArtist(id, name, refresh)
if (Util.getShouldShowAllSongsByArtist() &&
if (Settings.shouldShowAllSongsByArtist &&
musicDirectory.findChild(allSongsId) == null &&
hasOnlyFolders(musicDirectory)
) {
@ -207,7 +208,7 @@ class TrackCollectionModel(application: Application) : GenericListModel(applicat
val service = MusicServiceFactory.getMusicService()
val musicDirectory: MusicDirectory
if (Util.getShouldUseId3Tags()) {
if (Settings.shouldUseId3Tags) {
musicDirectory = Util.getSongsFromSearchResult(service.getStarred2())
} else {
musicDirectory = Util.getSongsFromSearchResult(service.getStarred())

View File

@ -12,7 +12,7 @@ import androidx.media.AudioManagerCompat
import org.koin.java.KoinJavaComponent.inject
import org.moire.ultrasonic.domain.PlayerState
import org.moire.ultrasonic.util.Constants
import org.moire.ultrasonic.util.Util
import org.moire.ultrasonic.util.Settings
import timber.log.Timber
class AudioFocusHandler(private val context: Context) {
@ -26,7 +26,7 @@ class AudioFocusHandler(private val context: Context) {
}
private val preferences by lazy {
Util.getPreferences()
Settings.preferences
}
private val lossPref: Int

View File

@ -28,6 +28,7 @@ import org.moire.ultrasonic.domain.SearchResult
import org.moire.ultrasonic.util.MediaSessionEventDistributor
import org.moire.ultrasonic.util.MediaSessionEventListener
import org.moire.ultrasonic.util.MediaSessionHandler
import org.moire.ultrasonic.util.Settings
import org.moire.ultrasonic.util.Util
import timber.log.Timber
@ -89,7 +90,7 @@ class AutoMediaBrowserService : MediaBrowserServiceCompat() {
private var searchSongsCache: List<MusicDirectory.Entry>? = null
private val isOffline get() = ActiveServerProvider.isOffline()
private val useId3Tags get() = Util.getShouldUseId3Tags()
private val useId3Tags get() = Settings.shouldUseId3Tags
private val musicFolderId get() = activeServerProvider.getActiveServer().musicFolderId
@Suppress("MagicNumber")
@ -968,7 +969,7 @@ class AutoMediaBrowserService : MediaBrowserServiceCompat() {
}
private fun listSongsInMusicService(id: String, name: String): MusicDirectory? {
return if (!ActiveServerProvider.isOffline() && Util.getShouldUseId3Tags()) {
return if (!ActiveServerProvider.isOffline() && Settings.shouldUseId3Tags) {
callWithErrorHandling { musicService.getAlbum(id, name, false) }
} else {
callWithErrorHandling { musicService.getMusicDirectory(id, name, false) }
@ -976,7 +977,7 @@ class AutoMediaBrowserService : MediaBrowserServiceCompat() {
}
private fun listStarredSongsInMusicService(): SearchResult? {
return if (Util.getShouldUseId3Tags()) {
return if (Settings.shouldUseId3Tags) {
callWithErrorHandling { musicService.getStarred2() }
} else {
callWithErrorHandling { musicService.getStarred() }

View File

@ -8,6 +8,7 @@ package org.moire.ultrasonic.service
import java.io.InputStream
import java.util.concurrent.TimeUnit
import kotlin.Pair
import org.koin.core.component.KoinComponent
import org.koin.core.component.inject
import org.moire.ultrasonic.data.ActiveServerProvider
@ -29,6 +30,7 @@ import org.moire.ultrasonic.domain.Share
import org.moire.ultrasonic.domain.UserInfo
import org.moire.ultrasonic.util.Constants
import org.moire.ultrasonic.util.LRUCache
import org.moire.ultrasonic.util.Settings
import org.moire.ultrasonic.util.TimeLimitedCache
import org.moire.ultrasonic.util.Util
@ -137,7 +139,7 @@ class CachedMusicService(private val musicService: MusicService) : MusicService,
if (dir == null) {
dir = musicService.getMusicDirectory(id, name, refresh)
cache = TimeLimitedCache(
Util.getDirectoryCacheTime().toLong(), TimeUnit.SECONDS
Settings.directoryCacheTime.toLong(), TimeUnit.SECONDS
)
cache.set(dir)
cachedMusicDirectories.put(id, cache)
@ -153,7 +155,7 @@ class CachedMusicService(private val musicService: MusicService) : MusicService,
if (dir == null) {
dir = musicService.getArtist(id, name, refresh)
cache = TimeLimitedCache(
Util.getDirectoryCacheTime().toLong(), TimeUnit.SECONDS
Settings.directoryCacheTime.toLong(), TimeUnit.SECONDS
)
cache.set(dir)
cachedArtist.put(id, cache)
@ -169,7 +171,7 @@ class CachedMusicService(private val musicService: MusicService) : MusicService,
if (dir == null) {
dir = musicService.getAlbum(id, name, refresh)
cache = TimeLimitedCache(
Util.getDirectoryCacheTime().toLong(), TimeUnit.SECONDS
Settings.directoryCacheTime.toLong(), TimeUnit.SECONDS
)
cache.set(dir)
cachedAlbum.put(id, cache)
@ -418,7 +420,7 @@ class CachedMusicService(private val musicService: MusicService) : MusicService,
if (dir == null) {
dir = musicService.getVideos(refresh)
cache = TimeLimitedCache(
Util.getDirectoryCacheTime().toLong(), TimeUnit.SECONDS
Settings.directoryCacheTime.toLong(), TimeUnit.SECONDS
)
cache.set(dir)
cachedMusicDirectories.put(Constants.INTENT_EXTRA_NAME_VIDEOS, cache)
@ -434,7 +436,7 @@ class CachedMusicService(private val musicService: MusicService) : MusicService,
if (userInfo == null) {
userInfo = musicService.getUser(username)
cache = TimeLimitedCache(
Util.getDirectoryCacheTime().toLong(), TimeUnit.SECONDS
Settings.directoryCacheTime.toLong(), TimeUnit.SECONDS
)
cache.set(userInfo)
cachedUserInfo.put(username, cache)

View File

@ -28,6 +28,7 @@ import org.moire.ultrasonic.subsonic.ImageLoaderProvider
import org.moire.ultrasonic.util.CacheCleaner
import org.moire.ultrasonic.util.CancellableTask
import org.moire.ultrasonic.util.FileUtil
import org.moire.ultrasonic.util.Settings
import org.moire.ultrasonic.util.Util
import timber.log.Timber
@ -48,7 +49,7 @@ class DownloadFile(
var isFailed = false
private var retryCount = MAX_RETRIES
private val desiredBitRate: Int = Util.getMaxBitRate()
private val desiredBitRate: Int = Settings.maxBitRate
var priority = 100
@ -318,7 +319,7 @@ class DownloadFile(
private fun acquireWakeLock(wakeLock: WakeLock?): WakeLock? {
var wakeLock1 = wakeLock
if (Util.isScreenLitOnDownload()) {
if (Settings.isScreenLitOnDownload) {
val context = UApp.applicationContext()
val pm = context.getSystemService(Context.POWER_SERVICE) as PowerManager
val flags = PowerManager.SCREEN_DIM_WAKE_LOCK or PowerManager.ON_AFTER_RELEASE

View File

@ -35,6 +35,7 @@ import org.moire.ultrasonic.domain.PlayerState
import org.moire.ultrasonic.util.CancellableTask
import org.moire.ultrasonic.util.Constants
import org.moire.ultrasonic.util.MediaSessionHandler
import org.moire.ultrasonic.util.Settings
import org.moire.ultrasonic.util.StreamProxy
import org.moire.ultrasonic.util.Util
import timber.log.Timber
@ -405,7 +406,7 @@ class LocalMediaPlayer : KoinComponent {
}
// The secondary progress is an indicator of how far the song is cached.
if (song.transcodedContentType == null && Util.getMaxBitRate() == 0) {
if (song.transcodedContentType == null && Settings.maxBitRate == 0) {
val progress = (percent.toDouble() / 100.toDouble() * playerDuration).toInt()
secondaryProgress.postValue(progress)
}
@ -454,6 +455,7 @@ class LocalMediaPlayer : KoinComponent {
}
}
@Suppress("ComplexCondition")
@Synchronized
private fun setupNext(downloadFile: DownloadFile) {
try {
@ -482,7 +484,7 @@ class LocalMediaPlayer : KoinComponent {
nextMediaPlayer!!.setOnPreparedListener {
try {
setNextPlayerState(PlayerState.PREPARED)
if (Util.getGaplessPlaybackPreference() &&
if (Settings.gaplessPlayback &&
Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN &&
(
playerState === PlayerState.STARTED ||
@ -536,7 +538,7 @@ class LocalMediaPlayer : KoinComponent {
Timber.i("Ending position %d of %d", pos, duration)
if (!isPartial || downloadFile.isWorkDone && abs(duration - pos) < 1000) {
setPlayerState(PlayerState.COMPLETED)
if (Util.getGaplessPlaybackPreference() &&
if (Settings.gaplessPlayback &&
nextPlaying != null &&
nextPlayerState === PlayerState.PREPARED
) {
@ -638,7 +640,7 @@ class LocalMediaPlayer : KoinComponent {
}
init {
var bufferLength = Util.getBufferLength().toLong()
var bufferLength = Settings.bufferLength.toLong()
if (bufferLength == 0L) {
// Set to seconds in a day, basically infinity
bufferLength = 86400L

View File

@ -21,8 +21,8 @@ import org.moire.ultrasonic.service.MediaPlayerService.Companion.executeOnStarte
import org.moire.ultrasonic.service.MediaPlayerService.Companion.getInstance
import org.moire.ultrasonic.service.MediaPlayerService.Companion.runningInstance
import org.moire.ultrasonic.service.MusicServiceFactory.getMusicService
import org.moire.ultrasonic.util.Settings
import org.moire.ultrasonic.util.ShufflePlayBuffer
import org.moire.ultrasonic.util.Util
import timber.log.Timber
/**
@ -252,9 +252,9 @@ class MediaPlayerController(
@set:Synchronized
var repeatMode: RepeatMode
get() = Util.repeatMode
get() = Settings.repeatMode
set(repeatMode) {
Util.repeatMode = repeatMode
Settings.repeatMode = repeatMode
val mediaPlayerService = runningInstance
mediaPlayerService?.setNextPlaying()
}

View File

@ -23,7 +23,7 @@ import org.moire.ultrasonic.util.CacheCleaner
import org.moire.ultrasonic.util.Constants
import org.moire.ultrasonic.util.MediaSessionEventDistributor
import org.moire.ultrasonic.util.MediaSessionEventListener
import org.moire.ultrasonic.util.Util
import org.moire.ultrasonic.util.Settings
import timber.log.Timber
/**
@ -136,7 +136,7 @@ class MediaPlayerLifecycleSupport : KoinComponent {
*/
private fun registerHeadsetReceiver() {
val sp = Util.getPreferences()
val sp = Settings.preferences
val context = applicationContext()
val spKey = context
.getString(R.string.settings_playback_resume_play_on_headphones_plug)
@ -185,7 +185,7 @@ class MediaPlayerLifecycleSupport : KoinComponent {
val receivedKeyCode = event.keyCode
// Translate PLAY and PAUSE codes to PLAY_PAUSE to improve compatibility with old Bluetooth devices
keyCode = if (Util.getSingleButtonPlayPause() && (
keyCode = if (Settings.singleButtonPlayPause && (
receivedKeyCode == KeyEvent.KEYCODE_MEDIA_PLAY ||
receivedKeyCode == KeyEvent.KEYCODE_MEDIA_PAUSE
)

View File

@ -39,6 +39,7 @@ import org.moire.ultrasonic.util.MediaSessionEventDistributor
import org.moire.ultrasonic.util.MediaSessionEventListener
import org.moire.ultrasonic.util.MediaSessionHandler
import org.moire.ultrasonic.util.NowPlayingEventDistributor
import org.moire.ultrasonic.util.Settings
import org.moire.ultrasonic.util.ShufflePlayBuffer
import org.moire.ultrasonic.util.SimpleServiceBinder
import org.moire.ultrasonic.util.Util
@ -69,7 +70,7 @@ class MediaPlayerService : Service() {
private lateinit var mediaSessionEventListener: MediaSessionEventListener
private val repeatMode: RepeatMode
get() = Util.repeatMode
get() = Settings.repeatMode
override fun onBind(intent: Intent): IBinder {
return binder
@ -196,7 +197,7 @@ class MediaPlayerService : Service() {
@Synchronized
fun setNextPlaying() {
val gaplessPlayback = Util.getGaplessPlaybackPreference()
val gaplessPlayback = Settings.gaplessPlayback
if (!gaplessPlayback) {
localMediaPlayer.clearNextPlaying(true)
@ -400,7 +401,7 @@ class MediaPlayerService : Service() {
}
val showWhenPaused = playerState !== PlayerState.STOPPED &&
Util.isNotificationAlwaysEnabled()
Settings.isNotificationAlwaysEnabled
val show = playerState === PlayerState.STARTED || showWhenPaused
val song = currentPlaying?.song
@ -444,7 +445,7 @@ class MediaPlayerService : Service() {
if (currentPlaying != null) {
val song = currentPlaying.song
if (song.bookmarkPosition > 0 && Util.getShouldClearBookmark()) {
if (song.bookmarkPosition > 0 && Settings.shouldClearBookmark) {
val musicService = getMusicService()
try {
musicService.deleteBookmark(song.id)
@ -456,7 +457,7 @@ class MediaPlayerService : Service() {
when (repeatMode) {
RepeatMode.OFF -> {
if (index + 1 < 0 || index + 1 >= downloader.playlist.size) {
if (Util.getShouldClearPlaylist()) {
if (Settings.shouldClearPlaylist) {
clear(true)
jukeboxMediaPlayer.updatePlaylist()
}
@ -513,7 +514,7 @@ class MediaPlayerService : Service() {
fun updateNotification(playerState: PlayerState, currentPlaying: DownloadFile?) {
val notification = buildForegroundNotification(playerState, currentPlaying)
if (Util.isNotificationEnabled()) {
if (Settings.isNotificationEnabled) {
if (isInForeground) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
val manager = getSystemService(NOTIFICATION_SERVICE) as NotificationManager

View File

@ -43,7 +43,7 @@ import org.moire.ultrasonic.domain.toIndexList
import org.moire.ultrasonic.domain.toMusicDirectoryDomainEntity
import org.moire.ultrasonic.util.FileUtil
import org.moire.ultrasonic.util.FileUtilKt
import org.moire.ultrasonic.util.Util
import org.moire.ultrasonic.util.Settings
import timber.log.Timber
/**
@ -166,7 +166,7 @@ open class RESTMusicService(
criteria: SearchCriteria
): SearchResult {
return try {
if (!isOffline() && Util.getShouldUseId3Tags()) {
if (!isOffline() && Settings.shouldUseId3Tags) {
search3(criteria)
} else {
search2(criteria)

View File

@ -13,6 +13,7 @@ import org.moire.ultrasonic.service.MusicServiceFactory.getMusicService
import org.moire.ultrasonic.util.Constants
import org.moire.ultrasonic.util.EntryByDiscAndTrackComparator
import org.moire.ultrasonic.util.ModalBackgroundTask
import org.moire.ultrasonic.util.Settings
import org.moire.ultrasonic.util.Util
/**
@ -54,7 +55,7 @@ class DownloadHandler(
mediaPlayerController.suggestedPlaylistName = playlistName
}
if (autoPlay) {
if (Util.getShouldTransitionOnPlaybackPreference()) {
if (Settings.shouldTransitionOnPlayback) {
fragment.findNavController().popBackStack(R.id.playerFragment, true)
fragment.findNavController().navigate(R.id.playerFragment)
}
@ -204,11 +205,11 @@ class DownloadHandler(
val musicService = getMusicService()
val songs: MutableList<MusicDirectory.Entry> = LinkedList()
val root: MusicDirectory
if (!isOffline() && isArtist && Util.getShouldUseId3Tags()) {
if (!isOffline() && isArtist && Settings.shouldUseId3Tags) {
getSongsForArtist(id, songs)
} else {
if (isDirectory) {
root = if (!isOffline() && Util.getShouldUseId3Tags())
root = if (!isOffline() && Settings.shouldUseId3Tags)
musicService.getAlbum(id, name, false)
else
musicService.getMusicDirectory(id, name, false)
@ -253,7 +254,7 @@ class DownloadHandler(
) {
val root: MusicDirectory = if (
!isOffline() &&
Util.getShouldUseId3Tags()
Settings.shouldUseId3Tags
) musicService.getAlbum(id1, title, false)
else musicService.getMusicDirectory(id1, title, false)
getSongsRecursively(root, songs)
@ -285,7 +286,7 @@ class DownloadHandler(
}
override fun done(songs: List<MusicDirectory.Entry>) {
if (Util.getShouldSortByDisc()) {
if (Settings.shouldSortByDisc) {
Collections.sort(songs, EntryByDiscAndTrackComparator())
}
if (songs.isNotEmpty()) {
@ -307,7 +308,7 @@ class DownloadHandler(
)
if (
!append &&
Util.getShouldTransitionOnPlaybackPreference()
Settings.shouldTransitionOnPlayback
) {
fragment.findNavController().popBackStack(
R.id.playerFragment,

View File

@ -9,7 +9,9 @@ import android.widget.CheckBox
import android.widget.EditText
import androidx.fragment.app.Fragment
import androidx.swiperefreshlayout.widget.SwipeRefreshLayout
import java.util.Locale
import java.util.regex.Pattern
import kotlin.collections.ArrayList
import org.moire.ultrasonic.R
import org.moire.ultrasonic.domain.MusicDirectory
import org.moire.ultrasonic.domain.Share
@ -18,10 +20,10 @@ import org.moire.ultrasonic.util.BackgroundTask
import org.moire.ultrasonic.util.CancellationToken
import org.moire.ultrasonic.util.Constants
import org.moire.ultrasonic.util.FragmentBackgroundTask
import org.moire.ultrasonic.util.Settings
import org.moire.ultrasonic.util.ShareDetails
import org.moire.ultrasonic.util.TimeSpan
import org.moire.ultrasonic.util.TimeSpanPicker
import org.moire.ultrasonic.util.Util
/**
* This class handles sharing items in the media library
@ -40,15 +42,15 @@ class ShareHandler(val context: Context) {
swipe: SwipeRefreshLayout?,
cancellationToken: CancellationToken
) {
val askForDetails = Util.shouldAskForShareDetails
val askForDetails = Settings.shouldAskForShareDetails
val shareDetails = ShareDetails()
shareDetails.Entries = entries
if (askForDetails) {
showDialog(fragment, shareDetails, swipe, cancellationToken)
} else {
shareDetails.Description = Util.defaultShareDescription
shareDetails.Description = Settings.defaultShareDescription
shareDetails.Expiration = TimeSpan.getCurrentTime().add(
Util.getDefaultShareExpirationInMillis(context)
Settings.defaultShareExpirationInMillis
).totalMilliseconds
share(fragment, shareDetails, swipe, cancellationToken)
}
@ -93,7 +95,7 @@ class ShareHandler(val context: Context) {
intent.type = "text/plain"
intent.putExtra(
Intent.EXTRA_TEXT,
String.format("%s\n\n%s", Util.getShareGreeting(), result.url)
String.format(Locale.ROOT, "%s\n\n%s", Settings.shareGreeting, result.url)
)
fragment.activity?.startActivity(
Intent.createChooser(
@ -133,16 +135,16 @@ class ShareHandler(val context: Context) {
}
shareDetails.Description = shareDescription!!.text.toString()
if (hideDialogCheckBox!!.isChecked) {
Util.shouldAskForShareDetails = false
Settings.shouldAskForShareDetails = false
}
if (saveAsDefaultsCheckBox!!.isChecked) {
val timeSpanType: String = timeSpanPicker!!.timeSpanType
val timeSpanAmount: Int = timeSpanPicker!!.timeSpanAmount
Util.defaultShareExpiration =
Settings.defaultShareExpiration =
if (!noExpirationCheckBox!!.isChecked && timeSpanAmount > 0)
String.format("%d:%s", timeSpanAmount, timeSpanType) else ""
Util.defaultShareDescription = shareDetails.Description
Settings.defaultShareDescription = shareDetails.Description
}
share(fragment, shareDetails, swipe, cancellationToken)
}
@ -157,8 +159,8 @@ class ShareHandler(val context: Context) {
b ->
timeSpanPicker!!.isEnabled = !b
}
val defaultDescription = Util.defaultShareDescription
val timeSpan = Util.defaultShareExpiration
val defaultDescription = Settings.defaultShareDescription
val timeSpan = Settings.defaultShareExpiration
val split = pattern.split(timeSpan)
if (split.size == 2) {
val timeSpanAmount = split[0].toInt()

View File

@ -43,7 +43,7 @@ class MediaSessionHandler : KoinComponent {
private val applicationContext by inject<Context>()
private var referenceCount: Int = 0
private var cachedPlaylist: Iterable<MusicDirectory.Entry>? = null
private var cachedPlaylist: List<MediaSessionCompat.QueueItem>? = null
private var playbackPositionDelayCount: Int = 0
private var cachedPosition: Long = 0
@ -160,7 +160,7 @@ class MediaSessionHandler : KoinComponent {
// It seems to be the best practice to set this to true for the lifetime of the session
mediaSession?.isActive = true
if (cachedPlaylist != null) updateMediaSessionQueue(cachedPlaylist!!)
if (cachedPlaylist != null) setMediaSessionQueue(cachedPlaylist)
Timber.i("MediaSessionHandler.initialize Media Session created")
}
@ -245,7 +245,11 @@ class MediaSessionHandler : KoinComponent {
playbackStateBuilder.setActions(playbackActions!!)
cachedPlayingIndex = currentPlayingIndex
if (currentPlayingIndex != null)
setMediaSessionQueue(cachedPlaylist)
if (
currentPlayingIndex != null && cachedPlaylist != null &&
!Settings.shouldDisableNowPlayingListSending
)
playbackStateBuilder.setActiveQueueItemId(currentPlayingIndex)
// Save the playback state
@ -254,18 +258,21 @@ class MediaSessionHandler : KoinComponent {
fun updateMediaSessionQueue(playlist: Iterable<MusicDirectory.Entry>) {
// This call is cached because Downloader may initialize earlier than the MediaSession
cachedPlaylist = playlist
cachedPlaylist = playlist.mapIndexed { id, song ->
MediaSessionCompat.QueueItem(
Util.getMediaDescriptionForEntry(song),
id.toLong()
)
}
setMediaSessionQueue(cachedPlaylist)
}
private fun setMediaSessionQueue(queue: List<MediaSessionCompat.QueueItem>?) {
if (mediaSession == null) return
if (Settings.shouldDisableNowPlayingListSending) return
mediaSession?.setQueueTitle(applicationContext.getString(R.string.button_bar_now_playing))
mediaSession?.setQueue(
playlist.mapIndexed { id, song ->
MediaSessionCompat.QueueItem(
Util.getMediaDescriptionForEntry(song),
id.toLong()
)
}
)
mediaSession?.setQueue(queue)
}
fun updateMediaSessionPlaybackPosition(playbackPosition: Long) {
@ -285,14 +292,17 @@ class MediaSessionHandler : KoinComponent {
playbackStateBuilder.setState(playbackState!!, playbackPosition, 1.0f)
playbackStateBuilder.setActions(playbackActions!!)
if (cachedPlayingIndex != null)
if (
cachedPlayingIndex != null && cachedPlaylist != null &&
!Settings.shouldDisableNowPlayingListSending
)
playbackStateBuilder.setActiveQueueItemId(cachedPlayingIndex!!)
mediaSession?.setPlaybackState(playbackStateBuilder.build())
}
fun updateMediaButtonReceiver() {
if (Util.getMediaButtonsEnabled()) {
if (Settings.mediaButtonsEnabled) {
registerMediaButtonEventReceiver()
} else {
unregisterMediaButtonEventReceiver()

View File

@ -0,0 +1,459 @@
/*
* Settings.kt
* Copyright (C) 2009-2021 Ultrasonic developers
*
* Distributed under terms of the GNU GPLv3 license.
*/
package org.moire.ultrasonic.util
import android.content.Context
import android.content.SharedPreferences
import android.net.ConnectivityManager
import android.os.Build
import androidx.preference.PreferenceManager
import java.util.regex.Pattern
import org.moire.ultrasonic.R
import org.moire.ultrasonic.app.UApp
import org.moire.ultrasonic.data.ActiveServerProvider
import org.moire.ultrasonic.domain.RepeatMode
/**
* Contains convenience functions for reading and writing preferences
*/
object Settings {
private val PATTERN = Pattern.compile(":")
val isScreenLitOnDownload: Boolean
get() {
val preferences = preferences
return preferences.getBoolean(
Constants.PREFERENCES_KEY_SCREEN_LIT_ON_DOWNLOAD,
false
)
}
var repeatMode: RepeatMode
get() {
val preferences = preferences
return RepeatMode.valueOf(
preferences.getString(
Constants.PREFERENCES_KEY_REPEAT_MODE,
RepeatMode.OFF.name
)!!
)
}
set(repeatMode) {
val preferences = preferences
val editor = preferences.edit()
editor.putString(Constants.PREFERENCES_KEY_REPEAT_MODE, repeatMode.name)
editor.apply()
}
// After API26 foreground services must be used for music playback,
// and they must have a notification
val isNotificationEnabled: Boolean
get() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) return true
val preferences = preferences
return preferences.getBoolean(Constants.PREFERENCES_KEY_SHOW_NOTIFICATION, false)
}
// After API26 foreground services must be used for music playback,
// and they must have a notification
val isNotificationAlwaysEnabled: Boolean
get() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) return true
val preferences = preferences
return preferences.getBoolean(Constants.PREFERENCES_KEY_ALWAYS_SHOW_NOTIFICATION, false)
}
val isLockScreenEnabled: Boolean
get() {
val preferences = preferences
return preferences.getBoolean(
Constants.PREFERENCES_KEY_SHOW_LOCK_SCREEN_CONTROLS,
false
)
}
@JvmStatic
val theme: String?
get() {
val preferences = preferences
return preferences.getString(
Constants.PREFERENCES_KEY_THEME,
Constants.PREFERENCES_KEY_THEME_DARK
)
}
@JvmStatic
val maxBitRate: Int
get() {
val manager = Util.getConnectivityManager()
val networkInfo = manager.activeNetworkInfo ?: return 0
val wifi = networkInfo.type == ConnectivityManager.TYPE_WIFI
val preferences = preferences
return preferences.getString(
if (wifi) Constants.PREFERENCES_KEY_MAX_BITRATE_WIFI
else Constants.PREFERENCES_KEY_MAX_BITRATE_MOBILE,
"0"
)!!.toInt()
}
@JvmStatic
val preloadCount: Int
get() {
val preferences = preferences
val preloadCount =
preferences.getString(Constants.PREFERENCES_KEY_PRELOAD_COUNT, "-1")!!
.toInt()
return if (preloadCount == -1) Int.MAX_VALUE else preloadCount
}
@JvmStatic
val cacheSizeMB: Int
get() {
val preferences = preferences
val cacheSize = preferences.getString(
Constants.PREFERENCES_KEY_CACHE_SIZE,
"-1"
)!!.toInt()
return if (cacheSize == -1) Int.MAX_VALUE else cacheSize
}
val isWifiRequiredForDownload: Boolean
get() {
val preferences = preferences
return preferences.getBoolean(
Constants.PREFERENCES_KEY_WIFI_REQUIRED_FOR_DOWNLOAD,
false
)
}
val shouldDisplayBitrateWithArtist: Boolean
get() {
val preferences = preferences
return preferences.getBoolean(
Constants.PREFERENCES_KEY_DISPLAY_BITRATE_WITH_ARTIST,
true
)
}
@JvmStatic
val shouldUseFolderForArtistName: Boolean
get() {
val preferences = preferences
return preferences.getBoolean(
Constants.PREFERENCES_KEY_USE_FOLDER_FOR_ALBUM_ARTIST,
false
)
}
val shouldShowTrackNumber: Boolean
get() {
val preferences = preferences
return preferences.getBoolean(Constants.PREFERENCES_KEY_SHOW_TRACK_NUMBER, false)
}
@JvmStatic
val defaultAlbums: Int
get() {
val preferences = preferences
return preferences.getString(Constants.PREFERENCES_KEY_DEFAULT_ALBUMS, "5")!!
.toInt()
}
@JvmStatic
val maxAlbums: Int
get() {
val preferences = preferences
return preferences.getString(Constants.PREFERENCES_KEY_MAX_ALBUMS, "20")!!
.toInt()
}
@JvmStatic
val defaultSongs: Int
get() {
val preferences = preferences
return preferences.getString(Constants.PREFERENCES_KEY_DEFAULT_SONGS, "10")!!
.toInt()
}
@JvmStatic
val maxSongs: Int
get() {
val preferences = preferences
return preferences.getString(Constants.PREFERENCES_KEY_MAX_SONGS, "25")!!
.toInt()
}
@JvmStatic
val maxArtists: Int
get() {
val preferences = preferences
return preferences.getString(Constants.PREFERENCES_KEY_MAX_ARTISTS, "10")!!
.toInt()
}
@JvmStatic
val defaultArtists: Int
get() {
val preferences = preferences
return preferences.getString(Constants.PREFERENCES_KEY_DEFAULT_ARTISTS, "3")!!
.toInt()
}
@JvmStatic
val bufferLength: Int
get() {
val preferences = preferences
return preferences.getString(Constants.PREFERENCES_KEY_BUFFER_LENGTH, "5")!!
.toInt()
}
@JvmStatic
val incrementTime: Int
get() {
val preferences = preferences
return preferences.getString(Constants.PREFERENCES_KEY_INCREMENT_TIME, "5")!!
.toInt()
}
@JvmStatic
val mediaButtonsEnabled: Boolean
get() {
val preferences = preferences
return preferences.getBoolean(Constants.PREFERENCES_KEY_MEDIA_BUTTONS, true)
}
@JvmStatic
val showNowPlaying: Boolean
get() {
val preferences = preferences
return preferences.getBoolean(Constants.PREFERENCES_KEY_SHOW_NOW_PLAYING, true)
}
@JvmStatic
val gaplessPlayback: Boolean
get() {
val preferences = preferences
return preferences.getBoolean(Constants.PREFERENCES_KEY_GAPLESS_PLAYBACK, false)
}
@JvmStatic
val shouldTransitionOnPlayback: Boolean
get() {
val preferences = preferences
return preferences.getBoolean(Constants.PREFERENCES_KEY_DOWNLOAD_TRANSITION, true)
}
@JvmStatic
val shouldUseId3Tags: Boolean
get() {
val preferences = preferences
return preferences.getBoolean(Constants.PREFERENCES_KEY_ID3_TAGS, false)
}
val shouldShowArtistPicture: Boolean
get() {
val preferences = preferences
val isOffline = ActiveServerProvider.isOffline()
val isId3Enabled = preferences.getBoolean(Constants.PREFERENCES_KEY_ID3_TAGS, false)
val shouldShowArtistPicture =
preferences.getBoolean(Constants.PREFERENCES_KEY_SHOW_ARTIST_PICTURE, false)
return !isOffline && isId3Enabled && shouldShowArtistPicture
}
@JvmStatic
val chatRefreshInterval: Int
get() {
val preferences = preferences
return preferences.getString(
Constants.PREFERENCES_KEY_CHAT_REFRESH_INTERVAL,
"5000"
)!!.toInt()
}
val directoryCacheTime: Int
get() {
val preferences = preferences
return preferences.getString(
Constants.PREFERENCES_KEY_DIRECTORY_CACHE_TIME,
"300"
)!!.toInt()
}
val shouldClearPlaylist: Boolean
get() {
val preferences = preferences
return preferences.getBoolean(Constants.PREFERENCES_KEY_CLEAR_PLAYLIST, false)
}
val shouldSortByDisc: Boolean
get() {
val preferences = preferences
return preferences.getBoolean(Constants.PREFERENCES_KEY_DISC_SORT, false)
}
val shouldClearBookmark: Boolean
get() {
val preferences = preferences
return preferences.getBoolean(Constants.PREFERENCES_KEY_CLEAR_BOOKMARK, false)
}
val singleButtonPlayPause: Boolean
get() {
val preferences = preferences
return preferences.getBoolean(Constants.PREFERENCES_KEY_SINGLE_BUTTON_PLAY_PAUSE, false)
}
// Inverted for readability
val shouldSendBluetoothNotifications: Boolean
get() {
val preferences = preferences
return preferences.getBoolean(
Constants.PREFERENCES_KEY_SEND_BLUETOOTH_NOTIFICATIONS,
true
)
}
val shouldSendBluetoothAlbumArt: Boolean
get() {
val preferences = preferences
return preferences.getBoolean(Constants.PREFERENCES_KEY_SEND_BLUETOOTH_ALBUM_ART, true)
}
val shouldDisableNowPlayingListSending: Boolean
get() {
val preferences = preferences
return preferences.getBoolean(
Constants.PREFERENCES_KEY_DISABLE_SEND_NOW_PLAYING_LIST, false
)
}
@JvmStatic
val viewRefreshInterval: Int
get() {
val preferences = preferences
return preferences.getString(Constants.PREFERENCES_KEY_VIEW_REFRESH, "1000")!!
.toInt()
}
var shouldAskForShareDetails: Boolean
get() {
val preferences = preferences
return preferences.getBoolean(Constants.PREFERENCES_KEY_ASK_FOR_SHARE_DETAILS, true)
}
set(shouldAskForShareDetails) {
val preferences = preferences
val editor = preferences.edit()
editor.putBoolean(
Constants.PREFERENCES_KEY_ASK_FOR_SHARE_DETAILS,
shouldAskForShareDetails
)
editor.apply()
}
var defaultShareDescription: String?
get() {
val preferences = preferences
return preferences.getString(Constants.PREFERENCES_KEY_DEFAULT_SHARE_DESCRIPTION, "")
}
set(defaultShareDescription) {
val preferences = preferences
val editor = preferences.edit()
editor.putString(
Constants.PREFERENCES_KEY_DEFAULT_SHARE_DESCRIPTION,
defaultShareDescription
)
editor.apply()
}
@JvmStatic
val shareGreeting: String?
get() {
val preferences = preferences
val context = Util.appContext()
val defaultVal = String.format(
context.resources.getString(R.string.share_default_greeting),
context.resources.getString(R.string.common_appname)
)
return preferences.getString(
Constants.PREFERENCES_KEY_DEFAULT_SHARE_GREETING,
defaultVal
)
}
var defaultShareExpiration: String
get() {
val preferences = preferences
return preferences.getString(Constants.PREFERENCES_KEY_DEFAULT_SHARE_EXPIRATION, "0")!!
}
set(defaultShareExpiration) {
val preferences = preferences
val editor = preferences.edit()
editor.putString(
Constants.PREFERENCES_KEY_DEFAULT_SHARE_EXPIRATION,
defaultShareExpiration
)
editor.apply()
}
val defaultShareExpirationInMillis: Long
get() {
val preferences = preferences
val preference =
preferences.getString(Constants.PREFERENCES_KEY_DEFAULT_SHARE_EXPIRATION, "0")!!
val split = PATTERN.split(preference)
if (split.size == 2) {
val timeSpanAmount = split[0].toInt()
val timeSpanType = split[1]
val timeSpan =
TimeSpanPicker.calculateTimeSpan(appContext, timeSpanType, timeSpanAmount)
return timeSpan.totalMilliseconds
}
return 0
}
val shouldShowAllSongsByArtist: Boolean
get() {
val preferences = preferences
return preferences.getBoolean(Constants.PREFERENCES_KEY_SHOW_ALL_SONGS_BY_ARTIST, false)
}
@JvmStatic
val resumeOnBluetoothDevice: Int
get() {
val preferences = preferences
return preferences.getInt(
Constants.PREFERENCES_KEY_RESUME_ON_BLUETOOTH_DEVICE,
Constants.PREFERENCE_VALUE_DISABLED
)
}
@JvmStatic
val pauseOnBluetoothDevice: Int
get() {
val preferences = preferences
return preferences.getInt(
Constants.PREFERENCES_KEY_PAUSE_ON_BLUETOOTH_DEVICE,
Constants.PREFERENCE_VALUE_A2DP
)
}
val debugLogToFile: Boolean
get() {
val preferences = preferences
return preferences.getBoolean(Constants.PREFERENCES_KEY_DEBUG_LOG_TO_FILE, false)
}
@JvmStatic
val preferences: SharedPreferences
get() = PreferenceManager.getDefaultSharedPreferences(Util.appContext())
private val appContext: Context
get() {
return UApp.applicationContext()
}
}

View File

@ -15,7 +15,6 @@ import android.content.ContentResolver
import android.content.Context
import android.content.DialogInterface
import android.content.Intent
import android.content.SharedPreferences
import android.content.pm.PackageManager
import android.graphics.Bitmap
import android.graphics.BitmapFactory
@ -26,7 +25,6 @@ import android.net.ConnectivityManager
import android.net.Uri
import android.net.wifi.WifiManager
import android.net.wifi.WifiManager.WifiLock
import android.os.Build
import android.os.Bundle
import android.os.Environment
import android.os.Parcelable
@ -39,7 +37,6 @@ import android.view.inputmethod.InputMethodManager
import android.widget.Toast
import androidx.annotation.AnyRes
import androidx.media.utils.MediaConstants
import androidx.preference.PreferenceManager
import java.io.ByteArrayOutputStream
import java.io.Closeable
import java.io.File
@ -53,17 +50,14 @@ import java.security.MessageDigest
import java.text.DecimalFormat
import java.util.Locale
import java.util.concurrent.TimeUnit
import java.util.regex.Pattern
import kotlin.math.max
import kotlin.math.min
import kotlin.math.roundToInt
import org.moire.ultrasonic.R
import org.moire.ultrasonic.app.UApp.Companion.applicationContext
import org.moire.ultrasonic.data.ActiveServerProvider.Companion.isOffline
import org.moire.ultrasonic.domain.Bookmark
import org.moire.ultrasonic.domain.MusicDirectory
import org.moire.ultrasonic.domain.PlayerState
import org.moire.ultrasonic.domain.RepeatMode
import org.moire.ultrasonic.domain.SearchResult
import org.moire.ultrasonic.service.DownloadFile
import timber.log.Timber
@ -82,7 +76,6 @@ object Util {
private val GIGA_BYTE_FORMAT = DecimalFormat("0.00 GB")
private val MEGA_BYTE_FORMAT = DecimalFormat("0.00 MB")
private val KILO_BYTE_FORMAT = DecimalFormat("0 KB")
private val PATTERN = Pattern.compile(":")
private var GIGA_BYTE_LOCALIZED_FORMAT: DecimalFormat? = null
private var MEGA_BYTE_LOCALIZED_FORMAT: DecimalFormat? = null
private var KILO_BYTE_LOCALIZED_FORMAT: DecimalFormat? = null
@ -102,67 +95,9 @@ object Util {
return applicationContext()
}
fun isScreenLitOnDownload(): Boolean {
val preferences = getPreferences()
return preferences.getBoolean(
Constants.PREFERENCES_KEY_SCREEN_LIT_ON_DOWNLOAD,
false
)
}
var repeatMode: RepeatMode
get() {
val preferences = getPreferences()
return RepeatMode.valueOf(
preferences.getString(
Constants.PREFERENCES_KEY_REPEAT_MODE,
RepeatMode.OFF.name
)!!
)
}
set(repeatMode) {
val preferences = getPreferences()
val editor = preferences.edit()
editor.putString(Constants.PREFERENCES_KEY_REPEAT_MODE, repeatMode.name)
editor.apply()
}
// After API26 foreground services must be used for music playback,
// and they must have a notification
fun isNotificationEnabled(): Boolean {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) return true
val preferences = getPreferences()
return preferences.getBoolean(Constants.PREFERENCES_KEY_SHOW_NOTIFICATION, false)
}
// After API26 foreground services must be used for music playback,
// and they must have a notification
fun isNotificationAlwaysEnabled(): Boolean {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) return true
val preferences = getPreferences()
return preferences.getBoolean(Constants.PREFERENCES_KEY_ALWAYS_SHOW_NOTIFICATION, false)
}
fun isLockScreenEnabled(): Boolean {
val preferences = getPreferences()
return preferences.getBoolean(
Constants.PREFERENCES_KEY_SHOW_LOCK_SCREEN_CONTROLS,
false
)
}
@JvmStatic
fun getTheme(): String? {
val preferences = getPreferences()
return preferences.getString(
Constants.PREFERENCES_KEY_THEME,
Constants.PREFERENCES_KEY_THEME_DARK
)
}
@JvmStatic
fun applyTheme(context: Context?) {
val theme = getTheme()
val theme = Settings.theme
if (Constants.PREFERENCES_KEY_THEME_DARK.equals(
theme,
ignoreCase = true
@ -180,47 +115,6 @@ object Util {
}
}
private fun getConnectivityManager(): ConnectivityManager {
val context = appContext()
return context.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager
}
@JvmStatic
fun getMaxBitRate(): Int {
val manager = getConnectivityManager()
val networkInfo = manager.activeNetworkInfo ?: return 0
val wifi = networkInfo.type == ConnectivityManager.TYPE_WIFI
val preferences = getPreferences()
return preferences.getString(
if (wifi) Constants.PREFERENCES_KEY_MAX_BITRATE_WIFI
else Constants.PREFERENCES_KEY_MAX_BITRATE_MOBILE,
"0"
)!!.toInt()
}
@JvmStatic
fun getPreloadCount(): Int {
val preferences = getPreferences()
val preloadCount =
preferences.getString(Constants.PREFERENCES_KEY_PRELOAD_COUNT, "-1")!!
.toInt()
return if (preloadCount == -1) Int.MAX_VALUE else preloadCount
}
@JvmStatic
fun getCacheSizeMB(): Int {
val preferences = getPreferences()
val cacheSize = preferences.getString(
Constants.PREFERENCES_KEY_CACHE_SIZE,
"-1"
)!!.toInt()
return if (cacheSize == -1) Int.MAX_VALUE else cacheSize
}
@JvmStatic
fun getPreferences(): SharedPreferences =
PreferenceManager.getDefaultSharedPreferences(appContext())
/**
* Get the contents of an `InputStream` as a `byte[]`.
*
@ -523,7 +417,7 @@ object Util {
val networkInfo = manager.activeNetworkInfo
val connected = networkInfo != null && networkInfo.isConnected
val wifiConnected = connected && networkInfo!!.type == ConnectivityManager.TYPE_WIFI
val wifiRequired = isWifiRequiredForDownload()
val wifiRequired = Settings.isWifiRequiredForDownload
return connected && (!wifiRequired || wifiConnected)
}
@ -531,36 +425,6 @@ object Util {
fun isExternalStoragePresent(): Boolean =
Environment.MEDIA_MOUNTED == Environment.getExternalStorageState()
fun isWifiRequiredForDownload(): Boolean {
val preferences = getPreferences()
return preferences.getBoolean(
Constants.PREFERENCES_KEY_WIFI_REQUIRED_FOR_DOWNLOAD,
false
)
}
fun shouldDisplayBitrateWithArtist(): Boolean {
val preferences = getPreferences()
return preferences.getBoolean(
Constants.PREFERENCES_KEY_DISPLAY_BITRATE_WITH_ARTIST,
true
)
}
@JvmStatic
fun shouldUseFolderForArtistName(): Boolean {
val preferences = getPreferences()
return preferences.getBoolean(
Constants.PREFERENCES_KEY_USE_FOLDER_FOR_ALBUM_ARTIST,
false
)
}
fun shouldShowTrackNumber(): Boolean {
val preferences = getPreferences()
return preferences.getBoolean(Constants.PREFERENCES_KEY_SHOW_TRACK_NUMBER, false)
}
// The AlertDialog requires an Activity context, app context is not enough
// See https://stackoverflow.com/questions/5436822/
fun showDialog(context: Context?, icon: Int, titleId: Int, message: String?) {
@ -690,7 +554,7 @@ object Util {
listSize: Int,
id: Int
) {
if (!shouldSendBluetoothNotifications) {
if (!Settings.shouldSendBluetoothNotifications) {
return
}
var song: MusicDirectory.Entry? = null
@ -707,7 +571,7 @@ object Util {
avrcpIntent.putExtra("album_artist", "")
avrcpIntent.putExtra("album_artist_name", "")
if (getShouldSendBluetoothAlbumArt()) {
if (Settings.shouldSendBluetoothAlbumArt) {
avrcpIntent.putExtra("coverart", null as Parcelable?)
avrcpIntent.putExtra("cover", null as Parcelable?)
}
@ -731,7 +595,7 @@ object Util {
avrcpIntent.putExtra("album_artist", artist)
avrcpIntent.putExtra("album_artist_name", artist)
if (getShouldSendBluetoothAlbumArt()) {
if (Settings.shouldSendBluetoothAlbumArt) {
val albumArtFile = FileUtil.getAlbumArtFile(song)
avrcpIntent.putExtra("coverart", albumArtFile.absolutePath)
avrcpIntent.putExtra("cover", albumArtFile.absolutePath)
@ -757,7 +621,7 @@ object Util {
id: Int,
playerPosition: Int
) {
if (!shouldSendBluetoothNotifications) {
if (!Settings.shouldSendBluetoothNotifications) {
return
}
if (newSong != null) {
@ -777,7 +641,7 @@ object Util {
avrcpIntent.putExtra("album_artist", artist)
avrcpIntent.putExtra("album_artist_name", artist)
if (getShouldSendBluetoothAlbumArt()) {
if (Settings.shouldSendBluetoothAlbumArt) {
val albumArtFile = FileUtil.getAlbumArtFile(newSong)
avrcpIntent.putExtra("coverart", albumArtFile.absolutePath)
avrcpIntent.putExtra("cover", albumArtFile.absolutePath)
@ -881,143 +745,11 @@ object Util {
return inSampleSize
}
@JvmStatic
fun getDefaultAlbums(): Int {
val preferences = getPreferences()
return preferences.getString(Constants.PREFERENCES_KEY_DEFAULT_ALBUMS, "5")!!
.toInt()
}
@JvmStatic
fun getMaxAlbums(): Int {
val preferences = getPreferences()
return preferences.getString(Constants.PREFERENCES_KEY_MAX_ALBUMS, "20")!!
.toInt()
}
@JvmStatic
fun getDefaultSongs(): Int {
val preferences = getPreferences()
return preferences.getString(Constants.PREFERENCES_KEY_DEFAULT_SONGS, "10")!!
.toInt()
}
@JvmStatic
fun getMaxSongs(): Int {
val preferences = getPreferences()
return preferences.getString(Constants.PREFERENCES_KEY_MAX_SONGS, "25")!!
.toInt()
}
@JvmStatic
fun getMaxArtists(): Int {
val preferences = getPreferences()
return preferences.getString(Constants.PREFERENCES_KEY_MAX_ARTISTS, "10")!!
.toInt()
}
@JvmStatic
fun getDefaultArtists(): Int {
val preferences = getPreferences()
return preferences.getString(Constants.PREFERENCES_KEY_DEFAULT_ARTISTS, "3")!!
.toInt()
}
@JvmStatic
fun getBufferLength(): Int {
val preferences = getPreferences()
return preferences.getString(Constants.PREFERENCES_KEY_BUFFER_LENGTH, "5")!!
.toInt()
}
@JvmStatic
fun getIncrementTime(): Int {
val preferences = getPreferences()
return preferences.getString(Constants.PREFERENCES_KEY_INCREMENT_TIME, "5")!!
.toInt()
}
@JvmStatic
fun getMediaButtonsEnabled(): Boolean {
val preferences = getPreferences()
return preferences.getBoolean(Constants.PREFERENCES_KEY_MEDIA_BUTTONS, true)
}
@JvmStatic
fun getShowNowPlayingPreference(): Boolean {
val preferences = getPreferences()
return preferences.getBoolean(Constants.PREFERENCES_KEY_SHOW_NOW_PLAYING, true)
}
@JvmStatic
fun getGaplessPlaybackPreference(): Boolean {
val preferences = getPreferences()
return preferences.getBoolean(Constants.PREFERENCES_KEY_GAPLESS_PLAYBACK, false)
}
@JvmStatic
fun getShouldTransitionOnPlaybackPreference(): Boolean {
val preferences = getPreferences()
return preferences.getBoolean(Constants.PREFERENCES_KEY_DOWNLOAD_TRANSITION, true)
}
@JvmStatic
fun getShouldUseId3Tags(): Boolean {
val preferences = getPreferences()
return preferences.getBoolean(Constants.PREFERENCES_KEY_ID3_TAGS, false)
}
fun getShouldShowArtistPicture(): Boolean {
val preferences = getPreferences()
val isOffline = isOffline()
val isId3Enabled = preferences.getBoolean(Constants.PREFERENCES_KEY_ID3_TAGS, false)
val shouldShowArtistPicture =
preferences.getBoolean(Constants.PREFERENCES_KEY_SHOW_ARTIST_PICTURE, false)
return !isOffline && isId3Enabled && shouldShowArtistPicture
}
@JvmStatic
fun getChatRefreshInterval(): Int {
val preferences = getPreferences()
return preferences.getString(
Constants.PREFERENCES_KEY_CHAT_REFRESH_INTERVAL,
"5000"
)!!.toInt()
}
fun getDirectoryCacheTime(): Int {
val preferences = getPreferences()
return preferences.getString(
Constants.PREFERENCES_KEY_DIRECTORY_CACHE_TIME,
"300"
)!!.toInt()
}
@JvmStatic
fun isNullOrWhiteSpace(string: String?): Boolean {
return string == null || string.isEmpty() || string.trim { it <= ' ' }.isEmpty()
}
fun getShouldClearPlaylist(): Boolean {
val preferences = getPreferences()
return preferences.getBoolean(Constants.PREFERENCES_KEY_CLEAR_PLAYLIST, false)
}
fun getShouldSortByDisc(): Boolean {
val preferences = getPreferences()
return preferences.getBoolean(Constants.PREFERENCES_KEY_DISC_SORT, false)
}
fun getShouldClearBookmark(): Boolean {
val preferences = getPreferences()
return preferences.getBoolean(Constants.PREFERENCES_KEY_CLEAR_BOOKMARK, false)
}
fun getSingleButtonPlayPause(): Boolean {
val preferences = getPreferences()
return preferences.getBoolean(Constants.PREFERENCES_KEY_SINGLE_BUTTON_PLAY_PAUSE, false)
}
@JvmOverloads
fun formatTotalDuration(totalDuration: Long, inMilliseconds: Boolean = false): String {
var millis = totalDuration
@ -1082,106 +814,6 @@ object Util {
return versionCode
}
// Inverted for readability
val shouldSendBluetoothNotifications: Boolean
get() {
val preferences = getPreferences()
return preferences.getBoolean(
Constants.PREFERENCES_KEY_SEND_BLUETOOTH_NOTIFICATIONS,
true
)
}
private fun getShouldSendBluetoothAlbumArt(): Boolean {
val preferences = getPreferences()
return preferences.getBoolean(Constants.PREFERENCES_KEY_SEND_BLUETOOTH_ALBUM_ART, true)
}
@JvmStatic
fun getViewRefreshInterval(): Int {
val preferences = getPreferences()
return preferences.getString(Constants.PREFERENCES_KEY_VIEW_REFRESH, "1000")!!
.toInt()
}
var shouldAskForShareDetails: Boolean
get() {
val preferences = getPreferences()
return preferences.getBoolean(Constants.PREFERENCES_KEY_ASK_FOR_SHARE_DETAILS, true)
}
set(shouldAskForShareDetails) {
val preferences = getPreferences()
val editor = preferences.edit()
editor.putBoolean(
Constants.PREFERENCES_KEY_ASK_FOR_SHARE_DETAILS,
shouldAskForShareDetails
)
editor.apply()
}
var defaultShareDescription: String?
get() {
val preferences = getPreferences()
return preferences.getString(Constants.PREFERENCES_KEY_DEFAULT_SHARE_DESCRIPTION, "")
}
set(defaultShareDescription) {
val preferences = getPreferences()
val editor = preferences.edit()
editor.putString(
Constants.PREFERENCES_KEY_DEFAULT_SHARE_DESCRIPTION,
defaultShareDescription
)
editor.apply()
}
@JvmStatic
fun getShareGreeting(): String? {
val preferences = getPreferences()
val context = appContext()
val defaultVal = String.format(
context.resources.getString(R.string.share_default_greeting),
context.resources.getString(R.string.common_appname)
)
return preferences.getString(
Constants.PREFERENCES_KEY_DEFAULT_SHARE_GREETING,
defaultVal
)
}
var defaultShareExpiration: String
get() {
val preferences = getPreferences()
return preferences.getString(Constants.PREFERENCES_KEY_DEFAULT_SHARE_EXPIRATION, "0")!!
}
set(defaultShareExpiration) {
val preferences = getPreferences()
val editor = preferences.edit()
editor.putString(
Constants.PREFERENCES_KEY_DEFAULT_SHARE_EXPIRATION,
defaultShareExpiration
)
editor.apply()
}
fun getDefaultShareExpirationInMillis(context: Context?): Long {
val preferences = getPreferences()
val preference =
preferences.getString(Constants.PREFERENCES_KEY_DEFAULT_SHARE_EXPIRATION, "0")!!
val split = PATTERN.split(preference)
if (split.size == 2) {
val timeSpanAmount = split[0].toInt()
val timeSpanType = split[1]
val timeSpan = TimeSpanPicker.calculateTimeSpan(context, timeSpanType, timeSpanAmount)
return timeSpan.totalMilliseconds
}
return 0
}
fun getShouldShowAllSongsByArtist(): Boolean {
val preferences = getPreferences()
return preferences.getBoolean(Constants.PREFERENCES_KEY_SHOW_ALL_SONGS_BY_ARTIST, false)
}
@JvmStatic
fun scanMedia(file: File?) {
val uri = Uri.fromFile(file)
@ -1197,7 +829,7 @@ object Util {
}
fun isFirstRun(): Boolean {
val preferences = getPreferences()
val preferences = Settings.preferences
val firstExecuted =
preferences.getBoolean(Constants.PREFERENCES_KEY_FIRST_RUN_EXECUTED, false)
if (firstExecuted) return false
@ -1207,29 +839,6 @@ object Util {
return true
}
@JvmStatic
fun getResumeOnBluetoothDevice(): Int {
val preferences = getPreferences()
return preferences.getInt(
Constants.PREFERENCES_KEY_RESUME_ON_BLUETOOTH_DEVICE,
Constants.PREFERENCE_VALUE_DISABLED
)
}
@JvmStatic
fun getPauseOnBluetoothDevice(): Int {
val preferences = getPreferences()
return preferences.getInt(
Constants.PREFERENCES_KEY_PAUSE_ON_BLUETOOTH_DEVICE,
Constants.PREFERENCE_VALUE_A2DP
)
}
fun getDebugLogToFile(): Boolean {
val preferences = getPreferences()
return preferences.getBoolean(Constants.PREFERENCES_KEY_DEBUG_LOG_TO_FILE, false)
}
fun hideKeyboard(activity: Activity?) {
val inputManager =
activity!!.getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager
@ -1285,7 +894,7 @@ object Util {
val artistName = song.artist
if (artistName != null) {
if (shouldDisplayBitrateWithArtist() && (
if (Settings.shouldDisplayBitrateWithArtist && (
!bitRate.isNullOrBlank() || !fileFormat.isNullOrBlank()
)
) {
@ -1305,12 +914,12 @@ object Util {
val trackNumber = song.track ?: 0
val title = StringBuilder(LINE_LENGTH)
if (shouldShowTrackNumber() && trackNumber > 0)
if (Settings.shouldShowTrackNumber && trackNumber > 0)
title.append(String.format(Locale.ROOT, "%02d - ", trackNumber))
title.append(song.title)
if (song.isVideo && shouldDisplayBitrateWithArtist()) {
if (song.isVideo && Settings.shouldDisplayBitrateWithArtist) {
title.append(" (").append(
String.format(
appContext().getString(R.string.song_details_all),
@ -1349,4 +958,9 @@ object Util {
intent.putExtra(Intent.EXTRA_KEY_EVENT, KeyEvent(KeyEvent.ACTION_DOWN, keycode))
return PendingIntent.getBroadcast(context, requestCode, intent, flags)
}
fun getConnectivityManager(): ConnectivityManager {
val context = Util.appContext()
return context.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager
}
}

View File

@ -35,6 +35,7 @@ import org.moire.ultrasonic.featureflags.FeatureStorage
import org.moire.ultrasonic.service.DownloadFile
import org.moire.ultrasonic.service.MediaPlayerController
import org.moire.ultrasonic.service.MusicServiceFactory.getMusicService
import org.moire.ultrasonic.util.Settings
import org.moire.ultrasonic.util.Util
import org.moire.ultrasonic.view.EntryAdapter.SongViewHolder
import timber.log.Timber
@ -116,7 +117,7 @@ class SongView(context: Context) : UpdateView(context), Checkable, KoinComponent
val artistName = song.artist
if (artistName != null) {
if (Util.shouldDisplayBitrateWithArtist()) {
if (Settings.shouldDisplayBitrateWithArtist) {
artist.append(artistName).append(" (").append(
String.format(
this.context.getString(R.string.song_details_all),
@ -130,7 +131,7 @@ class SongView(context: Context) : UpdateView(context), Checkable, KoinComponent
val trackNumber = song.track ?: 0
if (Util.shouldShowTrackNumber() && trackNumber != 0) {
if (Settings.shouldShowTrackNumber && trackNumber != 0) {
viewHolder?.track?.text = String.format("%02d.", trackNumber)
} else {
viewHolder?.track?.visibility = GONE
@ -139,7 +140,7 @@ class SongView(context: Context) : UpdateView(context), Checkable, KoinComponent
val title = StringBuilder(60)
title.append(song.title)
if (song.isVideo && Util.shouldDisplayBitrateWithArtist()) {
if (song.isVideo && Settings.shouldDisplayBitrateWithArtist) {
title.append(" (").append(
String.format(
this.context.getString(R.string.song_details_all),
@ -359,7 +360,7 @@ class SongView(context: Context) : UpdateView(context), Checkable, KoinComponent
}
init {
val theme = Util.getTheme()
val theme = Settings.theme
val themesMatch = theme == Companion.theme
inflater = LayoutInflater.from(this.context)

View File

@ -284,6 +284,8 @@
<string name="settings.search_title">Search Settings</string>
<string name="settings.send_bluetooth_album_art_summary">Send album art over Bluetooth (May cause Bluetooth notifications to fail)</string>
<string name="settings.send_bluetooth_album_art">Album Art Over Bluetooth</string>
<string name="settings.disable_send_now_playing_list_summary">Now Playing List won\'t be sent to connected devices. This may restore compatibility with AVRCP 1.3 devices, when current track display is not updated</string>
<string name="settings.disable_send_now_playing_list">Disable sending of Now Playing List</string>
<string name="settings.send_bluetooth_notification_summary">Send playback notifications via Bluetooth</string>
<string name="settings.send_bluetooth_notification">Send Bluetooth Notification</string>
<string name="settings.server_manage_servers">Manage Servers</string>

View File

@ -179,6 +179,12 @@
a:summary="@string/settings.send_bluetooth_album_art_summary"
a:title="@string/settings.send_bluetooth_album_art"
app:iconSpaceReserved="false"/>
<CheckBoxPreference
a:defaultValue="false"
a:key="disableNowPlayingListSending"
a:summary="@string/settings.disable_send_now_playing_list_summary"
a:title="@string/settings.disable_send_now_playing_list"
app:iconSpaceReserved="false"/>
</PreferenceCategory>
<PreferenceCategory
a:title="@string/settings.sharing_title"