diff --git a/README.md b/README.md index 9f4d83f..166c604 100644 --- a/README.md +++ b/README.md @@ -52,6 +52,15 @@ avoided for new code (e.g. the "m" member variable prefix). It's possible that contributions may be folded into future releases of Orange Squeeze. If so, the authors will be recognized in the release notes. +## Languages and Translations + +Open Squeeze was developed by a native American English speaker. The German and French translations were +initially machine generated and then heavily modified by users and contributors. + +Translations to new languages and modifications to existing translations should be done via +[Weblate](https://hosted.weblate.org/projects/open-squeeze/) which is freely provided for +Open Source projects. Thank you to them for providing this service! + ## License The license for the code is [Apache License, Version 2.0](https://www.apache.org/licenses/LICENSE-2.0). diff --git a/app/build.gradle b/app/build.gradle index de33327..08f3bb4 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -190,7 +190,7 @@ dependencies { implementation "com.google.code.findbugs:jsr305:${obl_jsr305Version}" // ReactiveX - implementation "io.reactivex.rxjava3:rxandroid:3.0.0" + implementation "io.reactivex.rxjava3:rxandroid:3.0.2" implementation "io.reactivex.rxjava3:rxjava:3.1.5" implementation "io.reactivex.rxjava3:rxkotlin:3.0.1" @@ -198,7 +198,7 @@ dependencies { implementation "com.squareup.sqldelight:android-driver:${sqldelight_version}" implementation "com.squareup.sqldelight:coroutines-extensions:${sqldelight_version}" - debugImplementation 'com.squareup.leakcanary:leakcanary-android:2.9.1' + debugImplementation 'com.squareup.leakcanary:leakcanary-android:2.10' implementation 'androidx.multidex:multidex:2.0.1' @@ -211,17 +211,17 @@ dependencies { testImplementation "io.mockk:mockk-android:1.13.2" testImplementation "com.google.truth:truth:1.1.3" - androidTestImplementation "androidx.test:runner:1.4.0" - androidTestImplementation "androidx.test:rules:1.4.0" - androidTestImplementation "androidx.test:core:1.4.0" - androidTestImplementation "androidx.test:core-ktx:1.4.0" - androidTestImplementation "androidx.test.espresso:espresso-core:3.4.0" - androidTestImplementation "androidx.test.espresso:espresso-intents:3.4.0" - androidTestImplementation "androidx.test.ext:junit:1.1.3" - androidTestImplementation "androidx.test.ext:junit-ktx:1.1.3" - androidTestImplementation "androidx.test.ext:truth:1.4.0" + androidTestImplementation "androidx.test:runner:1.5.1" + androidTestImplementation "androidx.test:rules:1.5.0" + androidTestImplementation "androidx.test:core:1.5.0" + androidTestImplementation "androidx.test:core-ktx:1.5.0" + androidTestImplementation "androidx.test.espresso:espresso-core:3.5.0" + androidTestImplementation "androidx.test.espresso:espresso-intents:3.5.0" + androidTestImplementation "androidx.test.ext:junit:1.1.4" + androidTestImplementation "androidx.test.ext:junit-ktx:1.1.4" + androidTestImplementation "androidx.test.ext:truth:1.5.0" androidTestImplementation "io.mockk:mockk-android:1.13.2" - androidTestUtil "androidx.test:orchestrator:1.4.1" + androidTestUtil "androidx.test:orchestrator:1.4.2" } tasks.withType(JavaCompile) { diff --git a/app/src/main/java/com/orangebikelabs/orangesqueeze/app/SBActivity.java b/app/src/main/java/com/orangebikelabs/orangesqueeze/app/SBActivity.java index 68ca308..5b9f42d 100644 --- a/app/src/main/java/com/orangebikelabs/orangesqueeze/app/SBActivity.java +++ b/app/src/main/java/com/orangebikelabs/orangesqueeze/app/SBActivity.java @@ -11,6 +11,8 @@ import android.content.Context; import android.content.Intent; import android.os.Bundle; +import android.os.Handler; +import android.os.Looper; import android.support.v4.media.session.MediaControllerCompat; import androidx.appcompat.app.AppCompatActivity; @@ -78,6 +80,8 @@ public static int getInstanceCount() { return sInstanceCount; } + final static private Handler sHandler = new Handler(Looper.getMainLooper()); + static public boolean sShouldAutoStart = true; static private int sInstanceCount = 0; @@ -209,13 +213,15 @@ protected void onStart() { } setWindowFlags(); - // show deferred player snackbar when the UI is ready - if (sDeferredPlayerSnackbar != null) { - PlayerStatus status = sDeferredPlayerSnackbar; - sDeferredPlayerSnackbar = null; + sHandler.postDelayed(() -> { + // show deferred player snackbar when the UI is ready + if (sDeferredPlayerSnackbar != null) { + PlayerStatus status = sDeferredPlayerSnackbar; + sDeferredPlayerSnackbar = null; - showPlayerSnackbar(status); - } + showPlayerSnackbar(status); + } + }, 250); } @Override @@ -445,7 +451,8 @@ protected void setWindowFlags() { protected void showPlayerSnackbar(PlayerStatus status) { OSAssert.assertMainThread(); - if (!mStarted || isFinishing() || !allowSnackbarDisplay() || getSnackbarView() == null) { + View snackbarView = getSnackbarView(); + if (!mStarted || isFinishing() || !allowSnackbarDisplay() || snackbarView == null || snackbarView.getWidth() <= 0 || snackbarView.getHeight() <= 0) { sDeferredPlayerSnackbar = status; return; } @@ -454,7 +461,10 @@ protected void showPlayerSnackbar(PlayerStatus status) { if (!status.getId().equals(mLastShownPlayerSnackbar)) { mLastShownPlayerSnackbar = status.getId(); String text = getString(R.string.change_player_snackbar, status.getName()); - Snackbar.make(getSnackbarView(), HtmlCompat.fromHtml(text, HtmlCompat.FROM_HTML_MODE_COMPACT), Snackbar.LENGTH_SHORT).show(); + Snackbar + .make(snackbarView, HtmlCompat.fromHtml(text, HtmlCompat.FROM_HTML_MODE_COMPACT), Snackbar.LENGTH_SHORT) + .setAnchorView(snackbarView) + .show(); } } diff --git a/app/src/main/java/com/orangebikelabs/orangesqueeze/menu/AbsMenuFragment.java b/app/src/main/java/com/orangebikelabs/orangesqueeze/menu/AbsMenuFragment.java index ee0ae55..73c58ab 100644 --- a/app/src/main/java/com/orangebikelabs/orangesqueeze/menu/AbsMenuFragment.java +++ b/app/src/main/java/com/orangebikelabs/orangesqueeze/menu/AbsMenuFragment.java @@ -245,7 +245,7 @@ public void showSnackbar(CharSequence text, SnackbarLength length) { } else { translatedLength = Snackbar.LENGTH_SHORT; } - mLastSnackbar = Snackbar.make(getSnackbarView(), text, translatedLength); + mLastSnackbar = Snackbar.make(getSnackbarView(), text, translatedLength).setAnchorView(getSnackbarView()); mLastSnackbar.show(); } diff --git a/app/src/main/java/com/orangebikelabs/orangesqueeze/nowplaying/NowPlayingActivity.java b/app/src/main/java/com/orangebikelabs/orangesqueeze/nowplaying/NowPlayingActivity.java index f768b8d..b45aae8 100644 --- a/app/src/main/java/com/orangebikelabs/orangesqueeze/nowplaying/NowPlayingActivity.java +++ b/app/src/main/java/com/orangebikelabs/orangesqueeze/nowplaying/NowPlayingActivity.java @@ -23,6 +23,7 @@ import android.view.Menu; import android.view.MenuItem; +import android.view.View; import com.orangebikelabs.orangesqueeze.BuildConfig; import com.orangebikelabs.orangesqueeze.R; @@ -191,6 +192,17 @@ public boolean onOptionsItemSelected(MenuItem item) { } } + @Override + protected boolean allowSnackbarDisplay() { + return true; + } + + @Nullable + @Override + protected View getSnackbarView() { + return findViewById(R.id.controls); + } + private void setHidePlaylistItemDrawable() { if (mHidePlaylistItem == null) { return; diff --git a/app/src/main/java/com/orangebikelabs/orangesqueeze/players/ManagePlayersAdapter.java b/app/src/main/java/com/orangebikelabs/orangesqueeze/players/ManagePlayersAdapter.java index ca35ff7..8c354df 100644 --- a/app/src/main/java/com/orangebikelabs/orangesqueeze/players/ManagePlayersAdapter.java +++ b/app/src/main/java/com/orangebikelabs/orangesqueeze/players/ManagePlayersAdapter.java @@ -5,7 +5,6 @@ package com.orangebikelabs.orangesqueeze.players; -import android.annotation.SuppressLint; import android.content.Context; import arrow.core.Option; @@ -40,6 +39,7 @@ import java.net.URI; import java.net.URISyntaxException; +import java.text.NumberFormat; import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; @@ -84,11 +84,13 @@ public interface OnPlayerCommandListener { private SyncStatus mSyncStatus; private boolean mDrawerMode; private int mPlayerItemLayoutRid; + final private NumberFormat mNumberFormat; public ManagePlayersAdapter(Context context) { super(context, 0); setDrawerMode(false); + mNumberFormat = NumberFormat.getInstance(); } @Nonnull @@ -291,15 +293,31 @@ public View getView(int pos, @Nullable View convertView, ViewGroup parent) { return convertView; } - @SuppressLint("SetTextI18n") - protected void setVolume(Slider sb, TextView playerVolumeLabel, int volume) { + /** called when volume is set by user */ + protected void setVolumeFromUser(Slider sb, TextView playerVolumeLabel, int volume) { View parentView = (View) sb.getTag(R.id.tag_containerview); PlayerId pid = (PlayerId) parentView.getTag(R.id.tag_playerid); - playerVolumeLabel.setText(Integer.toString(volume)); + updateVolumeText(playerVolumeLabel, volume); mOnPlayerCommandListener.onPlayerCommand(pid, PlayerCommand.VOLUME, volume); } + protected void hideVolumeText(@Nullable TextView playerVolumeLabel) { + if(playerVolumeLabel != null) { + playerVolumeLabel.setVisibility(View.INVISIBLE); + } + } + + /** called to update the text field to a specific volume level */ + protected void updateVolumeText(@Nullable TextView playerVolumeLabel, int volume) { + if(playerVolumeLabel != null) { + if(playerVolumeLabel.getVisibility() != View.VISIBLE) { + playerVolumeLabel.setVisibility(View.VISIBLE); + } + playerVolumeLabel.setText(mNumberFormat.format(volume)); + } + } + /** * tag should be the player status */ @@ -422,7 +440,7 @@ protected void updateView(View view) { SwitchMaterial powerButton = view.findViewById(R.id.player_power_toggle); Slider volumeBar = view.findViewById(R.id.volume_bar); View actionButton = view.findViewById(R.id.action_button); - TextView playerStatusText = view.findViewById(R.id.player_status_label); + TextView playerStatusLabel = view.findViewById(R.id.player_status_label); final TextView playerVolumeLabel = view.findViewById(R.id.player_volume_label); if (powerButton != null) { @@ -441,7 +459,7 @@ protected void updateView(View view) { volumeBar.addOnChangeListener((slider, value, fromUser) -> { if (fromUser) { // only respond to user-generated events - setVolume(slider, playerVolumeLabel, (int) value); + setVolumeFromUser(slider, playerVolumeLabel, (int) value); } }); volumeBar.addOnSliderTouchListener(new Slider.OnSliderTouchListener() { @@ -457,7 +475,7 @@ public void onStopTrackingTouch(Slider slider) { playerVolumeLabel.setVisibility(View.VISIBLE); // called at the end of a touch/drag cycle, call with update to make // sure we are in sync with remote volume - setVolume(slider, playerVolumeLabel, (int) slider.getValue()); + setVolumeFromUser(slider, playerVolumeLabel, (int) slider.getValue()); } }); volumeBar.setLabelFormatter((value -> Integer.toString((int) value))); @@ -475,10 +493,11 @@ public void onStopTrackingTouch(Slider slider) { // when progress is visible, don't routinely update the volume, // power buttons because they may lag + int clampedVolume = MoreMath.coerceIn(mPlayerStatus.getVolume(), 0, 100); int playerStatusVisibility = View.GONE; - boolean progressVisible = false; + boolean statusInProgress = false; if (!mPlayerStatus.isInitialized()) { - progressVisible = true; + statusInProgress = true; if (volumeBar != null) { volumeBar.setValue(0); @@ -489,7 +508,7 @@ public void onStopTrackingTouch(Slider slider) { powerButton.setChecked(false); } } else if (isWorkInProgress(mPlayerStatus.getId())) { - progressVisible = true; + statusInProgress = true; } else { if (powerButton != null) { powerButton.setChecked(mPlayerStatus.isPowered()); @@ -502,10 +521,10 @@ public void onStopTrackingTouch(Slider slider) { } else { if (volumeBar != null) { // ensure received values are within 0 <= value <= 100 - int clampedVolume = MoreMath.coerceIn(mPlayerStatus.getVolume(), 0, 100); volumeBar.setValue(clampedVolume); } } + updateVolumeText(playerVolumeLabel, clampedVolume); // TODO add different text if mPlayerStatus.isVolumeLocked() if (volumeBar != null) { @@ -513,17 +532,23 @@ public void onStopTrackingTouch(Slider slider) { } if (mPlayerStatus.isPowered()) { playerStatusVisibility = View.VISIBLE; - if (playerStatusText != null) { + if (playerStatusLabel != null) { if (mPlayerStatus.isConnected()) { - playerStatusText.setText(mPlayerStatus.getMode().getRid()); + playerStatusLabel.setText(mPlayerStatus.getMode().getRid()); } else { - playerStatusText.setText(getContext().getString(R.string.disconnected)); + playerStatusLabel.setText(getContext().getString(R.string.disconnected)); } } } } - if (playerStatusText != null) { - playerStatusText.setVisibility(playerStatusVisibility); + + if(statusInProgress) { + hideVolumeText(playerVolumeLabel); + } else { + updateVolumeText(playerVolumeLabel, clampedVolume); + } + if (playerStatusLabel != null) { + playerStatusLabel.setVisibility(playerStatusVisibility); } if (mPlayerStatus.getId().equals(mSelectedPlayer)) { view.setBackgroundResource(R.drawable.manageplayers_item_selected); diff --git a/app/src/main/java/com/orangebikelabs/orangesqueeze/ui/MainActivity.kt b/app/src/main/java/com/orangebikelabs/orangesqueeze/ui/MainActivity.kt index 156f1c6..9521b7f 100644 --- a/app/src/main/java/com/orangebikelabs/orangesqueeze/ui/MainActivity.kt +++ b/app/src/main/java/com/orangebikelabs/orangesqueeze/ui/MainActivity.kt @@ -8,6 +8,7 @@ package com.orangebikelabs.orangesqueeze.ui import android.content.Context import android.content.Intent import android.os.Bundle +import android.view.View import androidx.fragment.app.commitNow import com.orangebikelabs.orangesqueeze.BuildConfig @@ -105,6 +106,11 @@ class MainActivity : DrawerActivity() { return true } + override fun getSnackbarView(): View? { + val retval = findViewById(R.id.tiny_nowplaying_container) + return retval + } + override fun applyDrawerState(drawerState: DrawerState) { if (drawerState !== DrawerState.BROWSE) { supportActionBar.title = title diff --git a/app/src/main/java/com/orangebikelabs/orangesqueeze/ui/MaintenanceDialogFragment.java b/app/src/main/java/com/orangebikelabs/orangesqueeze/ui/MaintenanceDialogFragment.java index 3b45f1b..ae17693 100644 --- a/app/src/main/java/com/orangebikelabs/orangesqueeze/ui/MaintenanceDialogFragment.java +++ b/app/src/main/java/com/orangebikelabs/orangesqueeze/ui/MaintenanceDialogFragment.java @@ -118,7 +118,7 @@ public View getView(int position, @Nullable View convertView, ViewGroup parent) } dialog.dismiss(); }); - builder.setNegativeButton(R.string.close, (dialog, which) -> { + builder.setNegativeButton(R.string.dismiss_dialog, (dialog, which) -> { // nothing to do }); Dialog retval = builder.create(); diff --git a/app/src/main/res/values-de/strings.xml b/app/src/main/res/values-de/strings.xml index 87c84fd..ec5da4c 100644 --- a/app/src/main/res/values-de/strings.xml +++ b/app/src/main/res/values-de/strings.xml @@ -104,7 +104,7 @@ Weiter Abbrechen OK - OK + OK Speicherberechtigung Die Berechtigung zu speichern wird nie wieder angefordert. Die Berechtigung zu speichern wurde abgelehnt. diff --git a/app/src/main/res/values-fr/strings.xml b/app/src/main/res/values-fr/strings.xml index 7291500..6eb1e60 100644 --- a/app/src/main/res/values-fr/strings.xml +++ b/app/src/main/res/values-fr/strings.xml @@ -100,7 +100,7 @@ Pause de la lecture Nom d\'utilisateur et/ou mot de passe incorrect Annuler - OK + OK Aucun téléchargement actif ou terminé Pas d\'objet Sélectionner un platine: diff --git a/app/src/main/res/values/about_strings.xml b/app/src/main/res/values/about_strings.xml deleted file mode 100644 index 3f42ed3..0000000 --- a/app/src/main/res/values/about_strings.xml +++ /dev/null @@ -1,9 +0,0 @@ - - - - About %1$s - Version %1$s - \ No newline at end of file diff --git a/app/src/main/res/values/exception_strings.xml b/app/src/main/res/values/exception_strings.xml deleted file mode 100644 index b171047..0000000 --- a/app/src/main/res/values/exception_strings.xml +++ /dev/null @@ -1,11 +0,0 @@ - - - - - Timeout waiting for server connection to complete - No Network Available - Connection error - \ No newline at end of file diff --git a/app/src/main/res/values/prefs.xml b/app/src/main/res/values/prefs.xml deleted file mode 100644 index 80ce358..0000000 --- a/app/src/main/res/values/prefs.xml +++ /dev/null @@ -1,166 +0,0 @@ - - - - - Automatically connect to the last connected server - Automatic Connect - Periodically send discovery broadcast requests to - find local servers - Automatic Discovery - Advanced - Shows advanced preferences - Download - Shows download preferences - Cache Location - Artwork cache will be stored on %1$s - - - - Use Internal Storage - Use External Storage (SD card, etc) - - - Storage Cache Size - The maximum amount of space that the artwork cache will - use on device storage.\n\nThe current maximum value is %1$s MB. - - - - Automatic - 50 MB - 100 MB - 250 MB - 500 MB - 1000 MB - - - Artwork - Caching - Removes all cache data from storage - Wipe Cache - Do you want to remove all cache data from - permanent storage? If you select yes, then the cache will begin to - fill again on demand. - On-Call Behavior - On Call Received - What to do when a call is made or received and connected players are playing.\n\nCurrent value: \"%1$s\" - - - Nothing - Mute All Players - Mute Current Player - Pause All Players - Pause Current Player - - - Resume Playback - For paused and muted players, playback continues automatically if the call ends within the configured time. - - - Never - 1 minute - 5 minutes - 10 minutes - 30 minutes - 60 minutes - Forever - - - Integrate with System Volume Control - The app will integrate into the system volume. - The app\'s volume control will operate independent of the system volume control. - - Play Silent Audio - The app will play silent audio in the background to help manage audio focus on newer Android versions. - The app will not play silent audio. - - Pause when Headphones Disconnect - The current player will pause whenever bluetooth or wired headphones disconnect when audio is playing (requires that "Play Silent Audio" be enabled). - Playback continues unaffected by headphones status. - - Time Format - Use 24 hour time format. - Use 12 hour time format. - This app can use your device - volume controls to control your Squeezebox device volume. Would you like to - enable this behavior?\n\nIt can be changed at any time within - the app preferences. - Browse Preferences - Album Sort - Choose the way that albums are sorted. Please note that this preference is stored on the server and can only be changed when connected. - Show Title Bar - If selected, during browsing the title bar has breadcrumbs to navigate the browse history. - Show Now Playing Bar - If selected, during browsing the bottom bar shows the now playing information and allows quick access to the now playing screen. - Disable Artist Artwork - Disables generation of the artist artwork on devices where this feature does not work properly or is undesired. - Browse Column Count - Configure the number of columns (in portrait mode) that browsing will use for grid-based items. - General - Keep screen on whenever this app is in the foreground. - Keep Screen On - SqueezePlayer Start - When connection established to a server, automatically start SqueezePlayer and connect it to the server. - Great, you\'ve got SqueezePlayer installed! Would you like to automatically start SqueezePlayer whenever this app connects to a server? - Default Play Mode - Choose the play mode to use when selecting tracks directly - - - Prompt - Play Now - Play Next - Add to Playlist - - - Other - Volume - Temporarily enable this, then perform a troublesome operation. Then return and use the “Send Feedback” option. - Verbose Logging - Disable this if you don\'t want to read the release notes whenever the app is upgraded. - Show Release Notes - Theme - Choose a visual style for the app. - - - - Light - Dark - Set by Battery Saver - - - Compact Mode - Use a compact visual style - Use a normal visual style - - Language - Choose the language for text within this app - - English - Français - Deutsch - - - Download location - The location on your device to which downloads will be stored.\n\nCurrent value:\n %1$s - Track download - Tracks will be download in the native format as they are hosted on your server. - Tracks will be transcoded to an alternative format as they are downloaded to your device. - Transcoding - If transcoding is enabled, downloads will be transcoded to %1$s format. - Transcode Format - Comma-delimited list of transcoding options.\n\nCurrent value: %1$s - Transcode Options - - Always use lists for browsing - - Show Now Playing Notification - When leaving the app with a player playing, a notification will be presented that can be used to control that player. - No notification will be shown. - - Automatic Text Size - The text size will dynamically shrink to fit more when necessary - Longer text will be truncated when necessary - \ No newline at end of file diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 4072f2f..b6e8ffd 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -273,7 +273,174 @@ Now Playing Launch direct to Now Playing All Items - Close + Close Snap to Current Track Forgot your password? + + + Automatically connect to the last connected server + Automatic Connect + Periodically send discovery broadcast requests to + find local servers + Automatic Discovery + Advanced + Shows advanced preferences + Download + Shows download preferences + Cache Location + Artwork cache will be stored on %1$s + + + + Use Internal Storage + Use External Storage (SD card, etc) + + + Storage Cache Size + The maximum amount of space that the artwork cache will + use on device storage.\n\nThe current maximum value is %1$s MB. + + + + Automatic + 50 MB + 100 MB + 250 MB + 500 MB + 1000 MB + + + Artwork + Caching + Removes all cache data from storage + Wipe Cache + Do you want to remove all cache data from + permanent storage? If you select yes, then the cache will begin to + fill again on demand. + On-Call Behavior + On Call Received + What to do when a call is made or received and connected players are playing.\n\nCurrent value: \"%1$s\" + + + Nothing + Mute All Players + Mute Current Player + Pause All Players + Pause Current Player + + + Resume Playback + For paused and muted players, playback continues automatically if the call ends within the configured time. + + + Never + 1 minute + 5 minutes + 10 minutes + 30 minutes + 60 minutes + Forever + + + Integrate with System Volume Control + The app will integrate into the system volume. + The app\'s volume control will operate independent of the system volume control. + + Play Silent Audio + The app will play silent audio in the background to help manage audio focus on newer Android versions. + The app will not play silent audio. + + Pause when Headphones Disconnect + The current player will pause whenever bluetooth or wired headphones disconnect when audio is playing (requires that "Play Silent Audio" be enabled). + Playback continues unaffected by headphones status. + + Time Format + Use 24 hour time format. + Use 12 hour time format. + This app can use your device + volume controls to control your Squeezebox device volume. Would you like to + enable this behavior?\n\nIt can be changed at any time within + the app preferences. + Browse Preferences + Album Sort + Choose the way that albums are sorted. Please note that this preference is stored on the server and can only be changed when connected. + Show Title Bar + If selected, during browsing the title bar has breadcrumbs to navigate the browse history. + Show Now Playing Bar + If selected, during browsing the bottom bar shows the now playing information and allows quick access to the now playing screen. + Disable Artist Artwork + Disables generation of the artist artwork on devices where this feature does not work properly or is undesired. + Browse Column Count + Configure the number of columns (in portrait mode) that browsing will use for grid-based items. + General + Keep screen on whenever this app is in the foreground. + Keep Screen On + SqueezePlayer Start + When connection established to a server, automatically start SqueezePlayer and connect it to the server. + Great, you\'ve got SqueezePlayer installed! Would you like to automatically start SqueezePlayer whenever this app connects to a server? + Default Play Mode + Choose the play mode to use when selecting tracks directly + + + Prompt + Play Now + Play Next + Add to Playlist + + + Other + Volume + Temporarily enable this, then perform a troublesome operation. Then return and use the “Send Feedback” option. + Verbose Logging + Disable this if you don\'t want to read the release notes whenever the app is upgraded. + Show Release Notes + Theme + Choose a visual style for the app. + + + + Light + Dark + Set by Battery Saver + + + Compact Mode + Use a compact visual style + Use a normal visual style + + Language + Choose the language for text within this app + + English + Français + Deutsch + + + Download location + The location on your device to which downloads will be stored.\n\nCurrent value:\n %1$s + Track download + Tracks will be download in the native format as they are hosted on your server. + Tracks will be transcoded to an alternative format as they are downloaded to your device. + Transcoding + If transcoding is enabled, downloads will be transcoded to %1$s format. + Transcode Format + Comma-delimited list of transcoding options.\n\nCurrent value: %1$s + Transcode Options + + Always use lists for browsing + + Show Now Playing Notification + When leaving the app with a player playing, a notification will be presented that can be used to control that player. + No notification will be shown. + + Automatic Text Size + The text size will dynamically shrink to fit more when necessary + Longer text will be truncated when necessary + + About %1$s + Version %1$s + + Timeout waiting for server connection to complete + No Network Available + Connection error diff --git a/build.gradle b/build.gradle index a68dd3c..1207df3 100644 --- a/build.gradle +++ b/build.gradle @@ -4,7 +4,7 @@ */ buildscript { - ext.kotlin_version = '1.7.20' + ext.kotlin_version = '1.7.21' ext.sqldelight_version = '1.5.4' repositories {