40 Commits
3.5.7 ... 3.5.8

Author SHA1 Message Date
antonio
dfc246d079 feat: increased buffering multiplier limits 2023-11-26 19:14:42 +01:00
antonio
0a5983e32b feat: implemented streaming buffering strategy 2023-11-26 19:10:21 +01:00
antonio
9fde629233 fix: network security configuration with cleartext traffic opt-out 2023-11-26 17:36:38 +01:00
antonio
e089c5e466 gradle: bump up code version 2023-11-26 17:27:55 +01:00
antonio
94b0572958 feat: network security configuration 2023-11-26 17:22:38 +01:00
antonio
133b5e4794 feat: implemented settings for enabling or disabling music scrobbling 2023-11-26 16:39:05 +01:00
antonio
6b0ba573de feat: improved live transcoding UI 2023-11-26 16:20:07 +01:00
antonio
6ae7fc2172 gradle: dependencies update 2023-11-26 16:18:47 +01:00
antonio
9cabfb0e2c style: PR code cleanup 2023-11-05 17:10:13 +01:00
antonio
17f05cb3d8 Merge remote-tracking branch 'origin/main' 2023-11-05 16:44:23 +01:00
CappielloAntonio
f2839f4ff9 Merge pull request #100 from kingbluezback/main
style: updated dialog graphics to comply with Material You guidelines
2023-11-05 16:44:05 +01:00
antonio
9aadcb91fb fix: null checking 2023-11-05 16:43:13 +01:00
antonio
5d4dfe1ac7 gradle: gradle and dependencies update 2023-11-05 16:07:12 +01:00
kingbluezback
d3d76dd435 Change Dialogs
Update the dialogs to use material you theme.
2023-10-22 20:42:40 -07:00
kingbluezback
0c3086d68b Update activity_main.xml
Update the apps background color for material you.
2023-10-22 20:35:41 -07:00
kingbluezback
9b3b9771e6 Update strings.xml
When editing a playlist the title is "create playlist" instead of "edit playlist"
2023-10-22 20:33:51 -07:00
antonio
a92403bda4 style: sort translation strings 2023-10-14 16:09:19 +02:00
antonio
67905affd3 feat: added podcast description to the right page of the player 2023-10-12 22:57:38 +02:00
antonio
c20cadff94 clean: cleaned up the podcast listening UI 2023-10-12 22:36:48 +02:00
antonio
0cc45b2b12 clean: code cleanup 2023-10-12 22:36:03 +02:00
antonio
b6063f6b20 fix: forced media type during playback 2023-10-12 22:35:34 +02:00
antonio
678c61e569 clean: removed unused properties of podcast episodes 2023-10-12 22:34:48 +02:00
antonio
e88d6d7844 fix: music player now stays closed on startup if there are no songs in the queue 2023-10-12 21:31:46 +02:00
antonio
bae43cbfe9 gradle: dependencies update 2023-10-12 21:11:24 +02:00
antonio
68c77cefff feat: added songBottomSheet to track files within directories 2023-10-11 22:49:26 +02:00
antonio
75980ee18b feat: show download button only if there are music files in the current directory fragment 2023-10-11 22:20:50 +02:00
antonio
ed30198c8d feat: implemented playlist deletion starting from current track 2023-10-11 21:48:04 +02:00
antonio
185a671f82 fix: resolved an issue with podcast cover image display 2023-10-11 20:55:33 +02:00
antonio
42905819a7 Merge remote-tracking branch 'origin/main' 2023-10-07 16:01:40 +02:00
CappielloAntonio
93d6faa392 github: update crash-report.md 2023-10-07 15:52:28 +02:00
CappielloAntonio
64337775d6 Merge pull request #97 from rkowalsk/main
feat: added french localization
2023-10-07 15:47:29 +02:00
Romain Kowalski
d690cf37fb fix: shortened Wifi transcoding string that was overflowing 2023-10-05 16:56:14 +02:00
Romain Kowalski
32c8ef3b25 Add French localization 2023-10-05 16:23:17 +02:00
antonio
607c68967d gradle: dependencies update 2023-09-29 11:11:30 +02:00
antonio
7fb9f63d1f Merge remote-tracking branch 'origin/main' 2023-09-17 22:33:39 +02:00
antonio
a04a2072f7 feat: implemented a second grid layout for album display on the artist page 2023-09-17 22:33:25 +02:00
antonio
72bd71dea2 fix: error handling 2023-09-17 22:04:07 +02:00
CappielloAntonio
f87328f874 Merge pull request #84 from GallowsDove/templates
style: use proper markdown for issue templates
2023-09-17 21:16:54 +02:00
GallowsDove
4d9b71d48e fix: fix indent in templates 2023-09-17 20:02:43 +02:00
GallowsDove
06f8bc771a feat: Use markdown for github templates 2023-09-17 19:59:27 +02:00
58 changed files with 1407 additions and 568 deletions

View File

@@ -7,27 +7,29 @@ assignees: ''
---
**Describe the bug**
A clear and concise description of what the bug is.
## Describe the bug
<!-- A clear and concise description of what the bug is. -->
**Expected behavior**
A clear and concise description of what you expected to happen.
## Expected behavior
<!-- A clear and concise description of what you expected to happen. -->
**To Reproduce**
## To Reproduce
<!--
Outline the steps required to reproduce the bug, including any specific actions, inputs, or conditions:
1. Go to '...'
2. Click on '....'
3. Scroll down to '....'
4. See error
-->
**Environment**
## Environment
- Android device: [Device Model]
- Android OS version: [Android Version]
- App version: [App Version]
- Other relevant details: [e.g., specific network conditions, external dependencies]
**Logs or Screenshots**
If applicable, add screenshots to help explain your problem.
## Logs or Screenshots
<!-- If applicable, add screenshots to help explain your problem. -->
**Additional context**
Add any other context about the problem here.
## Additional context
<!-- Add any other context about the problem here. -->

View File

@@ -7,33 +7,35 @@ assignees: ''
---
**Description**
Provide a clear and concise description of the crash you encountered.
## Description
<!-- Provide a clear and concise description of the crash you encountered. -->
**Steps to Reproduce**
## Steps to Reproduce
<!--
Please provide the steps to reproduce the crash:
1. Go to '...'
2. Click on '...'
3. Scroll down to '...'
4. See the crash
-->
**Environment**
## Environment
- Android device: [Device Model]
- Android OS version: [Android Version]
- App version: [App Version]
- Other relevant details: [e.g., specific network conditions, external dependencies]
**Crash Logs/Stack Trace**
If available, please provide the crash log or stack trace related to the crash. Include it inside a code block (surround with triple backticks ```).
## Crash Logs/Stack trace
<!-- If available, please provide the crash log or stack trace related to the crash. Include it inside a code block (surround with triple backticks ```). Please use the unsigned apk (app-tempo-debug.apk), as the logs would be illegible and therefore useless for this purpose. -->
**Screenshots**
If applicable, add screenshots to help explain the problem.
## Screenshots
<!-- If applicable, add screenshots to help explain the problem. -->
**Additional Context**
Add any other context about the problem here.
## Additional Context
<!-- Add any other context about the problem here. -->
**Reproducibility**
Mention the frequency of the crash occurrence (e.g., always, sometimes, occasionally).
## Reproducibility
<!-- Mention the frequency of the crash occurrence (e.g., always, sometimes, occasionally). -->
**Additional Notes**
Include any other notes or details that could be helpful for troubleshooting the crash.
## Additional Notes
<!-- Include any other notes or details that could be helpful for troubleshooting the crash. -->

View File

@@ -7,14 +7,14 @@ assignees: ''
---
**Summary**
Provide a concise summary of the feature you are requesting.
## Summary
<!-- Provide a concise summary of the feature you are requesting. -->
**Description**
Please describe in detail the feature you would like to see implemented.
## Description
<!-- Please describe in detail the feature you would like to see implemented. -->
**Use Case**
Explain why this feature is important and how it would improve the user experience.
## Use Case
<!-- Explain why this feature is important and how it would improve the user experience. -->
**Additional context**
Include any additional information, screenshots, or examples that could be helpful in understanding or implementing the feature.
## Additional context
<!-- Include any additional information, screenshots, or examples that could be helpful in understanding or implementing the feature. -->

View File

@@ -3,8 +3,8 @@ apply plugin: 'kotlin-android'
apply plugin: 'kotlin-parcelize'
android {
compileSdk 34
buildToolsVersion "34.0.0"
compileSdk = 34
buildToolsVersion = "34.0.0"
defaultConfig {
minSdkVersion 24
@@ -22,18 +22,18 @@ android {
}
}
flavorDimensions "default"
flavorDimensions += "default"
productFlavors {
tempo {
dimension "default"
dimension = "default"
applicationId 'com.cappielloantonio.tempo'
versionCode 22
versionName '3.5.7'
versionName '3.5.8'
}
notquitemy {
dimension "default"
dimension = "default"
applicationId "com.cappielloantonio.notquitemy.tempo"
versionCode 1
versionName "1.0.0"
@@ -72,29 +72,29 @@ dependencies {
implementation 'androidx.constraintlayout:constraintlayout:2.1.4'
implementation 'androidx.coordinatorlayout:coordinatorlayout:1.2.0'
implementation 'androidx.preference:preference-ktx:1.2.1'
implementation 'androidx.navigation:navigation-fragment-ktx:2.7.2'
implementation 'androidx.navigation:navigation-ui-ktx:2.7.2'
implementation 'androidx.recyclerview:recyclerview:1.3.1'
implementation 'androidx.room:room-runtime:2.5.2'
implementation 'androidx.navigation:navigation-fragment-ktx:2.7.5'
implementation 'androidx.navigation:navigation-ui-ktx:2.7.5'
implementation 'androidx.recyclerview:recyclerview:1.3.2'
implementation 'androidx.room:room-runtime:2.6.0'
implementation 'androidx.core:core-splashscreen:1.0.1'
implementation "androidx.appcompat:appcompat:1.6.1"
// Android Material
implementation 'com.google.android.material:material:1.9.0'
implementation 'com.google.android.material:material:1.10.0'
// Glide
implementation 'com.github.bumptech.glide:glide:4.16.0'
implementation 'com.github.bumptech.glide:annotations:4.16.0'
// Media3
implementation 'androidx.media3:media3-session:1.1.1'
implementation 'androidx.media3:media3-common:1.1.1'
implementation 'androidx.media3:media3-exoplayer:1.1.1'
implementation 'androidx.media3:media3-ui:1.1.1'
tempoImplementation 'androidx.media3:media3-cast:1.1.1'
implementation 'androidx.media3:media3-session:1.2.0'
implementation 'androidx.media3:media3-common:1.2.0'
implementation 'androidx.media3:media3-exoplayer:1.2.0'
implementation 'androidx.media3:media3-ui:1.2.0'
tempoImplementation 'androidx.media3:media3-cast:1.2.0'
annotationProcessor 'com.github.bumptech.glide:compiler:4.16.0'
annotationProcessor 'androidx.room:room-compiler:2.5.2'
annotationProcessor 'androidx.room:room-compiler:2.6.0'
// Retrofit
implementation 'com.squareup.retrofit2:retrofit:2.9.0'

View File

@@ -19,7 +19,8 @@
android:roundIcon="@mipmap/ic_launcher"
android:supportsRtl="true"
android:theme="@style/AppTheme.SplashScreen"
android:usesCleartextTraffic="true">
android:usesCleartextTraffic="true"
android:networkSecurityConfig="@xml/network_security_config">
<meta-data
android:name="com.google.android.gms.cast.framework.OPTIONS_PROVIDER_CLASS_NAME"

View File

@@ -49,12 +49,14 @@ public class SharingRepository {
public void onResponse(@NonNull Call<ApiResponse> call, @NonNull Response<ApiResponse> response) {
if (response.isSuccessful() && response.body() != null && response.body().getSubsonicResponse().getShares() != null && response.body().getSubsonicResponse().getShares().getShares() != null && response.body().getSubsonicResponse().getShares().getShares().get(0) != null) {
share.setValue(response.body().getSubsonicResponse().getShares().getShares().get(0));
} else {
share.setValue(null);
}
}
@Override
public void onFailure(@NonNull Call<ApiResponse> call, @NonNull Throwable t) {
share.setValue(null);
}
});

View File

@@ -12,6 +12,7 @@ import com.cappielloantonio.tempo.subsonic.models.Child;
import com.cappielloantonio.tempo.subsonic.models.InternetRadioStation;
import com.cappielloantonio.tempo.subsonic.models.PodcastEpisode;
import com.cappielloantonio.tempo.util.MappingUtil;
import com.cappielloantonio.tempo.util.Preferences;
import com.google.common.util.concurrent.ListenableFuture;
import com.google.common.util.concurrent.MoreExecutors;
@@ -254,6 +255,21 @@ public class MediaManager {
}
}
public static void removeRange(ListenableFuture<MediaBrowser> mediaBrowserListenableFuture, List<Child> media, int fromItem, int toItem) {
if (mediaBrowserListenableFuture != null) {
mediaBrowserListenableFuture.addListener(() -> {
try {
if (mediaBrowserListenableFuture.isDone()) {
mediaBrowserListenableFuture.get().removeMediaItems(fromItem, toItem);
removeRangeDatabase(media, fromItem, toItem);
}
} catch (ExecutionException | InterruptedException e) {
e.printStackTrace();
}
}, MoreExecutors.directExecutor());
}
}
public static void getCurrentIndex(ListenableFuture<MediaBrowser> mediaBrowserListenableFuture, MediaIndexCallback callback) {
if (mediaBrowserListenableFuture != null) {
mediaBrowserListenableFuture.addListener(() -> {
@@ -278,7 +294,7 @@ public class MediaManager {
}
public static void scrobble(MediaItem mediaItem) {
if (mediaItem != null) {
if (mediaItem != null && Preferences.isScrobblingEnabled()) {
getSongRepository().scrobble(mediaItem.mediaMetadata.extras.getString("id"));
}
}
@@ -320,6 +336,14 @@ public class MediaManager {
}
}
private static void removeRangeDatabase(List<Child> media, int fromItem, int toItem) {
List<Child> toRemove = media.subList(fromItem, toItem);
media.removeAll(toRemove);
getQueueRepository().insertAll(media, true, 0);
}
public static void clearDatabase() {
getQueueRepository().deleteAll();
}

View File

@@ -14,6 +14,7 @@ class PodcastChannel : Parcelable {
var url: String? = null
var title: String? = null
var description: String? = null
@SerializedName("coverArt")
var coverArtId: String? = null
var originalImageUrl: String? = null
var status: String? = null

View File

@@ -12,12 +12,10 @@ class PodcastEpisode : Parcelable {
var id: String? = null
@SerializedName("parent")
var parentId: String? = null
@SerializedName("isDir")
var isDir = false
var title: String? = null
var album: String? = null
var artist: String? = null
var track: Int? = null
var year: Int? = null
var genre: String? = null
@SerializedName("coverArt")
@@ -25,26 +23,14 @@ class PodcastEpisode : Parcelable {
var size: Long? = null
var contentType: String? = null
var suffix: String? = null
var transcodedContentType: String? = null
var transcodedSuffix: String? = null
var duration: Int? = null
@SerializedName("bitRate")
var bitrate: Int? = null
var path: String? = null
@SerializedName("isVideo")
var isVideo: Boolean = false
var userRating: Int? = null
var averageRating: Double? = null
var playCount: Long? = null
var discNumber: Int? = null
var created: Date? = null
var starred: Date? = null
var albumId: String? = null
var artistId: String? = null
var type: String? = null
var bookmarkPosition: Long? = null
var originalWidth: Int? = null
var originalHeight: Int? = null
var streamId: String? = null
var channelId: String? = null
var description: String? = null

View File

@@ -119,8 +119,6 @@ public class MainActivity extends BaseActivity {
fragmentManager.beginTransaction().replace(R.id.player_bottom_sheet, new PlayerBottomSheetFragment(), "PlayerBottomSheet").commit();
setBottomSheetInPeek(mainViewModel.isQueueLoaded());
collapseBottomSheet();
}
public void setBottomSheetInPeek(Boolean isVisible) {
@@ -163,7 +161,7 @@ public class MainActivity extends BaseActivity {
switch (state) {
case BottomSheetBehavior.STATE_HIDDEN:
hideMusicSession();
resetMusicSession();
break;
case BottomSheetBehavior.STATE_COLLAPSED:
if (playerBottomSheetFragment != null)

View File

@@ -77,6 +77,8 @@ public class MusicDirectoryAdapter extends RecyclerView.Adapter<MusicDirectoryAd
item.musicDirectoryTitleTextView.setSelected(true);
itemView.setOnClickListener(v -> onClick());
itemView.setOnLongClickListener(v -> onLongClick());
item.musicDirectoryMoreButton.setOnClickListener(v -> onClick());
}
@@ -92,5 +94,18 @@ public class MusicDirectoryAdapter extends RecyclerView.Adapter<MusicDirectoryAd
click.onMediaClick(bundle);
}
}
private boolean onLongClick() {
if (!children.get(getBindingAdapterPosition()).isDir()) {
Bundle bundle = new Bundle();
bundle.putParcelable(Constants.TRACK_OBJECT, children.get(getBindingAdapterPosition()));
click.onMediaLongClick(bundle);
return true;
} else {
return false;
}
}
}
}

View File

@@ -42,7 +42,7 @@ public class PodcastChannelHorizontalAdapter extends RecyclerView.Adapter<Podcas
holder.item.podcastChannelDescriptionTextView.setText(MusicUtil.getReadableString(podcastChannel.getDescription()));
CustomGlideRequest.Builder
.from(holder.itemView.getContext(), podcastChannel.getOriginalImageUrl(), CustomGlideRequest.ResourceType.Podcast)
.from(holder.itemView.getContext(), podcastChannel.getCoverArtId(), CustomGlideRequest.ResourceType.Podcast)
.build()
.into(holder.item.podcastChannelCoverImageView);
}

View File

@@ -1,6 +1,5 @@
package com.cappielloantonio.tempo.ui.dialog;
import android.app.AlertDialog;
import android.app.Dialog;
import android.content.Intent;
import android.os.Bundle;
@@ -14,38 +13,23 @@ import androidx.media3.common.util.UnstableApi;
import com.cappielloantonio.tempo.R;
import com.cappielloantonio.tempo.databinding.DialogBatteryOptimizationBinding;
import com.cappielloantonio.tempo.util.Preferences;
import com.google.android.material.dialog.MaterialAlertDialogBuilder;
@OptIn(markerClass = UnstableApi.class)
public class BatteryOptimizationDialog extends DialogFragment {
private static final String TAG = "BatteryOptimizationDialog";
private DialogBatteryOptimizationBinding bind;
@NonNull
@Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
bind = DialogBatteryOptimizationBinding.inflate(getLayoutInflater());
DialogBatteryOptimizationBinding bind = DialogBatteryOptimizationBinding.inflate(getLayoutInflater());
AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
builder.setView(bind.getRoot())
return new MaterialAlertDialogBuilder(requireContext())
.setView(bind.getRoot())
.setTitle(R.string.activity_battery_optimizations_title)
.setNeutralButton(R.string.battery_optimization_neutral_button, (dialog, id) -> Preferences.dontAskForOptimization())
.setPositiveButton(R.string.battery_optimization_positive_button, (dialog, listener) -> openPowerSettings())
.setNeutralButton(R.string.battery_optimization_neutral_button, (dialog, listener) -> Preferences.dontAskForOptimization())
.setNegativeButton(R.string.battery_optimization_negative_button, null)
.setPositiveButton(R.string.battery_optimization_positive_button, (dialog, id) -> openPowerSettings());
AlertDialog popup = builder.create();
popup.setCancelable(false);
popup.setCanceledOnTouchOutside(false);
return popup;
}
@Override
public void onDestroyView() {
super.onDestroyView();
bind = null;
.create();
}
private void openPowerSettings() {

View File

@@ -1,6 +1,5 @@
package com.cappielloantonio.tempo.ui.dialog;
import android.app.AlertDialog;
import android.app.Dialog;
import android.os.Bundle;
@@ -10,22 +9,18 @@ import androidx.fragment.app.DialogFragment;
import com.cappielloantonio.tempo.R;
import com.cappielloantonio.tempo.databinding.DialogConnectionAlertBinding;
import com.cappielloantonio.tempo.util.Preferences;
import com.google.android.material.dialog.MaterialAlertDialogBuilder;
import java.util.Objects;
public class ConnectionAlertDialog extends DialogFragment {
private static final String TAG = "ServerUnreachableDialog";
private DialogConnectionAlertBinding bind;
@NonNull
@Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
bind = DialogConnectionAlertBinding.inflate(getLayoutInflater());
DialogConnectionAlertBinding bind = DialogConnectionAlertBinding.inflate(getLayoutInflater());
AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
builder.setView(bind.getRoot())
MaterialAlertDialogBuilder builder = new MaterialAlertDialogBuilder(getActivity())
.setView(bind.getRoot())
.setTitle(R.string.connection_alert_dialog_title)
.setPositiveButton(R.string.connection_alert_dialog_positive_button, (dialog, id) -> dialog.cancel())
.setNegativeButton(R.string.connection_alert_dialog_negative_button, (dialog, id) -> dialog.cancel());
@@ -45,16 +40,12 @@ public class ConnectionAlertDialog extends DialogFragment {
setButtonAction();
}
@Override
public void onDestroyView() {
super.onDestroyView();
bind = null;
}
private void setButtonAction() {
((AlertDialog) Objects.requireNonNull(getDialog())).getButton(AlertDialog.BUTTON_NEUTRAL).setOnClickListener(v -> {
androidx.appcompat.app.AlertDialog alertDialog = (androidx.appcompat.app.AlertDialog) Objects.requireNonNull(getDialog());
alertDialog.getButton(androidx.appcompat.app.AlertDialog.BUTTON_NEUTRAL).setOnClickListener(v -> {
Preferences.setDataSavingMode(true);
Objects.requireNonNull(getDialog()).dismiss();
});
}
}
}

View File

@@ -1,6 +1,5 @@
package com.cappielloantonio.tempo.ui.dialog;
import android.app.AlertDialog;
import android.app.Dialog;
import android.os.Bundle;
import android.widget.Button;
@@ -12,26 +11,23 @@ import androidx.media3.common.util.UnstableApi;
import com.cappielloantonio.tempo.R;
import com.cappielloantonio.tempo.databinding.DialogDeleteDownloadStorageBinding;
import com.cappielloantonio.tempo.interfaces.DialogClickCallback;
import com.cappielloantonio.tempo.util.DownloadUtil;
import com.google.android.material.dialog.MaterialAlertDialogBuilder;
@OptIn(markerClass = UnstableApi.class)
public class DeleteDownloadStorageDialog extends DialogFragment {
private DialogDeleteDownloadStorageBinding bind;
@NonNull
@Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
bind = DialogDeleteDownloadStorageBinding.inflate(getLayoutInflater());
DialogDeleteDownloadStorageBinding bind = DialogDeleteDownloadStorageBinding.inflate(getLayoutInflater());
AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
builder.setView(bind.getRoot())
return new MaterialAlertDialogBuilder(requireContext())
.setView(bind.getRoot())
.setTitle(R.string.delete_download_storage_dialog_title)
.setPositiveButton(R.string.delete_download_storage_dialog_positive_button, null)
.setNegativeButton(R.string.delete_download_storage_dialog_negative_button, null);
return builder.create();
.setNegativeButton(R.string.delete_download_storage_dialog_negative_button, null)
.create();
}
@Override
@@ -40,14 +36,8 @@ public class DeleteDownloadStorageDialog extends DialogFragment {
setButtonAction();
}
@Override
public void onDestroyView() {
super.onDestroyView();
bind = null;
}
private void setButtonAction() {
AlertDialog dialog = ((AlertDialog) getDialog());
androidx.appcompat.app.AlertDialog dialog = (androidx.appcompat.app.AlertDialog) getDialog();
if (dialog != null) {
Button positiveButton = dialog.getButton(Dialog.BUTTON_POSITIVE);

View File

@@ -0,0 +1,61 @@
package com.cappielloantonio.tempo.ui.dialog;
import android.app.Dialog;
import android.os.Bundle;
import android.widget.Button;
import androidx.annotation.NonNull;
import androidx.annotation.OptIn;
import androidx.fragment.app.DialogFragment;
import androidx.media3.common.util.UnstableApi;
import com.cappielloantonio.tempo.R;
import com.cappielloantonio.tempo.databinding.DialogDownloadDirectoryBinding;
import com.cappielloantonio.tempo.interfaces.DialogClickCallback;
import com.google.android.material.dialog.MaterialAlertDialogBuilder;
@OptIn(markerClass = UnstableApi.class)
public class DownloadDirectoryDialog extends DialogFragment {
private final DialogClickCallback dialogClickCallback;
public DownloadDirectoryDialog(DialogClickCallback dialogClickCallback) {
this.dialogClickCallback = dialogClickCallback;
}
@NonNull
@Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
DialogDownloadDirectoryBinding bind = DialogDownloadDirectoryBinding.inflate(getLayoutInflater());
return new MaterialAlertDialogBuilder(requireContext())
.setView(bind.getRoot())
.setTitle(R.string.download_directory_dialog_title)
.setPositiveButton(R.string.download_directory_dialog_positive_button, null)
.setNegativeButton(R.string.download_directory_dialog_negative_button, null)
.create();
}
@Override
public void onResume() {
super.onResume();
setButtonAction();
}
private void setButtonAction() {
androidx.appcompat.app.AlertDialog dialog = (androidx.appcompat.app.AlertDialog) getDialog();
if (dialog != null) {
Button positiveButton = dialog.getButton(Dialog.BUTTON_POSITIVE);
positiveButton.setOnClickListener(v -> {
dialogClickCallback.onPositiveClick();
dialog.dismiss();
});
Button negativeButton = dialog.getButton(Dialog.BUTTON_NEGATIVE);
negativeButton.setOnClickListener(v -> {
dialogClickCallback.onNegativeClick();
dialog.dismiss();
});
}
}
}

View File

@@ -1,6 +1,5 @@
package com.cappielloantonio.tempo.ui.dialog;
import android.app.AlertDialog;
import android.app.Dialog;
import android.os.Bundle;
import android.widget.Button;
@@ -15,11 +14,10 @@ import com.cappielloantonio.tempo.databinding.DialogDownloadStorageBinding;
import com.cappielloantonio.tempo.interfaces.DialogClickCallback;
import com.cappielloantonio.tempo.util.DownloadUtil;
import com.cappielloantonio.tempo.util.Preferences;
import com.google.android.material.dialog.MaterialAlertDialogBuilder;
@OptIn(markerClass = UnstableApi.class)
public class DownloadStorageDialog extends DialogFragment {
private DialogDownloadStorageBinding bind;
private final DialogClickCallback dialogClickCallback;
public DownloadStorageDialog(DialogClickCallback dialogClickCallback) {
@@ -29,16 +27,14 @@ public class DownloadStorageDialog extends DialogFragment {
@NonNull
@Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
bind = DialogDownloadStorageBinding.inflate(getLayoutInflater());
DialogDownloadStorageBinding bind = DialogDownloadStorageBinding.inflate(getLayoutInflater());
AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
builder.setView(bind.getRoot())
return new MaterialAlertDialogBuilder(getActivity())
.setView(bind.getRoot())
.setTitle(R.string.download_storage_dialog_title)
.setPositiveButton(R.string.download_storage_external_dialog_positive_button, null)
.setNegativeButton(R.string.download_storage_internal_dialog_negative_button, null);
return builder.create();
.setNegativeButton(R.string.download_storage_internal_dialog_negative_button, null)
.create();
}
@Override
@@ -47,14 +43,8 @@ public class DownloadStorageDialog extends DialogFragment {
setButtonAction();
}
@Override
public void onDestroyView() {
super.onDestroyView();
bind = null;
}
private void setButtonAction() {
AlertDialog dialog = ((AlertDialog) getDialog());
androidx.appcompat.app.AlertDialog dialog = (androidx.appcompat.app.AlertDialog) getDialog();
if (dialog != null) {
Button positiveButton = dialog.getButton(Dialog.BUTTON_POSITIVE);

View File

@@ -1,6 +1,5 @@
package com.cappielloantonio.tempo.ui.dialog;
import android.app.AlertDialog;
import android.app.Dialog;
import android.os.Bundle;
import android.view.View;
@@ -17,6 +16,7 @@ import com.cappielloantonio.tempo.subsonic.models.Playlist;
import com.cappielloantonio.tempo.ui.adapter.PlaylistDialogHorizontalAdapter;
import com.cappielloantonio.tempo.util.Constants;
import com.cappielloantonio.tempo.viewmodel.PlaylistChooserViewModel;
import com.google.android.material.dialog.MaterialAlertDialogBuilder;
import java.util.Objects;
@@ -30,17 +30,15 @@ public class PlaylistChooserDialog extends DialogFragment implements ClickCallba
@Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
bind = DialogPlaylistChooserBinding.inflate(getLayoutInflater());
playlistChooserViewModel = new ViewModelProvider(requireActivity()).get(PlaylistChooserViewModel.class);
AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
builder.setView(bind.getRoot())
return new MaterialAlertDialogBuilder(getActivity())
.setView(bind.getRoot())
.setTitle(R.string.playlist_chooser_dialog_title)
.setNeutralButton(R.string.playlist_chooser_dialog_neutral_button, (dialog, id) -> {
})
.setNegativeButton(R.string.playlist_chooser_dialog_negative_button, (dialog, id) -> dialog.cancel());
return builder.create();
.setNeutralButton(R.string.playlist_chooser_dialog_neutral_button, (dialog, id) -> { })
.setNegativeButton(R.string.playlist_chooser_dialog_negative_button, (dialog, id) -> dialog.cancel())
.create();
}
@Override
@@ -63,7 +61,8 @@ public class PlaylistChooserDialog extends DialogFragment implements ClickCallba
}
private void setButtonAction() {
((AlertDialog) Objects.requireNonNull(getDialog())).getButton(AlertDialog.BUTTON_NEUTRAL).setOnClickListener(v -> {
androidx.appcompat.app.AlertDialog alertDialog = (androidx.appcompat.app.AlertDialog) Objects.requireNonNull(getDialog());
alertDialog.getButton(androidx.appcompat.app.AlertDialog.BUTTON_NEUTRAL).setOnClickListener(v -> {
Bundle bundle = new Bundle();
bundle.putParcelable(Constants.TRACK_OBJECT, playlistChooserViewModel.getSongToAdd());

View File

@@ -1,6 +1,5 @@
package com.cappielloantonio.tempo.ui.dialog;
import android.app.AlertDialog;
import android.app.Dialog;
import android.content.ClipData;
import android.content.ClipboardManager;
@@ -24,6 +23,7 @@ import com.cappielloantonio.tempo.util.Constants;
import com.cappielloantonio.tempo.util.MusicUtil;
import com.cappielloantonio.tempo.util.Preferences;
import com.cappielloantonio.tempo.viewmodel.PlaylistEditorViewModel;
import com.google.android.material.dialog.MaterialAlertDialogBuilder;
import java.util.Collections;
import java.util.Objects;
@@ -44,18 +44,16 @@ public class PlaylistEditorDialog extends DialogFragment {
@Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
bind = DialogPlaylistEditorBinding.inflate(getLayoutInflater());
playlistEditorViewModel = new ViewModelProvider(requireActivity()).get(PlaylistEditorViewModel.class);
AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
builder.setView(bind.getRoot())
return new MaterialAlertDialogBuilder(getActivity())
.setView(bind.getRoot())
.setTitle(R.string.playlist_editor_dialog_title)
.setPositiveButton(R.string.playlist_editor_dialog_positive_button, (dialog, id) -> {
})
.setPositiveButton(R.string.playlist_editor_dialog_positive_button, (dialog, id) -> { })
.setNeutralButton(R.string.playlist_editor_dialog_neutral_button, (dialog, id) -> dialog.cancel())
.setNegativeButton(R.string.playlist_editor_dialog_negative_button, (dialog, id) -> dialog.cancel());
return builder.create();
.setNegativeButton(R.string.playlist_editor_dialog_negative_button, (dialog, id) -> dialog.cancel())
.create();
}
@Override
@@ -88,7 +86,9 @@ public class PlaylistEditorDialog extends DialogFragment {
}
private void setButtonAction() {
((AlertDialog) Objects.requireNonNull(getDialog())).getButton(AlertDialog.BUTTON_POSITIVE).setOnClickListener(v -> {
androidx.appcompat.app.AlertDialog alertDialog = (androidx.appcompat.app.AlertDialog) Objects.requireNonNull(getDialog());
alertDialog.getButton(androidx.appcompat.app.AlertDialog.BUTTON_POSITIVE).setOnClickListener(v -> {
if (validateInput()) {
if (playlistEditorViewModel.getSongToAdd() != null) {
playlistEditorViewModel.createPlaylist(playlistName);
@@ -100,7 +100,7 @@ public class PlaylistEditorDialog extends DialogFragment {
}
});
((AlertDialog) Objects.requireNonNull(getDialog())).getButton(AlertDialog.BUTTON_NEUTRAL).setOnClickListener(v -> {
alertDialog.getButton(androidx.appcompat.app.AlertDialog.BUTTON_NEUTRAL).setOnClickListener(v -> {
playlistEditorViewModel.deletePlaylist();
dialogDismiss();
});
@@ -183,6 +183,8 @@ public class PlaylistEditorDialog extends DialogFragment {
private void dialogDismiss() {
Objects.requireNonNull(getDialog()).dismiss();
playlistCallback.onDismiss();
if (playlistCallback != null) {
playlistCallback.onDismiss();
}
}
}

View File

@@ -1,9 +1,9 @@
package com.cappielloantonio.tempo.ui.dialog;
import android.app.AlertDialog;
import android.app.Dialog;
import android.os.Bundle;
import android.text.TextUtils;
import android.widget.Button;
import androidx.annotation.NonNull;
import androidx.fragment.app.DialogFragment;
@@ -13,6 +13,7 @@ import com.cappielloantonio.tempo.R;
import com.cappielloantonio.tempo.databinding.DialogPodcastChannelEditorBinding;
import com.cappielloantonio.tempo.interfaces.PodcastCallback;
import com.cappielloantonio.tempo.viewmodel.PodcastChannelEditorViewModel;
import com.google.android.material.dialog.MaterialAlertDialogBuilder;
import java.util.Objects;
@@ -31,17 +32,15 @@ public class PodcastChannelEditorDialog extends DialogFragment {
@Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
bind = DialogPodcastChannelEditorBinding.inflate(getLayoutInflater());
podcastChannelEditorViewModel = new ViewModelProvider(requireActivity()).get(PodcastChannelEditorViewModel.class);
AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
builder.setView(bind.getRoot())
return new MaterialAlertDialogBuilder(getActivity())
.setView(bind.getRoot())
.setTitle(R.string.podcast_channel_editor_dialog_title)
.setPositiveButton(R.string.radio_editor_dialog_positive_button, (dialog, id) -> {
})
.setNegativeButton(R.string.radio_editor_dialog_negative_button, (dialog, id) -> dialog.cancel());
return builder.create();
.setPositiveButton(R.string.radio_editor_dialog_positive_button, (dialog, id) -> { })
.setNegativeButton(R.string.radio_editor_dialog_negative_button, (dialog, id) -> dialog.cancel())
.create();
}
@Override
@@ -58,14 +57,19 @@ public class PodcastChannelEditorDialog extends DialogFragment {
}
private void setButtonAction() {
((AlertDialog) Objects.requireNonNull(getDialog())).getButton(AlertDialog.BUTTON_POSITIVE).setOnClickListener(v -> {
if (validateInput()) {
podcastChannelEditorViewModel.createChannel(channelUrl);
dismissDialog();
}
});
androidx.appcompat.app.AlertDialog dialog = (androidx.appcompat.app.AlertDialog) getDialog();
if (dialog != null) {
Button positiveButton = dialog.getButton(Dialog.BUTTON_POSITIVE);
positiveButton.setOnClickListener(v -> {
if (validateInput()) {
podcastChannelEditorViewModel.createChannel(channelUrl);
dismissDialog();
}
});
}
}
private boolean validateInput() {
channelUrl = Objects.requireNonNull(bind.podcastChannelRssUrlNameTextView.getText()).toString().trim();

View File

@@ -1,6 +1,5 @@
package com.cappielloantonio.tempo.ui.dialog;
import android.app.AlertDialog;
import android.app.Dialog;
import android.os.Bundle;
import android.text.TextUtils;
@@ -15,6 +14,7 @@ import com.cappielloantonio.tempo.interfaces.RadioCallback;
import com.cappielloantonio.tempo.subsonic.models.InternetRadioStation;
import com.cappielloantonio.tempo.util.Constants;
import com.cappielloantonio.tempo.viewmodel.RadioEditorViewModel;
import com.google.android.material.dialog.MaterialAlertDialogBuilder;
import java.util.Objects;
@@ -35,26 +35,36 @@ public class RadioEditorDialog extends DialogFragment {
@Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
bind = DialogRadioEditorBinding.inflate(getLayoutInflater());
radioEditorViewModel = new ViewModelProvider(requireActivity()).get(RadioEditorViewModel.class);
AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
builder.setView(bind.getRoot())
return new MaterialAlertDialogBuilder(requireContext())
.setView(bind.getRoot())
.setTitle(R.string.radio_editor_dialog_title)
.setPositiveButton(R.string.radio_editor_dialog_positive_button, (dialog, id) -> {
if (validateInput()) {
if (radioEditorViewModel.getRadioToEdit() == null) {
radioEditorViewModel.createRadio(radioName, radioStreamURL, radioHomepageURL.isEmpty() ? null : radioHomepageURL);
} else {
radioEditorViewModel.updateRadio(radioName, radioStreamURL, radioHomepageURL.isEmpty() ? null : radioHomepageURL);
}
dismissDialog();
}
})
.setNeutralButton(R.string.radio_editor_dialog_neutral_button, (dialog, id) -> dialog.cancel())
.setNegativeButton(R.string.radio_editor_dialog_negative_button, (dialog, id) -> dialog.cancel());
return builder.create();
.setNeutralButton(R.string.radio_editor_dialog_neutral_button, (dialog, id) -> {
radioEditorViewModel.deleteRadio();
dismissDialog();
})
.setNegativeButton(R.string.radio_editor_dialog_negative_button, (dialog, id) -> {
dialog.cancel();
})
.create();
}
@Override
public void onStart() {
super.onStart();
setParameterInfo();
setButtonAction();
}
@Override
@@ -75,25 +85,6 @@ public class RadioEditorDialog extends DialogFragment {
}
}
private void setButtonAction() {
((AlertDialog) Objects.requireNonNull(getDialog())).getButton(AlertDialog.BUTTON_POSITIVE).setOnClickListener(v -> {
if (validateInput()) {
if (radioEditorViewModel.getRadioToEdit() == null) {
radioEditorViewModel.createRadio(radioName, radioStreamURL, radioHomepageURL.isEmpty() ? null : radioHomepageURL);
} else {
radioEditorViewModel.updateRadio(radioName, radioStreamURL, radioHomepageURL.isEmpty() ? null : radioHomepageURL);
}
dismissDialog();
}
});
((AlertDialog) Objects.requireNonNull(getDialog())).getButton(AlertDialog.BUTTON_NEUTRAL).setOnClickListener(v -> {
radioEditorViewModel.deleteRadio();
dismissDialog();
});
}
private boolean validateInput() {
radioName = Objects.requireNonNull(bind.internetRadioStationNameTextView.getText()).toString().trim();
radioStreamURL = Objects.requireNonNull(bind.internetRadioStationStreamUrlTextView.getText()).toString().trim();

View File

@@ -1,6 +1,5 @@
package com.cappielloantonio.tempo.ui.dialog;
import android.app.AlertDialog;
import android.app.Dialog;
import android.os.Bundle;
@@ -12,6 +11,7 @@ import com.cappielloantonio.tempo.R;
import com.cappielloantonio.tempo.databinding.DialogRatingBinding;
import com.cappielloantonio.tempo.util.Constants;
import com.cappielloantonio.tempo.viewmodel.RatingViewModel;
import com.google.android.material.dialog.MaterialAlertDialogBuilder;
public class RatingDialog extends DialogFragment {
private static final String TAG = "ServerSignupDialog";
@@ -25,14 +25,12 @@ public class RatingDialog extends DialogFragment {
bind = DialogRatingBinding.inflate(getLayoutInflater());
ratingViewModel = new ViewModelProvider(requireActivity()).get(RatingViewModel.class);
AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
builder.setView(bind.getRoot())
return new MaterialAlertDialogBuilder(getActivity())
.setView(bind.getRoot())
.setTitle(R.string.rating_dialog_title)
.setNegativeButton(R.string.rating_dialog_negative_button, (dialog, id) -> dialog.cancel())
.setPositiveButton(R.string.rating_dialog_positive_button, (dialog, id) -> ratingViewModel.rate((int) bind.ratingBar.getRating()));
return builder.create();
.setPositiveButton(R.string.rating_dialog_positive_button, (dialog, id) -> ratingViewModel.rate((int) bind.ratingBar.getRating()))
.create();
}
@Override

View File

@@ -1,6 +1,5 @@
package com.cappielloantonio.tempo.ui.dialog;
import android.app.AlertDialog;
import android.app.Dialog;
import android.os.Bundle;
import android.text.TextUtils;
@@ -14,6 +13,7 @@ import com.cappielloantonio.tempo.databinding.DialogServerSignupBinding;
import com.cappielloantonio.tempo.model.Server;
import com.cappielloantonio.tempo.util.MusicUtil;
import com.cappielloantonio.tempo.viewmodel.LoginViewModel;
import com.google.android.material.dialog.MaterialAlertDialogBuilder;
import java.util.Objects;
import java.util.UUID;
@@ -33,21 +33,17 @@ public class ServerSignupDialog extends DialogFragment {
@NonNull
@Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
loginViewModel = new ViewModelProvider(requireActivity()).get(LoginViewModel.class);
bind = DialogServerSignupBinding.inflate(getLayoutInflater());
AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
loginViewModel = new ViewModelProvider(requireActivity()).get(LoginViewModel.class);
builder.setView(bind.getRoot())
return new MaterialAlertDialogBuilder(getActivity())
.setView(bind.getRoot())
.setTitle(R.string.server_signup_dialog_title)
.setNeutralButton(R.string.server_signup_dialog_neutral_button, (dialog, id) -> {
})
.setPositiveButton(R.string.server_signup_dialog_positive_button, (dialog, id) -> {
})
.setNegativeButton(R.string.server_signup_dialog_negative_button, (dialog, id) -> dialog.cancel());
return builder.create();
.setNeutralButton(R.string.server_signup_dialog_neutral_button, (dialog, id) -> { })
.setPositiveButton(R.string.server_signup_dialog_positive_button, (dialog, id) -> { })
.setNegativeButton(R.string.server_signup_dialog_negative_button, (dialog, id) -> dialog.cancel())
.create();
}
@Override
@@ -81,14 +77,16 @@ public class ServerSignupDialog extends DialogFragment {
}
private void setButtonAction() {
((AlertDialog) Objects.requireNonNull(getDialog())).getButton(AlertDialog.BUTTON_POSITIVE).setOnClickListener(v -> {
androidx.appcompat.app.AlertDialog alertDialog = (androidx.appcompat.app.AlertDialog) Objects.requireNonNull(getDialog());
alertDialog.getButton(androidx.appcompat.app.AlertDialog.BUTTON_POSITIVE).setOnClickListener(v -> {
if (validateInput()) {
saveServerPreference();
Objects.requireNonNull(getDialog()).dismiss();
}
});
((AlertDialog) Objects.requireNonNull(getDialog())).getButton(AlertDialog.BUTTON_NEUTRAL).setOnClickListener(v -> {
alertDialog.getButton(androidx.appcompat.app.AlertDialog.BUTTON_NEUTRAL).setOnClickListener(v -> {
loginViewModel.deleteServer(null);
Objects.requireNonNull(getDialog()).dismiss();
});

View File

@@ -1,11 +1,11 @@
package com.cappielloantonio.tempo.ui.dialog;
import android.app.AlertDialog;
import android.app.Dialog;
import android.os.Bundle;
import androidx.annotation.NonNull;
import androidx.annotation.OptIn;
import androidx.appcompat.app.AlertDialog;
import androidx.fragment.app.DialogFragment;
import androidx.media3.common.util.UnstableApi;
@@ -13,34 +13,32 @@ import com.cappielloantonio.tempo.R;
import com.cappielloantonio.tempo.databinding.DialogServerUnreachableBinding;
import com.cappielloantonio.tempo.ui.activity.MainActivity;
import com.cappielloantonio.tempo.util.Preferences;
import com.google.android.material.dialog.MaterialAlertDialogBuilder;
import java.util.Objects;
@OptIn(markerClass = UnstableApi.class)
public class ServerUnreachableDialog extends DialogFragment {
private static final String TAG = "ServerUnreachableDialog";
private DialogServerUnreachableBinding bind;
@NonNull
@Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
bind = DialogServerUnreachableBinding.inflate(getLayoutInflater());
DialogServerUnreachableBinding bind = DialogServerUnreachableBinding.inflate(getLayoutInflater());
AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
builder.setView(bind.getRoot())
AlertDialog popup = new MaterialAlertDialogBuilder(getActivity()).setView(bind.getRoot())
.setTitle(R.string.server_unreachable_dialog_title)
.setPositiveButton(R.string.server_unreachable_dialog_positive_button, null)
.setNeutralButton(R.string.server_unreachable_dialog_neutral_button, null)
.setNegativeButton(R.string.server_unreachable_dialog_negative_button, (dialog, id) -> dialog.cancel());
.setNegativeButton(R.string.server_unreachable_dialog_negative_button, (dialog, id) -> dialog.cancel())
.create();
AlertDialog popup = builder.create();
popup.setCancelable(false);
popup.setCanceledOnTouchOutside(false);
popup.setCancelable(false);
return popup;
}
@Override
public void onStart() {
super.onStart();
@@ -48,26 +46,18 @@ public class ServerUnreachableDialog extends DialogFragment {
setButtonAction();
}
@Override
public void onDestroyView() {
super.onDestroyView();
bind = null;
}
private void setButtonAction() {
AlertDialog dialog = (AlertDialog) getDialog();
androidx.appcompat.app.AlertDialog alertDialog = (androidx.appcompat.app.AlertDialog) Objects.requireNonNull(getDialog());
if(dialog != null) {
(dialog).getButton(AlertDialog.BUTTON_NEUTRAL).setOnClickListener(v -> {
MainActivity activity = (MainActivity) getActivity();
if (activity != null) activity.quit();
dialog.dismiss();
});
alertDialog.getButton(androidx.appcompat.app.AlertDialog.BUTTON_NEUTRAL).setOnClickListener(v -> {
MainActivity activity = (MainActivity) getActivity();
if (activity != null) activity.quit();
alertDialog.dismiss();
});
(dialog).getButton(AlertDialog.BUTTON_POSITIVE).setOnClickListener(v -> {
Preferences.setServerUnreachableDatetime(System.currentTimeMillis());
dialog.dismiss();
});
}
alertDialog.getButton(androidx.appcompat.app.AlertDialog.BUTTON_POSITIVE).setOnClickListener(v -> {
Preferences.setServerUnreachableDatetime(System.currentTimeMillis());
alertDialog.dismiss();
});
}
}

View File

@@ -17,15 +17,12 @@ import com.cappielloantonio.tempo.viewmodel.ShareBottomSheetViewModel;
import com.google.android.material.datepicker.CalendarConstraints;
import com.google.android.material.datepicker.DateValidatorPointForward;
import com.google.android.material.datepicker.MaterialDatePicker;
import com.google.android.material.datepicker.MaterialPickerOnPositiveButtonClickListener;
import com.google.android.material.dialog.MaterialAlertDialogBuilder;
import java.util.Calendar;
import java.util.Date;
import java.util.Objects;
public class ShareUpdateDialog extends DialogFragment {
private static final String TAG = "ShareUpdateDialog";
private DialogShareUpdateBinding bind;
private HomeViewModel homeViewModel;
private ShareBottomSheetViewModel shareBottomSheetViewModel;
@@ -40,19 +37,18 @@ public class ShareUpdateDialog extends DialogFragment {
@Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
homeViewModel = new ViewModelProvider(requireActivity()).get(HomeViewModel.class);
shareBottomSheetViewModel = new ViewModelProvider(requireActivity()).get(ShareBottomSheetViewModel.class);
bind = DialogShareUpdateBinding.inflate(getLayoutInflater());
AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
builder.setView(bind.getRoot())
return new MaterialAlertDialogBuilder(requireContext())
.setView(bind.getRoot())
.setTitle(R.string.share_update_dialog_title)
.setPositiveButton(R.string.share_update_dialog_positive_button, (dialog, id) -> {
})
.setNegativeButton(R.string.share_update_dialog_negative_button, (dialog, id) -> dialog.cancel());
return builder.create();
.setNegativeButton(R.string.share_update_dialog_negative_button, (dialog, id) -> dialog.cancel())
.create();
}
@Override

View File

@@ -1,6 +1,5 @@
package com.cappielloantonio.tempo.ui.dialog;
import android.app.AlertDialog;
import android.app.Dialog;
import android.content.Context;
import android.os.Bundle;
@@ -19,31 +18,28 @@ import com.cappielloantonio.tempo.util.DownloadUtil;
import com.cappielloantonio.tempo.util.MappingUtil;
import com.cappielloantonio.tempo.util.Preferences;
import com.cappielloantonio.tempo.viewmodel.StarredSyncViewModel;
import com.google.android.material.dialog.MaterialAlertDialogBuilder;
import java.util.stream.Collectors;
@OptIn(markerClass = UnstableApi.class)
public class StarredSyncDialog extends DialogFragment {
private static final String TAG = "ServerUnreachableDialog";
private DialogStarredSyncBinding bind;
private StarredSyncViewModel starredSyncViewModel;
@NonNull
@Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
bind = DialogStarredSyncBinding.inflate(getLayoutInflater());
DialogStarredSyncBinding bind = DialogStarredSyncBinding.inflate(getLayoutInflater());
starredSyncViewModel = new ViewModelProvider(requireActivity()).get(StarredSyncViewModel.class);
AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
builder.setView(bind.getRoot())
return new MaterialAlertDialogBuilder(getActivity())
.setView(bind.getRoot())
.setTitle(R.string.starred_sync_dialog_title)
.setPositiveButton(R.string.starred_sync_dialog_positive_button, null)
.setNeutralButton(R.string.starred_sync_dialog_neutral_button, null)
.setNegativeButton(R.string.starred_sync_dialog_negative_button, null);
return builder.create();
.setNegativeButton(R.string.starred_sync_dialog_negative_button, null)
.create();
}
@Override
@@ -52,14 +48,8 @@ public class StarredSyncDialog extends DialogFragment {
setButtonAction(requireContext());
}
@Override
public void onDestroyView() {
super.onDestroyView();
bind = null;
}
private void setButtonAction(Context context) {
AlertDialog dialog = ((AlertDialog) getDialog());
androidx.appcompat.app.AlertDialog dialog = (androidx.appcompat.app.AlertDialog) getDialog();
if (dialog != null) {
Button positiveButton = dialog.getButton(Dialog.BUTTON_POSITIVE);

View File

@@ -1,6 +1,5 @@
package com.cappielloantonio.tempo.ui.dialog;
import android.app.AlertDialog;
import android.app.Dialog;
import android.os.Bundle;
@@ -14,10 +13,9 @@ import com.cappielloantonio.tempo.glide.CustomGlideRequest;
import com.cappielloantonio.tempo.util.Constants;
import com.cappielloantonio.tempo.util.MusicUtil;
import com.cappielloantonio.tempo.util.Preferences;
import com.google.android.material.dialog.MaterialAlertDialogBuilder;
public class TrackInfoDialog extends DialogFragment {
private static final String TAG = "TrackInfoDialog";
private DialogTrackInfoBinding bind;
private MediaMetadata mediaMetadata;
@@ -30,12 +28,10 @@ public class TrackInfoDialog extends DialogFragment {
public Dialog onCreateDialog(Bundle savedInstanceState) {
bind = DialogTrackInfoBinding.inflate(getLayoutInflater());
AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
builder.setView(bind.getRoot())
.setPositiveButton(R.string.track_info_dialog_positive_button, (dialog, id) -> dialog.cancel());
return builder.create();
return new MaterialAlertDialogBuilder(getActivity())
.setView(bind.getRoot())
.setPositiveButton(R.string.track_info_dialog_positive_button, (dialog, id) -> dialog.cancel())
.create();
}
@Override

View File

@@ -16,17 +16,20 @@ import androidx.media3.common.util.UnstableApi;
import androidx.media3.session.MediaBrowser;
import androidx.media3.session.SessionToken;
import androidx.navigation.Navigation;
import androidx.recyclerview.widget.GridLayoutManager;
import androidx.recyclerview.widget.LinearLayoutManager;
import com.cappielloantonio.tempo.R;
import com.cappielloantonio.tempo.databinding.FragmentArtistPageBinding;
import com.cappielloantonio.tempo.glide.CustomGlideRequest;
import com.cappielloantonio.tempo.helper.recyclerview.CustomLinearSnapHelper;
import com.cappielloantonio.tempo.helper.recyclerview.GridItemDecoration;
import com.cappielloantonio.tempo.interfaces.ClickCallback;
import com.cappielloantonio.tempo.service.MediaManager;
import com.cappielloantonio.tempo.service.MediaService;
import com.cappielloantonio.tempo.ui.activity.MainActivity;
import com.cappielloantonio.tempo.ui.adapter.AlbumArtistPageOrSimilarAdapter;
import com.cappielloantonio.tempo.ui.adapter.AlbumCatalogueAdapter;
import com.cappielloantonio.tempo.ui.adapter.ArtistSimilarAdapter;
import com.cappielloantonio.tempo.ui.adapter.SongHorizontalAdapter;
import com.cappielloantonio.tempo.util.Constants;
@@ -42,6 +45,7 @@ public class ArtistPageFragment extends Fragment implements ClickCallback {
private SongHorizontalAdapter songHorizontalAdapter;
private AlbumArtistPageOrSimilarAdapter albumArtistPageOrSimilarAdapter;
private AlbumCatalogueAdapter albumCatalogueAdapter;
private ArtistSimilarAdapter artistSimilarAdapter;
private ListenableFuture<MediaBrowser> mediaBrowserListenableFuture;
@@ -59,7 +63,8 @@ public class ArtistPageFragment extends Fragment implements ClickCallback {
initArtistInfo();
initPlayButtons();
initTopSongsView();
initAlbumsView();
initHorizontalAlbumsView();
initVerticalAlbumsView();
initSimilarArtistsView();
return view;
@@ -93,6 +98,13 @@ public class ArtistPageFragment extends Fragment implements ClickCallback {
bundle.putParcelable(Constants.ARTIST_OBJECT, artistPageViewModel.getArtist());
activity.navController.navigate(R.id.action_artistPageFragment_to_songListPageFragment, bundle);
});
bind.artistPageAlbumsSwitchLayoutTextViewClickable.setOnClickListener(view -> {
boolean isHorizontalRecyclerViewVisible = bind.albumsHorizontalRecyclerView.getVisibility() == View.VISIBLE;
bind.albumsHorizontalRecyclerView.setVisibility(isHorizontalRecyclerViewVisible ? View.GONE : View.VISIBLE);
bind.albumsVerticalRecyclerView.setVisibility(isHorizontalRecyclerViewVisible ? View.VISIBLE : View.GONE);
});
}
private void initAppBar() {
@@ -107,8 +119,9 @@ public class ArtistPageFragment extends Fragment implements ClickCallback {
private void initArtistInfo() {
artistPageViewModel.getArtistInfo(artistPageViewModel.getArtist().getId()).observe(getViewLifecycleOwner(), artistInfo -> {
if(artistInfo == null) {
if (bind != null) bind.artistPageBioPlaceholder.placeholder.setVisibility(View.VISIBLE);
if (artistInfo == null) {
if (bind != null)
bind.artistPageBioPlaceholder.placeholder.setVisibility(View.VISIBLE);
if (bind != null) bind.artistPageBioSector.setVisibility(View.GONE);
} else {
String normalizedBio = MusicUtil.forceReadableString(artistInfo.getBiography());
@@ -131,7 +144,8 @@ public class ArtistPageFragment extends Fragment implements ClickCallback {
startActivity(intent);
});
if (bind != null) bind.artistPageBioPlaceholder.placeholder.setVisibility(View.GONE);
if (bind != null)
bind.artistPageBioPlaceholder.placeholder.setVisibility(View.GONE);
if (bind != null) bind.artistPageBioSector.setVisibility(View.VISIBLE);
}
});
@@ -168,34 +182,63 @@ public class ArtistPageFragment extends Fragment implements ClickCallback {
bind.mostStreamedSongRecyclerView.setAdapter(songHorizontalAdapter);
artistPageViewModel.getArtistTopSongList().observe(getViewLifecycleOwner(), songs -> {
if (songs == null) {
if (bind != null) bind.artistPageTopTracksPlaceholder.placeholder.setVisibility(View.VISIBLE);
if (bind != null)
bind.artistPageTopTracksPlaceholder.placeholder.setVisibility(View.VISIBLE);
if (bind != null) bind.artistPageTopSongsSector.setVisibility(View.GONE);
} else {
if (bind != null) bind.artistPageTopTracksPlaceholder.placeholder.setVisibility(View.GONE);
if (bind != null) bind.artistPageTopSongsSector.setVisibility(!songs.isEmpty() ? View.VISIBLE : View.GONE);
if (bind != null)
bind.artistPageTopTracksPlaceholder.placeholder.setVisibility(View.GONE);
if (bind != null)
bind.artistPageTopSongsSector.setVisibility(!songs.isEmpty() ? View.VISIBLE : View.GONE);
songHorizontalAdapter.setItems(songs);
}
});
}
private void initAlbumsView() {
bind.albumsRecyclerView.setLayoutManager(new LinearLayoutManager(requireContext(), LinearLayoutManager.HORIZONTAL, false));
private void initHorizontalAlbumsView() {
bind.albumsHorizontalRecyclerView.setLayoutManager(new LinearLayoutManager(requireContext(), LinearLayoutManager.HORIZONTAL, false));
albumArtistPageOrSimilarAdapter = new AlbumArtistPageOrSimilarAdapter(this);
bind.albumsRecyclerView.setAdapter(albumArtistPageOrSimilarAdapter);
bind.albumsHorizontalRecyclerView.setAdapter(albumArtistPageOrSimilarAdapter);
artistPageViewModel.getAlbumList().observe(getViewLifecycleOwner(), albums -> {
if (albums == null) {
if (bind != null) bind.artistPageAlbumPlaceholder.placeholder.setVisibility(View.VISIBLE);
if (bind != null)
bind.artistPageAlbumPlaceholder.placeholder.setVisibility(View.VISIBLE);
if (bind != null) bind.artistPageAlbumsSector.setVisibility(View.GONE);
} else {
if (bind != null) bind.artistPageAlbumPlaceholder.placeholder.setVisibility(View.GONE);
if (bind != null) bind.artistPageAlbumsSector.setVisibility(!albums.isEmpty() ? View.VISIBLE : View.GONE);
if (bind != null)
bind.artistPageAlbumPlaceholder.placeholder.setVisibility(View.GONE);
if (bind != null)
bind.artistPageAlbumsSector.setVisibility(!albums.isEmpty() ? View.VISIBLE : View.GONE);
albumArtistPageOrSimilarAdapter.setItems(albums);
}
});
CustomLinearSnapHelper albumSnapHelper = new CustomLinearSnapHelper();
albumSnapHelper.attachToRecyclerView(bind.albumsRecyclerView);
albumSnapHelper.attachToRecyclerView(bind.albumsHorizontalRecyclerView);
}
private void initVerticalAlbumsView() {
bind.albumsVerticalRecyclerView.setLayoutManager(new GridLayoutManager(requireContext(), 2));
bind.albumsVerticalRecyclerView.addItemDecoration(new GridItemDecoration(2, 20, false));
bind.albumsVerticalRecyclerView.setHasFixedSize(true);
albumCatalogueAdapter = new AlbumCatalogueAdapter(this);
bind.albumsVerticalRecyclerView.setAdapter(albumCatalogueAdapter);
artistPageViewModel.getAlbumList().observe(getViewLifecycleOwner(), albums -> {
if (albums == null) {
if (bind != null)
bind.artistPageAlbumPlaceholder.placeholder.setVisibility(View.VISIBLE);
if (bind != null) bind.artistPageAlbumsSector.setVisibility(View.GONE);
} else {
if (bind != null)
bind.artistPageAlbumPlaceholder.placeholder.setVisibility(View.GONE);
if (bind != null)
bind.artistPageAlbumsSector.setVisibility(!albums.isEmpty() ? View.VISIBLE : View.GONE);
albumCatalogueAdapter.setItems(albums);
}
});
}
private void initSimilarArtistsView() {
@@ -206,11 +249,14 @@ public class ArtistPageFragment extends Fragment implements ClickCallback {
bind.similarArtistsRecyclerView.setAdapter(artistSimilarAdapter);
artistPageViewModel.getArtistInfo(artistPageViewModel.getArtist().getId()).observe(getViewLifecycleOwner(), artist -> {
if (artist == null) {
if (bind != null) bind.artistPageSimilarArtistPlaceholder.placeholder.setVisibility(View.VISIBLE);
if (bind != null)
bind.artistPageSimilarArtistPlaceholder.placeholder.setVisibility(View.VISIBLE);
if (bind != null) bind.similarArtistSector.setVisibility(View.GONE);
} else {
if (bind != null) bind.artistPageSimilarArtistPlaceholder.placeholder.setVisibility(View.GONE);
if (bind != null) bind.similarArtistSector.setVisibility(!artist.getSimilarArtists().isEmpty() ? View.VISIBLE : View.GONE);
if (bind != null)
bind.artistPageSimilarArtistPlaceholder.placeholder.setVisibility(View.GONE);
if (bind != null)
bind.similarArtistSector.setVisibility(!artist.getSimilarArtists().isEmpty() ? View.VISIBLE : View.GONE);
artistSimilarAdapter.setItems(artist.getSimilarArtists());
}
});

View File

@@ -23,12 +23,14 @@ import androidx.recyclerview.widget.LinearLayoutManager;
import com.cappielloantonio.tempo.R;
import com.cappielloantonio.tempo.databinding.FragmentDirectoryBinding;
import com.cappielloantonio.tempo.interfaces.ClickCallback;
import com.cappielloantonio.tempo.interfaces.DialogClickCallback;
import com.cappielloantonio.tempo.model.Download;
import com.cappielloantonio.tempo.service.MediaManager;
import com.cappielloantonio.tempo.service.MediaService;
import com.cappielloantonio.tempo.subsonic.models.Child;
import com.cappielloantonio.tempo.ui.activity.MainActivity;
import com.cappielloantonio.tempo.ui.adapter.MusicDirectoryAdapter;
import com.cappielloantonio.tempo.ui.dialog.DownloadDirectoryDialog;
import com.cappielloantonio.tempo.util.Constants;
import com.cappielloantonio.tempo.util.DownloadUtil;
import com.cappielloantonio.tempo.util.MappingUtil;
@@ -50,6 +52,8 @@ public class DirectoryFragment extends Fragment implements ClickCallback {
private ListenableFuture<MediaBrowser> mediaBrowserListenableFuture;
private MenuItem menuItem;
@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
@@ -60,6 +64,8 @@ public class DirectoryFragment extends Fragment implements ClickCallback {
public void onCreateOptionsMenu(@NonNull Menu menu, @NonNull MenuInflater inflater) {
super.onCreateOptionsMenu(menu, inflater);
inflater.inflate(R.menu.directory_page_menu, menu);
menuItem = menu.getItem(0);
}
@Override
@@ -97,15 +103,23 @@ public class DirectoryFragment extends Fragment implements ClickCallback {
@Override
public boolean onOptionsItemSelected(@NonNull MenuItem item) {
if (item.getItemId() == R.id.action_download_directory) {
directoryViewModel.loadMusicDirectory(getArguments().getString(Constants.MUSIC_DIRECTORY_ID)).observe(getViewLifecycleOwner(), directory -> {
if (isVisible() && getActivity() != null) {
List<Child> songs = directory.getChildren().stream().filter(child -> !child.isDir()).collect(Collectors.toList());
DownloadUtil.getDownloadTracker(requireContext()).download(
MappingUtil.mapDownloads(songs),
songs.stream().map(Download::new).collect(Collectors.toList())
);
DownloadDirectoryDialog dialog = new DownloadDirectoryDialog(new DialogClickCallback() {
@Override
public void onPositiveClick() {
directoryViewModel.loadMusicDirectory(getArguments().getString(Constants.MUSIC_DIRECTORY_ID)).observe(getViewLifecycleOwner(), directory -> {
if (isVisible() && getActivity() != null) {
List<Child> songs = directory.getChildren().stream().filter(child -> !child.isDir()).collect(Collectors.toList());
DownloadUtil.getDownloadTracker(requireContext()).download(
MappingUtil.mapDownloads(songs),
songs.stream().map(Download::new).collect(Collectors.toList())
);
}
});
}
});
dialog.show(activity.getSupportFragmentManager(), null);
return true;
}
@@ -144,6 +158,14 @@ public class DirectoryFragment extends Fragment implements ClickCallback {
bind.directoryTitleLabel.setText(directory.getName());
musicDirectoryAdapter.setItems(directory.getChildren());
menuItem.setVisible(
directory.getChildren() != null && directory.getChildren()
.stream()
.filter(child -> !child.isDir())
.findFirst()
.orElse(null) != null
);
});
}
@@ -160,6 +182,11 @@ public class DirectoryFragment extends Fragment implements ClickCallback {
MediaManager.startQueue(mediaBrowserListenableFuture, bundle.getParcelableArrayList(Constants.TRACKS_OBJECT), bundle.getInt(Constants.ITEM_POSITION));
}
@Override
public void onMediaLongClick(Bundle bundle) {
Navigation.findNavController(requireView()).navigate(R.id.songBottomSheetDialog, bundle);
}
@Override
public void onMusicDirectoryClick(Bundle bundle) {
Navigation.findNavController(requireView()).navigate(R.id.directoryFragment, bundle);

View File

@@ -706,7 +706,9 @@ public class HomeTabMusicFragment extends Fragment implements ClickCallback {
private void refreshSharesView() {
final Handler handler = new Handler();
final Runnable runnable = () -> {
if (Preferences.isSharingEnabled()) homeViewModel.refreshShares(getViewLifecycleOwner());
if (getView() != null && bind != null && Preferences.isSharingEnabled()) {
homeViewModel.refreshShares(getViewLifecycleOwner());
}
};
handler.postDelayed(runnable, 100);
}

View File

@@ -254,7 +254,12 @@ public class LibraryFragment extends Fragment implements ClickCallback {
private void refreshPlaylistView() {
final Handler handler = new Handler();
final Runnable runnable = () -> libraryViewModel.refreshPlaylistSample(getViewLifecycleOwner());
final Runnable runnable = () -> {
if (getView() != null && bind != null && libraryViewModel != null)
libraryViewModel.refreshPlaylistSample(getViewLifecycleOwner());
};
handler.postDelayed(runnable, 100);
}

View File

@@ -37,6 +37,7 @@ import com.google.android.material.elevation.SurfaceColors;
import com.google.common.util.concurrent.ListenableFuture;
import com.google.common.util.concurrent.MoreExecutors;
import java.util.Objects;
import java.util.stream.IntStream;
@OptIn(markerClass = UnstableApi.class)
@@ -156,6 +157,7 @@ public class PlayerBottomSheetFragment extends Fragment {
if (mediaMetadata.extras != null) {
playerBottomSheetViewModel.setLiveMedia(getViewLifecycleOwner(), mediaMetadata.extras.getString("type"), mediaMetadata.extras.getString("id"));
playerBottomSheetViewModel.setLiveArtist(getViewLifecycleOwner(), mediaMetadata.extras.getString("type"), mediaMetadata.extras.getString("artistId"));
playerBottomSheetViewModel.setLiveDescription(mediaMetadata.extras.getString("description", null));
bind.playerHeaderLayout.playerHeaderMediaTitleLabel.setText(MusicUtil.getReadableString(mediaMetadata.extras.getString("title")));
bind.playerHeaderLayout.playerHeaderMediaArtistLabel.setText(MusicUtil.getReadableString(mediaMetadata.extras.getString("artist")));
@@ -164,6 +166,9 @@ public class PlayerBottomSheetFragment extends Fragment {
.from(requireContext(), mediaMetadata.extras.getString("coverArtId"), CustomGlideRequest.ResourceType.Song)
.build()
.into(bind.playerHeaderLayout.playerHeaderMediaCoverImage);
bind.playerHeaderLayout.playerHeaderMediaTitleLabel.setVisibility(mediaMetadata.extras.getString("title") != null && !Objects.equals(mediaMetadata.extras.getString("title"), "") ? View.VISIBLE : View.GONE);
bind.playerHeaderLayout.playerHeaderMediaArtistLabel.setVisibility(mediaMetadata.extras.getString("artist") != null && !Objects.equals(mediaMetadata.extras.getString("artist"), "") ? View.VISIBLE : View.GONE);
}
}

View File

@@ -40,6 +40,8 @@ import com.google.android.material.elevation.SurfaceColors;
import com.google.common.util.concurrent.ListenableFuture;
import com.google.common.util.concurrent.MoreExecutors;
import java.util.Objects;
@UnstableApi
public class PlayerControllerFragment extends Fragment {
private static final String TAG = "PlayerCoverFragment";
@@ -164,6 +166,9 @@ public class PlayerControllerFragment extends Fragment {
playerMediaTitleLabel.setSelected(true);
playerArtistNameLabel.setSelected(true);
playerMediaTitleLabel.setVisibility(mediaMetadata.title != null && !Objects.equals(mediaMetadata.title, "") ? View.VISIBLE : View.GONE);
playerArtistNameLabel.setVisibility(mediaMetadata.artist != null && !Objects.equals(mediaMetadata.artist, "") ? View.VISIBLE : View.GONE);
}
private void setMediaInfo(MediaMetadata mediaMetadata) {
@@ -181,6 +186,14 @@ public class PlayerControllerFragment extends Fragment {
}
}
boolean isTranscodingExtension = !MusicUtil.getTranscodingFormatPreference().equals("raw");
boolean isTranscodingBitrate = !MusicUtil.getBitratePreference().equals("0");
if (isTranscodingExtension || isTranscodingBitrate) {
playerMediaExtension.setText("Transcoding");
playerMediaBitrate.setText("requested");
}
playerTrackInfo.setOnClickListener(view -> {
TrackInfoDialog dialog = new TrackInfoDialog(mediaMetadata);
dialog.show(activity.getSupportFragmentManager(), null);
@@ -201,6 +214,7 @@ public class PlayerControllerFragment extends Fragment {
bind.getRoot().setRepeatToggleModes(RepeatModeUtil.REPEAT_TOGGLE_MODE_NONE);
bind.getRoot().findViewById(R.id.player_playback_speed_button).setVisibility(View.VISIBLE);
bind.getRoot().findViewById(R.id.player_skip_silence_toggle_button).setVisibility(View.VISIBLE);
bind.getRoot().findViewById(R.id.button_favorite).setVisibility(View.GONE);
setPlaybackParameters(mediaBrowser);
break;
case Constants.MEDIA_TYPE_RADIO:
@@ -212,6 +226,7 @@ public class PlayerControllerFragment extends Fragment {
bind.getRoot().setRepeatToggleModes(RepeatModeUtil.REPEAT_TOGGLE_MODE_NONE);
bind.getRoot().findViewById(R.id.player_playback_speed_button).setVisibility(View.GONE);
bind.getRoot().findViewById(R.id.player_skip_silence_toggle_button).setVisibility(View.GONE);
bind.getRoot().findViewById(R.id.button_favorite).setVisibility(View.GONE);
setPlaybackParameters(mediaBrowser);
break;
case Constants.MEDIA_TYPE_MUSIC:
@@ -224,6 +239,7 @@ public class PlayerControllerFragment extends Fragment {
bind.getRoot().setRepeatToggleModes(RepeatModeUtil.REPEAT_TOGGLE_MODE_ALL | RepeatModeUtil.REPEAT_TOGGLE_MODE_ONE);
bind.getRoot().findViewById(R.id.player_playback_speed_button).setVisibility(View.GONE);
bind.getRoot().findViewById(R.id.player_skip_silence_toggle_button).setVisibility(View.GONE);
bind.getRoot().findViewById(R.id.button_favorite).setVisibility(View.VISIBLE);
resetPlaybackParameters(mediaBrowser);
break;
}

View File

@@ -44,18 +44,25 @@ public class PlayerLyricsFragment extends Fragment {
private void initLyrics() {
playerBottomSheetViewModel.getLiveLyrics().observe(getViewLifecycleOwner(), lyrics -> {
if (bind != null) {
if (lyrics == null || lyrics.trim().equals("")) {
bind.nowPlayingSongLyricsTextView.setVisibility(View.GONE);
bind.emptyDescriptionImageView.setVisibility(View.VISIBLE);
bind.titleEmptyDescriptionLabel.setVisibility(View.VISIBLE);
} else {
bind.nowPlayingSongLyricsTextView.setText(MusicUtil.getReadableLyrics(lyrics));
bind.nowPlayingSongLyricsTextView.setVisibility(View.VISIBLE);
bind.emptyDescriptionImageView.setVisibility(View.GONE);
bind.titleEmptyDescriptionLabel.setVisibility(View.GONE);
playerBottomSheetViewModel.getLiveDescription().observe(getViewLifecycleOwner(), description -> {
if (bind != null) {
if (lyrics != null && !lyrics.trim().equals("")) {
bind.nowPlayingSongLyricsTextView.setText(MusicUtil.getReadableLyrics(lyrics));
bind.nowPlayingSongLyricsTextView.setVisibility(View.VISIBLE);
bind.emptyDescriptionImageView.setVisibility(View.GONE);
bind.titleEmptyDescriptionLabel.setVisibility(View.GONE);
} else if (description != null && !description.trim().equals("")) {
bind.nowPlayingSongLyricsTextView.setText(MusicUtil.getReadableLyrics(description));
bind.nowPlayingSongLyricsTextView.setVisibility(View.VISIBLE);
bind.emptyDescriptionImageView.setVisibility(View.GONE);
bind.titleEmptyDescriptionLabel.setVisibility(View.GONE);
} else {
bind.nowPlayingSongLyricsTextView.setVisibility(View.GONE);
bind.emptyDescriptionImageView.setVisibility(View.VISIBLE);
bind.titleEmptyDescriptionLabel.setVisibility(View.VISIBLE);
}
}
}
});
});
}
}

View File

@@ -93,6 +93,7 @@ public class PlayerQueueFragment extends Fragment implements ClickCallback {
try {
MediaBrowser mediaBrowser = mediaBrowserListenableFuture.get();
initShuffleButton(mediaBrowser);
initCleanButton(mediaBrowser);
} catch (Exception exception) {
exception.printStackTrace();
}
@@ -197,6 +198,16 @@ public class PlayerQueueFragment extends Fragment implements ClickCallback {
});
}
private void initCleanButton(MediaBrowser mediaBrowser) {
bind.playerCleanQueueButton.setOnClickListener(view -> {
int startPosition = mediaBrowser.getCurrentMediaItemIndex() + 1;
int endPosition = playerSongQueueAdapter.getItems().size();
MediaManager.removeRange(mediaBrowserListenableFuture, playerSongQueueAdapter.getItems(), startPosition, endPosition);
bind.playerQueueRecyclerView.getAdapter().notifyItemRangeRemoved(startPosition, endPosition);
});
}
private void updateNowPlayingItem() {
playerSongQueueAdapter.notifyDataSetChanged();
}

View File

@@ -39,6 +39,7 @@ import com.cappielloantonio.tempo.util.Preferences;
import com.cappielloantonio.tempo.viewmodel.AlbumBottomSheetViewModel;
import com.cappielloantonio.tempo.viewmodel.HomeViewModel;
import com.google.android.material.bottomsheet.BottomSheetDialogFragment;
import com.google.android.material.snackbar.Snackbar;
import com.google.common.util.concurrent.ListenableFuture;
import java.util.ArrayList;
@@ -198,6 +199,9 @@ public class AlbumBottomSheetDialog extends BottomSheetDialogFragment implements
clipboardManager.setPrimaryClip(clipData);
refreshShares();
dismissBottomSheet();
} else {
Toast.makeText(requireContext(), getString(R.string.share_unsupported_error), Toast.LENGTH_SHORT).show();
dismissBottomSheet();
}
}));

View File

@@ -196,6 +196,8 @@ public class SongBottomSheetDialog extends BottomSheetDialogFragment implements
dismissBottomSheet();
}));
goToAlbum.setVisibility(songBottomSheetViewModel.getSong().getAlbumId() != null ? View.VISIBLE : View.GONE);
TextView goToArtist = view.findViewById(R.id.go_to_artist_text_view);
goToArtist.setOnClickListener(v -> songBottomSheetViewModel.getArtist().observe(getViewLifecycleOwner(), artist -> {
if (artist != null) {
@@ -208,6 +210,8 @@ public class SongBottomSheetDialog extends BottomSheetDialogFragment implements
dismissBottomSheet();
}));
goToArtist.setVisibility(songBottomSheetViewModel.getSong().getArtistId() != null ? View.VISIBLE : View.GONE);
TextView share = view.findViewById(R.id.share_text_view);
share.setOnClickListener(v -> songBottomSheetViewModel.shareTrack().observe(getViewLifecycleOwner(), sharedTrack -> {
if (sharedTrack != null) {
@@ -216,6 +220,9 @@ public class SongBottomSheetDialog extends BottomSheetDialogFragment implements
clipboardManager.setPrimaryClip(clipData);
refreshShares();
dismissBottomSheet();
} else {
Toast.makeText(requireContext(), getString(R.string.share_unsupported_error), Toast.LENGTH_SHORT).show();
dismissBottomSheet();
}
}));

View File

@@ -64,7 +64,7 @@ public class MappingUtil {
bundle.putLong("starred", media.getStarred() != null ? media.getStarred().getTime() : 0);
bundle.putString("albumId", media.getAlbumId());
bundle.putString("artistId", media.getArtistId());
bundle.putString("type", media.getType());
bundle.putString("type", Constants.MEDIA_TYPE_MUSIC);
bundle.putLong("bookmarkPosition", media.getBookmarkPosition() != null ? media.getBookmarkPosition() : 0);
bundle.putInt("originalWidth", media.getOriginalWidth() != null ? media.getOriginalWidth() : 0);
bundle.putInt("originalHeight", media.getOriginalHeight() != null ? media.getOriginalHeight() : 0);
@@ -169,31 +169,18 @@ public class MappingUtil {
bundle.putString("title", podcastEpisode.getTitle());
bundle.putString("album", podcastEpisode.getAlbum());
bundle.putString("artist", podcastEpisode.getArtist());
bundle.putInt("track", podcastEpisode.getTrack() != null ? podcastEpisode.getTrack() : 0);
bundle.putInt("year", podcastEpisode.getYear() != null ? podcastEpisode.getYear() : 0);
bundle.putString("genre", podcastEpisode.getGenre());
bundle.putString("coverArtId", podcastEpisode.getCoverArtId());
bundle.putLong("size", podcastEpisode.getSize() != null ? podcastEpisode.getSize() : 0);
bundle.putString("contentType", podcastEpisode.getContentType());
bundle.putString("suffix", podcastEpisode.getSuffix());
bundle.putString("transcodedContentType", podcastEpisode.getTranscodedContentType());
bundle.putString("transcodedSuffix", podcastEpisode.getTranscodedSuffix());
bundle.putInt("duration", podcastEpisode.getDuration() != null ? podcastEpisode.getDuration() : 0);
bundle.putInt("bitrate", podcastEpisode.getBitrate() != null ? podcastEpisode.getBitrate() : 0);
bundle.putString("path", podcastEpisode.getPath());
bundle.putBoolean("isVideo", podcastEpisode.isVideo());
bundle.putInt("userRating", podcastEpisode.getUserRating() != null ? podcastEpisode.getUserRating() : 0);
bundle.putDouble("averageRating", podcastEpisode.getAverageRating() != null ? podcastEpisode.getAverageRating() : 0);
bundle.putLong("playCount", podcastEpisode.getPlayCount() != null ? podcastEpisode.getPlayCount() : 0);
bundle.putInt("discNumber", podcastEpisode.getDiscNumber() != null ? podcastEpisode.getDiscNumber() : 0);
bundle.putLong("created", podcastEpisode.getCreated() != null ? podcastEpisode.getCreated().getTime() : 0);
bundle.putLong("starred", podcastEpisode.getStarred() != null ? podcastEpisode.getStarred().getTime() : 0);
bundle.putString("albumId", podcastEpisode.getAlbumId());
bundle.putString("artistId", podcastEpisode.getArtistId());
bundle.putString("type", podcastEpisode.getType());
bundle.putLong("bookmarkPosition", podcastEpisode.getBookmarkPosition() != null ? podcastEpisode.getBookmarkPosition() : 0);
bundle.putInt("originalWidth", podcastEpisode.getOriginalWidth() != null ? podcastEpisode.getOriginalWidth() : 0);
bundle.putInt("originalHeight", podcastEpisode.getOriginalHeight() != null ? podcastEpisode.getOriginalHeight() : 0);
bundle.putString("description", podcastEpisode.getDescription());
bundle.putString("type", Constants.MEDIA_TYPE_PODCAST);
bundle.putString("uri", uri.toString());
MediaItem item = new MediaItem.Builder()
@@ -201,8 +188,6 @@ public class MappingUtil {
.setMediaMetadata(
new MediaMetadata.Builder()
.setTitle(MusicUtil.getReadableString(podcastEpisode.getTitle()))
.setTrackNumber(podcastEpisode.getTrack() != null ? podcastEpisode.getTrack() : 0)
.setDiscNumber(podcastEpisode.getDiscNumber() != null ? podcastEpisode.getDiscNumber() : 0)
.setReleaseYear(podcastEpisode.getYear() != null ? podcastEpisode.getYear() : 0)
.setAlbumTitle(MusicUtil.getReadableString(podcastEpisode.getAlbum()))
.setArtist(MusicUtil.getReadableString(podcastEpisode.getArtist()))

View File

@@ -40,7 +40,9 @@ object Preferences {
private const val MAX_BITRATE_DOWNLOAD = "max_bitrate_download"
private const val AUDIO_TRANSCODE_FORMAT_DOWNLOAD = "audio_transcode_format_download"
private const val SHARE = "share"
private const val SCROBBLING = "scrobbling"
private const val ESTIMATE_CONTENT_LENGTH = "estimate_content_length"
private const val BUFFERING_STRATEGY = "buffering_strategy"
@JvmStatic
fun getServer(): String? {
@@ -321,8 +323,19 @@ object Preferences {
return App.getInstance().preferences.getBoolean(SHARE, false)
}
@JvmStatic
fun isScrobblingEnabled(): Boolean {
return App.getInstance().preferences.getBoolean(SCROBBLING, true)
}
@JvmStatic
fun askForEstimateContentLength(): Boolean {
return App.getInstance().preferences.getBoolean(ESTIMATE_CONTENT_LENGTH, false)
}
@JvmStatic
fun getBufferingStrategy(): Double {
return App.getInstance().preferences.getString(BUFFERING_STRATEGY, "1")!!.toDouble()
}
}

View File

@@ -61,9 +61,8 @@ public class AlbumCatalogueViewModel extends AndroidViewModel {
.enqueue(new Callback<ApiResponse>() {
@Override
public void onResponse(@NonNull Call<ApiResponse> call, @NonNull retrofit2.Response<ApiResponse> response) {
if (response.isSuccessful() && response.body() != null && response.body().getSubsonicResponse().getAlbumList2() != null) {
List<AlbumID3> albumList = new ArrayList<>();
albumList.addAll(response.body().getSubsonicResponse().getAlbumList2().getAlbums());
if (response.isSuccessful() && response.body() != null && response.body().getSubsonicResponse().getAlbumList2() != null && response.body().getSubsonicResponse().getAlbumList2().getAlbums() != null) {
List<AlbumID3> albumList = new ArrayList<>(response.body().getSubsonicResponse().getAlbumList2().getAlbums());
callback.onLoadMedia(albumList);
}
}

View File

@@ -42,6 +42,7 @@ public class PlayerBottomSheetViewModel extends AndroidViewModel {
private final FavoriteRepository favoriteRepository;
private final MutableLiveData<String> lyricsLiveData = new MutableLiveData<>(null);
private final MutableLiveData<String> descriptionLiveData = new MutableLiveData<>(null);
private final MutableLiveData<Child> liveMedia = new MutableLiveData<>(null);
private final MutableLiveData<ArtistID3> liveArtist = new MutableLiveData<>(null);
@@ -137,6 +138,7 @@ public class PlayerBottomSheetViewModel extends AndroidViewModel {
switch (mediaType) {
case Constants.MEDIA_TYPE_MUSIC:
songRepository.getSong(mediaId).observe(owner, liveMedia::postValue);
descriptionLiveData.postValue(null);
break;
case Constants.MEDIA_TYPE_PODCAST:
liveMedia.postValue(null);
@@ -162,6 +164,14 @@ public class PlayerBottomSheetViewModel extends AndroidViewModel {
}
}
public void setLiveDescription(String description) {
descriptionLiveData.postValue(description);
}
public LiveData<String> getLiveDescription() {
return descriptionLiveData;
}
public LiveData<List<Child>> getMediaInstantMix(LifecycleOwner owner, Child media) {
instantMix.setValue(Collections.emptyList());
@@ -186,8 +196,4 @@ public class PlayerBottomSheetViewModel extends AndroidViewModel {
return false;
}
public void emptyPlayQueue() {
queueRepository.savePlayQueue(null, null, 0);
}
}

View File

@@ -3,6 +3,7 @@
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="?attr/colorSurface"
android:orientation="vertical">
<androidx.coordinatorlayout.widget.CoordinatorLayout
@@ -31,9 +32,9 @@
android:id="@+id/bottom_navigation"
android:layout_width="match_parent"
android:layout_height="80dp"
android:layout_gravity="bottom"
android:paddingStart="24dp"
android:paddingEnd="24dp"
android:layout_gravity="bottom"
android:visibility="gone"
app:menu="@menu/bottom_nav_menu" />
@@ -48,4 +49,4 @@
android:text="@string/activity_info_offline_mode"
android:textSize="6sp"
android:visibility="gone" />
</LinearLayout>
</LinearLayout>

View File

@@ -0,0 +1,15 @@
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginStart="24dp"
android:layout_marginTop="12dp"
android:layout_marginEnd="24dp"
android:layout_marginBottom="4dp"
android:text="@string/download_directory_dialog_summary" />
</LinearLayout>

View File

@@ -204,17 +204,31 @@
android:layout_height="wrap_content"
android:orientation="vertical">
<TextView
style="@style/TitleLarge"
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingStart="16dp"
android:paddingTop="8dp"
android:paddingEnd="20dp"
android:text="@string/artist_page_title_album_section" />
android:orientation="horizontal">
<TextView
style="@style/TitleLarge"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:paddingStart="16dp"
android:paddingEnd="8dp"
android:text="@string/artist_page_title_album_section" />
<TextView
android:id="@+id/artist_page_albums_switch_layout_text_view_clickable"
style="@style/TitleMedium"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:paddingEnd="16dp"
android:text="@string/artist_page_switch_layout_button" />
</LinearLayout>
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/albums_recycler_view"
android:id="@+id/albums_horizontal_recycler_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginTop="8dp"
@@ -223,7 +237,21 @@
android:paddingStart="16dp"
android:paddingTop="8dp"
android:paddingEnd="8dp"
android:paddingBottom="8dp" />
android:paddingBottom="8dp"
android:visibility="visible"/>
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/albums_vertical_recycler_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginTop="8dp"
android:layout_marginBottom="8dp"
android:clipToPadding="false"
android:paddingStart="16dp"
android:paddingTop="8dp"
android:paddingEnd="16dp"
android:paddingBottom="8dp"
android:visibility="gone"/>
</LinearLayout>
<include

View File

@@ -82,7 +82,7 @@
android:layout_height="wrap_content"
android:layout_marginStart="24dp"
android:layout_marginTop="24dp"
android:layout_marginEnd="12dp"
android:layout_marginEnd="24dp"
android:ellipsize="marquee"
android:singleLine="true"
android:text="@string/label_placeholder"
@@ -90,6 +90,20 @@
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/guideline" />
<TextView
android:id="@+id/player_artist_name_label"
style="@style/TitleMedium"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="24dp"
android:layout_marginEnd="24dp"
android:ellipsize="marquee"
android:singleLine="true"
android:text="@string/label_placeholder"
app:layout_constraintEnd_toStartOf="@+id/button_favorite"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/player_media_title_label" />
<ToggleButton
android:id="@+id/button_favorite"
android:layout_width="26dp"
@@ -104,20 +118,6 @@
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="@+id/player_media_title_label" />
<TextView
android:id="@+id/player_artist_name_label"
style="@style/TitleMedium"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="24dp"
android:layout_marginEnd="12dp"
android:ellipsize="marquee"
android:singleLine="true"
android:text="@string/label_placeholder"
app:layout_constraintEnd_toStartOf="@+id/button_favorite"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/player_media_title_label" />
<TextView
android:id="@+id/exo_position"
android:layout_width="wrap_content"
@@ -136,7 +136,7 @@
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="16dp"
android:layout_marginTop="12dp"
android:layout_marginTop="20dp"
android:layout_marginEnd="16dp"
app:bar_height="2dp"
app:buffered_color="?attr/colorOnSecondaryContainer"

View File

@@ -1,6 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.coordinatorlayout.widget.CoordinatorLayout
xmlns:android="http://schemas.android.com/apk/res/android"
<androidx.coordinatorlayout.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent">
@@ -10,14 +9,34 @@
android:layout_width="match_parent"
android:layout_height="match_parent">
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/player_queue_recycler_view"
<androidx.core.widget.NestedScrollView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:clipToPadding="false"
android:orientation="vertical"
android:paddingTop="8dp"
android:paddingBottom="@dimen/global_padding_bottom" />
android:layout_height="match_parent">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:paddingTop="8dp"
android:paddingBottom="@dimen/global_padding_bottom">
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/player_queue_recycler_view"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical" />
<TextView
android:id="@+id/player_clean_queue_button"
style="@style/TitleMedium"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:layout_marginTop="24dp"
android:text="@string/player_queue_clean_all_button"/>
</LinearLayout>
</androidx.core.widget.NestedScrollView>
</com.cappielloantonio.tempo.helper.recyclerview.NestedScrollableHost>
<com.google.android.material.floatingactionbutton.FloatingActionButton
@@ -27,6 +46,6 @@
android:layout_gravity="bottom|end"
android:layout_margin="16dp"
app:layout_behavior="com.google.android.material.behavior.HideBottomViewOnScrollBehavior"
app:srcCompat="@drawable/ic_shuffle"/>
app:srcCompat="@drawable/ic_shuffle" />
</androidx.coordinatorlayout.widget.CoordinatorLayout>

View File

@@ -21,14 +21,15 @@
style="@style/LabelMedium"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginTop="10dp"
android:ellipsize="end"
android:maxLines="1"
android:paddingStart="8dp"
android:paddingEnd="8dp"
app:layout_constraintVertical_chainStyle="packed"
app:layout_constraintEnd_toStartOf="@+id/placeholder_left_view"
app:layout_constraintStart_toEndOf="@+id/player_header_media_cover_image"
app:layout_constraintTop_toTopOf="parent" />
app:layout_constraintTop_toTopOf="@+id/player_header_media_cover_image"
app:layout_constraintBottom_toTopOf="@+id/player_header_media_artist_label"/>
<TextView
android:id="@+id/player_header_media_artist_label"
@@ -41,7 +42,8 @@
android:paddingEnd="8dp"
app:layout_constraintEnd_toStartOf="@+id/placeholder_left_view"
app:layout_constraintStart_toEndOf="@+id/player_header_media_cover_image"
app:layout_constraintTop_toBottomOf="@+id/player_header_media_title_label" />
app:layout_constraintTop_toBottomOf="@+id/player_header_media_title_label"
app:layout_constraintBottom_toBottomOf="@+id/player_header_media_cover_image"/>
<View
android:id="@+id/placeholder_left_view"

View File

@@ -5,5 +5,6 @@
android:id="@+id/action_download_directory"
android:icon="@drawable/ic_file_download"
android:title="@string/menu_download_all_button"
android:visible="false"
app:showAsAction="never" />
</menu>

View File

@@ -1,11 +1,8 @@
<resources>
<string name="activity_battery_optimizations_summary">Bitte deaktiviere die Batterieoptimierung, damit die Medienwiedergabe bei ausgeschaltetem Bildschirm richtig funktioniert.</string>
<string name="activity_battery_optimizations_conclusion">Bei Problemen besuche https://dontkillmyapp.com. Dort findest Du detaillierte Anweisungen wie Du Energiesparfunktionen, welche die App-Performance beeinflussen können, deaktivieren kannst.</string>
<string name="activity_battery_optimizations_summary">Bitte deaktiviere die Batterieoptimierung, damit die Medienwiedergabe bei ausgeschaltetem Bildschirm richtig funktioniert.</string>
<string name="activity_battery_optimizations_title">Batterie Optimierung</string>
<string name="activity_info_offline_mode">Offlinebetrieb</string>
<string name="battery_optimization_negative_button">Ignorieren</string>
<string name="battery_optimization_positive_button">Ausschalten</string>
<string name="battery_optimization_neutral_button">Nicht wieder fragen</string>
<string name="album_bottom_sheet_add_to_queue">Zur Warteschlange hinzufügen</string>
<string name="album_bottom_sheet_download_all">Alle herunterladen</string>
<string name="album_bottom_sheet_go_to_artist">Gehe zu Künstler</string>
@@ -27,6 +24,7 @@
<string name="album_page_play_button">Wiedergabe</string>
<string name="album_page_shuffle_button">Zufällige Wiedergabe</string>
<string name="app_name">Tempo</string>
<string name="artist_adapter_radio_station_starting">Suche…</string>
<string name="artist_bottom_sheet_instant_mix">Instant mix</string>
<string name="artist_bottom_sheet_shuffle">Mischen</string>
<string name="artist_catalogue_title">Künstler</string>
@@ -44,25 +42,34 @@
<string name="artist_page_title_biography_section">Biographie</string>
<string name="artist_page_title_most_streamed_song_section">Oft gestreamte Tracks</string>
<string name="artist_page_title_most_streamed_song_see_all_button">Alles</string>
<string name="battery_optimization_negative_button">Ignorieren</string>
<string name="battery_optimization_neutral_button">Nicht wieder fragen</string>
<string name="battery_optimization_positive_button">Ausschalten</string>
<string name="connection_alert_dialog_negative_button">Abbrechen</string>
<string name="connection_alert_dialog_neutral_button">Enable data saver</string>
<string name="connection_alert_dialog_positive_button">OK</string>
<string name="connection_alert_dialog_title">Wi-Fi ist nicht verbuden</string>
<string name="connection_alert_dialog_summary">Der Zugriff auf den Subsonic server ohne Wi-Fi Verbindung ist deaktiviert. Du kannst das in den App-Einstellungen ändern.</string>
<string name="connection_alert_dialog_title">Wi-Fi ist nicht verbuden</string>
<string name="delete_download_storage_dialog_negative_button">Abbrechen</string>
<string name="delete_download_storage_dialog_positive_button">Weiter</string>
<string name="delete_download_storage_dialog_summary">Wenn Du weitermachst werden alle zuvor heruntergeladenen Inhalte gelöscht.</string>
<string name="delete_download_storage_dialog_title">Heruntergeladene Inhalte löschen</string>
<string name="description_empty_title">Keine Beschreibung verfügbar</string>
<string name="download_info_empty_subtitle">Wenn Du einen Track heruntergeladen hast findest Du ihn hier</string>
<string name="download_info_empty_title">Bisher keine Downloads!</string>
<string name="download_item_multiple_subtitle_formatter">%1$s • %2$s items</string>
<string name="download_item_single_subtitle_formatter">%1$s items</string>
<string name="download_title_section">Downloads</string>
<string name="download_storage_internal_dialog_negative_button">Intern</string>
<string name="download_storage_external_dialog_positive_button">Extern</string>
<string name="download_storage_dialog_summary">Das Ändern des Speicherorts löscht alle Inhalte im zuvor gewählten Speicherort.</string>
<string name="download_storage_dialog_sub_summary">Neustart der Anwendung ist nötig.</string>
<string name="download_storage_dialog_summary">Das Ändern des Speicherorts löscht alle Inhalte im zuvor gewählten Speicherort.</string>
<string name="download_storage_dialog_title">Wähle den Speicherort aus</string>
<string name="download_storage_external_dialog_positive_button">Extern</string>
<string name="download_storage_internal_dialog_negative_button">Intern</string>
<string name="download_title_section">Downloads</string>
<string name="downloaded_bottom_sheet_add_to_queue">Zur Warteschlange hinzufügen</string>
<string name="downloaded_bottom_sheet_play_next">Nächsten Titel spielen</string>
<string name="downloaded_bottom_sheet_remove">Entfernen</string>
<string name="downloaded_bottom_sheet_remove_all">Alle entfernen</string>
<string name="downloaded_bottom_sheet_shuffle">Mischen</string>
<string name="empty_string" />
<string name="error_required">Benötigt</string>
<string name="error_server_prefix">http or https prefix benötigt</string>
@@ -72,23 +79,32 @@
<string name="filter_title_expanded">Genres filtern</string>
<string name="genre_catalogue_title">Genre Übersicht</string>
<string name="genre_catalogue_title_expanded">Genres durchsuchen</string>
<string name="home_subtitle_best_of">Top Tracks Deiner Lieblingskünstler</string>
<string name="home_subtitle_made_for_you">Ein Mix von einem deiner Lieblingslieder erstellen</string>
<string name="home_subtitle_new_internet_radio_station">Radio hinzufügen</string>
<string name="home_subtitle_new_podcast_channel">Podcast Kanal hinzufügen</string>
<string name="home_subtitle_made_for_you">Ein Mix von einem deiner Lieblingslieder erstellen</string>
<string name="home_sync_starred_title">Einige Lieblingslieder müssen synchronisiert werden</string>
<string name="home_sync_starred_subtitle">Das Herunterladen dieser Tracks kann erheblichen Datenverbrauch verursachen</string>
<string name="home_sync_starred_cancel">Abbrechen</string>
<string name="home_sync_starred_download">Download</string>
<string name="home_sync_starred_subtitle">Das Herunterladen dieser Tracks kann erheblichen Datenverbrauch verursachen</string>
<string name="home_sync_starred_title">Einige Lieblingslieder müssen synchronisiert werden</string>
<string name="home_title_best_of">Best Of</string>
<string name="home_title_discovery">Entdeckungsreise</string>
<string name="home_title_discovery_shuffle_all_button">Alle mischen</string>
<string name="home_title_flashback">Flashback</string>
<string name="home_title_internet_radio_station">Internet Radios</string>
<string name="home_title_last_played">Zuletzt gespielt</string>
<string name="home_title_last_played_see_all_button">Alle zeigen</string>
<string name="home_title_last_week">Letzte Woche</string>
<string name="home_title_made_for_you">Wie für Dich gemacht</string>
<string name="home_title_most_played">Oft gespielt</string>
<string name="home_title_most_played_see_all_button">Alle zeigen</string>
<string name="home_title_discovery">Entdeckungsreise</string>
<string name="home_title_new_releases">Neue Releases</string>
<string name="home_title_newest_podcasts">Neueste Podcasts</string>
<string name="home_title_podcast_channels">Kanäle</string>
<string name="home_title_podcast_channels_see_all_button">Alle zeigen</string>
<string name="home_title_radio_station">Radio Stationen</string>
<string name="home_title_recently_added">Kürzlich hinzugefügt</string>
<string name="home_title_recently_added_see_all_button">Alle zeigen</string>
<string name="home_title_discovery_shuffle_all_button">Alle mischen</string>
<string name="home_title_shares">Shares</string>
<string name="home_title_starred_albums">★ Lieblingsalben</string>
<string name="home_title_starred_albums_see_all_button">Alle zeigen</string>
@@ -96,15 +112,14 @@
<string name="home_title_starred_artists_see_all_button">Alle zeigen</string>
<string name="home_title_starred_tracks">★ Lieblingslieder</string>
<string name="home_title_starred_tracks_see_all_button">Alle zeigen</string>
<string name="home_title_internet_radio_station">Internet Radios</string>
<string name="home_title_podcast_channels_see_all_button">Alle zeigen</string>
<string name="library_title_music_folder">Sammlung</string>
<string name="home_title_top_songs">Deine Top Songs</string>
<string name="library_title_album">Alben</string>
<string name="library_title_album_see_all_button">Alle zeigen</string>
<string name="library_title_artist">Künstler</string>
<string name="library_title_artist_see_all_button">Alle zeigen</string>
<string name="library_title_genre">Genres</string>
<string name="library_title_genre_see_all_button">Alle zeigen</string>
<string name="library_title_music_folder">Sammlung</string>
<string name="library_title_playlist">Playlisten</string>
<string name="library_title_playlist_see_all_button">Alle zeigen</string>
<string name="login_empty">Kein Server hinzugefügt</string>
@@ -114,10 +129,21 @@
<string name="menu_add_button">Hinzufügen</string>
<string name="menu_download_all_button">Alle Herunterladen</string>
<string name="menu_download_label">Downloads</string>
<string name="menu_filter_all">Alle</string>
<string name="menu_filter_download">Heruntergeladen</string>
<string name="menu_group_by_album">Album</string>
<string name="menu_group_by_artist">Künstler</string>
<string name="menu_group_by_genre">Genre</string>
<string name="menu_group_by_track">Track</string>
<string name="menu_group_by_year">Jahr</string>
<string name="menu_home_label">Start</string>
<string name="menu_library_label">Sammlung</string>
<string name="menu_search_button">Suche</string>
<string name="menu_settings_button">Einstellungen</string>
<string name="menu_sort_artist">Künstler</string>
<string name="menu_sort_name">Name</string>
<string name="menu_sort_random">Zufall</string>
<string name="menu_sort_year">Jahr</string>
<string name="player_playback_speed">%1$.2fx</string>
<string name="player_server_priority">Server Priorität</string>
<string name="playlist_catalogue_title">Playlisten</string>
@@ -136,28 +162,34 @@
<string name="playlist_page_play_button">Wiedergabe</string>
<string name="playlist_page_shuffle_button">Shuffle</string>
<string name="playlist_song_count">Playliste • %1$d Tracks</string>
<string name="podcast_channel_catalogue_title_expanded">Kanäle durchsuchen</string>
<string name="podcast_bottom_sheet_add_to_queue">Zur Warteschlange hinzufügen</string>
<string name="podcast_bottom_sheet_delete">Löschen</string>
<string name="podcast_bottom_sheet_download">Download</string>
<string name="podcast_bottom_sheet_go_to_channel">Zum Kanal gehen</string>
<string name="podcast_bottom_sheet_play_next">Nächsten Titel spielen</string>
<string name="podcast_bottom_sheet_remove">Entfernen</string>
<string name="podcast_channel_catalogue_title">Kanäle</string>
<string name="podcast_channel_catalogue_title_expanded">Kanäle durchsuchen</string>
<string name="podcast_channel_editor_dialog_hint_rss_url">RSS Url</string>
<string name="podcast_channel_editor_dialog_title">Podcast Kanal</string>
<string name="podcast_channel_page_title_description_section">Beschreibung</string>
<string name="podcast_channel_page_title_episode_section">Episoden</string>
<string name="podcast_channel_page_title_no_episode_available">Keine Episoden verfügbar</string>
<string name="podcast_channel_editor_dialog_hint_rss_url">RSS Url</string>
<string name="podcast_channel_editor_dialog_title">Podcast Kanal</string>
<string name="podcast_release_date_duration_formatter">%1$s • %2$s</string>
<string name="podcast_episode_download_request_snackbar">Der Request wurde an den Server geschickt.</string>
<string name="podcast_info_empty_button">Hier klicken, um den Bereich auszublenden\nAnwendungsneustart ist notwendig</string>
<string name="podcast_info_empty_subtitle">Wenn Du einen Kanal hinzufügst findest Du ihn hier</string>
<string name="podcast_info_empty_title">Keine Podcasts gefunden.</string>
<string name="podcast_info_empty_button">Hier klicken, um den Bereich auszublenden\nAnwendungsneustart ist notwendig</string>
<string name="podcast_release_date_duration_formatter">%1$s • %2$s</string>
<string name="radio_editor_dialog_hint_homepage_url">Radio Homepage URL</string>
<string name="radio_editor_dialog_hint_name">Radio Name</string>
<string name="radio_editor_dialog_hint_stream_url">Radio Stream URL</string>
<string name="radio_editor_dialog_hint_homepage_url">Radio Homepage URL</string>
<string name="radio_editor_dialog_negative_button">Abbrechen</string>
<string name="radio_editor_dialog_neutral_button">Löschen</string>
<string name="radio_editor_dialog_positive_button">Speichern</string>
<string name="radio_editor_dialog_title">Internet Radio Station</string>
<string name="radio_station_info_empty_button">Hier klicken, um den Bereich auszublenden\nAnwendungsneustart ist notwendig</string>
<string name="radio_station_info_empty_subtitle">Wenn Du eine Radio Station hinzugefügt hast findest Du sie hier</string>
<string name="radio_station_info_empty_title">Keine Radio Stationen gefunden.</string>
<string name="radio_station_info_empty_button">Hier klicken, um den Bereich auszublenden\nAnwendungsneustart ist notwendig</string>
<string name="rating_dialog_negative_button">Abbrechen</string>
<string name="rating_dialog_positive_button">Speichern</string>
<string name="rating_dialog_title">Bewerten</string>
@@ -178,26 +210,26 @@
<string name="server_unreachable_dialog_negative_button">Abbrechen</string>
<string name="server_unreachable_dialog_neutral_button">Gehe zum Login</string>
<string name="server_unreachable_dialog_positive_button">Trotzdem weitermachen</string>
<string name="server_unreachable_dialog_title">Server nicht erreichbar</string>
<string name="server_unreachable_dialog_summary">Der angefragte Server ist nicht erreichbar. Wenn Du trotzdem weitermachst, wird dieser Dialog für eine Stunden nicht wieder erscheinen.</string>
<string name="server_unreachable_dialog_title">Server nicht erreichbar</string>
<string name="settings_about_summary">Tempo ist ein nativ für Android entwickelter, leichtgewichtiger Open-Source Client für Subsonic.</string>
<string name="settings_about_title">Über</string>
<string name="settings_audio_transcode_download_format">Transkodierungs-Format</string>
<string name="settings_audio_transcode_download_priority_summary">Diese Option deaktiviert die Transkodierungssettings für Downloads.</string>
<string name="settings_audio_transcode_download_priority_title">Transkodierungseinstellungen des Servers für Downloads bevorzugen.</string>
<string name="settings_audio_transcode_download_summary">Diese Option aktiviert das Transkodieren für heruntergeladene Tracks.</string>
<string name="settings_audio_transcode_download_title">Transkodierte Tracks herunterladen</string>
<string name="settings_audio_transcode_download_format">Transkodierungs-Format</string>
<string name="settings_audio_transcode_priority_summary">Diese Option deaktiviert die weiter unten folgenden Transkodierungseinstellungen.</string>
<string name="settings_audio_transcode_priority_title">Transkodierungseinstellungen des Servers bevorzugen</string>
<string name="settings_audio_transcode_priority_toast">Servereinstellungen zur Transkodierung des Tracks werden bevorzugt</string>
<string name="settings_audio_transcode_format_download">Transkodierungs-Format für Downloads</string>
<string name="settings_audio_transcode_format_mobile">Transkodierungsformat im mobilen Netz</string>
<string name="settings_audio_transcode_format_wifi">Transkodierungsformat im Wi-Fi</string>
<string name="settings_audio_transcode_priority_summary">Diese Option deaktiviert die weiter unten folgenden Transkodierungseinstellungen.</string>
<string name="settings_audio_transcode_priority_title">Transkodierungseinstellungen des Servers bevorzugen</string>
<string name="settings_audio_transcode_priority_toast">Servereinstellungen zur Transkodierung des Tracks werden bevorzugt</string>
<string name="settings_covers_cache">Größe des Artwork Caches</string>
<string name="settings_data_saving_mode_summary">Um das Datenvolumen zu begrenzen werden keine Cover heruntergeladen.</string>
<string name="settings_data_saving_mode_title">Mobile Datennutzung begrenzen</string>
<string name="settings_delete_download_storage_title">Gespeicherte Inhalte löschen</string>
<string name="settings_delete_download_storage_summary">Wenn Du weitermachst werden alle gespeicherten Inhalte unwiderruflich gelöscht.</string>
<string name="settings_delete_download_storage_title">Gespeicherte Inhalte löschen</string>
<string name="settings_download_storage_title">Download storage</string>
<string name="settings_equalizer_summary">Audio Einstellungen anpassen</string>
<string name="settings_equalizer_title">Equalizer</string>
@@ -208,23 +240,23 @@
<string name="settings_language">Sprache</string>
<string name="settings_logout_title">Abmelden</string>
<string name="settings_max_bitrate_download">Bitrate für Downloads</string>
<string name="settings_max_bitrate_wifi">Bitrate bei Wi-Fi Nutzung</string>
<string name="settings_max_bitrate_mobile">Bitrate bei mobiler Nutzung</string>
<string name="settings_max_bitrate_wifi">Bitrate bei Wi-Fi Nutzung</string>
<string name="settings_media_cache">Größe des Medienfile Caches</string>
<string name="settings_music_directory">Zeige Musikverzeichnisse</string>
<string name="settings_music_directory_summary">Zeige den Bereich für Musikverzeichnisse. Der Server muss das Feature unterstützen.</string>
<string name="settings_queue_syncing_title">Warteschlange für diesen User synchronisieren</string>
<string name="settings_queue_syncing_countdown">Timer synchronisieren</string>
<string name="settings_queue_syncing_summary">Der Benutzer kann seine Warteschlange speichern und beim Neustart der Anwendung wiederherstellen.</string>
<string name="settings_podcast">Podcasts anzeigen</string>
<string name="settings_podcast_summary">Zeige den Bereich für Podcasts.</string>
<string name="settings_queue_syncing_countdown">Timer synchronisieren</string>
<string name="settings_queue_syncing_summary">Der Benutzer kann seine Warteschlange speichern und beim Neustart der Anwendung wiederherstellen.</string>
<string name="settings_queue_syncing_title">Warteschlange für diesen User synchronisieren</string>
<string name="settings_radio">Radios anzeigen</string>
<string name="settings_radio_summary">Zeige den Bereich für Radios.</string>
<string name="settings_replay_gain">Set replay gain mode</string>
<string name="settings_rounded_corner">Abgerundete Ecken</string>
<string name="settings_rounded_corner_summary">Abgerundete Ecken für alle gerenderten Cover. Anwendungsneustart ist notwendig.</string>
<string name="settings_rounded_corner_size">Eckenradius</string>
<string name="settings_rounded_corner_size_summary">Definiert den Eckenradius.</string>
<string name="settings_rounded_corner_summary">Abgerundete Ecken für alle gerenderten Cover. Anwendungsneustart ist notwendig.</string>
<string name="settings_scan_title">Sammlung scannen</string>
<string name="settings_summary_replay_gain">Replay-Gain ist ein Feature, das die Lautstärke von Tracks für ein konsistentes Hörerlebnis anpasst. Diese Einstellung funktioniert nur, wenn Tracks die entsprechenden Metadaten haben.</string>
<string name="settings_summary_syncing">Den Zustand der Warteschlange synchronisieren. Das beinhaltet die Tracks in der Warteschlange, den aktuell gespielten Track und die Position innerhalb dieses Tracks. Der Server muss dieses Feature unterstützen.</string>
@@ -242,8 +274,8 @@
<string name="settings_title_ui">Benutzeroberfläche</string>
<string name="settings_transcoded_download">Transcoded download</string>
<string name="settings_version_title">Version</string>
<string name="settings_wifi_only_title">Warnung bei Streamen ohne Wi-Fi</string>
<string name="settings_wifi_only_summary">Um Erlaubnis fragen bevor über das mobile Netzwerk gestreamed wird.</string>
<string name="settings_wifi_only_title">Warnung bei Streamen ohne Wi-Fi</string>
<string name="song_bottom_sheet_add_to_playlist">Zu Playliste hinzufügen</string>
<string name="song_bottom_sheet_add_to_queue">Zur Warteschlange hinzufügen</string>
<string name="song_bottom_sheet_download">Download</string>
@@ -268,39 +300,7 @@
<string name="starred_sync_dialog_positive_button">Weiter und Herunterladen</string>
<string name="starred_sync_dialog_summary">Das Herunterladen deiner Lieblingslieder kann viel Datenvolumen verbrauchen.</string>
<string name="starred_sync_dialog_title">Lieblingslieder synchronisieren</string>
<string name="undraw_url">https://undraw.co/</string>
<string name="undraw_page">unDraw</string>
<string name="undraw_thanks">Besonders möchten wir uns bei unDraw bedanken, durch deren Illustrationen wir diese App so schön machen konnten.</string>
<string name="home_title_radio_station">Radio Stationen</string>
<string name="home_title_last_week">Letzte Woche</string>
<string name="home_title_top_songs">Deine Top Songs</string>
<string name="home_title_new_releases">Neue Releases</string>
<string name="home_title_best_of">Best Of</string>
<string name="home_subtitle_best_of">Top Tracks Deiner Lieblingskünstler</string>
<string name="home_title_newest_podcasts">Neueste Podcasts</string>
<string name="home_title_podcast_channels">Kanäle</string>
<string name="artist_adapter_radio_station_starting">Suche…</string>
<string name="podcast_bottom_sheet_go_to_channel">Zum Kanal gehen</string>
<string name="podcast_bottom_sheet_delete">Löschen</string>
<string name="podcast_bottom_sheet_remove">Entfernen</string>
<string name="podcast_bottom_sheet_download">Download</string>
<string name="podcast_bottom_sheet_add_to_queue">Zur Warteschlange hinzufügen</string>
<string name="podcast_bottom_sheet_play_next">Nächsten Titel spielen</string>
<string name="menu_sort_year">Jahr</string>
<string name="menu_sort_artist">Künstler</string>
<string name="menu_sort_name">Name</string>
<string name="menu_sort_random">Zufall</string>
<string name="description_empty_title">Keine Beschreibung verfügbar</string>
<string name="menu_filter_download">Heruntergeladen</string>
<string name="menu_filter_all">Alle</string>
<string name="menu_group_by_track">Track</string>
<string name="menu_group_by_album">Album</string>
<string name="menu_group_by_artist">Künstler</string>
<string name="menu_group_by_genre">Genre</string>
<string name="menu_group_by_year">Jahr</string>
<string name="downloaded_bottom_sheet_shuffle">Mischen</string>
<string name="downloaded_bottom_sheet_play_next">Nächsten Titel spielen</string>
<string name="downloaded_bottom_sheet_add_to_queue">Zur Warteschlange hinzufügen</string>
<string name="downloaded_bottom_sheet_remove">Entfernen</string>
<string name="downloaded_bottom_sheet_remove_all">Alle entfernen</string>
<string name="undraw_url">https://undraw.co/</string>
</resources>

View File

@@ -0,0 +1,214 @@
<resources>
<string-array name="theme_list_titles">
<item>Clair</item>
<item>Sombre</item>
<item>Système</item>
</string-array>
<string-array name="theme_list_values">
<item>light</item>
<item>dark</item>
<item>default</item>
</string-array>
<string-array name="pref_cache_size_titles">
<item>Grand</item>
<item>Moyen</item>
<item>Petit</item>
</string-array>
<string-array name="pref_cache_size_values">
<item>500</item>
<item>250</item>
<item>125</item>
</string-array>
<string-array name="pref_image_size_titles">
<item>Haute</item>
<item>Moyenne</item>
<item>Basse</item>
</string-array>
<string-array name="pref_image_size_values">
<item>-1</item>
<item>500</item>
<item>300</item>
</string-array>
<string-array name="max_bitrate_wifi_list_titles">
<item>Original</item>
<item>32 kbps</item>
<item>48 kbps</item>
<item>64 kbps</item>
<item>80 kbps</item>
<item>96 kbps</item>
<item>112 kbps</item>
<item>128 kbps</item>
<item>160 kbps</item>
<item>192 kbps</item>
<item>256 kbps</item>
<item>320 kbps</item>
</string-array>
<string-array name="max_bitrate_wifi_list_values">
<item>0</item>
<item>32</item>
<item>48</item>
<item>64</item>
<item>80</item>
<item>96</item>
<item>112</item>
<item>128</item>
<item>160</item>
<item>192</item>
<item>256</item>
<item>320</item>
</string-array>
<string-array name="max_bitrate_mobile_list_titles">
<item>Original</item>
<item>32 kbps</item>
<item>48 kbps</item>
<item>64 kbps</item>
<item>80 kbps</item>
<item>96 kbps</item>
<item>112 kbps</item>
<item>128 kbps</item>
<item>160 kbps</item>
<item>192 kbps</item>
<item>256 kbps</item>
<item>320 kbps</item>
</string-array>
<string-array name="max_bitrate_mobile_list_values">
<item>0</item>
<item>32</item>
<item>48</item>
<item>64</item>
<item>80</item>
<item>96</item>
<item>112</item>
<item>128</item>
<item>160</item>
<item>192</item>
<item>256</item>
<item>320</item>
</string-array>
<string-array name="max_bitrate_download_list_titles">
<item>Original</item>
<item>32 kbps</item>
<item>48 kbps</item>
<item>64 kbps</item>
<item>80 kbps</item>
<item>96 kbps</item>
<item>112 kbps</item>
<item>128 kbps</item>
<item>160 kbps</item>
<item>192 kbps</item>
<item>256 kbps</item>
<item>320 kbps</item>
</string-array>
<string-array name="max_bitrate_download_list_values">
<item>0</item>
<item>32</item>
<item>48</item>
<item>64</item>
<item>80</item>
<item>96</item>
<item>112</item>
<item>128</item>
<item>160</item>
<item>192</item>
<item>256</item>
<item>320</item>
</string-array>
<string-array name="audio_transcode_format_wifi_list_titles">
<item>Lecture directe</item>
<item>Opus</item>
<item>AAC</item>
<item>Mp3</item>
<item>Flac</item>
</string-array>
<string-array name="audio_transcode_format_wifi_list_values">
<item>raw</item>
<item>opus</item>
<item>aac</item>
<item>mp3</item>
<item>flac</item>
</string-array>
<string-array name="audio_transcode_format_mobile_list_titles">
<item>Lecture directe</item>
<item>Opus</item>
<item>AAC</item>
<item>Mp3</item>
<item>Flac</item>
</string-array>
<string-array name="audio_transcode_format_mobile_list_values">
<item>raw</item>
<item>opus</item>
<item>aac</item>
<item>mp3</item>
<item>flac</item>
</string-array>
<string-array name="audio_transcode_format_download_list_titles">
<item>Téléchargement direct</item>
<item>Opus</item>
<item>AAC</item>
<item>Mp3</item>
<item>Flac</item>
</string-array>
<string-array name="audio_transcode_format_download_list_values">
<item>raw</item>
<item>opus</item>
<item>aac</item>
<item>mp3</item>
<item>flac</item>
</string-array>
<string-array name="queue_syncing_countdown_titles">
<item>Dix secondes</item>
<item>Cinq secondes</item>
<item>Deux secondes</item>
</string-array>
<string-array name="queue_syncing_countdown_values">
<item>10</item>
<item>5</item>
<item>2</item>
</string-array>
<string-array name="rounded_corner_size_titles">
<item>Grand</item>
<item>Moyen</item>
<item>Petit</item>
</string-array>
<string-array name="rounded_corner_size_values">
<item>18</item>
<item>12</item>
<item>6</item>
</string-array>
<string-array name="replay_gain_titles">
<item>Désactivé</item>
<item>Piste</item>
<item>Album</item>
<item>Auto</item>
</string-array>
<string-array name="replay_gain_values">
<item>disabled</item>
<item>track</item>
<item>album</item>
<item>auto</item>
</string-array>
<string-array name="transcoded_download_option_list_titles">
<item>Ne pas transcoder</item>
<item>Réglages du serveur</item>
<item>Format de transcodage (Wi-FI)</item>
<item>Format de transcodage (Mobile)</item>
</string-array>
<string-array name="transcoded_download_option_list_values">
<item>0</item>
<item>1</item>
<item>2</item>
<item>3</item>
</string-array>
</resources>

View File

@@ -0,0 +1,348 @@
<resources>
<string name="activity_battery_optimizations_conclusion">Si vous rencontrez un problème, visitez https://dontkillmyapp.com. Des instructions pour désactiver les fonctions de sauvegarde d\'énergie qui pourrait affecter les performance de l\'app y sont disponibles.</string>
<string name="activity_battery_optimizations_summary">Veuillez désactiver les optimisations de la batterie pour permettre la lecture des médias lorsque l\'écran est éteint.</string>
<string name="activity_battery_optimizations_title">Optimisations de la batterie</string>
<string name="activity_info_offline_mode">Mode hors-ligne</string>
<string name="album_bottom_sheet_add_to_queue">Ajouter à la file d\'attente</string>
<string name="album_bottom_sheet_download_all">Télécharger tout</string>
<string name="album_bottom_sheet_go_to_artist">Aller à l\'artiste</string>
<string name="album_bottom_sheet_instant_mix">Mix instantané</string>
<string name="album_bottom_sheet_play_next">Lire après</string>
<string name="album_bottom_sheet_remove_all">Retirer tout</string>
<string name="album_bottom_sheet_share">Partager</string>
<string name="album_bottom_sheet_shuffle">Mélanger</string>
<string name="album_catalogue_title">Albums</string>
<string name="album_catalogue_title_expanded">Parcourir les Albums</string>
<string name="album_error_retrieving_artist">Erreur de récupération de l\'artiste</string>
<string name="album_list_page_downloaded">Albums téléchargés</string>
<string name="album_list_page_most_played">Albums les plus joués</string>
<string name="album_list_page_new_releases">Nouvelles sorties</string>
<string name="album_list_page_recently_added">Albums récemment ajoutés</string>
<string name="album_list_page_recently_played">Albums récemment joués</string>
<string name="album_list_page_starred">Albums favoris</string>
<string name="album_list_page_title">Albums</string>
<string name="album_page_extra_info_button">Similaire</string>
<string name="album_page_play_button">Lire</string>
<string name="album_page_shuffle_button">Mélanger</string>
<string name="app_name">Tempo</string>
<string name="artist_adapter_radio_station_starting">Recherche…</string>
<string name="artist_bottom_sheet_instant_mix">Mix instantané</string>
<string name="artist_bottom_sheet_shuffle">Mélanger</string>
<string name="artist_catalogue_title">Artistes</string>
<string name="artist_catalogue_title_expanded">Parcourir les artistes</string>
<string name="artist_error_retrieving_radio">Erreur de récupération de la radio de l\'artiste</string>
<string name="artist_error_retrieving_tracks">Erreur de récupération des titres de l\'artiste</string>
<string name="artist_list_page_downloaded">Artistes téléchargés</string>
<string name="artist_list_page_starred">Artistes favoris</string>
<string name="artist_list_page_title">Artistes</string>
<string name="artist_page_radio_button">Radio</string>
<string name="artist_page_shuffle_button">Mélanger</string>
<string name="artist_page_switch_layout_button">Changer la disposition</string>
<string name="artist_page_title_album_more_like_this_button">Similaire</string>
<string name="artist_page_title_album_section">Albums</string>
<string name="artist_page_title_biography_more_button">Plus</string>
<string name="artist_page_title_biography_section">Biographie</string>
<string name="artist_page_title_most_streamed_song_section">Musiques les plus streamées</string>
<string name="artist_page_title_most_streamed_song_see_all_button">Voir tout</string>
<string name="battery_optimization_negative_button">Ignorer</string>
<string name="battery_optimization_neutral_button">Ne pas me redemander</string>
<string name="battery_optimization_positive_button">Désactiver</string>
<string name="connection_alert_dialog_negative_button">Annuler</string>
<string name="connection_alert_dialog_neutral_button">Activer l\'économie de données</string>
<string name="connection_alert_dialog_positive_button">OK</string>
<string name="connection_alert_dialog_summary">L\'accès au serveur Subsonic sur des connexions autres que le Wi-Fi ont été bloquées. Pour empêcher cette alerte de réapparaître, désactiver la vérification de la connexion dans les paramètres de l\'app.</string>
<string name="connection_alert_dialog_title">Wi-Fi déconnecté</string>
<string name="delete_download_storage_dialog_negative_button">Annuler</string>
<string name="delete_download_storage_dialog_positive_button">Continuer</string>
<string name="delete_download_storage_dialog_summary">Sachez que la poursuite de cette action entraînera la suppression permanente de tous les éléments sauvegardés et téléchargés à partir de tous les serveurs</string>
<string name="delete_download_storage_dialog_title">Supprimer les éléments téléchargés</string>
<string name="description_empty_title">Aucune description disponible</string>
<string name="download_info_empty_subtitle">Dès que vous téléchargerez une musique, vous la trouverez ici</string>
<string name="download_info_empty_title">Aucun téléchargement pour l\'instant</string>
<string name="download_item_multiple_subtitle_formatter">%1$s • %2$s éléments</string>
<string name="download_item_single_subtitle_formatter">%1$s éléments</string>
<string name="download_storage_dialog_sub_summary">Redémarrez l\'app pour appliquer les changements.</string>
<string name="download_storage_dialog_summary">Changer la destination des téléchargements d\'un espace de stockage à un autre résultera en la suppression immédiate de tous les fichiers précédemment téléchargés dans l\'autre espace de stockage.</string>
<string name="download_storage_dialog_title">Sélectionnez l\'option de stockage</string>
<string name="download_storage_external_dialog_positive_button">Externe</string>
<string name="download_storage_internal_dialog_negative_button">Interne</string>
<string name="download_title_section">Téléchargements</string>
<string name="downloaded_bottom_sheet_add_to_queue">Ajouter à la liste d\'attente</string>
<string name="downloaded_bottom_sheet_play_next">Lire juste après</string>
<string name="downloaded_bottom_sheet_remove">Retirer</string>
<string name="downloaded_bottom_sheet_remove_all">Retirer tout</string>
<string name="downloaded_bottom_sheet_shuffle">Mélanger</string>
<string name="empty_string" />
<string name="error_required">Requis</string>
<string name="error_server_prefix">prefix http ou https requis</string>
<string name="exo_download_notification_channel_name">Téléchargements</string>
<string name="filter_info_selection">Sélectionnez deux filtres ou plus</string>
<string name="filter_title">Filtrer</string>
<string name="filter_title_expanded">Filtrer par genre</string>
<string name="genre_catalogue_title">Catalogue des Genres</string>
<string name="genre_catalogue_title_expanded">Parcourir les Genres</string>
<string name="home_subtitle_best_of">Meilleurs morceaux de vos artistes préférés</string>
<string name="home_subtitle_made_for_you">Commencez le mix à partir d\'une chanson que vous aimez</string>
<string name="home_subtitle_new_internet_radio_station">Ajouter une radio</string>
<string name="home_subtitle_new_podcast_channel">Ajouter une chaîne de podcasts</string>
<string name="home_sync_starred_cancel">Annuler</string>
<string name="home_sync_starred_download">Télécharger</string>
<string name="home_sync_starred_subtitle">Télécharger ces titres peut entraîner une utilisation importante de données</string>
<string name="home_sync_starred_title">On dirait qu\'il y a des titres favoris à synchroniser</string>
<string name="home_title_best_of">Best of</string>
<string name="home_title_discovery">Découverte</string>
<string name="home_title_discovery_shuffle_all_button">Tout mélanger</string>
<string name="home_title_flashback">Flashback</string>
<string name="home_title_internet_radio_station">Stations Radio Internet</string>
<string name="home_title_last_played">Écouté dernièrement</string>
<string name="home_title_last_played_see_all_button">Voir tout</string>
<string name="home_title_last_week">Sur la dernière semaine</string>
<string name="home_title_made_for_you">Faits pour vous</string>
<string name="home_title_most_played">Les plus écoutés</string>
<string name="home_title_most_played_see_all_button">Voir tout</string>
<string name="home_title_new_releases">Nouvelles sorties</string>
<string name="home_title_newest_podcasts">Nouveau podcasts</string>
<string name="home_title_podcast_channels">Chaînes</string>
<string name="home_title_podcast_channels_see_all_button">Voir tout</string>
<string name="home_title_radio_station">Stations radio</string>
<string name="home_title_recently_added">Ajouté récemment</string>
<string name="home_title_recently_added_see_all_button">Voir tout</string>
<string name="home_title_shares">Partages</string>
<string name="home_title_starred_albums">★ Albums favoris</string>
<string name="home_title_starred_albums_see_all_button">Voir tout</string>
<string name="home_title_starred_artists">★ Artistes favoris</string>
<string name="home_title_starred_artists_see_all_button">Voir tout</string>
<string name="home_title_starred_tracks">★ Titres favoris</string>
<string name="home_title_starred_tracks_see_all_button">Voir tout</string>
<string name="home_title_top_songs">Vos morceaux préférés</string>
<string name="library_title_album">Albums</string>
<string name="library_title_album_see_all_button">Voir tout</string>
<string name="library_title_artist">Artistes</string>
<string name="library_title_artist_see_all_button">Voir tout</string>
<string name="library_title_genre">Genres</string>
<string name="library_title_genre_see_all_button">Voir tout</string>
<string name="library_title_music_folder">Dossiers de musiques</string>
<string name="library_title_playlist">Playlists</string>
<string name="library_title_playlist_see_all_button">Voir tout</string>
<string name="login_empty">Aucun serveur ajouté</string>
<string name="login_title">Serveurs Subsonic</string>
<string name="login_title_expanded">Serveurs Subsonic</string>
<string name="media_route_menu_title">Cast</string>
<string name="menu_add_button">Ajouter</string>
<string name="menu_download_all_button">Télécharger tout</string>
<string name="menu_download_label">Téléchargé</string>
<string name="menu_filter_all">Tout</string>
<string name="menu_filter_download">Téléchargé</string>
<string name="menu_group_by_album">Album</string>
<string name="menu_group_by_artist">Artiste</string>
<string name="menu_group_by_genre">Genre</string>
<string name="menu_group_by_track">Piste</string>
<string name="menu_group_by_year">Année</string>
<string name="menu_home_label">Home</string>
<string name="menu_library_label">Librairie</string>
<string name="menu_search_button">Rechercher</string>
<string name="menu_settings_button">Paramètres</string>
<string name="menu_sort_artist">Artiste</string>
<string name="menu_sort_name">Nom</string>
<string name="menu_sort_random">Aléatoire</string>
<string name="menu_sort_year">Année</string>
<string name="player_playback_speed">%1$.2fx</string>
<string name="player_server_priority">Priorité serveur</string>
<string name="playlist_catalogue_title">Catalogue des Playlists</string>
<string name="playlist_catalogue_title_expanded">Parcourir les playlists</string>
<string name="playlist_chooser_dialog_empty">Pas de playlist</string>
<string name="playlist_chooser_dialog_negative_button">Annuler</string>
<string name="playlist_chooser_dialog_neutral_button">Créer</string>
<string name="playlist_chooser_dialog_title">Ajouter à une playlist</string>
<string name="playlist_counted_tracks">%1$d titres • %2$s</string>
<string name="playlist_duration">Durée • %1$s</string>
<string name="playlist_editor_dialog_hint_name">Nom de la playlist</string>
<string name="playlist_editor_dialog_negative_button">Annuler</string>
<string name="playlist_editor_dialog_neutral_button">Supprimer</string>
<string name="playlist_editor_dialog_positive_button">Enregistrer</string>
<string name="playlist_editor_dialog_title">Créer une playlist</string>
<string name="playlist_page_play_button">Lire</string>
<string name="playlist_page_shuffle_button">Mélanger</string>
<string name="playlist_song_count">Playlist • %1$d titres</string>
<string name="podcast_bottom_sheet_add_to_queue">Ajouter à la liste d\'attente</string>
<string name="podcast_bottom_sheet_delete">Supprimer</string>
<string name="podcast_bottom_sheet_download">Télécharger</string>
<string name="podcast_bottom_sheet_go_to_channel">Aller à la chaîne</string>
<string name="podcast_bottom_sheet_play_next">Lire juste après</string>
<string name="podcast_bottom_sheet_remove">Retirer</string>
<string name="podcast_channel_catalogue_title">Chaînes</string>
<string name="podcast_channel_catalogue_title_expanded">Parcourir les chaînes</string>
<string name="podcast_channel_editor_dialog_hint_rss_url">Url RSS</string>
<string name="podcast_channel_editor_dialog_title">Chaîne</string>
<string name="podcast_channel_page_title_description_section">Description</string>
<string name="podcast_channel_page_title_episode_section">Épisodes</string>
<string name="podcast_channel_page_title_no_episode_available">Aucun épisode disponible</string>
<string name="podcast_episode_download_request_snackbar">Votre requête a été envoyée au serveur</string>
<string name="podcast_info_empty_button">Cliquez pour cacher la section\nLes changements seront visibles au redémarrage de l\'app</string>
<string name="podcast_info_empty_subtitle">Dès que vous ajouterez une chaîne, vous la retrouverez ici</string>
<string name="podcast_info_empty_title">Aucun podcast trouvé!</string>
<string name="podcast_release_date_duration_formatter">%1$s • %2$s</string>
<string name="radio_editor_dialog_hint_homepage_url">URL de la page d\'accueil de la radio</string>
<string name="radio_editor_dialog_hint_name">Nom de la radio</string>
<string name="radio_editor_dialog_hint_stream_url">URL du flux radio</string>
<string name="radio_editor_dialog_negative_button">Annuler</string>
<string name="radio_editor_dialog_neutral_button">Supprimer</string>
<string name="radio_editor_dialog_positive_button">Enregistrer</string>
<string name="radio_editor_dialog_title">Station Radio Internet</string>
<string name="radio_station_info_empty_button">Cliquez pour cacher la section\nLes changements seront visibles au redémarrage de l\'app</string>
<string name="radio_station_info_empty_subtitle">Dès que vous ajouterez une station radio, vous la retrouverez ici</string>
<string name="radio_station_info_empty_title">Aucune station trouvée!</string>
<string name="rating_dialog_negative_button">Annuler</string>
<string name="rating_dialog_positive_button">Enregistrer</string>
<string name="rating_dialog_title">Noter</string>
<string name="search_hint">Rechercher des titres, artistes ou albums</string>
<string name="search_info_minimum_characters">Entrez 3 charactères minimum</string>
<string name="search_title_album">Albums</string>
<string name="search_title_artist">Artistes</string>
<string name="search_title_song">Pistes</string>
<string name="server_signup_dialog_action_low_security">Sécurité basse</string>
<string name="server_signup_dialog_hint_name">Nom du serveur</string>
<string name="server_signup_dialog_hint_password">Mot de passe</string>
<string name="server_signup_dialog_hint_url">URL du serveur</string>
<string name="server_signup_dialog_hint_username">Nom d\'utilisateur</string>
<string name="server_signup_dialog_negative_button">Annuler</string>
<string name="server_signup_dialog_neutral_button">Supprimer</string>
<string name="server_signup_dialog_positive_button">Enregistrer</string>
<string name="server_signup_dialog_title">Ajouter un serveur</string>
<string name="server_unreachable_dialog_negative_button">Annuler</string>
<string name="server_unreachable_dialog_neutral_button">Aller à la connexion</string>
<string name="server_unreachable_dialog_positive_button">Continuer quand même</string>
<string name="server_unreachable_dialog_summary">Le serveur est injoignable. Si vous décidez de continuer, cette fenêtre n\'apparaîtra plus pendant une heure.</string>
<string name="server_unreachable_dialog_title">Serveur injoignable</string>
<string name="settings_about_summary">Tempo est un client open source et léger pour Subsonic, développé et build nativement pour Android.</string>
<string name="settings_about_title">À propos</string>
<string name="settings_audio_transcode_download_format">Format de transcodage</string>
<string name="settings_audio_transcode_download_priority_summary">Si activé, Tempo ne forcera pas le téléchargement de la piste avec les paramètre de transcodage ci-dessous.</string>
<string name="settings_audio_transcode_download_priority_title">Prioriser les paramètres du serveurs, utilisés pour le streaming, dans les téléchargements</string>
<string name="settings_audio_transcode_download_summary">Si activé, Tempo téléchargera les pistes transcodées.</string>
<string name="settings_audio_transcode_download_title">Télécharger les pistes transcodées</string>
<string name="settings_audio_transcode_estimate_content_length_summary">Si activé, une estimation de la durée de la piste sera demandée au serveur.</string>
<string name="settings_audio_transcode_estimate_content_length_title">Estimer la durée du contenu</string>
<string name="settings_audio_transcode_format_download">Format de transcodage pour les téléchargements</string>
<string name="settings_audio_transcode_format_mobile">Format de transcodage (mobile)</string>
<string name="settings_audio_transcode_format_wifi">Format de transcodage (Wi-Fi)</string>
<string name="settings_audio_transcode_priority_summary">Si activé, Tempo ne forcera pas le streaming des pistes avec les paramètres ci-dessous.</string>
<string name="settings_audio_transcode_priority_title">Prioriser les paramètres de transcodage du serveur</string>
<string name="settings_audio_transcode_priority_toast">La priorité au transcodage de la piste est donnée au serveur</string>
<string name="settings_covers_cache">Taille du cache des illustrations</string>
<string name="settings_data_saving_mode_summary">Pour réduire la consommation de données, évitez de télécharger les illustrations.</string>
<string name="settings_data_saving_mode_title">Limiter l\'utilisation des données mobiles</string>
<string name="settings_delete_download_storage_summary">Continuer entraînera la suppression irréversible de tous les éléments sauvegardés.</string>
<string name="settings_delete_download_storage_title">Supprimer les éléments sauvegardés</string>
<string name="settings_download_storage_title">Stockage des téléchargements</string>
<string name="settings_equalizer_summary">Ajuster les paramètres audios</string>
<string name="settings_equalizer_title">Égaliseur</string>
<string name="settings_github_link">https://github.com/CappielloAntonio/tempo</string>
<string name="settings_github_summary">Suivre le développement</string>
<string name="settings_github_title">Github</string>
<string name="settings_image_size">Définir la résolution des images</string>
<string name="settings_language">Langue</string>
<string name="settings_logout_title">Se déconnecter</string>
<string name="settings_max_bitrate_download">Bitrate pour les téléchargements</string>
<string name="settings_max_bitrate_mobile">Bitrate en données mobile</string>
<string name="settings_max_bitrate_wifi">Bitrate en Wi-Fi</string>
<string name="settings_media_cache">Taille du cache des fichiers audios</string>
<string name="settings_music_directory">Afficher les dossiers</string>
<string name="settings_music_directory_summary">Si activé, rend possible la navigation dans les répertoires. À noter que pour que la navigation dans les dossiers fonctionne correctement, le serveur doit supporter cette fonctionnalité.</string>
<string name="settings_podcast">Voir les podcasts</string>
<string name="settings_podcast_summary">Si activé, rend visible la section Podcast</string>
<string name="settings_queue_syncing_countdown">Minuteur de synchronisation</string>
<string name="settings_queue_syncing_summary">Si activé, l\'utilisateur pourra sauvegarder sa file d\'attente et la recharger au démarrage de l\'application.</string>
<string name="settings_queue_syncing_title">Synchroniser la file d\'attente pour cet utilisateur</string>
<string name="settings_radio">Voir les radios</string>
<string name="settings_radio_summary">Si activé, rend visible la section Radio</string>
<string name="settings_replay_gain">Ajuster le Replay Gain</string>
<string name="settings_rounded_corner">Coins arrondis</string>
<string name="settings_rounded_corner_size">Taille des arrondis</string>
<string name="settings_rounded_corner_size_summary">Définit l\'ampleur de l\'angle de courbure.</string>
<string name="settings_rounded_corner_summary">Si activé, arrondi les angles des illustrations. Les modifications prendront effet au redémarrage.</string>
<string name="settings_scan_title">Scanner la librairie</string>
<string name="settings_share_title">Activer le partage de musique</string>
<string name="settings_summary_replay_gain">Le Replay Gain est une fonctionnalité qui vous permet d\'ajuster le volume des pistes audio pour une expérience d\'écoute cohérente. Fonctionne uniquement si la piste contient les métadonnées nécessaires.</string>
<string name="settings_summary_share">Permet à l\'utilisateur de partager de la musique via un lien. Cette fonctionnalité doit être supportée et activée sur le serveur et est limitée aux pistes, albums et playlists individuellement.</string>
<string name="settings_summary_syncing">Renvoie l\'état de la file d\'attente de cet utilisateur. Cela inclut les pistes dans la file, la piste actuellement écoutée et la position dans la piste. Cette fonctionnalité doit être supportée par le serveur.</string>
<string name="settings_summary_transcoding">Le mode de transcodage à prioriser. Si reglé sur \"Lecture directe\", le bitrate du fichier ne sera pas modifié.</string>
<string name="settings_summary_transcoding_download">Télécharge les médias transcodés. Si activé, les paramètres de transcodage suivants seront utilisés pour les téléchargements.\n\n Si le format de transcodage est reglé à \"Téléchargement direct\", le bitrate du fichier ne sera pas modifé.</string>
<string name="settings_summary_transcoding_estimate_content_length">Quand le fichier est transcodé à la volé, en général, le client n\'affiche pas la durée de la piste. Il est possible de demander aux serveurs qui le supportent d\'estimer la durée de la piste écoutée, mais les temps de réponses peuvent être plus longs.</string>
<string name="settings_sync_starred_tracks_for_offline_use_summary">Si activés, les pistes favorites seront téléchargées pour l\'écoute hors-ligne</string>
<string name="settings_sync_starred_tracks_for_offline_use_title">Synchronisation des pistes favorites pour écoute hors-ligne</string>
<string name="settings_theme">Thème</string>
<string name="settings_title_data">Données</string>
<string name="settings_title_general">Géneral</string>
<string name="settings_title_replay_gain">Replay Gain</string>
<string name="settings_title_share">Partage</string>
<string name="settings_title_syncing">Synchronisation</string>
<string name="settings_title_transcoding">Transcodage</string>
<string name="settings_title_transcoding_download">Transcodage des téléchargements</string>
<string name="settings_title_ui">UI</string>
<string name="settings_transcoded_download">Transcodage des téléchargements</string>
<string name="settings_version_title">Version</string>
<string name="settings_wifi_only_summary">Demander confirmation à l\'utilisateur avant de streamer sur le réseau mobile.</string>
<string name="settings_wifi_only_title">Alerte de streaming sur données mobiles</string>
<string name="share_bottom_sheet_copy_link">Copier le lien</string>
<string name="share_bottom_sheet_delete">Supprimer le partage</string>
<string name="share_bottom_sheet_update">Mettre à jour le partage</string>
<string name="share_subtitle_item">Date d\'expiration : %1$s</string>
<string name="share_unsupported_error">Le partage n\'est pas supporté ou pas activé</string>
<string name="share_update_dialog_hint_description">Description</string>
<string name="share_update_dialog_hint_expiration_date">Date d\'expiration</string>
<string name="share_update_dialog_negative_button">Annuler</string>
<string name="share_update_dialog_positive_button">Enregistrer</string>
<string name="share_update_dialog_title">Partager</string>
<string name="song_bottom_sheet_add_to_playlist">Ajouter à une playlist</string>
<string name="song_bottom_sheet_add_to_queue">Ajouter à la fil d\'attente</string>
<string name="song_bottom_sheet_download">Télécharger</string>
<string name="song_bottom_sheet_error_retrieving_album">Erreur de récupération de l\'album</string>
<string name="song_bottom_sheet_error_retrieving_artist">Erreur de récupération de l\'artiste</string>
<string name="song_bottom_sheet_go_to_album">Aller à l\'album</string>
<string name="song_bottom_sheet_go_to_artist">Aller à l\'artiste</string>
<string name="song_bottom_sheet_instant_mix">Mix instantané</string>
<string name="song_bottom_sheet_play_next">Lire juste après</string>
<string name="song_bottom_sheet_rate">Noter</string>
<string name="song_bottom_sheet_remove">Retirer</string>
<string name="song_bottom_sheet_share">Partager</string>
<string name="song_list_page_downloaded">Téléchargé</string>
<string name="song_list_page_most_played">Titres les plus joués</string>
<string name="song_list_page_recently_added">Titres ajoutés récemment</string>
<string name="song_list_page_recently_played">Titrés joués récemment</string>
<string name="song_list_page_starred">Titres favoris</string>
<string name="song_list_page_top">Les meilleurs titres de %1$s</string>
<string name="song_list_page_year">Année %1$d</string>
<string name="song_subtitle_formatter">%1$s • %2$s</string>
<string name="starred_sync_dialog_negative_button">Annuler</string>
<string name="starred_sync_dialog_neutral_button">Continuer</string>
<string name="starred_sync_dialog_positive_button">Continuer et télécharger</string>
<string name="starred_sync_dialog_summary">Le téléchargement des titres favoris pourrer utiliser beaucoup de données.</string>
<string name="starred_sync_dialog_title">Synchroniser les titres favoris</string>
<string name="track_info_album">Album</string>
<string name="track_info_artist">Artiste</string>
<string name="track_info_bitrate">Bitrate</string>
<string name="track_info_content_type">Type de contenu</string>
<string name="track_info_dialog_positive_button">OK</string>
<string name="track_info_dialog_title">Infos piste</string>
<string name="track_info_disc_number">Numéro de disque</string>
<string name="track_info_duration">Durée</string>
<string name="track_info_genre">Genre</string>
<string name="track_info_path">Chemin</string>
<string name="track_info_size">Taille</string>
<string name="track_info_suffix">Suffixe</string>
<string name="track_info_summary_downloaded_file">Le fichier a été téléchargé depuis les APIs Subsonic. Le codec et le bitrate du fichier demeure inchangé du fichier d\'origine.</string>
<string name="track_info_summary_full_transcode">L\'application demandera au serveur de transcoder le fichier et de modifier son bitrate. Le codec demandé par l\'utilisateur est %1$s, avec un bitrate de %2$s. Toute modification éventuelle du codec et du bitrate du fichier dans le format choisi sera gérée par le serveur, qui peut ou non prendre en charge l\'opération.</string>
<string name="track_info_summary_original_file">L\'application ne lira que le fichier original tel que fourni par le serveur. L\'application demandera explicitement au serveur le fichier non transcodé avec le bitrate de la source originale.</string>
<string name="track_info_summary_server_prioritized">La qualité du fichier à lire est laissée à l\'appréciation du serveur. L\'application n\'impose pas le choix du codec et du bitrate pour un éventuel transcodage.</string>
<string name="track_info_summary_transcoding_bitrate">L\'application demandera au serveur de modifier le bitrate du fichier. L\'utilisateur a choisi un bitrate de %1$s, tandis que le codec du fichier restera le même. Toute modification du bitrate du fichier dans le format choisi sera effectuée par le serveur, qui peut ou non prendre en charge l\'opération. </string>
<string name="track_info_summary_transcoding_codec">L\'application demandera au serveur de transcoder le fichier. Le codec choisi par l\'utilisateur est le %1$s, tandis que le bitrate sera le même que celui du fichier source. Le transcodage éventuel du fichier dans le codec choisi dépend du serveur, qui peut ou non prendre en charge l\'opération.</string>
<string name="track_info_title">Titre</string>
<string name="track_info_track_number">Numéro de piste</string>
<string name="track_info_transcoded_content_type">Transcodé type de contenu</string>
<string name="track_info_transcoded_suffix">Transcodé suffixe</string>
<string name="track_info_year">Année</string>
<string name="undraw_page">unDraw</string>
<string name="undraw_thanks">Un grand merci à unDraw, nous n\'aurions pas pu rendre cette application aussi belle sans leurs illustrations.</string>
<string name="undraw_url">https://undraw.co/</string>
</resources>

View File

@@ -211,4 +211,17 @@
<item>2</item>
<item>3</item>
</string-array>
<string-array name="buffering_strategy_titles">
<item>Minimum</item>
<item>Moderate</item>
<item>Aggressive</item>
<item>Extreme</item>
</string-array>
<string-array name="buffering_strategy_values">
<item>.1</item>
<item>1</item>
<item>4</item>
<item>8</item>
</string-array>
</resources>

View File

@@ -1,19 +1,16 @@
<resources>
<string name="activity_battery_optimizations_summary">Please disable battery optimizations for media playback while the screen is off.</string>
<string name="activity_battery_optimizations_conclusion">If in trouble visit https://dontkillmyapp.com. It provides detailed instructions on how to disable any power-saving features that may affect app\'s performance.</string>
<string name="activity_battery_optimizations_summary">Please disable battery optimizations for media playback while the screen is off.</string>
<string name="activity_battery_optimizations_title">Battery Optimizations</string>
<string name="activity_info_offline_mode">Offline mode</string>
<string name="battery_optimization_negative_button">Ignore</string>
<string name="battery_optimization_positive_button">Disable</string>
<string name="battery_optimization_neutral_button">Don\'t ask again</string>
<string name="album_bottom_sheet_add_to_queue">Add to queue</string>
<string name="album_bottom_sheet_download_all">Download all</string>
<string name="album_bottom_sheet_go_to_artist">Go to artist</string>
<string name="album_bottom_sheet_instant_mix">Instant mix</string>
<string name="album_bottom_sheet_play_next">Play next</string>
<string name="album_bottom_sheet_remove_all">Remove all</string>
<string name="album_bottom_sheet_shuffle">Shuffle</string>
<string name="album_bottom_sheet_share">Share</string>
<string name="album_bottom_sheet_shuffle">Shuffle</string>
<string name="album_catalogue_title">Albums</string>
<string name="album_catalogue_title_expanded">Browse Albums</string>
<string name="album_error_retrieving_artist">Error retrieving artist</string>
@@ -28,6 +25,7 @@
<string name="album_page_play_button">Play</string>
<string name="album_page_shuffle_button">Shuffle</string>
<string name="app_name">Tempo</string>
<string name="artist_adapter_radio_station_starting">Searching…</string>
<string name="artist_bottom_sheet_instant_mix">Instant mix</string>
<string name="artist_bottom_sheet_shuffle">Shuffle</string>
<string name="artist_catalogue_title">Artists</string>
@@ -39,31 +37,45 @@
<string name="artist_list_page_title">Artists</string>
<string name="artist_page_radio_button">Radio</string>
<string name="artist_page_shuffle_button">Shuffle</string>
<string name="artist_page_switch_layout_button">Switch layout</string>
<string name="artist_page_title_album_more_like_this_button">More like this</string>
<string name="artist_page_title_album_section">Albums</string>
<string name="artist_page_title_biography_more_button">More</string>
<string name="artist_page_title_biography_section">Biography</string>
<string name="artist_page_title_most_streamed_song_section">Most Streamed Songs</string>
<string name="artist_page_title_most_streamed_song_see_all_button">See all</string>
<string name="battery_optimization_negative_button">Ignore</string>
<string name="battery_optimization_neutral_button">Don\'t ask again</string>
<string name="battery_optimization_positive_button">Disable</string>
<string name="connection_alert_dialog_negative_button">Cancel</string>
<string name="connection_alert_dialog_neutral_button">Enable data saver</string>
<string name="connection_alert_dialog_positive_button">OK</string>
<string name="connection_alert_dialog_title">Wi-Fi not connected</string>
<string name="connection_alert_dialog_summary">Access to the Subsonic server on connections other than Wi-Fi has been restricted. To prevent this alert dialod from reappearing, disable the connection check in the app settings.</string>
<string name="connection_alert_dialog_title">Wi-Fi not connected</string>
<string name="delete_download_storage_dialog_negative_button">Cancel</string>
<string name="delete_download_storage_dialog_positive_button">Continue</string>
<string name="delete_download_storage_dialog_summary">Please be aware that continuing with this action will result in the permanent deletion of all saved items downloaded from all servers.</string>
<string name="delete_download_storage_dialog_title">Delete saved items</string>
<string name="description_empty_title">No description available</string>
<string name="download_directory_dialog_negative_button">Cancel</string>
<string name="download_directory_dialog_positive_button">Download</string>
<string name="download_directory_dialog_summary">All tracks in this folder will be downloaded. Tracks present in subfolders will not be downloaded.</string>
<string name="download_directory_dialog_title">Download the tracks</string>
<string name="download_info_empty_subtitle">Once you download a song, you\'ll find it here</string>
<string name="download_info_empty_title">No downloads yet!</string>
<string name="download_item_multiple_subtitle_formatter">%1$s • %2$s items</string>
<string name="download_item_single_subtitle_formatter">%1$s items</string>
<string name="download_title_section">Downloads</string>
<string name="download_storage_internal_dialog_negative_button">Internal</string>
<string name="download_storage_external_dialog_positive_button">External</string>
<string name="download_storage_dialog_summary">Changing the destination of downloaded files from one storage to another will result in the immediate deletion of any previously downloaded files in the other storage.</string>
<string name="download_storage_dialog_sub_summary">For the changes to take effect, restart the app.</string>
<string name="download_storage_dialog_summary">Changing the destination of downloaded files from one storage to another will result in the immediate deletion of any previously downloaded files in the other storage.</string>
<string name="download_storage_dialog_title">Select storage option</string>
<string name="download_storage_external_dialog_positive_button">External</string>
<string name="download_storage_internal_dialog_negative_button">Internal</string>
<string name="download_title_section">Downloads</string>
<string name="downloaded_bottom_sheet_add_to_queue">Add to queue</string>
<string name="downloaded_bottom_sheet_play_next">Play next</string>
<string name="downloaded_bottom_sheet_remove">Remove</string>
<string name="downloaded_bottom_sheet_remove_all">Remove all</string>
<string name="downloaded_bottom_sheet_shuffle">Shuffle</string>
<string name="empty_string" />
<string name="error_required">Required</string>
<string name="error_server_prefix">http or https prefix required</string>
@@ -73,23 +85,32 @@
<string name="filter_title_expanded">Filter Genres</string>
<string name="genre_catalogue_title">Genre Catalogue</string>
<string name="genre_catalogue_title_expanded">Browse Genres</string>
<string name="home_subtitle_best_of">Top songs of your favorite artists</string>
<string name="home_subtitle_made_for_you">Start mix from a song you liked</string>
<string name="home_subtitle_new_internet_radio_station">Add a new radio</string>
<string name="home_subtitle_new_podcast_channel">Add a new podcast channel</string>
<string name="home_subtitle_made_for_you">Start mix from a song you liked</string>
<string name="home_sync_starred_title">Looks like there are some starred tracks to sync</string>
<string name="home_sync_starred_subtitle">Downloading these tracks may involve significant data usage</string>
<string name="home_sync_starred_cancel">Cancel</string>
<string name="home_sync_starred_download">Download</string>
<string name="home_sync_starred_subtitle">Downloading these tracks may involve significant data usage</string>
<string name="home_sync_starred_title">Looks like there are some starred tracks to sync</string>
<string name="home_title_best_of">Best of</string>
<string name="home_title_discovery">Discovery</string>
<string name="home_title_discovery_shuffle_all_button">Shuffle all</string>
<string name="home_title_flashback">Flashback</string>
<string name="home_title_internet_radio_station">Internet radio stations</string>
<string name="home_title_last_played">Last played</string>
<string name="home_title_last_played_see_all_button">See all</string>
<string name="home_title_last_week">Last week</string>
<string name="home_title_made_for_you">Made for you</string>
<string name="home_title_most_played">Most played</string>
<string name="home_title_most_played_see_all_button">See all</string>
<string name="home_title_discovery">Discovery</string>
<string name="home_title_new_releases">New releases</string>
<string name="home_title_newest_podcasts">Newest podcasts</string>
<string name="home_title_podcast_channels">Channels</string>
<string name="home_title_podcast_channels_see_all_button">See all</string>
<string name="home_title_radio_station">Radio stations</string>
<string name="home_title_recently_added">Recently added</string>
<string name="home_title_recently_added_see_all_button">See all</string>
<string name="home_title_discovery_shuffle_all_button">Shuffle all</string>
<string name="home_title_shares">Shares</string>
<string name="home_title_starred_albums">★ Starred albums</string>
<string name="home_title_starred_albums_see_all_button">See all</string>
@@ -97,17 +118,16 @@
<string name="home_title_starred_artists_see_all_button">See all</string>
<string name="home_title_starred_tracks">★ Starred tracks</string>
<string name="home_title_starred_tracks_see_all_button">See all</string>
<string name="home_title_internet_radio_station">Internet radio stations</string>
<string name="home_title_podcast_channels_see_all_button">See all</string>
<string name="home_title_top_songs">Your top songs</string>
<string name="label_dot_separator" translatable="false"></string>
<string name="label_placeholder" translatable="false">--</string>
<string name="library_title_music_folder">Music folders</string>
<string name="library_title_album">Albums</string>
<string name="library_title_album_see_all_button">See all</string>
<string name="library_title_artist">Artists</string>
<string name="library_title_artist_see_all_button">See all</string>
<string name="library_title_genre">Genres</string>
<string name="library_title_genre_see_all_button">See all</string>
<string name="library_title_music_folder">Music folders</string>
<string name="library_title_playlist">Playlists</string>
<string name="library_title_playlist_see_all_button">See all</string>
<string name="login_empty">No server added</string>
@@ -117,11 +137,23 @@
<string name="menu_add_button">Add</string>
<string name="menu_download_all_button">Download all</string>
<string name="menu_download_label">Download</string>
<string name="menu_filter_all">All</string>
<string name="menu_filter_download">Downloaded</string>
<string name="menu_group_by_album">Album</string>
<string name="menu_group_by_artist">Artist</string>
<string name="menu_group_by_genre">Genre</string>
<string name="menu_group_by_track">Track</string>
<string name="menu_group_by_year">Year</string>
<string name="menu_home_label">Home</string>
<string name="menu_library_label">Library</string>
<string name="menu_search_button">Search</string>
<string name="menu_settings_button">Settings</string>
<string name="menu_sort_artist">Artist</string>
<string name="menu_sort_name">Name</string>
<string name="menu_sort_random">Random</string>
<string name="menu_sort_year">Year</string>
<string name="player_playback_speed">%1$.2fx</string>
<string name="player_queue_clean_all_button">Clean play queue</string>
<string name="player_server_priority">Server Priority</string>
<string name="playlist_catalogue_title">Playlist Catalogue</string>
<string name="playlist_catalogue_title_expanded">Browse Playlists</string>
@@ -135,32 +167,38 @@
<string name="playlist_editor_dialog_negative_button">Cancel</string>
<string name="playlist_editor_dialog_neutral_button">Delete</string>
<string name="playlist_editor_dialog_positive_button">Save</string>
<string name="playlist_editor_dialog_title">Create playlist</string>
<string name="playlist_editor_dialog_title">Edit playlist</string>
<string name="playlist_page_play_button">Play</string>
<string name="playlist_page_shuffle_button">Shuffle</string>
<string name="playlist_song_count">Playlist • %1$d songs</string>
<string name="podcast_channel_catalogue_title_expanded">Browse Channels</string>
<string name="podcast_bottom_sheet_add_to_queue">Add to queue</string>
<string name="podcast_bottom_sheet_delete">Delete</string>
<string name="podcast_bottom_sheet_download">Download</string>
<string name="podcast_bottom_sheet_go_to_channel">Go to channel</string>
<string name="podcast_bottom_sheet_play_next">Play next</string>
<string name="podcast_bottom_sheet_remove">Remove</string>
<string name="podcast_channel_catalogue_title">Channels</string>
<string name="podcast_channel_catalogue_title_expanded">Browse Channels</string>
<string name="podcast_channel_editor_dialog_hint_rss_url">RSS Url</string>
<string name="podcast_channel_editor_dialog_title">Podcast Channel</string>
<string name="podcast_channel_page_title_description_section">Description</string>
<string name="podcast_channel_page_title_episode_section">Episodes</string>
<string name="podcast_channel_page_title_no_episode_available">No episodes available</string>
<string name="podcast_channel_editor_dialog_hint_rss_url">RSS Url</string>
<string name="podcast_channel_editor_dialog_title">Podcast Channel</string>
<string name="podcast_release_date_duration_formatter">%1$s • %2$s</string>
<string name="podcast_episode_download_request_snackbar">Your request has been sent to the server</string>
<string name="podcast_info_empty_button">Click to hide the section\nThe effects will be visible on restart</string>
<string name="podcast_info_empty_subtitle">Once you add a channel, you\'ll find it here</string>
<string name="podcast_info_empty_title">No podcasts found!</string>
<string name="podcast_info_empty_button">Click to hide the section\nThe effects will be visible on restart</string>
<string name="podcast_release_date_duration_formatter">%1$s • %2$s</string>
<string name="radio_editor_dialog_hint_homepage_url">Radio Homepage URL</string>
<string name="radio_editor_dialog_hint_name">Radio Name</string>
<string name="radio_editor_dialog_hint_stream_url">Radio Stream URL</string>
<string name="radio_editor_dialog_hint_homepage_url">Radio Homepage URL</string>
<string name="radio_editor_dialog_negative_button">Cancel</string>
<string name="radio_editor_dialog_neutral_button">Delete</string>
<string name="radio_editor_dialog_positive_button">Save</string>
<string name="radio_editor_dialog_title">Internet Radio Station</string>
<string name="radio_station_info_empty_button">Click to hide the section\nThe effects will be visible on restart</string>
<string name="radio_station_info_empty_subtitle">Once you add a radio station, you\'ll find it here</string>
<string name="radio_station_info_empty_title">No stations found!</string>
<string name="radio_station_info_empty_button">Click to hide the section\nThe effects will be visible on restart</string>
<string name="rating_dialog_negative_button">Cancel</string>
<string name="rating_dialog_positive_button">Save</string>
<string name="rating_dialog_title">Rate</string>
@@ -181,28 +219,30 @@
<string name="server_unreachable_dialog_negative_button">Cancel</string>
<string name="server_unreachable_dialog_neutral_button">Go to login</string>
<string name="server_unreachable_dialog_positive_button">Continue anyway</string>
<string name="server_unreachable_dialog_title">Server unreachable</string>
<string name="server_unreachable_dialog_summary">The requested server is unavailable. If you choose to continue this dialog will not appear for the next hour.</string>
<string name="server_unreachable_dialog_title">Server unreachable</string>
<string name="settings_about_summary">Tempo is an open source and lightweight music client for Subsonic, designed and built natively for Android.</string>
<string name="settings_about_title">About</string>
<string name="settings_audio_transcode_download_format">Transcode format</string>
<string name="settings_audio_transcode_download_priority_summary">If enabled, Tempo will not force download the track with the transcode settings below.</string>
<string name="settings_audio_transcode_download_priority_title">Prioritize server settings used for streaming in downloads</string>
<string name="settings_audio_transcode_download_summary">If enabled, Tempo will download transcoded tracks.</string>
<string name="settings_audio_transcode_download_title">Download transcoded tracks</string>
<string name="settings_audio_transcode_download_format">Transcode format</string>
<string name="settings_audio_transcode_estimate_content_length_summary">If enabled, the server will be asked for the estimated duration of the track.</string>
<string name="settings_audio_transcode_estimate_content_length_title">Estimate content length</string>
<string name="settings_audio_transcode_priority_summary">If enabled, Tempo will not force stream the track with the transcode settings below.</string>
<string name="settings_audio_transcode_priority_title">Prioritize server transcode settings</string>
<string name="settings_audio_transcode_priority_toast">Priority on transcoding of track given to server</string>
<string name="settings_audio_transcode_format_download">Transcode format for downloads</string>
<string name="settings_audio_transcode_format_mobile">Transcode format in mobile</string>
<string name="settings_audio_transcode_format_wifi">Transcode format in Wi-Fi</string>
<string name="settings_audio_transcode_priority_summary">If enabled, Tempo will not force stream the track with the transcode settings below.</string>
<string name="settings_audio_transcode_priority_title">Prioritize server transcode settings</string>
<string name="settings_audio_transcode_priority_toast">Priority on transcoding of track given to server</string>
<string name="settings_buffering_strategy">Buffering strategy</string>
<string name="settings_buffering_strategy_summary">For the change to take effect you must manually restart the app.</string>
<string name="settings_covers_cache">Size of artwork cache</string>
<string name="settings_data_saving_mode_summary">In order to reduce data consumption, avoid downloading covers.</string>
<string name="settings_data_saving_mode_title">Limit mobile data usage</string>
<string name="settings_delete_download_storage_title">Delete saved items</string>
<string name="settings_delete_download_storage_summary">Proceeding will result in the irreversible deletion of all saved items.</string>
<string name="settings_delete_download_storage_title">Delete saved items</string>
<string name="settings_download_storage_title">Download storage</string>
<string name="settings_equalizer_summary">Adjust audio settings</string>
<string name="settings_equalizer_title">Equalizer</string>
@@ -213,37 +253,41 @@
<string name="settings_language">Language</string>
<string name="settings_logout_title">Log out</string>
<string name="settings_max_bitrate_download">Bitrate for downloads</string>
<string name="settings_max_bitrate_wifi">Bitrate in Wi-Fi</string>
<string name="settings_max_bitrate_mobile">Bitrate in mobile</string>
<string name="settings_max_bitrate_wifi">Bitrate in Wi-Fi</string>
<string name="settings_media_cache">Size of media file cache</string>
<string name="settings_music_directory">Show music directories</string>
<string name="settings_music_directory_summary">If enabled, show the music directory section. Please note that for folder navigation to work properly, the server must support this feature.</string>
<string name="settings_queue_syncing_title">Sync play queue for this user</string>
<string name="settings_queue_syncing_countdown">Sync timer</string>
<string name="settings_queue_syncing_summary">If enabled, the user will have the ability to save their play queue and will have the ability to load state when opening the application.</string>
<string name="settings_podcast">Show podcast</string>
<string name="settings_podcast_summary">If enabled, show the podcast section.</string>
<string name="settings_queue_syncing_countdown">Sync timer</string>
<string name="settings_queue_syncing_summary">If enabled, the user will have the ability to save their play queue and will have the ability to load state when opening the application.</string>
<string name="settings_queue_syncing_title">Sync play queue for this user</string>
<string name="settings_radio">Show radio</string>
<string name="settings_radio_summary">If enabled, show the radio section.</string>
<string name="settings_replay_gain">Set replay gain mode</string>
<string name="settings_rounded_corner">Rounded corners</string>
<string name="settings_rounded_corner_summary">If enabled, sets a curvature angle for all rendered covers. The changes will take effect on restart.</string>
<string name="settings_rounded_corner_size">Corners size</string>
<string name="settings_rounded_corner_size_summary">Sets the magnitude of the curvature angle.</string>
<string name="settings_rounded_corner_summary">If enabled, sets a curvature angle for all rendered covers. The changes will take effect on restart.</string>
<string name="settings_scan_title">Scan library</string>
<string name="settings_scrobble_title">Enable music scrobbling</string>
<string name="settings_share_title">Enable music sharing</string>
<string name="settings_sub_summary_scrobble">It\'s important to note that scrobbling also relies on the server being enabled to receive this data.</string>
<string name="settings_summary_replay_gain">Replay gain is a feature that allows you to adjust the volume level of audio tracks for a consistent listening experience. This setting is only effective if the track contains the necessary metadata.</string>
<string name="settings_summary_scrobble">Scrobbling is a feature that allows your device to send information about the songs you listen to the music server. This information helps create personalized recommendations based on your music preferences.</string>
<string name="settings_summary_share">Allows the user to share music via a link. The functionality must be supported and enabled server-side and is limited to individual tracks, albums and playlists.</string>
<string name="settings_summary_syncing">Returns the state of the play queue for this user. This includes the tracks in the play queue, the currently playing track, and the position within this track. The server must support this feature.</string>
<string name="settings_summary_transcoding">Priority given to the transcoding mode. If set to \"Direct play\" the bitrate of the file will not be changed.</string>
<string name="settings_summary_transcoding_estimate_content_length">When the file is transcoded on the fly, the client usually does not show the track length. It is possible to request the servers that support the functionality to estimate the duration of the track being played, but the response times may take longer.</string>
<string name="settings_summary_transcoding_download">Download transcoded media. If enabled, the download endpoint will not be used, but the following settings. \n\n If \"Transcode format\" is set to \"Direct play\" the bitrate of the file will not be changed.</string>
<string name="settings_summary_transcoding_estimate_content_length">When the file is transcoded on the fly, the client usually does not show the track length. It is possible to request the servers that support the functionality to estimate the duration of the track being played, but the response times may take longer.</string>
<string name="settings_sync_starred_tracks_for_offline_use_summary">If enabled, starred tracks will be downloaded for offline use.</string>
<string name="settings_sync_starred_tracks_for_offline_use_title">Sync starred tracks for offline use</string>
<string name="settings_theme">Theme</string>
<string name="settings_title_data">Data</string>
<string name="settings_title_general">General</string>
<string name="settings_title_replay_gain">Replay Gain</string>
<string name="settings_title_scrobble">Scrobble</string>
<string name="settings_title_share">Share</string>
<string name="settings_title_syncing">Syncing</string>
<string name="settings_title_transcoding">Transcoding</string>
@@ -252,16 +296,17 @@
<string name="settings_transcoded_download">Transcoded download</string>
<string name="settings_version_summary" translatable="false">3.1.0</string>
<string name="settings_version_title">Version</string>
<string name="settings_wifi_only_title">Stream via Wi-Fi only alert</string>
<string name="settings_wifi_only_summary">Ask for user confirmation before streaming over mobile network.</string>
<string name="settings_wifi_only_title">Stream via Wi-Fi only alert</string>
<string name="share_bottom_sheet_copy_link">Copy link</string>
<string name="share_bottom_sheet_delete">Delete share</string>
<string name="share_bottom_sheet_update">Update share</string>
<string name="share_subtitle_item">Expiration date: %1$s</string>
<string name="share_update_dialog_negative_button">Cancel</string>
<string name="share_update_dialog_positive_button">Save</string>
<string name="share_unsupported_error">Sharing is not supported or not enabled</string>
<string name="share_update_dialog_hint_description">Description</string>
<string name="share_update_dialog_hint_expiration_date">Expiration date</string>
<string name="share_update_dialog_negative_button">Cancel</string>
<string name="share_update_dialog_positive_button">Save</string>
<string name="share_update_dialog_title">Share</string>
<string name="song_bottom_sheet_add_to_playlist">Add to playlist</string>
<string name="song_bottom_sheet_add_to_queue">Add to queue</string>
@@ -270,11 +315,11 @@
<string name="song_bottom_sheet_error_retrieving_artist">Error retrieving artist</string>
<string name="song_bottom_sheet_go_to_album">Go to album</string>
<string name="song_bottom_sheet_go_to_artist">Go to artist</string>
<string name="song_bottom_sheet_share">Share</string>
<string name="song_bottom_sheet_instant_mix">Instant mix</string>
<string name="song_bottom_sheet_play_next">Play next</string>
<string name="song_bottom_sheet_rate">Rate</string>
<string name="song_bottom_sheet_remove">Remove</string>
<string name="song_bottom_sheet_share">Share</string>
<string name="song_list_page_downloaded">Downloaded</string>
<string name="song_list_page_most_played">Most played tracks</string>
<string name="song_list_page_recently_added">Recently added tracks</string>
@@ -288,62 +333,30 @@
<string name="starred_sync_dialog_positive_button">Continue and download</string>
<string name="starred_sync_dialog_summary">Downloading starry tracks may require a large amount of data.</string>
<string name="starred_sync_dialog_title">Sync starred tracks</string>
<string name="undraw_url">https://undraw.co/</string>
<string name="undraw_page">unDraw</string>
<string name="undraw_thanks">A special thanks goes to unDraw without whose illustrations we could not have made this application more beautiful.</string>
<string name="home_title_radio_station">Radio stations</string>
<string name="home_title_last_week">Last week</string>
<string name="home_title_top_songs">Your top songs</string>
<string name="home_title_new_releases">New releases</string>
<string name="home_title_best_of">Best of</string>
<string name="home_subtitle_best_of">Top songs of your favorite artists</string>
<string name="home_title_newest_podcasts">Newest podcasts</string>
<string name="home_title_podcast_channels">Channels</string>
<string name="artist_adapter_radio_station_starting">Searching…</string>
<string name="podcast_bottom_sheet_go_to_channel">Go to channel</string>
<string name="podcast_bottom_sheet_delete">Delete</string>
<string name="podcast_bottom_sheet_remove">Remove</string>
<string name="podcast_bottom_sheet_download">Download</string>
<string name="podcast_bottom_sheet_add_to_queue">Add to queue</string>
<string name="podcast_bottom_sheet_play_next">Play next</string>
<string name="menu_sort_year">Year</string>
<string name="menu_sort_artist">Artist</string>
<string name="menu_sort_name">Name</string>
<string name="menu_sort_random">Random</string>
<string name="description_empty_title">No description available</string>
<string name="menu_filter_download">Downloaded</string>
<string name="menu_filter_all">All</string>
<string name="menu_group_by_track">Track</string>
<string name="menu_group_by_album">Album</string>
<string name="menu_group_by_artist">Artist</string>
<string name="menu_group_by_genre">Genre</string>
<string name="menu_group_by_year">Year</string>
<string name="downloaded_bottom_sheet_shuffle">Shuffle</string>
<string name="downloaded_bottom_sheet_play_next">Play next</string>
<string name="downloaded_bottom_sheet_add_to_queue">Add to queue</string>
<string name="downloaded_bottom_sheet_remove">Remove</string>
<string name="downloaded_bottom_sheet_remove_all">Remove all</string>
<string name="track_info_dialog_positive_button">OK</string>
<string name="track_info_dialog_title">Track info</string>
<string name="track_info_title">Title</string>
<string name="track_info_album">Album</string>
<string name="track_info_artist">Artist</string>
<string name="track_info_track_number">Track number</string>
<string name="track_info_year">Year</string>
<string name="track_info_genre">Genre</string>
<string name="track_info_size">Size</string>
<string name="track_info_bitrate">Bitrate</string>
<string name="track_info_content_type">Content Type</string>
<string name="track_info_dialog_positive_button">OK</string>
<string name="track_info_dialog_title">Track info</string>
<string name="track_info_disc_number">Disc number</string>
<string name="track_info_duration">Duration</string>
<string name="track_info_genre">Genre</string>
<string name="track_info_path">Path</string>
<string name="track_info_size">Size</string>
<string name="track_info_suffix">Suffix</string>
<string name="track_info_summary_downloaded_file">The file has been downloaded using the Subsonic APIs. The codec and bitrate of the file remain unchanged from the source file.</string>
<string name="track_info_summary_full_transcode">The application will request the server to transcode the file and modify its bitrate. The user requested codec is %1$s, with a bitrate of %2$s. Any potential changes to the codec and bitrate of the file in the chosen format will be handled by the server, which may or may not support the operation.</string>
<string name="track_info_summary_original_file">The application will only read the original file as provided by the server. The app will explicitly request the server for the untranscoded file with the bitrate of the original source.</string>
<string name="track_info_summary_server_prioritized">The quality of the file to be played is left up to the server\'s decision. The app will not enforce the choice of codec and bitrate for any potential transcoding.</string>
<string name="track_info_summary_transcoding_bitrate">The application will request the server to modify the bitrate of the file. The user requested a bitrate of %1$s, while the codec of the source file will remain the same. Any changes to the bitrate of the file in the chosen format will be done by the server, which may or may not support the operation.</string>
<string name="track_info_summary_transcoding_codec">The application will request the server to transcode the file. The requested codec by the user is %1$s, while the bitrate will be the same as the source file. The potential transcoding of the file into the chosen format is dependent on the server, as it may or may not support the operation.</string>
<string name="track_info_title">Title</string>
<string name="track_info_track_number">Track number</string>
<string name="track_info_transcoded_content_type">Transcoded content type</string>
<string name="track_info_transcoded_suffix">Transcoded suffix</string>
<string name="track_info_duration">Duration</string>
<string name="track_info_bitrate">Bitrate</string>
<string name="track_info_path">Path</string>
<string name="track_info_disc_number">Disc number</string>
<string name="track_info_summary_downloaded_file">The file has been downloaded using the Subsonic APIs. The codec and bitrate of the file remain unchanged from the source file.</string>
<string name="track_info_summary_server_prioritized">The quality of the file to be played is left up to the server\'s decision. The app will not enforce the choice of codec and bitrate for any potential transcoding.</string>
<string name="track_info_summary_original_file">The application will only read the original file as provided by the server. The app will explicitly request the server for the untranscoded file with the bitrate of the original source.</string>
<string name="track_info_summary_transcoding_codec">The application will request the server to transcode the file. The requested codec by the user is %1$s, while the bitrate will be the same as the source file. The potential transcoding of the file into the chosen format is dependent on the server, as it may or may not support the operation.</string>
<string name="track_info_summary_transcoding_bitrate">The application will request the server to modify the bitrate of the file. The user requested a bitrate of %1$s, while the codec of the source file will remain the same. Any changes to the bitrate of the file in the chosen format will be done by the server, which may or may not support the operation.</string>
<string name="track_info_summary_full_transcode">The application will request the server to transcode the file and modify its bitrate. The user requested codec is %1$s, with a bitrate of %2$s. Any potential changes to the codec and bitrate of the file in the chosen format will be handled by the server, which may or may not support the operation.</string>
</resources>
<string name="track_info_year">Year</string>
<string name="undraw_page">unDraw</string>
<string name="undraw_thanks">A special thanks goes to unDraw without whose illustrations we could not have made this application more beautiful.</string>
<string name="undraw_url">https://undraw.co/</string>
</resources>

View File

@@ -102,6 +102,16 @@
android:summary="@string/settings_sync_starred_tracks_for_offline_use_summary"
android:key="sync_starred_tracks_for_offline_use" />
<ListPreference
app:defaultValue="1"
app:dialogTitle="@string/settings_buffering_strategy"
app:entries="@array/buffering_strategy_titles"
app:entryValues="@array/buffering_strategy_values"
app:key="buffering_strategy"
app:title="@string/settings_buffering_strategy"
app:summary="@string/settings_buffering_strategy_summary"
app:useSimpleSummaryProvider="false" />
<Preference
android:key="download_storage"
app:title="@string/settings_download_storage_title" />
@@ -222,6 +232,22 @@
</PreferenceCategory>
<PreferenceCategory app:title="@string/settings_title_scrobble">
<Preference
app:selectable="false"
app:summary="@string/settings_summary_scrobble" />
<Preference
app:selectable="false"
app:summary="@string/settings_sub_summary_scrobble" />
<SwitchPreference
android:title="@string/settings_scrobble_title"
android:defaultValue="true"
android:key="scrobbling" />
</PreferenceCategory>
<PreferenceCategory app:title="@string/settings_title_share">
<Preference
app:selectable="false"

View File

@@ -2,4 +2,5 @@
<locale-config xmlns:android="http://schemas.android.com/apk/res/android">
<locale android:name="en"/> <!-- English -->
<locale android:name="de-DE"/> <!-- German -->
</locale-config>
<locale android:name="fr-FR"/> <!-- French -->
</locale-config>

View File

@@ -0,0 +1,13 @@
<?xml version="1.0" encoding="utf-8"?>
<network-security-config>
<base-config cleartextTrafficPermitted="true">
<trust-anchors>
<certificates src="system" />
</trust-anchors>
</base-config>
<debug-overrides cleartextTrafficPermitted="true">
<trust-anchors>
<certificates src="user" />
</trust-anchors>
</debug-overrides>
</network-security-config>

View File

@@ -19,6 +19,7 @@ import com.cappielloantonio.tempo.R
import com.cappielloantonio.tempo.ui.activity.MainActivity
import com.cappielloantonio.tempo.util.Constants
import com.cappielloantonio.tempo.util.DownloadUtil
import com.cappielloantonio.tempo.util.Preferences
import com.cappielloantonio.tempo.util.ReplayGainUtil
import com.google.android.gms.cast.framework.CastContext
import com.google.android.gms.common.ConnectionResult
@@ -208,7 +209,7 @@ class MediaService : MediaLibraryService(), SessionAvailabilityListener {
.setAudioAttributes(AudioAttributes.DEFAULT, true)
.setHandleAudioBecomingNoisy(true)
.setWakeMode(C.WAKE_MODE_NETWORK)
// .setLoadControl(initializeLoadControl())
.setLoadControl(initializeLoadControl())
.build()
}
@@ -296,8 +297,8 @@ class MediaService : MediaLibraryService(), SessionAvailabilityListener {
private fun initializeLoadControl(): DefaultLoadControl {
return DefaultLoadControl.Builder()
.setBufferDurationsMs(
60_000,
120_000,
(DefaultLoadControl.DEFAULT_MIN_BUFFER_MS * Preferences.getBufferingStrategy()).toInt(),
(DefaultLoadControl.DEFAULT_MAX_BUFFER_MS * Preferences.getBufferingStrategy()).toInt(),
DefaultLoadControl.DEFAULT_BUFFER_FOR_PLAYBACK_MS,
DefaultLoadControl.DEFAULT_BUFFER_FOR_PLAYBACK_AFTER_REBUFFER_MS
)

View File

@@ -4,7 +4,7 @@ buildscript {
mavenCentral()
}
dependencies {
classpath 'com.android.tools.build:gradle:8.1.0'
classpath 'com.android.tools.build:gradle:8.1.2'
classpath 'org.jetbrains.kotlin:kotlin-gradle-plugin:1.8.0'
}
}