mirror of
https://gitlab.com/ultrasonic/ultrasonic.git
synced 2025-07-19 18:01:58 +03:00
Compare commits
32 Commits
e284cd1fa1
...
4a5f7d67a0
Author | SHA1 | Date | |
---|---|---|---|
|
4a5f7d67a0 | ||
|
9be6c8d371 | ||
|
5a4989186e | ||
|
eb380b9af9 | ||
|
01124c8ecf | ||
|
6a97636c7a | ||
|
53ea17d2b9 | ||
|
a1e339f850 | ||
|
4809317c63 | ||
|
c5c0497716 | ||
|
79ac73020b | ||
|
d9dfef4016 | ||
|
3bd3607220 | ||
|
e35a33edde | ||
|
c1013f6b80 | ||
|
21a27c691d | ||
|
25f3ff0bd3 | ||
|
4feb84bd83 | ||
|
4c049671db | ||
|
3a1251dd2a | ||
|
8dd7758bc6 | ||
|
296308cebf | ||
|
45ca0966fd | ||
|
77d3f8c11b | ||
|
7a453dbd30 | ||
|
0a6a12c70a | ||
|
448fdb70b0 | ||
|
5e4ec56ae7 | ||
|
8c42700676 | ||
|
22fda501f4 | ||
|
556d3bb90d | ||
|
4e9cea87a8 |
@ -74,7 +74,9 @@ Unit Tests:
|
|||||||
|
|
||||||
Assemble Release:
|
Assemble Release:
|
||||||
stage: Build
|
stage: Build
|
||||||
script: ./gradlew assembleRelease
|
script:
|
||||||
|
- sed -i 's/applicationId \"org.moire.ultrasonic\"/applicationId "org.moire.ultrasonic.gitlab"/' ultrasonic/build.gradle
|
||||||
|
- ./gradlew assembleRelease
|
||||||
artifacts:
|
artifacts:
|
||||||
name: ultrasonic-release-unsigned-${CI_COMMIT_SHA}
|
name: ultrasonic-release-unsigned-${CI_COMMIT_SHA}
|
||||||
paths:
|
paths:
|
||||||
|
10
.gitlab/merge_request_templates/Release.md
Normal file
10
.gitlab/merge_request_templates/Release.md
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
#### Before merge:
|
||||||
|
- [ ] MR is targetting the master branch
|
||||||
|
- [ ] **Squash commits must be disabled!**
|
||||||
|
- [ ] RoboTests (5 physical, 10 virtual) on a Release apk return no errors
|
||||||
|
- [ ] Release notes present
|
||||||
|
|
||||||
|
#### After merge
|
||||||
|
- [ ] ``git fetch``
|
||||||
|
- [ ] Create an annotated and signed tag: ``git tag -sa``
|
||||||
|
- [ ] Push the tag to git:``git push --tags``
|
@ -52,7 +52,11 @@ style:
|
|||||||
active: true
|
active: true
|
||||||
ForbiddenComment:
|
ForbiddenComment:
|
||||||
active: true
|
active: true
|
||||||
values: ['FIXME:', 'STOPSHIP:']
|
comments:
|
||||||
|
- reason: 'Forbidden FIXME todo marker in comment, please fix the problem.'
|
||||||
|
value: 'FIXME:'
|
||||||
|
- reason: 'Forbidden STOPSHIP todo marker in comment, please address the problem before shipping the code.'
|
||||||
|
value: 'STOPSHIP:'
|
||||||
WildcardImport:
|
WildcardImport:
|
||||||
active: true
|
active: true
|
||||||
MaxLineLength:
|
MaxLineLength:
|
||||||
|
@ -21,5 +21,5 @@ android.nonFinalResIds=true
|
|||||||
org.gradle.unsafe.configuration-cache=true
|
org.gradle.unsafe.configuration-cache=true
|
||||||
|
|
||||||
# TODO Renable on day (check that Retrofit, Jackson, and Imageloader are working)
|
# TODO Renable on day (check that Retrofit, Jackson, and Imageloader are working)
|
||||||
android.enableR8.fullMode=false
|
android.enableR8.fullMode=true
|
||||||
|
|
||||||
|
@ -3,11 +3,11 @@
|
|||||||
gradle = "8.1.1"
|
gradle = "8.1.1"
|
||||||
|
|
||||||
navigation = "2.5.3"
|
navigation = "2.5.3"
|
||||||
gradlePlugin = "8.0.1"
|
gradlePlugin = "8.0.2"
|
||||||
androidxcore = "1.10.1"
|
androidxcore = "1.10.1"
|
||||||
ktlint = "0.43.2"
|
ktlint = "0.43.2"
|
||||||
ktlintGradle = "11.3.2"
|
ktlintGradle = "11.3.2"
|
||||||
detekt = "1.22.0"
|
detekt = "1.23.0"
|
||||||
preferences = "1.2.0"
|
preferences = "1.2.0"
|
||||||
media3 = "1.0.2"
|
media3 = "1.0.2"
|
||||||
|
|
||||||
@ -31,7 +31,7 @@ picasso = "2.8"
|
|||||||
junit4 = "4.13.2"
|
junit4 = "4.13.2"
|
||||||
junit5 = "5.9.3"
|
junit5 = "5.9.3"
|
||||||
mockito = "5.3.1"
|
mockito = "5.3.1"
|
||||||
mockitoKotlin = "4.1.0"
|
mockitoKotlin = "5.0.0"
|
||||||
kluent = "1.73"
|
kluent = "1.73"
|
||||||
apacheCodecs = "1.15"
|
apacheCodecs = "1.15"
|
||||||
robolectric = "4.10.3"
|
robolectric = "4.10.3"
|
||||||
|
@ -14,7 +14,7 @@ android {
|
|||||||
|
|
||||||
minSdkVersion versions.minSdk
|
minSdkVersion versions.minSdk
|
||||||
targetSdkVersion versions.targetSdk
|
targetSdkVersion versions.targetSdk
|
||||||
resConfigs 'cs', 'de', 'en', 'es', 'fr', 'gl', 'hu', 'it', 'ja', 'nb-rNO', 'nl', 'pl', 'pt', 'pt-rBR', 'ru', 'zh-rCN', 'zh-rTW'
|
resourceConfigurations += ['cs', 'de', 'en', 'es', 'fr', 'gl', 'hu', 'it', 'ja', 'nb-rNO', 'nl', 'pl', 'pt', 'pt-rBR', 'ru', 'zh-rCN', 'zh-rTW']
|
||||||
}
|
}
|
||||||
|
|
||||||
bundle.language.enableSplit = false
|
bundle.language.enableSplit = false
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
#### From Jackson
|
#### From Jackson
|
||||||
|
|
||||||
-keepattributes *Annotation*,EnclosingMethod,Signature
|
-keepattributes *Annotation*,EnclosingMethod,Signature
|
||||||
-keepnames class com.fasterxml.jackson.** {
|
-keepnames class com.fasterxml.jackson.** {
|
||||||
*;
|
*;
|
||||||
|
@ -1,8 +1,14 @@
|
|||||||
-dontobfuscate
|
-dontobfuscate
|
||||||
|
|
||||||
### Don't remove subsonic api serializers/entities
|
### Don't remove subsonic api serializers/entities
|
||||||
-keep class org.moire.ultrasonic.api.subsonic.response.** { *; }
|
-keep class org.moire.ultrasonic.api.subsonic.** { *; }
|
||||||
-keep class org.moire.ultrasonic.api.subsonic.models.** { *; }
|
|
||||||
|
## Don't remove the domain models
|
||||||
|
-keep class org.moire.ultrasonic.domain.** { *; }
|
||||||
|
|
||||||
|
## Don't remove the imageloader
|
||||||
|
-keep class org.moire.ultrasonic.imageloader.** { *; }
|
||||||
|
-keep class org.moire.ultrasonic.provider.AlbumArtContentProvider { *; }
|
||||||
|
|
||||||
## Don't remove NowPlayingFragment
|
## Don't remove NowPlayingFragment
|
||||||
-keep class org.moire.ultrasonic.fragment.NowPlayingFragment { *; }
|
-keep class org.moire.ultrasonic.fragment.NowPlayingFragment { *; }
|
||||||
|
@ -58,7 +58,7 @@ public abstract class BackgroundTask<T> implements ProgressListener
|
|||||||
|
|
||||||
protected String getErrorMessage(Throwable error)
|
protected String getErrorMessage(Throwable error)
|
||||||
{
|
{
|
||||||
return CommunicationError.getErrorMessage(error, activity);
|
return CommunicationError.getErrorMessage(error);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -286,7 +286,8 @@ class NavigationActivity : AppCompatActivity() {
|
|||||||
@RequiresApi(Build.VERSION_CODES.N_MR1)
|
@RequiresApi(Build.VERSION_CODES.N_MR1)
|
||||||
private fun setupAppShortcut() {
|
private fun setupAppShortcut() {
|
||||||
|
|
||||||
// TODO: Handle adding shortcut only if player is ready to add songs (has any servers setup)
|
if (UApp.instance!!.isFirstRun)
|
||||||
|
return
|
||||||
val shortcutIntent = Intent(this, NavigationActivity::class.java).apply {
|
val shortcutIntent = Intent(this, NavigationActivity::class.java).apply {
|
||||||
action = Constants.INTENT_PLAY_RANDOM_SONGS
|
action = Constants.INTENT_PLAY_RANDOM_SONGS
|
||||||
}
|
}
|
||||||
@ -398,7 +399,7 @@ class NavigationActivity : AppCompatActivity() {
|
|||||||
if (intent == null) return
|
if (intent == null) return
|
||||||
|
|
||||||
if (intent.action == Constants.INTENT_PLAY_RANDOM_SONGS) {
|
if (intent.action == Constants.INTENT_PLAY_RANDOM_SONGS) {
|
||||||
val currentFragment = host!!.childFragmentManager.fragments.last()
|
val currentFragment = host?.childFragmentManager?.fragments?.last() ?: return
|
||||||
val service = MusicServiceFactory.getMusicService()
|
val service = MusicServiceFactory.getMusicService()
|
||||||
val musicDirectory = service.getRandomSongs(Settings.maxSongs)
|
val musicDirectory = service.getRandomSongs(Settings.maxSongs)
|
||||||
val downloadHandler: DownloadHandler by inject()
|
val downloadHandler: DownloadHandler by inject()
|
||||||
|
@ -142,13 +142,15 @@ class TrackViewHolder(val view: View) :
|
|||||||
|
|
||||||
// Listen for rating updates
|
// Listen for rating updates
|
||||||
rxBusSubscription!! += RxBus.ratingPublishedObservable.subscribe {
|
rxBusSubscription!! += RxBus.ratingPublishedObservable.subscribe {
|
||||||
// Ignore updates which are not for the current song
|
launch(Dispatchers.Main) {
|
||||||
if (it.id != song.id) return@subscribe
|
// Ignore updates which are not for the current song
|
||||||
|
if (it.id != song.id) return@launch
|
||||||
|
|
||||||
if (it.rating is HeartRating) {
|
if (it.rating is HeartRating) {
|
||||||
updateSingleStar(it.rating.isHeart)
|
updateSingleStar(it.rating.isHeart)
|
||||||
} else if (it.rating is StarRating) {
|
} else if (it.rating is StarRating) {
|
||||||
updateFiveStars(it.rating.starRating.toInt())
|
updateFiveStars(it.rating.starRating.toInt())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -401,7 +401,7 @@ class EditServerFragment : Fragment(), OnBackPressedHandler {
|
|||||||
Timber.w(exception)
|
Timber.w(exception)
|
||||||
ErrorDialog.Builder(requireContext())
|
ErrorDialog.Builder(requireContext())
|
||||||
.setTitle(R.string.error_label)
|
.setTitle(R.string.error_label)
|
||||||
.setMessage(getErrorMessage(exception, context))
|
.setMessage(getErrorMessage(exception))
|
||||||
.show()
|
.show()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -78,6 +78,7 @@ import org.moire.ultrasonic.R
|
|||||||
import org.moire.ultrasonic.adapters.BaseAdapter
|
import org.moire.ultrasonic.adapters.BaseAdapter
|
||||||
import org.moire.ultrasonic.adapters.TrackViewBinder
|
import org.moire.ultrasonic.adapters.TrackViewBinder
|
||||||
import org.moire.ultrasonic.api.subsonic.models.AlbumListType
|
import org.moire.ultrasonic.api.subsonic.models.AlbumListType
|
||||||
|
import org.moire.ultrasonic.app.UApp
|
||||||
import org.moire.ultrasonic.audiofx.EqualizerController
|
import org.moire.ultrasonic.audiofx.EqualizerController
|
||||||
import org.moire.ultrasonic.data.ActiveServerProvider.Companion.isOffline
|
import org.moire.ultrasonic.data.ActiveServerProvider.Companion.isOffline
|
||||||
import org.moire.ultrasonic.data.ActiveServerProvider.Companion.shouldUseId3Tags
|
import org.moire.ultrasonic.data.ActiveServerProvider.Companion.shouldUseId3Tags
|
||||||
@ -662,7 +663,6 @@ class PlayerFragment :
|
|||||||
parentId = track.parent,
|
parentId = track.parent,
|
||||||
isAlbum = true
|
isAlbum = true
|
||||||
)
|
)
|
||||||
|
|
||||||
findNavController().navigate(action)
|
findNavController().navigate(action)
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
@ -822,16 +822,16 @@ class PlayerFragment :
|
|||||||
musicService.createPlaylist(null, playlistName, entries)
|
musicService.createPlaylist(null, playlistName, entries)
|
||||||
}.invokeOnCompletion {
|
}.invokeOnCompletion {
|
||||||
if (it == null || it is CancellationException) {
|
if (it == null || it is CancellationException) {
|
||||||
Util.toast(context, R.string.download_playlist_done)
|
Util.toast(UApp.applicationContext(), R.string.download_playlist_done)
|
||||||
} else {
|
} else {
|
||||||
Timber.e(it, "Exception has occurred in savePlaylistInBackground")
|
Timber.e(it, "Exception has occurred in savePlaylistInBackground")
|
||||||
val msg = String.format(
|
val msg = String.format(
|
||||||
Locale.ROOT,
|
Locale.ROOT,
|
||||||
"%s %s",
|
"%s %s",
|
||||||
resources.getString(R.string.download_playlist_error),
|
resources.getString(R.string.download_playlist_error),
|
||||||
CommunicationError.getErrorMessage(it, context)
|
CommunicationError.getErrorMessage(it)
|
||||||
)
|
)
|
||||||
Util.toast(context, msg)
|
Util.toast(UApp.applicationContext(), msg)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -351,13 +351,11 @@ open class TrackCollectionFragment(
|
|||||||
|
|
||||||
val isArtist = navArgs.isArtist
|
val isArtist = navArgs.isArtist
|
||||||
|
|
||||||
// Need a valid id to download stuff
|
// Need a valid id to recurse sub directories stuff
|
||||||
val id = navArgs.id ?: return
|
if (hasSubFolders && navArgs.id != null) {
|
||||||
|
|
||||||
if (hasSubFolders) {
|
|
||||||
downloadHandler.fetchTracksAndAddToController(
|
downloadHandler.fetchTracksAndAddToController(
|
||||||
fragment = this,
|
fragment = this,
|
||||||
id = id,
|
id = navArgs.id!!,
|
||||||
append = append,
|
append = append,
|
||||||
autoPlay = !append,
|
autoPlay = !append,
|
||||||
shuffle = shuffle,
|
shuffle = shuffle,
|
||||||
|
@ -505,7 +505,7 @@ class JukeboxMediaPlayer : JukeboxUnimplementedFunctions(), Player {
|
|||||||
listeners.queueEvent(Player.EVENT_MEDIA_ITEM_TRANSITION) {
|
listeners.queueEvent(Player.EVENT_MEDIA_ITEM_TRANSITION) {
|
||||||
it.onMediaItemTransition(
|
it.onMediaItemTransition(
|
||||||
currentMedia,
|
currentMedia,
|
||||||
Player.MEDIA_ITEM_TRANSITION_REASON_SEEK
|
Player.MEDIA_ITEM_TRANSITION_REASON_AUTO
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -14,6 +14,6 @@ data class PlaybackState(
|
|||||||
var repeatMode: Int = 0
|
var repeatMode: Int = 0
|
||||||
) : Serializable {
|
) : Serializable {
|
||||||
companion object {
|
companion object {
|
||||||
const val serialVersionUID = -293487987L
|
private const val serialVersionUID = -293487987L
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -46,7 +46,7 @@ class DownloadHandler(
|
|||||||
var successString: String? = null
|
var successString: String? = null
|
||||||
|
|
||||||
// Launch the Job
|
// Launch the Job
|
||||||
executeTaskWithToast(fragment, {
|
executeTaskWithToast({
|
||||||
val tracksToDownload: List<Track> = tracks
|
val tracksToDownload: List<Track> = tracks
|
||||||
?: getTracksFromServer(isArtist, id!!, isDirectory, name, isShare)
|
?: getTracksFromServer(isArtist, id!!, isDirectory, name, isShare)
|
||||||
|
|
||||||
@ -104,7 +104,7 @@ class DownloadHandler(
|
|||||||
) {
|
) {
|
||||||
var successString: String? = null
|
var successString: String? = null
|
||||||
// Launch the Job
|
// Launch the Job
|
||||||
executeTaskWithToast(fragment, {
|
executeTaskWithToast({
|
||||||
val songs: MutableList<Track> =
|
val songs: MutableList<Track> =
|
||||||
getTracksFromServer(isArtist, id, isDirectory, name, isShare)
|
getTracksFromServer(isArtist, id, isDirectory, name, isShare)
|
||||||
|
|
||||||
|
@ -20,6 +20,7 @@ import kotlinx.coroutines.CoroutineExceptionHandler
|
|||||||
import org.moire.ultrasonic.R
|
import org.moire.ultrasonic.R
|
||||||
import org.moire.ultrasonic.api.subsonic.ApiNotSupportedException
|
import org.moire.ultrasonic.api.subsonic.ApiNotSupportedException
|
||||||
import org.moire.ultrasonic.api.subsonic.SubsonicRESTException
|
import org.moire.ultrasonic.api.subsonic.SubsonicRESTException
|
||||||
|
import org.moire.ultrasonic.app.UApp
|
||||||
import org.moire.ultrasonic.subsonic.getLocalizedErrorMessage
|
import org.moire.ultrasonic.subsonic.getLocalizedErrorMessage
|
||||||
import timber.log.Timber
|
import timber.log.Timber
|
||||||
|
|
||||||
@ -46,14 +47,14 @@ object CommunicationError {
|
|||||||
|
|
||||||
ErrorDialog(
|
ErrorDialog(
|
||||||
context = context,
|
context = context,
|
||||||
message = getErrorMessage(error, context)
|
message = getErrorMessage(error)
|
||||||
).show()
|
).show()
|
||||||
}
|
}
|
||||||
|
|
||||||
@JvmStatic
|
@JvmStatic
|
||||||
@Suppress("ReturnCount")
|
@Suppress("ReturnCount")
|
||||||
fun getErrorMessage(error: Throwable, context: Context?): String {
|
fun getErrorMessage(error: Throwable): String {
|
||||||
if (context == null) return "Couldn't get Error message, Context is null"
|
val context = UApp.applicationContext()
|
||||||
if (error is IOException && !Util.hasUsableNetwork()) {
|
if (error is IOException && !Util.hasUsableNetwork()) {
|
||||||
return context.resources.getString(R.string.background_task_no_network)
|
return context.resources.getString(R.string.background_task_no_network)
|
||||||
} else if (error is FileNotFoundException) {
|
} else if (error is FileNotFoundException) {
|
||||||
|
@ -17,6 +17,7 @@ import kotlinx.coroutines.Dispatchers
|
|||||||
import kotlinx.coroutines.Job
|
import kotlinx.coroutines.Job
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
import org.moire.ultrasonic.R
|
import org.moire.ultrasonic.R
|
||||||
|
import org.moire.ultrasonic.app.UApp
|
||||||
import timber.log.Timber
|
import timber.log.Timber
|
||||||
|
|
||||||
object CoroutinePatterns {
|
object CoroutinePatterns {
|
||||||
@ -30,7 +31,6 @@ object CoroutinePatterns {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun CoroutineScope.executeTaskWithToast(
|
fun CoroutineScope.executeTaskWithToast(
|
||||||
fragment: Fragment,
|
|
||||||
task: suspend CoroutineScope.() -> Unit,
|
task: suspend CoroutineScope.() -> Unit,
|
||||||
successString: () -> String?
|
successString: () -> String?
|
||||||
): Job {
|
): Job {
|
||||||
@ -40,7 +40,7 @@ fun CoroutineScope.executeTaskWithToast(
|
|||||||
// Setup a handler when the job is done
|
// Setup a handler when the job is done
|
||||||
job.invokeOnCompletion {
|
job.invokeOnCompletion {
|
||||||
val toastString = if (it != null && it !is CancellationException) {
|
val toastString = if (it != null && it !is CancellationException) {
|
||||||
CommunicationError.getErrorMessage(it, fragment.context)
|
CommunicationError.getErrorMessage(it)
|
||||||
} else {
|
} else {
|
||||||
successString()
|
successString()
|
||||||
}
|
}
|
||||||
@ -49,7 +49,7 @@ fun CoroutineScope.executeTaskWithToast(
|
|||||||
if (toastString == null) return@invokeOnCompletion
|
if (toastString == null) return@invokeOnCompletion
|
||||||
|
|
||||||
launch(Dispatchers.Main) {
|
launch(Dispatchers.Main) {
|
||||||
Util.toast(fragment.context, toastString)
|
Util.toast(UApp.applicationContext(), toastString)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -62,7 +62,7 @@ fun CoroutineScope.executeTaskWithModalDialog(
|
|||||||
successString: () -> String
|
successString: () -> String
|
||||||
) {
|
) {
|
||||||
// Create the job
|
// Create the job
|
||||||
val job = executeTaskWithToast(fragment, task, successString)
|
val job = executeTaskWithToast(task, successString)
|
||||||
|
|
||||||
// Create the dialog
|
// Create the dialog
|
||||||
val builder = InfoDialog.Builder(fragment.requireContext())
|
val builder = InfoDialog.Builder(fragment.requireContext())
|
||||||
|
@ -7,7 +7,7 @@
|
|||||||
android:orientation="horizontal"
|
android:orientation="horizontal"
|
||||||
android:padding="6dp" >
|
android:padding="6dp" >
|
||||||
|
|
||||||
<Button
|
<com.google.android.material.button.MaterialButton
|
||||||
android:id="@+id/select_album_select"
|
android:id="@+id/select_album_select"
|
||||||
style="@style/Widget.Material3.Button.IconButton"
|
style="@style/Widget.Material3.Button.IconButton"
|
||||||
android:layout_width="0dp"
|
android:layout_width="0dp"
|
||||||
@ -20,7 +20,7 @@
|
|||||||
app:iconGravity="textEnd"
|
app:iconGravity="textEnd"
|
||||||
app:iconSize="26dp" />
|
app:iconSize="26dp" />
|
||||||
|
|
||||||
<Button
|
<com.google.android.material.button.MaterialButton
|
||||||
android:id="@+id/select_album_play_now"
|
android:id="@+id/select_album_play_now"
|
||||||
style="@style/Widget.Material3.Button.IconButton"
|
style="@style/Widget.Material3.Button.IconButton"
|
||||||
android:layout_width="0dp"
|
android:layout_width="0dp"
|
||||||
@ -31,9 +31,10 @@
|
|||||||
android:contentDescription="@string/common.play_now"
|
android:contentDescription="@string/common.play_now"
|
||||||
app:icon="@drawable/media_start"
|
app:icon="@drawable/media_start"
|
||||||
app:iconGravity="textEnd"
|
app:iconGravity="textEnd"
|
||||||
app:iconSize="26dp" />
|
app:iconSize="26dp"
|
||||||
|
android:scrollbars="none" />
|
||||||
|
|
||||||
<Button
|
<com.google.android.material.button.MaterialButton
|
||||||
android:id="@+id/select_album_play_next"
|
android:id="@+id/select_album_play_next"
|
||||||
style="@style/Widget.Material3.Button.IconButton"
|
style="@style/Widget.Material3.Button.IconButton"
|
||||||
android:layout_width="0dp"
|
android:layout_width="0dp"
|
||||||
@ -44,9 +45,10 @@
|
|||||||
android:contentDescription="@string/common.play_next"
|
android:contentDescription="@string/common.play_next"
|
||||||
app:icon="@drawable/ic_play_next"
|
app:icon="@drawable/ic_play_next"
|
||||||
app:iconGravity="textEnd"
|
app:iconGravity="textEnd"
|
||||||
app:iconSize="26dp" />
|
app:iconSize="26dp"
|
||||||
|
android:scrollbars="none" />
|
||||||
|
|
||||||
<Button
|
<com.google.android.material.button.MaterialButton
|
||||||
android:id="@+id/select_album_play_last"
|
android:id="@+id/select_album_play_last"
|
||||||
style="@style/Widget.Material3.Button.IconButton"
|
style="@style/Widget.Material3.Button.IconButton"
|
||||||
android:layout_width="0dp"
|
android:layout_width="0dp"
|
||||||
@ -57,9 +59,11 @@
|
|||||||
android:contentDescription="@string/common.play_last"
|
android:contentDescription="@string/common.play_last"
|
||||||
app:icon="@drawable/ic_play_last"
|
app:icon="@drawable/ic_play_last"
|
||||||
app:iconGravity="textEnd"
|
app:iconGravity="textEnd"
|
||||||
app:iconSize="26dp" />
|
app:iconSize="26dp"
|
||||||
|
android:scrollbars="none"
|
||||||
|
/>
|
||||||
|
|
||||||
<Button
|
<com.google.android.material.button.MaterialButton
|
||||||
android:id="@+id/select_album_pin"
|
android:id="@+id/select_album_pin"
|
||||||
style="@style/Widget.Material3.Button.IconButton"
|
style="@style/Widget.Material3.Button.IconButton"
|
||||||
android:layout_width="0dp"
|
android:layout_width="0dp"
|
||||||
@ -70,9 +74,11 @@
|
|||||||
android:contentDescription="@string/common.pin"
|
android:contentDescription="@string/common.pin"
|
||||||
app:icon="@drawable/ic_menu_pin"
|
app:icon="@drawable/ic_menu_pin"
|
||||||
app:iconGravity="textEnd"
|
app:iconGravity="textEnd"
|
||||||
app:iconSize="26dp" />
|
app:iconSize="26dp"
|
||||||
|
android:scrollbars="none"
|
||||||
|
/>
|
||||||
|
|
||||||
<Button
|
<com.google.android.material.button.MaterialButton
|
||||||
android:id="@+id/select_album_unpin"
|
android:id="@+id/select_album_unpin"
|
||||||
style="@style/Widget.Material3.Button.IconButton"
|
style="@style/Widget.Material3.Button.IconButton"
|
||||||
android:layout_width="0dp"
|
android:layout_width="0dp"
|
||||||
@ -83,9 +89,11 @@
|
|||||||
android:contentDescription="@string/common.unpin"
|
android:contentDescription="@string/common.unpin"
|
||||||
app:icon="@drawable/ic_menu_unpin"
|
app:icon="@drawable/ic_menu_unpin"
|
||||||
app:iconGravity="textEnd"
|
app:iconGravity="textEnd"
|
||||||
app:iconSize="26dp" />
|
app:iconSize="26dp"
|
||||||
|
android:scrollbars="none"
|
||||||
|
/>
|
||||||
|
|
||||||
<Button
|
<com.google.android.material.button.MaterialButton
|
||||||
android:id="@+id/select_album_download"
|
android:id="@+id/select_album_download"
|
||||||
style="@style/Widget.Material3.Button.IconButton"
|
style="@style/Widget.Material3.Button.IconButton"
|
||||||
android:layout_width="0dp"
|
android:layout_width="0dp"
|
||||||
@ -96,9 +104,11 @@
|
|||||||
android:contentDescription="@string/common.download"
|
android:contentDescription="@string/common.download"
|
||||||
app:icon="@drawable/ic_menu_download"
|
app:icon="@drawable/ic_menu_download"
|
||||||
app:iconGravity="textEnd"
|
app:iconGravity="textEnd"
|
||||||
app:iconSize="26dp" />
|
app:iconSize="26dp"
|
||||||
|
android:scrollbars="none"
|
||||||
|
/>
|
||||||
|
|
||||||
<Button
|
<com.google.android.material.button.MaterialButton
|
||||||
android:id="@+id/select_album_delete"
|
android:id="@+id/select_album_delete"
|
||||||
style="@style/Widget.Material3.Button.IconButton"
|
style="@style/Widget.Material3.Button.IconButton"
|
||||||
android:layout_width="0dp"
|
android:layout_width="0dp"
|
||||||
@ -109,9 +119,11 @@
|
|||||||
android:contentDescription="@string/common.delete"
|
android:contentDescription="@string/common.delete"
|
||||||
app:icon="@drawable/ic_menu_close"
|
app:icon="@drawable/ic_menu_close"
|
||||||
app:iconGravity="textEnd"
|
app:iconGravity="textEnd"
|
||||||
app:iconSize="26dp" />
|
app:iconSize="26dp"
|
||||||
|
android:scrollbars="none"
|
||||||
|
/>
|
||||||
|
|
||||||
<Button
|
<com.google.android.material.button.MaterialButton
|
||||||
android:id="@+id/select_album_more"
|
android:id="@+id/select_album_more"
|
||||||
style="@style/Widget.Material3.Button.IconButton"
|
style="@style/Widget.Material3.Button.IconButton"
|
||||||
android:layout_width="0dp"
|
android:layout_width="0dp"
|
||||||
@ -122,6 +134,8 @@
|
|||||||
android:contentDescription="@string/search.more"
|
android:contentDescription="@string/search.more"
|
||||||
app:icon="@drawable/media_forward"
|
app:icon="@drawable/media_forward"
|
||||||
app:iconGravity="textEnd"
|
app:iconGravity="textEnd"
|
||||||
app:iconSize="26dp" />
|
app:iconSize="26dp"
|
||||||
|
android:scrollbars="none"
|
||||||
|
/>
|
||||||
|
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
|
@ -452,4 +452,5 @@
|
|||||||
<string name="supported_server_features">Funciones soportadas</string>
|
<string name="supported_server_features">Funciones soportadas</string>
|
||||||
<string name="foreground_exception_title">No se puede reanudar la reproducción</string>
|
<string name="foreground_exception_title">No se puede reanudar la reproducción</string>
|
||||||
<string name="foreground_exception_text">Presione el botón de reproducción en la notificación de medios si aún está presente; de lo contrario, abra la aplicación para iniciar la reproducción y vuelva a conectar la sesión al controlador</string>
|
<string name="foreground_exception_text">Presione el botón de reproducción en la notificación de medios si aún está presente; de lo contrario, abra la aplicación para iniciar la reproducción y vuelva a conectar la sesión al controlador</string>
|
||||||
|
<string name="settings.max_bitrate_pinning">Tasa de bits máxima: al fijar una canción de forma permanente</string>
|
||||||
</resources>
|
</resources>
|
@ -67,7 +67,7 @@
|
|||||||
<string name="download.menu_save">保存播放列表</string>
|
<string name="download.menu_save">保存播放列表</string>
|
||||||
<string name="download.menu_screen_off">关闭屏幕常亮</string>
|
<string name="download.menu_screen_off">关闭屏幕常亮</string>
|
||||||
<string name="download.menu_screen_on">开启屏幕常亮</string>
|
<string name="download.menu_screen_on">开启屏幕常亮</string>
|
||||||
<string name="download.menu_show_album">显示专辑</string>
|
<string name="download.menu_show_album">转到专辑</string>
|
||||||
<string name="download.menu_shuffle">随机</string>
|
<string name="download.menu_shuffle">随机</string>
|
||||||
<string name="download.menu_shuffle_on">随机播放模式已启用</string>
|
<string name="download.menu_shuffle_on">随机播放模式已启用</string>
|
||||||
<string name="download.menu_shuffle_off">随机播放模式已禁用</string>
|
<string name="download.menu_shuffle_off">随机播放模式已禁用</string>
|
||||||
@ -280,7 +280,7 @@
|
|||||||
<string name="settings.test_connection_title">测试连接</string>
|
<string name="settings.test_connection_title">测试连接</string>
|
||||||
<string name="settings.theme_light">亮色</string>
|
<string name="settings.theme_light">亮色</string>
|
||||||
<string name="settings.theme_dark">暗色</string>
|
<string name="settings.theme_dark">暗色</string>
|
||||||
<string name="settings.theme_black">Black</string>
|
<string name="settings.theme_black">黑色</string>
|
||||||
<string name="settings.theme_title">主题</string>
|
<string name="settings.theme_title">主题</string>
|
||||||
<string name="settings.title.allow_self_signed_certificate">允许自签名 HTTPS 证书</string>
|
<string name="settings.title.allow_self_signed_certificate">允许自签名 HTTPS 证书</string>
|
||||||
<string name="settings.title.force_plain_text_password">强制原始密码认证</string>
|
<string name="settings.title.force_plain_text_password">强制原始密码认证</string>
|
||||||
@ -337,7 +337,7 @@
|
|||||||
<string name="share_default_greeting">看看我从 %s 分享的这首音乐</string>
|
<string name="share_default_greeting">看看我从 %s 分享的这首音乐</string>
|
||||||
<string name="share_via">分享歌曲通过</string>
|
<string name="share_via">分享歌曲通过</string>
|
||||||
<string name="menu.share">分享</string>
|
<string name="menu.share">分享</string>
|
||||||
<string name="download.menu_show_artist">显示艺术家</string>
|
<string name="download.menu_show_artist">转到艺术家</string>
|
||||||
<string name="common_multiple_years">数年</string>
|
<string name="common_multiple_years">数年</string>
|
||||||
<string name="settings.debug.title">调试选项</string>
|
<string name="settings.debug.title">调试选项</string>
|
||||||
<string name="settings.debug.log_to_file">将调试日志写入文件</string>
|
<string name="settings.debug.log_to_file">将调试日志写入文件</string>
|
||||||
@ -448,4 +448,5 @@
|
|||||||
<string name="language.cs">捷克语</string>
|
<string name="language.cs">捷克语</string>
|
||||||
<string name="language.de">德语</string>
|
<string name="language.de">德语</string>
|
||||||
<string name="language.pt_BR">葡萄牙语(巴西)</string>
|
<string name="language.pt_BR">葡萄牙语(巴西)</string>
|
||||||
|
<string name="settings.max_bitrate_pinning">最大比特率 - 永久固定歌曲时</string>
|
||||||
</resources>
|
</resources>
|
@ -84,7 +84,7 @@
|
|||||||
<string name="settings.increment_time_8">8 秒</string>
|
<string name="settings.increment_time_8">8 秒</string>
|
||||||
<string name="settings.custom_cache_location">使用自訂緩衝路徑</string>
|
<string name="settings.custom_cache_location">使用自訂緩衝路徑</string>
|
||||||
<string name="settings.cache_location">緩衝路径</string>
|
<string name="settings.cache_location">緩衝路径</string>
|
||||||
<string name="settings.cache_location_error">錯誤緩衝路徑,使用預設緩衝路徑</string>
|
<string name="settings.cache_location_error">錯誤緩衝路徑,使用預設緩衝路徑。</string>
|
||||||
<string name="settings.cache_size">緩衝大小</string>
|
<string name="settings.cache_size">緩衝大小</string>
|
||||||
<string name="settings.cache_size_100">100 MB</string>
|
<string name="settings.cache_size_100">100 MB</string>
|
||||||
<string name="settings.cache_size_1000">1 GB</string>
|
<string name="settings.cache_size_1000">1 GB</string>
|
||||||
@ -129,7 +129,7 @@
|
|||||||
<string name="time_span_disabled">已停用</string>
|
<string name="time_span_disabled">已停用</string>
|
||||||
<string name="share_comment">註記</string>
|
<string name="share_comment">註記</string>
|
||||||
<string name="server_menu.delete">刪除</string>
|
<string name="server_menu.delete">刪除</string>
|
||||||
<string name="download.menu_show_album">顯示專輯</string>
|
<string name="download.menu_show_album">轉至專輯</string>
|
||||||
<string name="language.zh_CN">簡體中文(中國)</string>
|
<string name="language.zh_CN">簡體中文(中國)</string>
|
||||||
<string name="download.menu_save">儲存播放清單</string>
|
<string name="download.menu_save">儲存播放清單</string>
|
||||||
<string name="download.bookmark_set_at_position" formatted="false">書籤設置在 %s。</string>
|
<string name="download.bookmark_set_at_position" formatted="false">書籤設置在 %s。</string>
|
||||||
@ -232,4 +232,68 @@
|
|||||||
<string name="settings.hide_media_toast">在 Android 系統下次掃描裝置內音樂時生效。</string>
|
<string name="settings.hide_media_toast">在 Android 系統下次掃描裝置內音樂時生效。</string>
|
||||||
<string name="settings.download_transition">播放時顯示正在播放介面</string>
|
<string name="settings.download_transition">播放時顯示正在播放介面</string>
|
||||||
<string name="settings.download_transition_summary">在媒體庫介面開始播放後切換到正在播放介面</string>
|
<string name="settings.download_transition_summary">在媒體庫介面開始播放後切換到正在播放介面</string>
|
||||||
|
<string name="settings.search_50">50</string>
|
||||||
|
<string name="settings.preload_3">3 首歌</string>
|
||||||
|
<string name="settings.search_1">1</string>
|
||||||
|
<string name="settings.search_20">20</string>
|
||||||
|
<string name="settings.search_75">75</string>
|
||||||
|
<string name="settings.share_minutes">分鐘</string>
|
||||||
|
<string name="settings.preload_500">500 首歌</string>
|
||||||
|
<string name="settings.max_bitrate_112">112 Kbps</string>
|
||||||
|
<string name="settings.preload_1">1 首歌</string>
|
||||||
|
<string name="settings.search_3">3</string>
|
||||||
|
<string name="settings.search_40">40</string>
|
||||||
|
<string name="settings.search_500">500</string>
|
||||||
|
<string name="settings.max_bitrate_160">160 Kbps</string>
|
||||||
|
<string name="util.zero_time">0:00</string>
|
||||||
|
<string name="settings.network_timeout_120000">120 秒</string>
|
||||||
|
<string name="settings.share_hours">小時</string>
|
||||||
|
<string name="settings.theme_black">黑色</string>
|
||||||
|
<string name="server_editor.authentication">認證</string>
|
||||||
|
<string name="settings.preload_2">2 首歌</string>
|
||||||
|
<string name="settings.search_10">10</string>
|
||||||
|
<string name="settings.server_address">伺服器地址</string>
|
||||||
|
<string name="settings.network_timeout_60000">60 秒</string>
|
||||||
|
<string name="settings.search_5">5</string>
|
||||||
|
<string name="settings.preload_100">100 首歌</string>
|
||||||
|
<string name="settings.theme_light">明色</string>
|
||||||
|
<string name="settings.max_bitrate_96">96 Kbps</string>
|
||||||
|
<string name="util.bytes_format.kilobyte">0 KB</string>
|
||||||
|
<string name="settings.override_language">覆寫當前語言</string>
|
||||||
|
<string name="settings.preload_5">5 首歌</string>
|
||||||
|
<string name="settings.search_250">250</string>
|
||||||
|
<string name="settings.max_bitrate_192">192 Kbps</string>
|
||||||
|
<string name="settings.max_bitrate_80">80 Kbps</string>
|
||||||
|
<string name="settings.search_25">25</string>
|
||||||
|
<string name="settings.search_30">30</string>
|
||||||
|
<string name="settings.search_100">100</string>
|
||||||
|
<string name="main.video" tools:ignore="UnusedResources">影片</string>
|
||||||
|
<string name="time_span_disable">禁用</string>
|
||||||
|
<string name="settings.preload_50">50 首歌</string>
|
||||||
|
<string name="song_details.kbps">%d kbps</string>
|
||||||
|
<string name="settings.preload_10">10 首歌</string>
|
||||||
|
<string name="settings.max_bitrate_256">256 Kbps</string>
|
||||||
|
<string name="settings.max_bitrate_32">32 Kbps</string>
|
||||||
|
<string name="settings.max_bitrate_320">320 Kbps</string>
|
||||||
|
<string name="settings.max_bitrate_64">64 Kbps</string>
|
||||||
|
<string name="settings.network_timeout">網路延時</string>
|
||||||
|
<string name="settings.network_timeout_105000">105 秒</string>
|
||||||
|
<string name="settings.network_timeout_45000">45 秒</string>
|
||||||
|
<string name="settings.network_timeout_75000">75 秒</string>
|
||||||
|
<string name="settings.network_timeout_90000">90 秒</string>
|
||||||
|
<string name="settings.notifications_title">通知</string>
|
||||||
|
<string name="settings.network_title">網路</string>
|
||||||
|
<string name="settings.other_title">其他設定</string>
|
||||||
|
<string name="settings.search_15">15</string>
|
||||||
|
<string name="settings.server_color">伺服器顏色</string>
|
||||||
|
<string name="util.bytes_format.byte">0 B</string>
|
||||||
|
<string name="util.bytes_format.gigabyte">0.00 GB</string>
|
||||||
|
<string name="settings.server_username">用戶名</string>
|
||||||
|
<string name="settings.theme_dark">暗色</string>
|
||||||
|
<string name="util.no_time" tools:ignore="TypographyDashes">-:--</string>
|
||||||
|
<string name="util.bytes_format.megabyte">0.00 MB</string>
|
||||||
|
<string name="settings.preload_1000">1000 首歌</string>
|
||||||
|
<string name="settings.server_password">密碼</string>
|
||||||
|
<string name="settings.share_days">天</string>
|
||||||
|
<string name="settings.max_bitrate_128">128 Kbps</string>
|
||||||
</resources>
|
</resources>
|
Loading…
x
Reference in New Issue
Block a user