From 2d9a212b5c96b074f46f40047d060c1f090c430f Mon Sep 17 00:00:00 2001 From: tzugen Date: Sat, 23 Oct 2021 17:25:59 +0200 Subject: [PATCH 1/7] Cleanup a bunch of preference setters and getters by using the new utility class --- .../ultrasonic/fragment/SettingsFragment.java | 27 ++++--------- .../ultrasonic/data/ActiveServerProvider.kt | 12 ++---- .../ultrasonic/service/AudioFocusHandler.kt | 7 +--- .../org/moire/ultrasonic/util/Settings.kt | 9 +++++ .../kotlin/org/moire/ultrasonic/util/Util.kt | 39 ++++++++----------- 5 files changed, 36 insertions(+), 58 deletions(-) diff --git a/ultrasonic/src/main/java/org/moire/ultrasonic/fragment/SettingsFragment.java b/ultrasonic/src/main/java/org/moire/ultrasonic/fragment/SettingsFragment.java index c1fb0466..8ce6e4a9 100644 --- a/ultrasonic/src/main/java/org/moire/ultrasonic/fragment/SettingsFragment.java +++ b/ultrasonic/src/main/java/org/moire/ultrasonic/fragment/SettingsFragment.java @@ -26,7 +26,6 @@ import org.moire.ultrasonic.R; import org.moire.ultrasonic.featureflags.Feature; import org.moire.ultrasonic.featureflags.FeatureStorage; import org.moire.ultrasonic.filepicker.FilePickerDialog; -import org.moire.ultrasonic.filepicker.OnFileSelectedListener; import org.moire.ultrasonic.log.FileLoggerTree; import org.moire.ultrasonic.provider.SearchSuggestionProvider; import org.moire.ultrasonic.service.Consumer; @@ -233,15 +232,9 @@ public class SettingsFragment extends PreferenceFragmentCompat FilePickerDialog filePickerDialog = FilePickerDialog.Companion.createFilePickerDialog(getContext()); filePickerDialog.setDefaultDirectory(FileUtil.getDefaultMusicDirectory().getPath()); filePickerDialog.setInitialDirectory(cacheLocation.getSummary().toString()); - filePickerDialog.setOnFileSelectedListener(new OnFileSelectedListener() { - @Override - public void onFileSelected(File file, String path) { - SharedPreferences.Editor editor = cacheLocation.getSharedPreferences().edit(); - editor.putString(Constants.PREFERENCES_KEY_CACHE_LOCATION, path); - editor.apply(); - - setCacheLocation(path); - } + filePickerDialog.setOnFileSelectedListener((file, path) -> { + Settings.setCacheLocation(path); + setCacheLocation(path); }); filePickerDialog.show(); } @@ -287,9 +280,7 @@ public class SettingsFragment extends PreferenceFragmentCompat new Consumer() { @Override public void accept(Integer choice) { - SharedPreferences.Editor editor = pauseOnBluetoothDevice.getSharedPreferences().edit(); - editor.putInt(Constants.PREFERENCES_KEY_PAUSE_ON_BLUETOOTH_DEVICE, choice); - editor.apply(); + Settings.setPauseOnBluetoothDevice(choice); pauseOnBluetoothDevice.setSummary(bluetoothDevicePreferenceToString(choice)); } }); @@ -442,13 +433,9 @@ public class SettingsFragment extends PreferenceFragmentCompat File dir = new File(path); if (!FileUtil.ensureDirectoryExistsAndIsReadWritable(dir)) { - permissionUtil.getValue().handlePermissionFailed(new PermissionUtil.PermissionRequestFinishedCallback() { - @Override - public void onPermissionRequestFinished(boolean hasPermission) { - String currentPath = settings.getString(Constants.PREFERENCES_KEY_CACHE_LOCATION, - FileUtil.getDefaultMusicDirectory().getPath()); - cacheLocation.setSummary(currentPath); - } + permissionUtil.getValue().handlePermissionFailed(hasPermission -> { + String currentPath = Settings.getCacheLocation(); + cacheLocation.setSummary(currentPath); }); } else { diff --git a/ultrasonic/src/main/kotlin/org/moire/ultrasonic/data/ActiveServerProvider.kt b/ultrasonic/src/main/kotlin/org/moire/ultrasonic/data/ActiveServerProvider.kt index 1d768071..4cfab1a9 100644 --- a/ultrasonic/src/main/kotlin/org/moire/ultrasonic/data/ActiveServerProvider.kt +++ b/ultrasonic/src/main/kotlin/org/moire/ultrasonic/data/ActiveServerProvider.kt @@ -193,8 +193,7 @@ class ActiveServerProvider( * Queries the Id of the Active Server */ fun getActiveServerId(): Int { - val preferences = Settings.preferences - return preferences.getInt(Constants.PREFERENCES_KEY_SERVER_INSTANCE, -1) + return Settings.activeServer } /** @@ -203,11 +202,7 @@ class ActiveServerProvider( fun setActiveServerId(serverId: Int) { resetMusicService() - val preferences = Settings.preferences - val editor = preferences.edit() - editor.putInt(Constants.PREFERENCES_KEY_SERVER_INSTANCE, serverId) - editor.apply() - + Settings.activeServer = serverId liveActiveServerId.postValue(serverId) } @@ -229,8 +224,7 @@ class ActiveServerProvider( if (isOffline()) { return false } - val preferences = Settings.preferences - return preferences.getBoolean(Constants.PREFERENCES_KEY_SERVER_SCALING, false) + return Settings.serverScaling } } } diff --git a/ultrasonic/src/main/kotlin/org/moire/ultrasonic/service/AudioFocusHandler.kt b/ultrasonic/src/main/kotlin/org/moire/ultrasonic/service/AudioFocusHandler.kt index c49df186..2f36974a 100644 --- a/ultrasonic/src/main/kotlin/org/moire/ultrasonic/service/AudioFocusHandler.kt +++ b/ultrasonic/src/main/kotlin/org/moire/ultrasonic/service/AudioFocusHandler.kt @@ -11,7 +11,6 @@ import androidx.media.AudioFocusRequestCompat 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.Settings import timber.log.Timber @@ -25,12 +24,8 @@ class AudioFocusHandler(private val context: Context) { context.getSystemService(Context.AUDIO_SERVICE) as AudioManager } - private val preferences by lazy { - Settings.preferences - } - private val lossPref: Int - get() = preferences.getString(Constants.PREFERENCES_KEY_TEMP_LOSS, "1")!!.toInt() + get() = Settings.tempLoss private val audioAttributesCompat by lazy { AudioAttributesCompat.Builder() 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 73043a0b..7a45b123 100644 --- a/ultrasonic/src/main/kotlin/org/moire/ultrasonic/util/Settings.kt +++ b/ultrasonic/src/main/kotlin/org/moire/ultrasonic/util/Settings.kt @@ -185,6 +185,15 @@ object Settings { var shouldUseId3Tags by BooleanSetting(Constants.PREFERENCES_KEY_ID3_TAGS, false) + @JvmStatic + var tempLoss by StringIntSetting(Constants.PREFERENCES_KEY_TEMP_LOSS, "1") + + var activeServer by IntSetting(Constants.PREFERENCES_KEY_SERVER_INSTANCE, -1) + + var serverScaling by BooleanSetting(Constants.PREFERENCES_KEY_SERVER_SCALING, false) + + var firstRunExecuted by BooleanSetting(Constants.PREFERENCES_KEY_FIRST_RUN_EXECUTED, false) + val shouldShowArtistPicture: Boolean get() { val preferences = preferences diff --git a/ultrasonic/src/main/kotlin/org/moire/ultrasonic/util/Util.kt b/ultrasonic/src/main/kotlin/org/moire/ultrasonic/util/Util.kt index 3c5d2b91..c6a8af0b 100644 --- a/ultrasonic/src/main/kotlin/org/moire/ultrasonic/util/Util.kt +++ b/ultrasonic/src/main/kotlin/org/moire/ultrasonic/util/Util.kt @@ -95,21 +95,18 @@ object Util { @JvmStatic fun applyTheme(context: Context?) { - val theme = Settings.theme - if (Constants.PREFERENCES_KEY_THEME_DARK.equals( - theme, - ignoreCase = true - ) || "fullscreen".equals(theme, ignoreCase = true) - ) { - context!!.setTheme(R.style.UltrasonicTheme) - } else if (Constants.PREFERENCES_KEY_THEME_BLACK.equals(theme, ignoreCase = true)) { - context!!.setTheme(R.style.UltrasonicTheme_Black) - } else if (Constants.PREFERENCES_KEY_THEME_LIGHT.equals( - theme, - ignoreCase = true - ) || "fullscreenlight".equals(theme, ignoreCase = true) - ) { - context!!.setTheme(R.style.UltrasonicTheme_Light) + when (Settings.theme.lowercase()) { + Constants.PREFERENCES_KEY_THEME_DARK, + "fullscreen" -> { + context!!.setTheme(R.style.UltrasonicTheme) + } + Constants.PREFERENCES_KEY_THEME_BLACK -> { + context!!.setTheme(R.style.UltrasonicTheme_Black) + } + Constants.PREFERENCES_KEY_THEME_LIGHT, + "fullscreenlight" -> { + context!!.setTheme(R.style.UltrasonicTheme_Light) + } } } @@ -794,13 +791,9 @@ object Util { } fun isFirstRun(): Boolean { - val preferences = Settings.preferences - val firstExecuted = - preferences.getBoolean(Constants.PREFERENCES_KEY_FIRST_RUN_EXECUTED, false) - if (firstExecuted) return false - val editor = preferences.edit() - editor.putBoolean(Constants.PREFERENCES_KEY_FIRST_RUN_EXECUTED, true) - editor.apply() + if (Settings.firstRunExecuted) return false + + Settings.firstRunExecuted = true return true } @@ -925,7 +918,7 @@ object Util { } fun getConnectivityManager(): ConnectivityManager { - val context = Util.appContext() + val context = appContext() return context.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager } } From e19d43d6b33e4d0da7319b2f1e2987f00f5cb842 Mon Sep 17 00:00:00 2001 From: tzugen Date: Mon, 25 Oct 2021 18:43:20 +0200 Subject: [PATCH 2/7] Better wording --- ultrasonic/src/main/res/values/strings.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ultrasonic/src/main/res/values/strings.xml b/ultrasonic/src/main/res/values/strings.xml index f9666771..a4f4e6f2 100644 --- a/ultrasonic/src/main/res/values/strings.xml +++ b/ultrasonic/src/main/res/values/strings.xml @@ -400,7 +400,7 @@ All Bluetooth devices Only audio (A2DP) devices Disabled - Single button Play/Pause on Bluetooth device + Bluetooth device with only a single Play/Pause button Enabling this may help with older Bluetooth devices when Play/Pause doesn\'t work correctly Debug options Write debug log to file From 4d42c0d9d262398edf3c16f4e9f719ed5bfd4675 Mon Sep 17 00:00:00 2001 From: tzugen Date: Sat, 30 Oct 2021 15:28:53 +0200 Subject: [PATCH 3/7] Use lambdas in SettingsFragment, remove Consumer class. --- .../ultrasonic/fragment/SettingsFragment.java | 202 +++++++----------- .../moire/ultrasonic/service/Consumer.java | 12 -- 2 files changed, 73 insertions(+), 141 deletions(-) delete mode 100644 ultrasonic/src/main/java/org/moire/ultrasonic/service/Consumer.java diff --git a/ultrasonic/src/main/java/org/moire/ultrasonic/fragment/SettingsFragment.java b/ultrasonic/src/main/java/org/moire/ultrasonic/fragment/SettingsFragment.java index 8ce6e4a9..126039c8 100644 --- a/ultrasonic/src/main/java/org/moire/ultrasonic/fragment/SettingsFragment.java +++ b/ultrasonic/src/main/java/org/moire/ultrasonic/fragment/SettingsFragment.java @@ -1,7 +1,6 @@ package org.moire.ultrasonic.fragment; import android.app.AlertDialog; -import android.content.DialogInterface; import android.content.SharedPreferences; import android.os.Build; import android.os.Bundle; @@ -11,14 +10,12 @@ import android.view.View; import androidx.annotation.Nullable; import androidx.annotation.StringRes; import androidx.fragment.app.DialogFragment; -import androidx.navigation.Navigation; import androidx.preference.CheckBoxPreference; import androidx.preference.EditTextPreference; import androidx.preference.ListPreference; import androidx.preference.Preference; import androidx.preference.PreferenceCategory; import androidx.preference.PreferenceFragmentCompat; -import androidx.preference.PreferenceManager; import org.jetbrains.annotations.NotNull; import org.koin.java.KoinJavaComponent; @@ -28,7 +25,6 @@ import org.moire.ultrasonic.featureflags.FeatureStorage; import org.moire.ultrasonic.filepicker.FilePickerDialog; import org.moire.ultrasonic.log.FileLoggerTree; import org.moire.ultrasonic.provider.SearchSuggestionProvider; -import org.moire.ultrasonic.service.Consumer; import org.moire.ultrasonic.service.MediaPlayerController; import org.moire.ultrasonic.util.Constants; import org.moire.ultrasonic.util.FileUtil; @@ -43,10 +39,10 @@ import org.moire.ultrasonic.util.Util; import java.io.File; import kotlin.Lazy; +import kotlin.jvm.functions.Function1; import timber.log.Timber; import static org.koin.java.KoinJavaComponent.inject; -import static org.moire.ultrasonic.fragment.ServerSelectorFragment.SERVER_SELECTOR_MANAGE_MODE; /** * Shows main app settings. @@ -84,8 +80,6 @@ public class SettingsFragment extends PreferenceFragmentCompat private Preference pauseOnBluetoothDevice; private CheckBoxPreference debugLogToFile; - private SharedPreferences settings; - private final Lazy mediaPlayerControllerLazy = inject(MediaPlayerController.class); private final Lazy permissionUtil = inject(PermissionUtil.class); private final Lazy themeChangedEventDistributor = inject(ThemeChangedEventDistributor.class); @@ -94,8 +88,6 @@ public class SettingsFragment extends PreferenceFragmentCompat @Override public void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); - - settings = PreferenceManager.getDefaultSharedPreferences(getActivity()); } @Override @@ -148,9 +140,11 @@ public class SettingsFragment extends PreferenceFragmentCompat if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { PreferenceCategory notificationsCategory = findPreference(Constants.PREFERENCES_KEY_CATEGORY_NOTIFICATIONS); Preference preferenceToRemove = findPreference(Constants.PREFERENCES_KEY_SHOW_NOTIFICATION); - if (preferenceToRemove != null) notificationsCategory.removePreference(preferenceToRemove); + if (preferenceToRemove != null) + notificationsCategory.removePreference(preferenceToRemove); preferenceToRemove = findPreference(Constants.PREFERENCES_KEY_ALWAYS_SHOW_NOTIFICATION); - if (preferenceToRemove != null) notificationsCategory.removePreference(preferenceToRemove); + if (preferenceToRemove != null) + notificationsCategory.removePreference(preferenceToRemove); } } @@ -196,24 +190,19 @@ public class SettingsFragment extends PreferenceFragmentCompat } @Override - public void onDisplayPreferenceDialog(Preference preference) - { + public void onDisplayPreferenceDialog(Preference preference) { DialogFragment dialogFragment = null; - if (preference instanceof TimeSpanPreference) - { + if (preference instanceof TimeSpanPreference) { dialogFragment = new TimeSpanPreferenceDialogFragmentCompat(); Bundle bundle = new Bundle(1); bundle.putString("key", preference.getKey()); dialogFragment.setArguments(bundle); } - if (dialogFragment != null) - { + if (dialogFragment != null) { dialogFragment.setTargetFragment(this, 0); dialogFragment.show(this.getParentFragmentManager(), "android.support.v7.preference.PreferenceFragment.DIALOG"); - } - else - { + } else { super.onDisplayPreferenceDialog(preference); } } @@ -221,27 +210,21 @@ public class SettingsFragment extends PreferenceFragmentCompat private void setupCacheLocationPreference() { cacheLocation.setSummary(Settings.getCacheLocation()); - cacheLocation.setOnPreferenceClickListener(new Preference.OnPreferenceClickListener() { - @Override - public boolean onPreferenceClick(Preference preference) { + cacheLocation.setOnPreferenceClickListener(preference -> { // If the user tries to change the cache location, we must first check to see if we have write access. - PermissionUtil.requestInitialPermission(getActivity(), new PermissionUtil.PermissionRequestFinishedCallback() { - @Override - public void onPermissionRequestFinished(boolean hasPermission) { - if (hasPermission) { - FilePickerDialog filePickerDialog = FilePickerDialog.Companion.createFilePickerDialog(getContext()); - filePickerDialog.setDefaultDirectory(FileUtil.getDefaultMusicDirectory().getPath()); - filePickerDialog.setInitialDirectory(cacheLocation.getSummary().toString()); - filePickerDialog.setOnFileSelectedListener((file, path) -> { - Settings.setCacheLocation(path); - setCacheLocation(path); - }); - filePickerDialog.show(); - } - } - }); + PermissionUtil.requestInitialPermission(getActivity(), hasPermission -> { + if (hasPermission) { + FilePickerDialog filePickerDialog = FilePickerDialog.Companion.createFilePickerDialog(getContext()); + filePickerDialog.setDefaultDirectory(FileUtil.getDefaultMusicDirectory().getPath()); + filePickerDialog.setInitialDirectory(cacheLocation.getSummary().toString()); + filePickerDialog.setOnFileSelectedListener((file, path) -> { + Settings.setCacheLocation(path); + setCacheLocation(path); + }); + filePickerDialog.show(); + } + }); return true; - } }); } @@ -252,75 +235,56 @@ public class SettingsFragment extends PreferenceFragmentCompat resumeOnBluetoothDevice.setSummary(bluetoothDevicePreferenceToString(resumeSetting)); pauseOnBluetoothDevice.setSummary(bluetoothDevicePreferenceToString(pauseSetting)); - resumeOnBluetoothDevice.setOnPreferenceClickListener(new Preference.OnPreferenceClickListener() { - @Override - public boolean onPreferenceClick(Preference preference) { + resumeOnBluetoothDevice.setOnPreferenceClickListener(preference -> { showBluetoothDevicePreferenceDialog( - R.string.settings_playback_resume_on_bluetooth_device, - Settings.getResumeOnBluetoothDevice(), - new Consumer() { - @Override - public void accept(Integer choice) { + R.string.settings_playback_resume_on_bluetooth_device, + Settings.getResumeOnBluetoothDevice(), + choice -> { SharedPreferences.Editor editor = resumeOnBluetoothDevice.getSharedPreferences().edit(); editor.putInt(Constants.PREFERENCES_KEY_RESUME_ON_BLUETOOTH_DEVICE, choice); editor.apply(); resumeOnBluetoothDevice.setSummary(bluetoothDevicePreferenceToString(choice)); - } - }); + return null; + }); return true; - } }); - pauseOnBluetoothDevice.setOnPreferenceClickListener(new Preference.OnPreferenceClickListener() { - @Override - public boolean onPreferenceClick(Preference preference) { + pauseOnBluetoothDevice.setOnPreferenceClickListener(preference -> { showBluetoothDevicePreferenceDialog( - R.string.settings_playback_pause_on_bluetooth_device, - Settings.getPauseOnBluetoothDevice(), - new Consumer() { - @Override - public void accept(Integer choice) { + R.string.settings_playback_pause_on_bluetooth_device, + Settings.getPauseOnBluetoothDevice(), choice -> + { Settings.setPauseOnBluetoothDevice(choice); pauseOnBluetoothDevice.setSummary(bluetoothDevicePreferenceToString(choice)); - } - }); + return null; + }); return true; - } }); } - private void showBluetoothDevicePreferenceDialog(@StringRes int title, int defaultChoice, final Consumer onChosen) { + private void showBluetoothDevicePreferenceDialog(@StringRes int title, int defaultChoice, final Function1 onChosen) { final int[] choice = {defaultChoice}; new AlertDialog.Builder(getActivity()).setTitle(title) - .setSingleChoiceItems(R.array.bluetoothDeviceSettingNames, defaultChoice, - new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialogInterface, int i) { - choice[0] = i; - } - }) - .setNegativeButton(R.string.common_cancel, new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialogInterface, int i) { - dialogInterface.cancel(); - } - }) - .setPositiveButton(R.string.common_ok, new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialogInterface, int i) { - onChosen.accept(choice[0]); + .setSingleChoiceItems(R.array.bluetoothDeviceSettingNames, defaultChoice, + (dialogInterface, i) -> choice[0] = i) + .setNegativeButton(R.string.common_cancel, (dialogInterface, i) -> dialogInterface.cancel()) + .setPositiveButton(R.string.common_ok, (dialogInterface, i) -> { + onChosen.invoke(choice[0]); dialogInterface.dismiss(); - } - }) - .create().show(); + }) + .create().show(); } private String bluetoothDevicePreferenceToString(int preferenceValue) { switch (preferenceValue) { - case Constants.PREFERENCE_VALUE_ALL: return getString(R.string.settings_playback_bluetooth_all); - case Constants.PREFERENCE_VALUE_A2DP: return getString(R.string.settings_playback_bluetooth_a2dp); - case Constants.PREFERENCE_VALUE_DISABLED: return getString(R.string.settings_playback_bluetooth_disabled); - default: return ""; + case Constants.PREFERENCE_VALUE_ALL: + return getString(R.string.settings_playback_bluetooth_all); + case Constants.PREFERENCE_VALUE_A2DP: + return getString(R.string.settings_playback_bluetooth_a2dp); + case Constants.PREFERENCE_VALUE_DISABLED: + return getString(R.string.settings_playback_bluetooth_disabled); + default: + return ""; } } @@ -328,17 +292,14 @@ public class SettingsFragment extends PreferenceFragmentCompat Preference clearSearchPreference = findPreference(Constants.PREFERENCES_KEY_CLEAR_SEARCH_HISTORY); if (clearSearchPreference != null) { - clearSearchPreference.setOnPreferenceClickListener(new Preference.OnPreferenceClickListener() { - @Override - public boolean onPreferenceClick(Preference preference) { - SearchRecentSuggestions suggestions = - new SearchRecentSuggestions(getActivity(), - SearchSuggestionProvider.AUTHORITY, - SearchSuggestionProvider.MODE); - suggestions.clearHistory(); - Util.toast(getActivity(), R.string.settings_search_history_cleared); - return false; - } + clearSearchPreference.setOnPreferenceClickListener(preference -> { + SearchRecentSuggestions suggestions = + new SearchRecentSuggestions(getActivity(), + SearchSuggestionProvider.AUTHORITY, + SearchSuggestionProvider.MODE); + suggestions.clearHistory(); + Util.toast(getActivity(), R.string.settings_search_history_cleared); + return false; }); } } @@ -351,12 +312,9 @@ public class SettingsFragment extends PreferenceFragmentCompat if (useFiveStarRating != null) { useFiveStarRating.setChecked(featureStorage.isFeatureEnabled(Feature.FIVE_STAR_RATING)); - useFiveStarRating.setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener() { - @Override - public boolean onPreferenceChange(Preference preference, Object o) { - featureStorage.changeFeatureFlag(Feature.FIVE_STAR_RATING, (Boolean) o); - return true; - } + useFiveStarRating.setOnPreferenceChangeListener((preference, o) -> { + featureStorage.changeFeatureFlag(Feature.FIVE_STAR_RATING, (Boolean) o); + return true; }); } @@ -397,7 +355,7 @@ public class SettingsFragment extends PreferenceFragmentCompat if (debugLogToFile.isChecked()) { debugLogToFile.setSummary(getString(R.string.settings_debug_log_path, - FileUtil.getUltrasonicDirectory(), FileLoggerTree.FILENAME)); + FileUtil.getUltrasonicDirectory(), FileLoggerTree.FILENAME)); } else { debugLogToFile.setSummary(""); } @@ -437,8 +395,7 @@ public class SettingsFragment extends PreferenceFragmentCompat String currentPath = Settings.getCacheLocation(); cacheLocation.setSummary(currentPath); }); - } - else { + } else { cacheLocation.setSummary(path); } @@ -457,35 +414,22 @@ public class SettingsFragment extends PreferenceFragmentCompat int fileNum = FileLoggerTree.Companion.getLogFileNumber(); long fileSize = FileLoggerTree.Companion.getLogFileSizes(); String message = getString(R.string.settings_debug_log_summary, - String.valueOf(fileNum), - String.valueOf(Math.ceil(fileSize / 1000000d)), - FileUtil.getUltrasonicDirectory()); + String.valueOf(fileNum), + String.valueOf(Math.ceil(fileSize / 1000000d)), + FileUtil.getUltrasonicDirectory()); new AlertDialog.Builder(getActivity()) - .setMessage(message) - .setIcon(android.R.drawable.ic_dialog_info) - .setNegativeButton(R.string.settings_debug_log_keep, new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialogInterface, int i) { - dialogInterface.cancel(); - } - }) - .setPositiveButton(R.string.settings_debug_log_delete, new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialogInterface, int i) { + .setMessage(message) + .setIcon(android.R.drawable.ic_dialog_info) + .setNegativeButton(R.string.settings_debug_log_keep, (dialogInterface, i) -> dialogInterface.cancel()) + .setPositiveButton(R.string.settings_debug_log_delete, (dialogInterface, i) -> { FileLoggerTree.Companion.deleteLogFiles(); Timber.i("Deleted debug log files"); dialogInterface.dismiss(); new AlertDialog.Builder(getActivity()).setMessage(R.string.settings_debug_log_deleted) - .setPositiveButton(R.string.common_ok, new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialogInterface, int i) { - dialogInterface.dismiss(); - } - }).create().show(); - } - }) - .create().show(); + .setPositiveButton(R.string.common_ok, (dialogInterface1, i1) -> dialogInterface1.dismiss()).create().show(); + }) + .create().show(); } } } diff --git a/ultrasonic/src/main/java/org/moire/ultrasonic/service/Consumer.java b/ultrasonic/src/main/java/org/moire/ultrasonic/service/Consumer.java deleted file mode 100644 index 6b8ca564..00000000 --- a/ultrasonic/src/main/java/org/moire/ultrasonic/service/Consumer.java +++ /dev/null @@ -1,12 +0,0 @@ -package org.moire.ultrasonic.service; - -/** - * Deprecated: Should be replaced with lambdas - * Abstract class for consumers with one parameter - * @param The type of the object to consume - */ -@Deprecated -public abstract class Consumer -{ - public abstract void accept(T t); -} From e5f7ca631078f505657d805e52eba790d2a1cb23 Mon Sep 17 00:00:00 2001 From: tzugen Date: Sat, 30 Oct 2021 15:40:43 +0200 Subject: [PATCH 4/7] Convert SettingsFragment to Kotlin --- .../ultrasonic/fragment/SettingsFragment.java | 435 ---------------- .../ultrasonic/fragment/SettingsFragment.kt | 466 ++++++++++++++++++ 2 files changed, 466 insertions(+), 435 deletions(-) delete mode 100644 ultrasonic/src/main/java/org/moire/ultrasonic/fragment/SettingsFragment.java create mode 100644 ultrasonic/src/main/kotlin/org/moire/ultrasonic/fragment/SettingsFragment.kt diff --git a/ultrasonic/src/main/java/org/moire/ultrasonic/fragment/SettingsFragment.java b/ultrasonic/src/main/java/org/moire/ultrasonic/fragment/SettingsFragment.java deleted file mode 100644 index 126039c8..00000000 --- a/ultrasonic/src/main/java/org/moire/ultrasonic/fragment/SettingsFragment.java +++ /dev/null @@ -1,435 +0,0 @@ -package org.moire.ultrasonic.fragment; - -import android.app.AlertDialog; -import android.content.SharedPreferences; -import android.os.Build; -import android.os.Bundle; -import android.provider.SearchRecentSuggestions; -import android.view.View; - -import androidx.annotation.Nullable; -import androidx.annotation.StringRes; -import androidx.fragment.app.DialogFragment; -import androidx.preference.CheckBoxPreference; -import androidx.preference.EditTextPreference; -import androidx.preference.ListPreference; -import androidx.preference.Preference; -import androidx.preference.PreferenceCategory; -import androidx.preference.PreferenceFragmentCompat; - -import org.jetbrains.annotations.NotNull; -import org.koin.java.KoinJavaComponent; -import org.moire.ultrasonic.R; -import org.moire.ultrasonic.featureflags.Feature; -import org.moire.ultrasonic.featureflags.FeatureStorage; -import org.moire.ultrasonic.filepicker.FilePickerDialog; -import org.moire.ultrasonic.log.FileLoggerTree; -import org.moire.ultrasonic.provider.SearchSuggestionProvider; -import org.moire.ultrasonic.service.MediaPlayerController; -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; -import org.moire.ultrasonic.util.Util; - -import java.io.File; - -import kotlin.Lazy; -import kotlin.jvm.functions.Function1; -import timber.log.Timber; - -import static org.koin.java.KoinJavaComponent.inject; - -/** - * Shows main app settings. - */ -public class SettingsFragment extends PreferenceFragmentCompat - implements SharedPreferences.OnSharedPreferenceChangeListener { - - private ListPreference theme; - private ListPreference maxBitrateWifi; - private ListPreference maxBitrateMobile; - private ListPreference cacheSize; - private Preference cacheLocation; - private ListPreference preloadCount; - private ListPreference bufferLength; - private ListPreference incrementTime; - private ListPreference networkTimeout; - private ListPreference maxAlbums; - private ListPreference maxSongs; - private ListPreference maxArtists; - private ListPreference defaultAlbums; - private ListPreference defaultSongs; - private ListPreference defaultArtists; - private ListPreference chatRefreshInterval; - private ListPreference directoryCacheTime; - private CheckBoxPreference mediaButtonsEnabled; - private CheckBoxPreference lockScreenEnabled; - private CheckBoxPreference sendBluetoothNotifications; - private CheckBoxPreference sendBluetoothAlbumArt; - private CheckBoxPreference showArtistPicture; - private ListPreference viewRefresh; - private EditTextPreference sharingDefaultDescription; - private EditTextPreference sharingDefaultGreeting; - private TimeSpanPreference sharingDefaultExpiration; - private Preference resumeOnBluetoothDevice; - private Preference pauseOnBluetoothDevice; - private CheckBoxPreference debugLogToFile; - - private final Lazy mediaPlayerControllerLazy = inject(MediaPlayerController.class); - private final Lazy permissionUtil = inject(PermissionUtil.class); - private final Lazy themeChangedEventDistributor = inject(ThemeChangedEventDistributor.class); - private final Lazy mediaSessionHandler = inject(MediaSessionHandler.class); - - @Override - public void onCreate(@Nullable Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - } - - @Override - public void onCreatePreferences(Bundle savedInstanceState, String rootKey) { - setPreferencesFromResource(R.xml.settings, rootKey); - } - - @Override - public void onViewCreated(@NotNull View view, @Nullable Bundle savedInstanceState) { - super.onViewCreated(view, savedInstanceState); - FragmentTitle.Companion.setTitle(this, R.string.menu_settings); - - theme = findPreference(Constants.PREFERENCES_KEY_THEME); - maxBitrateWifi = findPreference(Constants.PREFERENCES_KEY_MAX_BITRATE_WIFI); - maxBitrateMobile = findPreference(Constants.PREFERENCES_KEY_MAX_BITRATE_MOBILE); - cacheSize = findPreference(Constants.PREFERENCES_KEY_CACHE_SIZE); - cacheLocation = findPreference(Constants.PREFERENCES_KEY_CACHE_LOCATION); - preloadCount = findPreference(Constants.PREFERENCES_KEY_PRELOAD_COUNT); - bufferLength = findPreference(Constants.PREFERENCES_KEY_BUFFER_LENGTH); - incrementTime = findPreference(Constants.PREFERENCES_KEY_INCREMENT_TIME); - networkTimeout = findPreference(Constants.PREFERENCES_KEY_NETWORK_TIMEOUT); - maxAlbums = findPreference(Constants.PREFERENCES_KEY_MAX_ALBUMS); - maxSongs = findPreference(Constants.PREFERENCES_KEY_MAX_SONGS); - maxArtists = findPreference(Constants.PREFERENCES_KEY_MAX_ARTISTS); - defaultArtists = findPreference(Constants.PREFERENCES_KEY_DEFAULT_ARTISTS); - defaultSongs = findPreference(Constants.PREFERENCES_KEY_DEFAULT_SONGS); - defaultAlbums = findPreference(Constants.PREFERENCES_KEY_DEFAULT_ALBUMS); - chatRefreshInterval = findPreference(Constants.PREFERENCES_KEY_CHAT_REFRESH_INTERVAL); - directoryCacheTime = findPreference(Constants.PREFERENCES_KEY_DIRECTORY_CACHE_TIME); - mediaButtonsEnabled = findPreference(Constants.PREFERENCES_KEY_MEDIA_BUTTONS); - lockScreenEnabled = findPreference(Constants.PREFERENCES_KEY_SHOW_LOCK_SCREEN_CONTROLS); - sendBluetoothAlbumArt = findPreference(Constants.PREFERENCES_KEY_SEND_BLUETOOTH_ALBUM_ART); - sendBluetoothNotifications = findPreference(Constants.PREFERENCES_KEY_SEND_BLUETOOTH_NOTIFICATIONS); - viewRefresh = findPreference(Constants.PREFERENCES_KEY_VIEW_REFRESH); - sharingDefaultDescription = findPreference(Constants.PREFERENCES_KEY_DEFAULT_SHARE_DESCRIPTION); - sharingDefaultGreeting = findPreference(Constants.PREFERENCES_KEY_DEFAULT_SHARE_GREETING); - sharingDefaultExpiration = findPreference(Constants.PREFERENCES_KEY_DEFAULT_SHARE_EXPIRATION); - resumeOnBluetoothDevice = findPreference(Constants.PREFERENCES_KEY_RESUME_ON_BLUETOOTH_DEVICE); - pauseOnBluetoothDevice = findPreference(Constants.PREFERENCES_KEY_PAUSE_ON_BLUETOOTH_DEVICE); - debugLogToFile = findPreference(Constants.PREFERENCES_KEY_DEBUG_LOG_TO_FILE); - showArtistPicture = findPreference(Constants.PREFERENCES_KEY_SHOW_ARTIST_PICTURE); - - sharingDefaultGreeting.setText(Settings.getShareGreeting()); - setupClearSearchPreference(); - setupFeatureFlagsPreferences(); - setupCacheLocationPreference(); - setupBluetoothDevicePreferences(); - - // After API26 foreground services must be used for music playback, and they must have a notification - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { - PreferenceCategory notificationsCategory = findPreference(Constants.PREFERENCES_KEY_CATEGORY_NOTIFICATIONS); - Preference preferenceToRemove = findPreference(Constants.PREFERENCES_KEY_SHOW_NOTIFICATION); - if (preferenceToRemove != null) - notificationsCategory.removePreference(preferenceToRemove); - preferenceToRemove = findPreference(Constants.PREFERENCES_KEY_ALWAYS_SHOW_NOTIFICATION); - if (preferenceToRemove != null) - notificationsCategory.removePreference(preferenceToRemove); - } - } - - @Override - public void onActivityCreated(@Nullable Bundle savedInstanceState) { - super.onActivityCreated(savedInstanceState); - - update(); - } - - @Override - public void onResume() { - super.onResume(); - SharedPreferences preferences = Settings.getPreferences(); - preferences.registerOnSharedPreferenceChangeListener(this); - } - - @Override - public void onPause() { - super.onPause(); - SharedPreferences prefs = Settings.getPreferences(); - prefs.unregisterOnSharedPreferenceChangeListener(this); - } - - @Override - public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) { - Timber.d("Preference changed: %s", key); - update(); - - if (Constants.PREFERENCES_KEY_HIDE_MEDIA.equals(key)) { - setHideMedia(sharedPreferences.getBoolean(key, false)); - } else if (Constants.PREFERENCES_KEY_MEDIA_BUTTONS.equals(key)) { - setMediaButtonsEnabled(sharedPreferences.getBoolean(key, true)); - } else if (Constants.PREFERENCES_KEY_SEND_BLUETOOTH_NOTIFICATIONS.equals(key)) { - setBluetoothPreferences(sharedPreferences.getBoolean(key, true)); - } else if (Constants.PREFERENCES_KEY_DEBUG_LOG_TO_FILE.equals(key)) { - setDebugLogToFile(sharedPreferences.getBoolean(key, false)); - } else if (Constants.PREFERENCES_KEY_ID3_TAGS.equals(key)) { - showArtistPicture.setEnabled(sharedPreferences.getBoolean(key, false)); - } else if (Constants.PREFERENCES_KEY_THEME.equals(key)) { - themeChangedEventDistributor.getValue().RaiseThemeChangedEvent(); - } - } - - @Override - public void onDisplayPreferenceDialog(Preference preference) { - DialogFragment dialogFragment = null; - if (preference instanceof TimeSpanPreference) { - dialogFragment = new TimeSpanPreferenceDialogFragmentCompat(); - Bundle bundle = new Bundle(1); - bundle.putString("key", preference.getKey()); - dialogFragment.setArguments(bundle); - } - - if (dialogFragment != null) { - dialogFragment.setTargetFragment(this, 0); - dialogFragment.show(this.getParentFragmentManager(), "android.support.v7.preference.PreferenceFragment.DIALOG"); - } else { - super.onDisplayPreferenceDialog(preference); - } - } - - private void setupCacheLocationPreference() { - cacheLocation.setSummary(Settings.getCacheLocation()); - - cacheLocation.setOnPreferenceClickListener(preference -> { - // If the user tries to change the cache location, we must first check to see if we have write access. - PermissionUtil.requestInitialPermission(getActivity(), hasPermission -> { - if (hasPermission) { - FilePickerDialog filePickerDialog = FilePickerDialog.Companion.createFilePickerDialog(getContext()); - filePickerDialog.setDefaultDirectory(FileUtil.getDefaultMusicDirectory().getPath()); - filePickerDialog.setInitialDirectory(cacheLocation.getSummary().toString()); - filePickerDialog.setOnFileSelectedListener((file, path) -> { - Settings.setCacheLocation(path); - setCacheLocation(path); - }); - filePickerDialog.show(); - } - }); - return true; - }); - } - - private void setupBluetoothDevicePreferences() { - final int resumeSetting = Settings.getResumeOnBluetoothDevice(); - final int pauseSetting = Settings.getPauseOnBluetoothDevice(); - - resumeOnBluetoothDevice.setSummary(bluetoothDevicePreferenceToString(resumeSetting)); - pauseOnBluetoothDevice.setSummary(bluetoothDevicePreferenceToString(pauseSetting)); - - resumeOnBluetoothDevice.setOnPreferenceClickListener(preference -> { - showBluetoothDevicePreferenceDialog( - R.string.settings_playback_resume_on_bluetooth_device, - Settings.getResumeOnBluetoothDevice(), - choice -> { - SharedPreferences.Editor editor = resumeOnBluetoothDevice.getSharedPreferences().edit(); - editor.putInt(Constants.PREFERENCES_KEY_RESUME_ON_BLUETOOTH_DEVICE, choice); - editor.apply(); - resumeOnBluetoothDevice.setSummary(bluetoothDevicePreferenceToString(choice)); - return null; - }); - return true; - }); - - pauseOnBluetoothDevice.setOnPreferenceClickListener(preference -> { - showBluetoothDevicePreferenceDialog( - R.string.settings_playback_pause_on_bluetooth_device, - Settings.getPauseOnBluetoothDevice(), choice -> - { - Settings.setPauseOnBluetoothDevice(choice); - pauseOnBluetoothDevice.setSummary(bluetoothDevicePreferenceToString(choice)); - return null; - }); - return true; - }); - } - - private void showBluetoothDevicePreferenceDialog(@StringRes int title, int defaultChoice, final Function1 onChosen) { - final int[] choice = {defaultChoice}; - new AlertDialog.Builder(getActivity()).setTitle(title) - .setSingleChoiceItems(R.array.bluetoothDeviceSettingNames, defaultChoice, - (dialogInterface, i) -> choice[0] = i) - .setNegativeButton(R.string.common_cancel, (dialogInterface, i) -> dialogInterface.cancel()) - .setPositiveButton(R.string.common_ok, (dialogInterface, i) -> { - onChosen.invoke(choice[0]); - dialogInterface.dismiss(); - }) - .create().show(); - } - - private String bluetoothDevicePreferenceToString(int preferenceValue) { - switch (preferenceValue) { - case Constants.PREFERENCE_VALUE_ALL: - return getString(R.string.settings_playback_bluetooth_all); - case Constants.PREFERENCE_VALUE_A2DP: - return getString(R.string.settings_playback_bluetooth_a2dp); - case Constants.PREFERENCE_VALUE_DISABLED: - return getString(R.string.settings_playback_bluetooth_disabled); - default: - return ""; - } - } - - private void setupClearSearchPreference() { - Preference clearSearchPreference = findPreference(Constants.PREFERENCES_KEY_CLEAR_SEARCH_HISTORY); - - if (clearSearchPreference != null) { - clearSearchPreference.setOnPreferenceClickListener(preference -> { - SearchRecentSuggestions suggestions = - new SearchRecentSuggestions(getActivity(), - SearchSuggestionProvider.AUTHORITY, - SearchSuggestionProvider.MODE); - suggestions.clearHistory(); - Util.toast(getActivity(), R.string.settings_search_history_cleared); - return false; - }); - } - } - - private void setupFeatureFlagsPreferences() { - final FeatureStorage featureStorage = KoinJavaComponent.get(FeatureStorage.class); - - CheckBoxPreference useFiveStarRating = (CheckBoxPreference) findPreference( - Constants.PREFERENCES_KEY_USE_FIVE_STAR_RATING); - - if (useFiveStarRating != null) { - useFiveStarRating.setChecked(featureStorage.isFeatureEnabled(Feature.FIVE_STAR_RATING)); - useFiveStarRating.setOnPreferenceChangeListener((preference, o) -> { - featureStorage.changeFeatureFlag(Feature.FIVE_STAR_RATING, (Boolean) o); - return true; - }); - } - - } - - private void update() { - theme.setSummary(theme.getEntry()); - maxBitrateWifi.setSummary(maxBitrateWifi.getEntry()); - maxBitrateMobile.setSummary(maxBitrateMobile.getEntry()); - cacheSize.setSummary(cacheSize.getEntry()); - preloadCount.setSummary(preloadCount.getEntry()); - bufferLength.setSummary(bufferLength.getEntry()); - incrementTime.setSummary(incrementTime.getEntry()); - networkTimeout.setSummary(networkTimeout.getEntry()); - maxAlbums.setSummary(maxAlbums.getEntry()); - maxArtists.setSummary(maxArtists.getEntry()); - maxSongs.setSummary(maxSongs.getEntry()); - defaultAlbums.setSummary(defaultAlbums.getEntry()); - defaultArtists.setSummary(defaultArtists.getEntry()); - defaultSongs.setSummary(defaultSongs.getEntry()); - chatRefreshInterval.setSummary(chatRefreshInterval.getEntry()); - directoryCacheTime.setSummary(directoryCacheTime.getEntry()); - viewRefresh.setSummary(viewRefresh.getEntry()); - sharingDefaultExpiration.setSummary(sharingDefaultExpiration.getText()); - sharingDefaultDescription.setSummary(sharingDefaultDescription.getText()); - sharingDefaultGreeting.setSummary(sharingDefaultGreeting.getText()); - cacheLocation.setSummary(Settings.getCacheLocation()); - - if (!mediaButtonsEnabled.isChecked()) { - lockScreenEnabled.setChecked(false); - lockScreenEnabled.setEnabled(false); - } - - if (!sendBluetoothNotifications.isChecked()) { - sendBluetoothAlbumArt.setChecked(false); - sendBluetoothAlbumArt.setEnabled(false); - } - - if (debugLogToFile.isChecked()) { - debugLogToFile.setSummary(getString(R.string.settings_debug_log_path, - FileUtil.getUltrasonicDirectory(), FileLoggerTree.FILENAME)); - } else { - debugLogToFile.setSummary(""); - } - - showArtistPicture.setEnabled(Settings.getShouldUseId3Tags()); - } - - - private void setHideMedia(boolean hide) { - File nomediaDir = new File(FileUtil.getUltrasonicDirectory(), ".nomedia"); - if (hide && !nomediaDir.exists()) { - if (!nomediaDir.mkdir()) { - Timber.w("Failed to create %s", nomediaDir); - } - } else if (nomediaDir.exists()) { - if (!nomediaDir.delete()) { - Timber.w("Failed to delete %s", nomediaDir); - } - } - Util.toast(getActivity(), R.string.settings_hide_media_toast, false); - } - - private void setMediaButtonsEnabled(boolean enabled) { - lockScreenEnabled.setEnabled(enabled); - mediaSessionHandler.getValue().updateMediaButtonReceiver(); - } - - private void setBluetoothPreferences(boolean enabled) { - sendBluetoothAlbumArt.setEnabled(enabled); - } - - private void setCacheLocation(String path) { - File dir = new File(path); - - if (!FileUtil.ensureDirectoryExistsAndIsReadWritable(dir)) { - permissionUtil.getValue().handlePermissionFailed(hasPermission -> { - String currentPath = Settings.getCacheLocation(); - cacheLocation.setSummary(currentPath); - }); - } else { - cacheLocation.setSummary(path); - } - - // Clear download queue. - mediaPlayerControllerLazy.getValue().clear(); - } - - private void setDebugLogToFile(boolean writeLog) { - if (writeLog) { - FileLoggerTree.Companion.plantToTimberForest(); - Timber.i("Enabled debug logging to file"); - } else { - FileLoggerTree.Companion.uprootFromTimberForest(); - Timber.i("Disabled debug logging to file"); - - int fileNum = FileLoggerTree.Companion.getLogFileNumber(); - long fileSize = FileLoggerTree.Companion.getLogFileSizes(); - String message = getString(R.string.settings_debug_log_summary, - String.valueOf(fileNum), - String.valueOf(Math.ceil(fileSize / 1000000d)), - FileUtil.getUltrasonicDirectory()); - - new AlertDialog.Builder(getActivity()) - .setMessage(message) - .setIcon(android.R.drawable.ic_dialog_info) - .setNegativeButton(R.string.settings_debug_log_keep, (dialogInterface, i) -> dialogInterface.cancel()) - .setPositiveButton(R.string.settings_debug_log_delete, (dialogInterface, i) -> { - FileLoggerTree.Companion.deleteLogFiles(); - Timber.i("Deleted debug log files"); - dialogInterface.dismiss(); - new AlertDialog.Builder(getActivity()).setMessage(R.string.settings_debug_log_deleted) - .setPositiveButton(R.string.common_ok, (dialogInterface1, i1) -> dialogInterface1.dismiss()).create().show(); - }) - .create().show(); - } - } -} diff --git a/ultrasonic/src/main/kotlin/org/moire/ultrasonic/fragment/SettingsFragment.kt b/ultrasonic/src/main/kotlin/org/moire/ultrasonic/fragment/SettingsFragment.kt new file mode 100644 index 00000000..f648aacb --- /dev/null +++ b/ultrasonic/src/main/kotlin/org/moire/ultrasonic/fragment/SettingsFragment.kt @@ -0,0 +1,466 @@ +package org.moire.ultrasonic.fragment + +import android.app.AlertDialog +import android.content.DialogInterface +import android.content.SharedPreferences +import android.content.SharedPreferences.OnSharedPreferenceChangeListener +import android.os.Build +import android.os.Bundle +import android.provider.SearchRecentSuggestions +import android.view.View +import androidx.annotation.StringRes +import androidx.fragment.app.DialogFragment +import androidx.preference.CheckBoxPreference +import androidx.preference.EditTextPreference +import androidx.preference.ListPreference +import androidx.preference.Preference +import androidx.preference.PreferenceCategory +import androidx.preference.PreferenceFragmentCompat +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.featureflags.Feature +import org.moire.ultrasonic.featureflags.FeatureStorage +import org.moire.ultrasonic.filepicker.FilePickerDialog.Companion.createFilePickerDialog +import org.moire.ultrasonic.filepicker.OnFileSelectedListener +import org.moire.ultrasonic.fragment.FragmentTitle.Companion.setTitle +import org.moire.ultrasonic.log.FileLoggerTree +import org.moire.ultrasonic.log.FileLoggerTree.Companion.deleteLogFiles +import org.moire.ultrasonic.log.FileLoggerTree.Companion.getLogFileNumber +import org.moire.ultrasonic.log.FileLoggerTree.Companion.getLogFileSizes +import org.moire.ultrasonic.log.FileLoggerTree.Companion.plantToTimberForest +import org.moire.ultrasonic.log.FileLoggerTree.Companion.uprootFromTimberForest +import org.moire.ultrasonic.provider.SearchSuggestionProvider +import org.moire.ultrasonic.service.MediaPlayerController +import org.moire.ultrasonic.util.Constants +import org.moire.ultrasonic.util.FileUtil.defaultMusicDirectory +import org.moire.ultrasonic.util.FileUtil.ensureDirectoryExistsAndIsReadWritable +import org.moire.ultrasonic.util.FileUtil.ultrasonicDirectory +import org.moire.ultrasonic.util.MediaSessionHandler +import org.moire.ultrasonic.util.PermissionUtil +import org.moire.ultrasonic.util.PermissionUtil.Companion.requestInitialPermission +import org.moire.ultrasonic.util.PermissionUtil.PermissionRequestFinishedCallback +import org.moire.ultrasonic.util.Settings +import org.moire.ultrasonic.util.Settings.preferences +import org.moire.ultrasonic.util.Settings.shareGreeting +import org.moire.ultrasonic.util.Settings.shouldUseId3Tags +import org.moire.ultrasonic.util.ThemeChangedEventDistributor +import org.moire.ultrasonic.util.TimeSpanPreference +import org.moire.ultrasonic.util.TimeSpanPreferenceDialogFragmentCompat +import org.moire.ultrasonic.util.Util.toast +import timber.log.Timber +import java.io.File +import kotlin.math.ceil + +/** + * Shows main app settings. + */ +class SettingsFragment : PreferenceFragmentCompat(), OnSharedPreferenceChangeListener, KoinComponent { + private var theme: ListPreference? = null + private var maxBitrateWifi: ListPreference? = null + private var maxBitrateMobile: ListPreference? = null + private var cacheSize: ListPreference? = null + private var cacheLocation: Preference? = null + private var preloadCount: ListPreference? = null + private var bufferLength: ListPreference? = null + private var incrementTime: ListPreference? = null + private var networkTimeout: ListPreference? = null + private var maxAlbums: ListPreference? = null + private var maxSongs: ListPreference? = null + private var maxArtists: ListPreference? = null + private var defaultAlbums: ListPreference? = null + private var defaultSongs: ListPreference? = null + private var defaultArtists: ListPreference? = null + private var chatRefreshInterval: ListPreference? = null + private var directoryCacheTime: ListPreference? = null + private var mediaButtonsEnabled: CheckBoxPreference? = null + private var lockScreenEnabled: CheckBoxPreference? = null + private var sendBluetoothNotifications: CheckBoxPreference? = null + private var sendBluetoothAlbumArt: CheckBoxPreference? = null + private var showArtistPicture: CheckBoxPreference? = null + private var viewRefresh: ListPreference? = null + private var sharingDefaultDescription: EditTextPreference? = null + private var sharingDefaultGreeting: EditTextPreference? = null + private var sharingDefaultExpiration: TimeSpanPreference? = null + private var resumeOnBluetoothDevice: Preference? = null + private var pauseOnBluetoothDevice: Preference? = null + private var debugLogToFile: CheckBoxPreference? = null + + private val mediaPlayerControllerLazy = inject( + MediaPlayerController::class.java + ) + private val permissionUtil = inject( + PermissionUtil::class.java + ) + private val themeChangedEventDistributor = inject( + ThemeChangedEventDistributor::class.java + ) + private val mediaSessionHandler = inject( + MediaSessionHandler::class.java + ) + + override fun onCreatePreferences(savedInstanceState: Bundle, rootKey: String) { + setPreferencesFromResource(R.xml.settings, rootKey) + } + + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) + setTitle(this, R.string.menu_settings) + theme = findPreference(Constants.PREFERENCES_KEY_THEME) + maxBitrateWifi = findPreference(Constants.PREFERENCES_KEY_MAX_BITRATE_WIFI) + maxBitrateMobile = findPreference(Constants.PREFERENCES_KEY_MAX_BITRATE_MOBILE) + cacheSize = findPreference(Constants.PREFERENCES_KEY_CACHE_SIZE) + cacheLocation = findPreference(Constants.PREFERENCES_KEY_CACHE_LOCATION) + preloadCount = findPreference(Constants.PREFERENCES_KEY_PRELOAD_COUNT) + bufferLength = findPreference(Constants.PREFERENCES_KEY_BUFFER_LENGTH) + incrementTime = findPreference(Constants.PREFERENCES_KEY_INCREMENT_TIME) + networkTimeout = findPreference(Constants.PREFERENCES_KEY_NETWORK_TIMEOUT) + maxAlbums = findPreference(Constants.PREFERENCES_KEY_MAX_ALBUMS) + maxSongs = findPreference(Constants.PREFERENCES_KEY_MAX_SONGS) + maxArtists = findPreference(Constants.PREFERENCES_KEY_MAX_ARTISTS) + defaultArtists = findPreference(Constants.PREFERENCES_KEY_DEFAULT_ARTISTS) + defaultSongs = findPreference(Constants.PREFERENCES_KEY_DEFAULT_SONGS) + defaultAlbums = findPreference(Constants.PREFERENCES_KEY_DEFAULT_ALBUMS) + chatRefreshInterval = findPreference(Constants.PREFERENCES_KEY_CHAT_REFRESH_INTERVAL) + directoryCacheTime = findPreference(Constants.PREFERENCES_KEY_DIRECTORY_CACHE_TIME) + mediaButtonsEnabled = findPreference(Constants.PREFERENCES_KEY_MEDIA_BUTTONS) + lockScreenEnabled = findPreference(Constants.PREFERENCES_KEY_SHOW_LOCK_SCREEN_CONTROLS) + sendBluetoothAlbumArt = findPreference(Constants.PREFERENCES_KEY_SEND_BLUETOOTH_ALBUM_ART) + sendBluetoothNotifications = + findPreference(Constants.PREFERENCES_KEY_SEND_BLUETOOTH_NOTIFICATIONS) + viewRefresh = findPreference(Constants.PREFERENCES_KEY_VIEW_REFRESH) + sharingDefaultDescription = + findPreference(Constants.PREFERENCES_KEY_DEFAULT_SHARE_DESCRIPTION) + sharingDefaultGreeting = findPreference(Constants.PREFERENCES_KEY_DEFAULT_SHARE_GREETING) + sharingDefaultExpiration = + findPreference(Constants.PREFERENCES_KEY_DEFAULT_SHARE_EXPIRATION) + resumeOnBluetoothDevice = + findPreference(Constants.PREFERENCES_KEY_RESUME_ON_BLUETOOTH_DEVICE) + pauseOnBluetoothDevice = findPreference(Constants.PREFERENCES_KEY_PAUSE_ON_BLUETOOTH_DEVICE) + debugLogToFile = findPreference(Constants.PREFERENCES_KEY_DEBUG_LOG_TO_FILE) + showArtistPicture = findPreference(Constants.PREFERENCES_KEY_SHOW_ARTIST_PICTURE) + sharingDefaultGreeting!!.text = shareGreeting + setupClearSearchPreference() + setupFeatureFlagsPreferences() + setupCacheLocationPreference() + setupBluetoothDevicePreferences() + + // After API26 foreground services must be used for music playback, and they must have a notification + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { + val notificationsCategory = + findPreference(Constants.PREFERENCES_KEY_CATEGORY_NOTIFICATIONS) + var preferenceToRemove = + findPreference(Constants.PREFERENCES_KEY_SHOW_NOTIFICATION) + if (preferenceToRemove != null) notificationsCategory!!.removePreference( + preferenceToRemove + ) + preferenceToRemove = findPreference(Constants.PREFERENCES_KEY_ALWAYS_SHOW_NOTIFICATION) + if (preferenceToRemove != null) notificationsCategory!!.removePreference( + preferenceToRemove + ) + } + } + + override fun onActivityCreated(savedInstanceState: Bundle?) { + super.onActivityCreated(savedInstanceState) + update() + } + + override fun onResume() { + super.onResume() + val preferences = preferences + preferences.registerOnSharedPreferenceChangeListener(this) + } + + override fun onPause() { + super.onPause() + val prefs = preferences + prefs.unregisterOnSharedPreferenceChangeListener(this) + } + + override fun onSharedPreferenceChanged(sharedPreferences: SharedPreferences, key: String) { + Timber.d("Preference changed: %s", key) + update() + when (key) { + Constants.PREFERENCES_KEY_HIDE_MEDIA -> { + setHideMedia(sharedPreferences.getBoolean(key, false)) + } + Constants.PREFERENCES_KEY_MEDIA_BUTTONS -> { + setMediaButtonsEnabled(sharedPreferences.getBoolean(key, true)) + } + Constants.PREFERENCES_KEY_SEND_BLUETOOTH_NOTIFICATIONS -> { + setBluetoothPreferences(sharedPreferences.getBoolean(key, true)) + } + Constants.PREFERENCES_KEY_DEBUG_LOG_TO_FILE -> { + setDebugLogToFile(sharedPreferences.getBoolean(key, false)) + } + Constants.PREFERENCES_KEY_ID3_TAGS -> { + showArtistPicture!!.isEnabled = sharedPreferences.getBoolean(key, false) + } + Constants.PREFERENCES_KEY_THEME -> { + themeChangedEventDistributor.value.RaiseThemeChangedEvent() + } + } + } + + override fun onDisplayPreferenceDialog(preference: Preference) { + var dialogFragment: DialogFragment? = null + if (preference is TimeSpanPreference) { + dialogFragment = TimeSpanPreferenceDialogFragmentCompat() + val bundle = Bundle(1) + bundle.putString("key", preference.getKey()) + dialogFragment.setArguments(bundle) + } + if (dialogFragment != null) { + dialogFragment.setTargetFragment(this, 0) + dialogFragment.show( + this.parentFragmentManager, + "android.support.v7.preference.PreferenceFragment.DIALOG" + ) + } else { + super.onDisplayPreferenceDialog(preference) + } + } + + private fun setupCacheLocationPreference() { + cacheLocation!!.summary = Settings.cacheLocation + cacheLocation!!.onPreferenceClickListener = + Preference.OnPreferenceClickListener { + // If the user tries to change the cache location, we must first check to see if we have write access. + requestInitialPermission( + requireActivity(), + object : PermissionRequestFinishedCallback { + override fun onPermissionRequestFinished(hasPermission: Boolean) { + if (hasPermission) { + val filePickerDialog = createFilePickerDialog( + context!! + ) + filePickerDialog.setDefaultDirectory(defaultMusicDirectory.path) + filePickerDialog.setInitialDirectory(cacheLocation!!.summary.toString()) + filePickerDialog.setOnFileSelectedListener(object : + OnFileSelectedListener { + override fun onFileSelected(file: File?, path: String?) { + if (path != null) { + Settings.cacheLocation = path + setCacheLocation(path) + } + } + }) + filePickerDialog.show() + } + } + }) + true + } + } + + private fun setupBluetoothDevicePreferences() { + val resumeSetting = Settings.resumeOnBluetoothDevice + val pauseSetting = Settings.pauseOnBluetoothDevice + resumeOnBluetoothDevice!!.summary = bluetoothDevicePreferenceToString(resumeSetting) + pauseOnBluetoothDevice!!.summary = bluetoothDevicePreferenceToString(pauseSetting) + resumeOnBluetoothDevice!!.onPreferenceClickListener = + Preference.OnPreferenceClickListener { + showBluetoothDevicePreferenceDialog( + R.string.settings_playback_resume_on_bluetooth_device, + Settings.resumeOnBluetoothDevice + ) { choice: Int -> + val editor = resumeOnBluetoothDevice!!.sharedPreferences.edit() + editor.putInt(Constants.PREFERENCES_KEY_RESUME_ON_BLUETOOTH_DEVICE, choice) + editor.apply() + resumeOnBluetoothDevice!!.summary = bluetoothDevicePreferenceToString(choice) + } + true + } + pauseOnBluetoothDevice!!.onPreferenceClickListener = + Preference.OnPreferenceClickListener { + showBluetoothDevicePreferenceDialog( + R.string.settings_playback_pause_on_bluetooth_device, + Settings.pauseOnBluetoothDevice + ) { choice: Int -> + Settings.pauseOnBluetoothDevice = choice + pauseOnBluetoothDevice!!.summary = bluetoothDevicePreferenceToString(choice) + } + true + } + } + + private fun showBluetoothDevicePreferenceDialog( + @StringRes title: Int, + defaultChoice: Int, + onChosen: (Int) -> Unit + ) { + val choice = intArrayOf(defaultChoice) + AlertDialog.Builder(activity).setTitle(title) + .setSingleChoiceItems( + R.array.bluetoothDeviceSettingNames, defaultChoice + ) { _: DialogInterface?, i: Int -> choice[0] = i } + .setNegativeButton(R.string.common_cancel) { dialogInterface: DialogInterface, _: Int -> + dialogInterface.cancel() + } + .setPositiveButton(R.string.common_ok) { dialogInterface: DialogInterface, _: Int -> + onChosen(choice[0]) + dialogInterface.dismiss() + } + .create().show() + } + + private fun bluetoothDevicePreferenceToString(preferenceValue: Int): String { + return when (preferenceValue) { + Constants.PREFERENCE_VALUE_ALL -> getString(R.string.settings_playback_bluetooth_all) + Constants.PREFERENCE_VALUE_A2DP -> getString(R.string.settings_playback_bluetooth_a2dp) + Constants.PREFERENCE_VALUE_DISABLED -> getString(R.string.settings_playback_bluetooth_disabled) + else -> "" + } + } + + private fun setupClearSearchPreference() { + val clearSearchPreference = + findPreference(Constants.PREFERENCES_KEY_CLEAR_SEARCH_HISTORY) + if (clearSearchPreference != null) { + clearSearchPreference.onPreferenceClickListener = + Preference.OnPreferenceClickListener { + val suggestions = SearchRecentSuggestions( + activity, + SearchSuggestionProvider.AUTHORITY, + SearchSuggestionProvider.MODE + ) + suggestions.clearHistory() + toast(activity, R.string.settings_search_history_cleared) + false + } + } + } + + 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 + maxBitrateMobile!!.summary = maxBitrateMobile!!.entry + cacheSize!!.summary = cacheSize!!.entry + preloadCount!!.summary = preloadCount!!.entry + bufferLength!!.summary = bufferLength!!.entry + incrementTime!!.summary = incrementTime!!.entry + networkTimeout!!.summary = networkTimeout!!.entry + maxAlbums!!.summary = maxAlbums!!.entry + maxArtists!!.summary = maxArtists!!.entry + maxSongs!!.summary = maxSongs!!.entry + defaultAlbums!!.summary = defaultAlbums!!.entry + defaultArtists!!.summary = defaultArtists!!.entry + defaultSongs!!.summary = defaultSongs!!.entry + chatRefreshInterval!!.summary = chatRefreshInterval!!.entry + directoryCacheTime!!.summary = directoryCacheTime!!.entry + viewRefresh!!.summary = viewRefresh!!.entry + sharingDefaultExpiration!!.summary = sharingDefaultExpiration!!.text + sharingDefaultDescription!!.summary = sharingDefaultDescription!!.text + sharingDefaultGreeting!!.summary = sharingDefaultGreeting!!.text + cacheLocation!!.summary = Settings.cacheLocation + if (!mediaButtonsEnabled!!.isChecked) { + lockScreenEnabled!!.isChecked = false + lockScreenEnabled!!.isEnabled = false + } + if (!sendBluetoothNotifications!!.isChecked) { + sendBluetoothAlbumArt!!.isChecked = false + sendBluetoothAlbumArt!!.isEnabled = false + } + if (debugLogToFile!!.isChecked) { + debugLogToFile!!.summary = getString( + R.string.settings_debug_log_path, + ultrasonicDirectory, FileLoggerTree.FILENAME + ) + } else { + debugLogToFile!!.summary = "" + } + showArtistPicture!!.isEnabled = shouldUseId3Tags + } + + private fun setHideMedia(hide: Boolean) { + val nomediaDir = File(ultrasonicDirectory, ".nomedia") + if (hide && !nomediaDir.exists()) { + if (!nomediaDir.mkdir()) { + Timber.w("Failed to create %s", nomediaDir) + } + } else if (nomediaDir.exists()) { + if (!nomediaDir.delete()) { + Timber.w("Failed to delete %s", nomediaDir) + } + } + toast(activity, R.string.settings_hide_media_toast, false) + } + + private fun setMediaButtonsEnabled(enabled: Boolean) { + lockScreenEnabled!!.isEnabled = enabled + mediaSessionHandler.value.updateMediaButtonReceiver() + } + + private fun setBluetoothPreferences(enabled: Boolean) { + sendBluetoothAlbumArt!!.isEnabled = enabled + } + + private fun setCacheLocation(path: String) { + val dir = File(path) + if (!ensureDirectoryExistsAndIsReadWritable(dir)) { + permissionUtil.value.handlePermissionFailed(object : PermissionRequestFinishedCallback { + override fun onPermissionRequestFinished(hasPermission: Boolean) { + val currentPath = Settings.cacheLocation + cacheLocation!!.summary = currentPath + } + }) + } else { + cacheLocation!!.summary = path + } + + // Clear download queue. + mediaPlayerControllerLazy.value.clear() + } + + private fun setDebugLogToFile(writeLog: Boolean) { + if (writeLog) { + plantToTimberForest() + Timber.i("Enabled debug logging to file") + } else { + uprootFromTimberForest() + Timber.i("Disabled debug logging to file") + val fileNum = getLogFileNumber() + val fileSize = getLogFileSizes() + val message = getString( + R.string.settings_debug_log_summary, + fileNum.toString(), + ceil(fileSize / 1000 * 1000.0).toString(), + ultrasonicDirectory + ) + AlertDialog.Builder(activity) + .setMessage(message) + .setIcon(android.R.drawable.ic_dialog_info) + .setNegativeButton(R.string.settings_debug_log_keep) { dialogInterface: DialogInterface, _: Int -> + dialogInterface.cancel() + } + .setPositiveButton(R.string.settings_debug_log_delete) { dialogInterface: DialogInterface, _: Int -> + deleteLogFiles() + Timber.i("Deleted debug log files") + dialogInterface.dismiss() + AlertDialog.Builder(activity).setMessage(R.string.settings_debug_log_deleted) + .setPositiveButton(R.string.common_ok) { dialogInterface1: DialogInterface, _: Int -> + dialogInterface1.dismiss() + } + .create().show() + } + .create().show() + } + } +} From 5fe1921ca57ea8c374e1133216b4120489779aae Mon Sep 17 00:00:00 2001 From: tzugen Date: Sat, 30 Oct 2021 15:59:51 +0200 Subject: [PATCH 5/7] Cleanup issues --- .../ultrasonic/fragment/SettingsFragment.kt | 92 ++++++++++--------- .../moire/ultrasonic/util/PermissionUtil.kt | 24 ++--- 2 files changed, 60 insertions(+), 56 deletions(-) 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 f648aacb..b171745a 100644 --- a/ultrasonic/src/main/kotlin/org/moire/ultrasonic/fragment/SettingsFragment.kt +++ b/ultrasonic/src/main/kotlin/org/moire/ultrasonic/fragment/SettingsFragment.kt @@ -16,6 +16,8 @@ import androidx.preference.ListPreference import androidx.preference.Preference import androidx.preference.PreferenceCategory 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 @@ -40,7 +42,6 @@ import org.moire.ultrasonic.util.FileUtil.ultrasonicDirectory import org.moire.ultrasonic.util.MediaSessionHandler import org.moire.ultrasonic.util.PermissionUtil import org.moire.ultrasonic.util.PermissionUtil.Companion.requestInitialPermission -import org.moire.ultrasonic.util.PermissionUtil.PermissionRequestFinishedCallback import org.moire.ultrasonic.util.Settings import org.moire.ultrasonic.util.Settings.preferences import org.moire.ultrasonic.util.Settings.shareGreeting @@ -50,13 +51,14 @@ import org.moire.ultrasonic.util.TimeSpanPreference import org.moire.ultrasonic.util.TimeSpanPreferenceDialogFragmentCompat import org.moire.ultrasonic.util.Util.toast import timber.log.Timber -import java.io.File -import kotlin.math.ceil /** * Shows main app settings. */ -class SettingsFragment : PreferenceFragmentCompat(), OnSharedPreferenceChangeListener, KoinComponent { +class SettingsFragment : + PreferenceFragmentCompat(), + OnSharedPreferenceChangeListener, + KoinComponent { private var theme: ListPreference? = null private var maxBitrateWifi: ListPreference? = null private var maxBitrateMobile: ListPreference? = null @@ -227,30 +229,29 @@ class SettingsFragment : PreferenceFragmentCompat(), OnSharedPreferenceChangeLis cacheLocation!!.summary = Settings.cacheLocation cacheLocation!!.onPreferenceClickListener = Preference.OnPreferenceClickListener { - // If the user tries to change the cache location, we must first check to see if we have write access. + // If the user tries to change the cache location, + // we must first check to see if we have write access. requestInitialPermission( - requireActivity(), - object : PermissionRequestFinishedCallback { - override fun onPermissionRequestFinished(hasPermission: Boolean) { - if (hasPermission) { - val filePickerDialog = createFilePickerDialog( - context!! - ) - filePickerDialog.setDefaultDirectory(defaultMusicDirectory.path) - filePickerDialog.setInitialDirectory(cacheLocation!!.summary.toString()) - filePickerDialog.setOnFileSelectedListener(object : - OnFileSelectedListener { - override fun onFileSelected(file: File?, path: String?) { - if (path != null) { - Settings.cacheLocation = path - setCacheLocation(path) - } + requireActivity() + ) { + if (it) { + val filePickerDialog = createFilePickerDialog( + requireContext() + ) + filePickerDialog.setDefaultDirectory(defaultMusicDirectory.path) + filePickerDialog.setInitialDirectory(cacheLocation!!.summary.toString()) + filePickerDialog.setOnFileSelectedListener(object : + OnFileSelectedListener { + override fun onFileSelected(file: File?, path: String?) { + if (path != null) { + Settings.cacheLocation = path + setCacheLocation(path) } - }) - filePickerDialog.show() - } - } - }) + } + }) + filePickerDialog.show() + } + } true } } @@ -308,9 +309,15 @@ class SettingsFragment : PreferenceFragmentCompat(), OnSharedPreferenceChangeLis private fun bluetoothDevicePreferenceToString(preferenceValue: Int): String { return when (preferenceValue) { - Constants.PREFERENCE_VALUE_ALL -> getString(R.string.settings_playback_bluetooth_all) - Constants.PREFERENCE_VALUE_A2DP -> getString(R.string.settings_playback_bluetooth_a2dp) - Constants.PREFERENCE_VALUE_DISABLED -> getString(R.string.settings_playback_bluetooth_disabled) + Constants.PREFERENCE_VALUE_ALL -> { + getString(R.string.settings_playback_bluetooth_all) + } + Constants.PREFERENCE_VALUE_A2DP -> { + getString(R.string.settings_playback_bluetooth_a2dp) + } + Constants.PREFERENCE_VALUE_DISABLED -> { + getString(R.string.settings_playback_bluetooth_disabled) + } else -> "" } } @@ -415,12 +422,10 @@ class SettingsFragment : PreferenceFragmentCompat(), OnSharedPreferenceChangeLis private fun setCacheLocation(path: String) { val dir = File(path) if (!ensureDirectoryExistsAndIsReadWritable(dir)) { - permissionUtil.value.handlePermissionFailed(object : PermissionRequestFinishedCallback { - override fun onPermissionRequestFinished(hasPermission: Boolean) { - val currentPath = Settings.cacheLocation - cacheLocation!!.summary = currentPath - } - }) + permissionUtil.value.handlePermissionFailed { + val currentPath = Settings.cacheLocation + cacheLocation!!.summary = currentPath + } } else { cacheLocation!!.summary = path } @@ -444,19 +449,22 @@ class SettingsFragment : PreferenceFragmentCompat(), OnSharedPreferenceChangeLis ceil(fileSize / 1000 * 1000.0).toString(), ultrasonicDirectory ) + val keep = R.string.settings_debug_log_keep + val delete = R.string.settings_debug_log_delete AlertDialog.Builder(activity) .setMessage(message) .setIcon(android.R.drawable.ic_dialog_info) - .setNegativeButton(R.string.settings_debug_log_keep) { dialogInterface: DialogInterface, _: Int -> - dialogInterface.cancel() + .setNegativeButton(keep) { dIf: DialogInterface, _: Int -> + dIf.cancel() } - .setPositiveButton(R.string.settings_debug_log_delete) { dialogInterface: DialogInterface, _: Int -> + .setPositiveButton(delete) { dIf: DialogInterface, _: Int -> deleteLogFiles() Timber.i("Deleted debug log files") - dialogInterface.dismiss() - AlertDialog.Builder(activity).setMessage(R.string.settings_debug_log_deleted) - .setPositiveButton(R.string.common_ok) { dialogInterface1: DialogInterface, _: Int -> - dialogInterface1.dismiss() + dIf.dismiss() + AlertDialog.Builder(activity) + .setMessage(R.string.settings_debug_log_deleted) + .setPositiveButton(R.string.common_ok) { dIf2: DialogInterface, _: Int -> + dIf2.dismiss() } .create().show() } diff --git a/ultrasonic/src/main/kotlin/org/moire/ultrasonic/util/PermissionUtil.kt b/ultrasonic/src/main/kotlin/org/moire/ultrasonic/util/PermissionUtil.kt index 92813226..e39154c0 100644 --- a/ultrasonic/src/main/kotlin/org/moire/ultrasonic/util/PermissionUtil.kt +++ b/ultrasonic/src/main/kotlin/org/moire/ultrasonic/util/PermissionUtil.kt @@ -22,10 +22,6 @@ import timber.log.Timber class PermissionUtil(private val applicationContext: Context) { private var activityContext: Context? = null - interface PermissionRequestFinishedCallback { - fun onPermissionRequestFinished(hasPermission: Boolean) - } - fun onForegroundApplicationStarted(context: Context?) { activityContext = context } @@ -42,7 +38,7 @@ class PermissionUtil(private val applicationContext: Context) { * * @param callback callback function to execute after the permission request is finished */ - fun handlePermissionFailed(callback: PermissionRequestFinishedCallback?) { + fun handlePermissionFailed(callback: ((Boolean) -> Unit)?) { val currentCachePath = Settings.cacheLocation val defaultCachePath = defaultMusicDirectory.path @@ -76,7 +72,7 @@ class PermissionUtil(private val applicationContext: Context) { ) } } - callback?.onPermissionRequestFinished(false) + callback?.invoke(false) } } @@ -91,7 +87,7 @@ class PermissionUtil(private val applicationContext: Context) { @JvmStatic fun requestInitialPermission( context: Context, - callback: PermissionRequestFinishedCallback? + callback: ((Boolean) -> Unit)? ) { Dexter.withContext(context) .withPermissions( @@ -102,7 +98,7 @@ class PermissionUtil(private val applicationContext: Context) { override fun onPermissionsChecked(report: MultiplePermissionsReport) { if (report.areAllPermissionsGranted()) { Timber.i("R/W permission granted for external storage") - callback?.onPermissionRequestFinished(true) + callback?.invoke(true) return } if (report.isAnyPermissionPermanentlyDenied) { @@ -110,7 +106,7 @@ class PermissionUtil(private val applicationContext: Context) { "R/W permission is permanently denied for external storage" ) showSettingsDialog(context) - callback?.onPermissionRequestFinished(false) + callback?.invoke(false) return } Timber.i("R/W permission is missing for external storage") @@ -120,7 +116,7 @@ class PermissionUtil(private val applicationContext: Context) { context.getString(R.string.permissions_rationale_description_initial), null ) - callback?.onPermissionRequestFinished(false) + callback?.invoke(false) } override fun onPermissionRationaleShouldBeShown( @@ -146,7 +142,7 @@ class PermissionUtil(private val applicationContext: Context) { private fun requestFailedPermission( context: Context, cacheLocation: String?, - callback: PermissionRequestFinishedCallback? + callback: ((Boolean) -> Unit)? ) { Dexter.withContext(context) .withPermissions( @@ -161,7 +157,7 @@ class PermissionUtil(private val applicationContext: Context) { if (cacheLocation != null) { Settings.cacheLocation = cacheLocation } - callback?.onPermissionRequestFinished(true) + callback?.invoke(true) return } if (report.isAnyPermissionPermanentlyDenied) { @@ -170,7 +166,7 @@ class PermissionUtil(private val applicationContext: Context) { cacheLocation ) showSettingsDialog(context) - callback?.onPermissionRequestFinished(false) + callback?.invoke(false) return } Timber.i( @@ -182,7 +178,7 @@ class PermissionUtil(private val applicationContext: Context) { context, context.getString(R.string.permissions_message_box_title), context.getString(R.string.permissions_permission_missing), null ) - callback?.onPermissionRequestFinished(false) + callback?.invoke(false) } override fun onPermissionRationaleShouldBeShown( From bd23f54783ed6ea7d09447773855fa8451a92f1b Mon Sep 17 00:00:00 2001 From: tzugen Date: Sat, 30 Oct 2021 16:07:47 +0200 Subject: [PATCH 6/7] Remove Build switches for Lollipop --- .../ultrasonic/fragment/ServerRowAdapter.kt | 36 +++++-------------- .../ultrasonic/service/AudioFocusHandler.kt | 3 -- .../ultrasonic/service/LocalMediaPlayer.kt | 9 +---- .../service/MediaPlayerLifecycleSupport.kt | 8 +---- 4 files changed, 10 insertions(+), 46 deletions(-) diff --git a/ultrasonic/src/main/kotlin/org/moire/ultrasonic/fragment/ServerRowAdapter.kt b/ultrasonic/src/main/kotlin/org/moire/ultrasonic/fragment/ServerRowAdapter.kt index 85190acb..2b9e4be1 100644 --- a/ultrasonic/src/main/kotlin/org/moire/ultrasonic/fragment/ServerRowAdapter.kt +++ b/ultrasonic/src/main/kotlin/org/moire/ultrasonic/fragment/ServerRowAdapter.kt @@ -1,9 +1,7 @@ package org.moire.ultrasonic.fragment import android.content.Context -import android.graphics.Color import android.graphics.drawable.Drawable -import android.os.Build import android.view.LayoutInflater import android.view.Menu import android.view.MenuItem @@ -109,10 +107,8 @@ internal class ServerRowAdapter( } // Set colors - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { - icon?.setTint(ServerColor.getForegroundColor(context, setting?.color)) - background?.setTint(ServerColor.getBackgroundColor(context, setting?.color)) - } + icon?.setTint(ServerColor.getForegroundColor(context, setting?.color)) + background?.setTint(ServerColor.getBackgroundColor(context, setting?.color)) // Set the final drawables image?.setImageDrawable(icon) @@ -120,32 +116,16 @@ internal class ServerRowAdapter( // Highlight the Active Server's row by changing its background if (index == activeServerProvider.getActiveServer().index) { - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { - layout?.background = ContextCompat.getDrawable(context, R.drawable.select_ripple) - } else { - layout?.setBackgroundResource( - Util.getResourceFromAttribute(context, R.attr.list_selector_holo_selected) - ) - } + layout?.background = ContextCompat.getDrawable(context, R.drawable.select_ripple) } else { - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { - layout?.background = ContextCompat.getDrawable(context, R.drawable.default_ripple) - } else { - layout?.setBackgroundResource( - Util.getResourceFromAttribute(context, R.attr.list_selector_holo) - ) - } + layout?.background = ContextCompat.getDrawable(context, R.drawable.default_ripple) } // Add the context menu for the row - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { - serverMenu?.background = ContextCompat.getDrawable( - context, - R.drawable.select_ripple_circle - ) - } else { - serverMenu?.setBackgroundColor(Color.TRANSPARENT) - } + serverMenu?.background = ContextCompat.getDrawable( + context, + R.drawable.select_ripple_circle + ) serverMenu?.setOnClickListener { view -> serverMenuClick(view, index) } diff --git a/ultrasonic/src/main/kotlin/org/moire/ultrasonic/service/AudioFocusHandler.kt b/ultrasonic/src/main/kotlin/org/moire/ultrasonic/service/AudioFocusHandler.kt index 2f36974a..34ad87cc 100644 --- a/ultrasonic/src/main/kotlin/org/moire/ultrasonic/service/AudioFocusHandler.kt +++ b/ultrasonic/src/main/kotlin/org/moire/ultrasonic/service/AudioFocusHandler.kt @@ -4,8 +4,6 @@ import android.content.Context import android.media.AudioAttributes import android.media.AudioManager import android.media.AudioManager.OnAudioFocusChangeListener -import android.os.Build -import androidx.annotation.RequiresApi import androidx.media.AudioAttributesCompat import androidx.media.AudioFocusRequestCompat import androidx.media.AudioManagerCompat @@ -109,7 +107,6 @@ class AudioFocusHandler(private val context: Context) { private var lowerFocus = false // TODO: This can be removed if we switch to androidx.media2.player - @RequiresApi(Build.VERSION_CODES.LOLLIPOP) fun getAudioAttributes(): AudioAttributes { return AudioAttributes.Builder() .setUsage(AudioAttributes.USAGE_MEDIA) diff --git a/ultrasonic/src/main/kotlin/org/moire/ultrasonic/service/LocalMediaPlayer.kt b/ultrasonic/src/main/kotlin/org/moire/ultrasonic/service/LocalMediaPlayer.kt index d30b5d00..0b0a1b42 100644 --- a/ultrasonic/src/main/kotlin/org/moire/ultrasonic/service/LocalMediaPlayer.kt +++ b/ultrasonic/src/main/kotlin/org/moire/ultrasonic/service/LocalMediaPlayer.kt @@ -10,11 +10,9 @@ package org.moire.ultrasonic.service import android.content.Context import android.content.Context.POWER_SERVICE import android.content.Intent -import android.media.AudioManager import android.media.MediaPlayer import android.media.MediaPlayer.OnCompletionListener import android.media.audiofx.AudioEffect -import android.os.Build import android.os.Handler import android.os.Looper import android.os.PowerManager @@ -447,12 +445,7 @@ class LocalMediaPlayer : KoinComponent { } private fun setAudioAttributes(player: MediaPlayer) { - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { - player.setAudioAttributes(AudioFocusHandler.getAudioAttributes()) - } else { - @Suppress("DEPRECATION") - player.setAudioStreamType(AudioManager.STREAM_MUSIC) - } + player.setAudioAttributes(AudioFocusHandler.getAudioAttributes()) } @Suppress("ComplexCondition") diff --git a/ultrasonic/src/main/kotlin/org/moire/ultrasonic/service/MediaPlayerLifecycleSupport.kt b/ultrasonic/src/main/kotlin/org/moire/ultrasonic/service/MediaPlayerLifecycleSupport.kt index 1bcdfce5..c69b820b 100644 --- a/ultrasonic/src/main/kotlin/org/moire/ultrasonic/service/MediaPlayerLifecycleSupport.kt +++ b/ultrasonic/src/main/kotlin/org/moire/ultrasonic/service/MediaPlayerLifecycleSupport.kt @@ -12,7 +12,6 @@ import android.content.Context import android.content.Intent import android.content.IntentFilter import android.media.AudioManager -import android.os.Build import android.view.KeyEvent import org.koin.core.component.KoinComponent import org.koin.core.component.inject @@ -165,12 +164,7 @@ class MediaPlayerLifecycleSupport : KoinComponent { } } - val headsetIntentFilter: IntentFilter = - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { - IntentFilter(AudioManager.ACTION_HEADSET_PLUG) - } else { - IntentFilter(Intent.ACTION_HEADSET_PLUG) - } + val headsetIntentFilter = IntentFilter(AudioManager.ACTION_HEADSET_PLUG) applicationContext().registerReceiver(headsetEventReceiver, headsetIntentFilter) } From 7c43d01f8e4551414728a1a87fdc9915b0c17d8b Mon Sep 17 00:00:00 2001 From: Nite Date: Sun, 31 Oct 2021 16:54:37 +0100 Subject: [PATCH 7/7] Fixed nullable parameters --- .../kotlin/org/moire/ultrasonic/fragment/SettingsFragment.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 b171745a..392c04a4 100644 --- a/ultrasonic/src/main/kotlin/org/moire/ultrasonic/fragment/SettingsFragment.kt +++ b/ultrasonic/src/main/kotlin/org/moire/ultrasonic/fragment/SettingsFragment.kt @@ -102,7 +102,7 @@ class SettingsFragment : MediaSessionHandler::class.java ) - override fun onCreatePreferences(savedInstanceState: Bundle, rootKey: String) { + override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) { setPreferencesFromResource(R.xml.settings, rootKey) }