Release 4.3.4

This commit is contained in:
birdbird 2023-05-07 15:23:38 +00:00
parent 404c7c05d5
commit 88364b15d6
11 changed files with 68 additions and 27 deletions

View File

@ -0,0 +1,8 @@
Bug fixes
- Fix more exceptions
Changes since 4.2.0
- #827: Make app full compliant Android Auto to publish in Play Store.
- #878: "Play shuffled" option for playlists always begins with the first track.
- #891: Dump config to log file when logging is enabled.
- #854: Remove Videos menu option for servers which don't support it.

View File

@ -9,7 +9,7 @@ ktlint = "0.43.2"
ktlintGradle = "11.3.1"
detekt = "1.22.0"
preferences = "1.2.0"
media3 = "1.0.0"
media3 = "1.0.1"
androidSupport = "1.6.0"
materialDesign = "1.8.0"
@ -23,7 +23,8 @@ viewModelKtx = "2.6.1"
swipeRefresh = "1.1.0"
retrofit = "2.9.0"
jackson = "2.14.2"
## KEEP ON 2.13 branch (https://github.com/FasterXML/jackson-databind/issues/3658#issuecomment-1312633064) for compatibility with API 24
jackson = "2.13.5"
okhttp = "4.10.0"
koin = "3.3.2"
picasso = "2.8"

View File

@ -9,8 +9,8 @@ android {
defaultConfig {
applicationId "org.moire.ultrasonic"
versionCode 116
versionName "4.3.3"
versionCode 117
versionName "4.3.4"
minSdkVersion versions.minSdk
targetSdkVersion versions.targetSdk

View File

@ -46,7 +46,7 @@ public class GenreAdapter extends ArrayAdapter<Genre> implements SectionIndexer
private final Object[] sections;
private final Integer[] positions;
public GenreAdapter(Context context, List<Genre> genres)
public GenreAdapter(@NonNull Context context, List<Genre> genres)
{
super(context, R.layout.list_item_generic, genres);

View File

@ -401,6 +401,8 @@ open class TrackCollectionFragment(
) {
// We are coming back from unknown context
// and need to ensure Main Thread in order to manipulate the UI
// If view is null, our view was disposed in the meantime
if (view == null) return
viewLifecycleOwner.lifecycleScope.launch(Dispatchers.Main) {
val multipleSelection = viewAdapter.hasMultipleSelection()

View File

@ -102,7 +102,9 @@ class SelectGenreFragment : Fragment() {
override fun done(result: List<Genre>) {
emptyView!!.isVisible = result.isEmpty()
genreListView!!.adapter = GenreAdapter(context, result)
if (context != null) {
genreListView!!.adapter = GenreAdapter(context!!, result)
}
}
}
task.execute()

View File

@ -240,6 +240,8 @@ class ImageLoader(
} finally {
inputStream.safeClose()
}
} catch (all: Exception) {
Timber.w(all)
} finally {
cacheInProgress.remove(file)?.countDown()
}

View File

@ -7,11 +7,14 @@
package org.moire.ultrasonic.subsonic
import android.os.Handler
import android.os.Looper
import androidx.fragment.app.Fragment
import androidx.navigation.fragment.findNavController
import java.util.Collections
import java.util.LinkedList
import kotlinx.coroutines.CancellationException
import kotlinx.coroutines.CoroutineExceptionHandler
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
@ -28,6 +31,7 @@ import org.moire.ultrasonic.util.EntryByDiscAndTrackComparator
import org.moire.ultrasonic.util.InfoDialog
import org.moire.ultrasonic.util.Settings
import org.moire.ultrasonic.util.Util
import timber.log.Timber
/**
* Retrieves a list of songs and adds them to the now playing list
@ -39,6 +43,16 @@ class DownloadHandler(
) : CoroutineScope by CoroutineScope(Dispatchers.IO) {
private val maxSongs = 500
/**
* Exception Handler for Coroutines
*/
val exceptionHandler = CoroutineExceptionHandler { _, exception ->
Handler(Looper.getMainLooper()).post {
Timber.w(exception)
}
}
// TODO: Use coroutine here (with proper exception handler)
fun download(
fragment: Fragment,
append: Boolean,
@ -210,7 +224,7 @@ class DownloadHandler(
isArtist: Boolean
) {
// Launch the Job
val job = launch {
val job = launch(exceptionHandler) {
val songs: MutableList<Track> =
getTracksFromServer(isArtist, id, isDirectory, name, isShare)

View File

@ -10,7 +10,9 @@ package org.moire.ultrasonic.util
import android.app.Activity
import android.content.Context
import com.google.android.material.dialog.MaterialAlertDialogBuilder
import java.lang.ref.WeakReference
import org.moire.ultrasonic.R
import timber.log.Timber
/*
* InfoDialog can be used to show some information to the user. Typically it cannot be cancelled,
@ -19,24 +21,30 @@ import org.moire.ultrasonic.R
open class InfoDialog(
context: Context,
message: CharSequence?,
private val activity: Activity? = null,
activity: Activity? = null,
private val finishActivityOnClose: Boolean = false
) {
open var builder: MaterialAlertDialogBuilder = Builder(activity ?: context, message)
private val activityRef: WeakReference<Activity?> = WeakReference(activity)
open var builder: MaterialAlertDialogBuilder = Builder(activityRef.get() ?: context, message)
fun show() {
builder.setOnCancelListener {
if (finishActivityOnClose) {
activity!!.finish()
activityRef.get()?.finish()
}
}
builder.setPositiveButton(R.string.common_ok) { _, _ ->
if (finishActivityOnClose) {
activity!!.finish()
activityRef.get()?.finish()
}
}
builder.create().show()
// If the app was put into the background in the meantime this would fail
try {
builder.create().show()
} catch (all: Exception) {
Timber.w(all, "Failed to create dialog")
}
}
class Builder(context: Context) : MaterialAlertDialogBuilder(context) {
@ -93,7 +101,6 @@ class ConfirmationDialog(
activity: Activity? = null,
finishActivityOnClose: Boolean = false
) : InfoDialog(context, message, activity, finishActivityOnClose) {
override var builder: MaterialAlertDialogBuilder = Builder(activity ?: context, message)
class Builder(context: Context) : MaterialAlertDialogBuilder(context) {

View File

@ -273,7 +273,7 @@ class StorageFile(
}
private fun getStorageFileForParentDirectory(path: String): StorageFile? {
val parentPath = FileUtil.getParentPath(path)!!
val parentPath = FileUtil.getParentPath(path) ?: return null
if (storageFilePathDictionary.containsKey(parentPath))
return storageFilePathDictionary[parentPath]!!
if (notExistingPathDictionary.contains(parentPath)) return null

View File

@ -133,19 +133,24 @@ object Util {
@JvmStatic
@SuppressLint("ShowToast") // Invalid warning
fun toast(context: Context?, message: CharSequence?, shortDuration: Boolean) {
if (toast == null) {
toast = Toast.makeText(
context,
message,
if (shortDuration) Toast.LENGTH_SHORT else Toast.LENGTH_LONG
)
toast!!.setGravity(Gravity.CENTER, 0, 0)
} else {
toast!!.setText(message)
toast!!.duration =
if (shortDuration) Toast.LENGTH_SHORT else Toast.LENGTH_LONG
// If called after doing some background processing, our context might have expired!
try {
if (toast == null) {
toast = Toast.makeText(
context,
message,
if (shortDuration) Toast.LENGTH_SHORT else Toast.LENGTH_LONG
)
toast!!.setGravity(Gravity.CENTER, 0, 0)
} else {
toast!!.setText(message)
toast!!.duration =
if (shortDuration) Toast.LENGTH_SHORT else Toast.LENGTH_LONG
}
toast!!.show()
} catch (_: Exception) {
// Ignore
}
toast!!.show()
}
/**