Add timeout for plugin updates and better texts, bottom menu lighter disable shade, library cursor cleanup

This commit is contained in:
Kelvin
2025-11-17 21:28:07 +01:00
parent f17e147b4e
commit 07f3140038
3 changed files with 130 additions and 97 deletions
@@ -187,9 +187,16 @@ class PluginUpdateDialog : AlertDialog {
val scope = StateApp.instance.scopeOrNull; val scope = StateApp.instance.scopeOrNull;
scope?.launch(Dispatchers.IO) { scope?.launch(Dispatchers.IO) {
try { try {
withContext(Dispatchers.Main) {
_textProgres.setText("Loading current script file...");
}
val client = ManagedHttpClient(); val client = ManagedHttpClient();
client.setTimeout(10000);
val script = StatePlugins.instance.getScript(_oldConfig.id) ?: ""; val script = StatePlugins.instance.getScript(_oldConfig.id) ?: "";
withContext(Dispatchers.Main) {
_textProgres.setText("Requesting new script file...");
}
val newScript = client.get(_newConfig.absoluteScriptUrl)?.body?.string(); val newScript = client.get(_newConfig.absoluteScriptUrl)?.body?.string();
if(newScript.isNullOrEmpty()) if(newScript.isNullOrEmpty())
throw IllegalStateException("No script found"); throw IllegalStateException("No script found");
@@ -143,7 +143,7 @@ class MenuBottomBarFragment : MainActivityFragment() {
val animations = arrayListOf<Animator>() val animations = arrayListOf<Animator>()
animations.add(ObjectAnimator.ofFloat(moreOverlayBackground, "alpha", 0.0f, 1.0f).setDuration(duration)) animations.add(ObjectAnimator.ofFloat(moreOverlayBackground, "alpha", 0.0f, 1.0f).setDuration(duration))
_bottomButtons.find { it.definition.id == 99 }?.let { _bottomButtons.find { it.definition.id == 99 }?.let {
animations.add(ObjectAnimator.ofFloat(it, "alpha", 0.4f, 1.0f) animations.add(ObjectAnimator.ofFloat(it, "alpha", 0.5f, 1.0f)
.setDuration(duration)); .setDuration(duration));
} }
@@ -165,7 +165,7 @@ class MenuBottomBarFragment : MainActivityFragment() {
.add(ObjectAnimator.ofFloat(moreOverlayBackground, "alpha", 1.0f, 0.0f) .add(ObjectAnimator.ofFloat(moreOverlayBackground, "alpha", 1.0f, 0.0f)
.setDuration(duration)) .setDuration(duration))
_bottomButtons.find { it.definition.id == 99 }?.let { _bottomButtons.find { it.definition.id == 99 }?.let {
animations.add(ObjectAnimator.ofFloat(it, "alpha", 1.0f, 0.4f) animations.add(ObjectAnimator.ofFloat(it, "alpha", 1.0f, 0.5f)
.setDuration(duration)); .setDuration(duration));
} }
@@ -369,7 +369,7 @@ class MenuBottomBarFragment : MainActivityFragment() {
this.alpha = 1f; this.alpha = 1f;
} }
else { else {
this.alpha = 0.4f; this.alpha = 0.5f;
} }
_textButton = findViewById(R.id.text_button); _textButton = findViewById(R.id.text_button);
@@ -389,7 +389,7 @@ class MenuBottomBarFragment : MainActivityFragment() {
this.alpha = 1f; this.alpha = 1f;
} }
else { else {
this.alpha = 0.4f; this.alpha = 0.5f;
} }
} }
} }
@@ -102,13 +102,15 @@ class StateLibrary {
MediaStore.Audio.Media.EXTERNAL_CONTENT_URI, StateLibrary.PROJECTION_MEDIA, MediaStore.Audio.Media.EXTERNAL_CONTENT_URI, StateLibrary.PROJECTION_MEDIA,
"LOWER(" + MediaStore.Audio.Media.DISPLAY_NAME + ") LIKE ? ", arrayOf("%" + str.trim().lowercase() + "%"), "LOWER(" + MediaStore.Audio.Media.DISPLAY_NAME + ") LIKE ? ", arrayOf("%" + str.trim().lowercase() + "%"),
null) ?: return listOf(); null) ?: return listOf();
cursor.moveToFirst(); return cursor.use {
val list = mutableListOf<IPlatformVideo>() cursor.moveToFirst();
while(!cursor.isAfterLast) { val list = mutableListOf<IPlatformVideo>()
list.add(StateLibrary.audioFromCursor(cursor)); while(!cursor.isAfterLast) {
cursor.moveToNext(); list.add(StateLibrary.audioFromCursor(cursor));
cursor.moveToNext();
}
return@use list;
} }
return list;
} }
fun getAlbums(): List<Album> { fun getAlbums(): List<Album> {
@@ -155,21 +157,23 @@ class StateLibrary {
query, query,
null, null,
MediaStore.Video.Media.DATE_ADDED + " DESC") ?: return EmptyPager(); MediaStore.Video.Media.DATE_ADDED + " DESC") ?: return EmptyPager();
cursor.moveToFirst(); return cursor.use {
val list = mutableListOf<IPlatformVideo>() cursor.moveToFirst();
while(!cursor.isAfterLast && list.size < 10) { val list = mutableListOf<IPlatformVideo>()
list.add(videoFromCursor(cursor));
cursor.moveToNext();
}
return AdhocPager<IPlatformContent>({
val list = mutableListOf<IPlatformContent>()
while(!cursor.isAfterLast && list.size < 10) { while(!cursor.isAfterLast && list.size < 10) {
list.add(videoFromCursor(cursor)); list.add(videoFromCursor(cursor));
cursor.moveToNext(); cursor.moveToNext();
} }
return@AdhocPager list;
}, list); return@use AdhocPager<IPlatformContent>({
val list = mutableListOf<IPlatformContent>()
while(!cursor.isAfterLast && list.size < 10) {
list.add(videoFromCursor(cursor));
cursor.moveToNext();
}
return@AdhocPager list;
}, list);
}
} }
fun getRecentVideos(buckets: List<String>? = null, count: Int = 20): List<IPlatformVideo> { fun getRecentVideos(buckets: List<String>? = null, count: Int = 20): List<IPlatformVideo> {
val videoPager = getVideos(buckets); val videoPager = getVideos(buckets);
@@ -194,26 +198,28 @@ class StateLibrary {
), null, null, null ), null, null, null
) ?: return listOf(); ) ?: return listOf();
val buckets = mutableListOf<Bucket>(); return cur.use {
val list = HashSet<Long>(); val buckets = mutableListOf<Bucket>();
if (cur.moveToFirst()) { val list = HashSet<Long>();
var id: Long; if (cur.moveToFirst()) {
var bucket: String var id: Long;
do { var bucket: String
try { do {
id = cur.getLong(0); try {
bucket = cur.getStringOrNull(1) ?: continue; id = cur.getLong(0);
if (!list.contains(id)) { bucket = cur.getStringOrNull(1) ?: continue;
list.add(id); if (!list.contains(id)) {
buckets.add(Bucket(id, bucket)); list.add(id);
buckets.add(Bucket(id, bucket));
}
} catch (ex: Throwable) {
Logger.e(TAG, "Failed to parse bucket due to ${ex.message}", ex);
} }
} catch (ex: Throwable) { } while (cur.moveToNext())
Logger.e(TAG, "Failed to parse bucket due to ${ex.message}", ex); }
} _cacheBucketNames = buckets.toList()
} while (cur.moveToNext()) return@use _cacheBucketNames ?: listOf();
} }
_cacheBucketNames = buckets.toList()
return _cacheBucketNames ?: listOf();
} }
catch(ex: Throwable) { catch(ex: Throwable) {
Logger.e(TAG, "Buckets loading failed, returning empty"); Logger.e(TAG, "Buckets loading failed, returning empty");
@@ -286,10 +292,12 @@ class StateLibrary {
val cursor = resolver?.query( val cursor = resolver?.query(
MediaStore.Audio.Media.EXTERNAL_CONTENT_URI, StateLibrary.PROJECTION_MEDIA, "${MediaStore.Audio.Media._ID} = ?", arrayOf(id.toString()), MediaStore.Audio.Media.EXTERNAL_CONTENT_URI, StateLibrary.PROJECTION_MEDIA, "${MediaStore.Audio.Media._ID} = ?", arrayOf(id.toString()),
null) ?: return null; null) ?: return null;
cursor.moveToFirst(); return cursor.use {
if(cursor.isAfterLast) cursor.moveToFirst();
return null; if(cursor.isAfterLast)
return audioFromCursor(cursor); return@use null;
return@use audioFromCursor(cursor);
}
} }
fun findAudioByName(name: String): IPlatformContentDetails? { fun findAudioByName(name: String): IPlatformContentDetails? {
val resolver = StateApp.instance.contextOrNull?.contentResolver; val resolver = StateApp.instance.contextOrNull?.contentResolver;
@@ -300,10 +308,12 @@ class StateLibrary {
val cursor = resolver?.query( val cursor = resolver?.query(
MediaStore.Audio.Media.EXTERNAL_CONTENT_URI, StateLibrary.PROJECTION_MEDIA, "${MediaStore.Audio.Media.DISPLAY_NAME} = ?", arrayOf(name), MediaStore.Audio.Media.EXTERNAL_CONTENT_URI, StateLibrary.PROJECTION_MEDIA, "${MediaStore.Audio.Media.DISPLAY_NAME} = ?", arrayOf(name),
null) ?: return null; null) ?: return null;
cursor.moveToFirst(); return cursor.use {
if(cursor.isAfterLast) cursor.moveToFirst();
return null; if(cursor.isAfterLast)
return audioFromCursor(cursor); return null;
return@use audioFromCursor(cursor);
}
} }
fun getVideoTrack(url: String): IPlatformContentDetails? { fun getVideoTrack(url: String): IPlatformContentDetails? {
val uri = Uri.parse(url); val uri = Uri.parse(url);
@@ -319,10 +329,12 @@ class StateLibrary {
val cursor = resolver?.query( val cursor = resolver?.query(
MediaStore.Audio.Media.EXTERNAL_CONTENT_URI, StateLibrary.PROJECTION_VIDEO, "${MediaStore.Video.Media._ID} = ?", arrayOf(id.toString()), MediaStore.Audio.Media.EXTERNAL_CONTENT_URI, StateLibrary.PROJECTION_VIDEO, "${MediaStore.Video.Media._ID} = ?", arrayOf(id.toString()),
null) ?: return null; null) ?: return null;
cursor.moveToFirst(); return cursor.use {
if(cursor.isAfterLast) cursor.moveToFirst();
return null; if(cursor.isAfterLast)
return videoFromCursor(cursor); return@use null;
return@use videoFromCursor(cursor);
}
} }
fun findVideoByName(name: String): IPlatformContentDetails? { fun findVideoByName(name: String): IPlatformContentDetails? {
val resolver = StateApp.instance.contextOrNull?.contentResolver; val resolver = StateApp.instance.contextOrNull?.contentResolver;
@@ -333,10 +345,12 @@ class StateLibrary {
val cursor = resolver?.query( val cursor = resolver?.query(
MediaStore.Audio.Media.EXTERNAL_CONTENT_URI, StateLibrary.PROJECTION_VIDEO, "${MediaStore.Video.Media.DISPLAY_NAME} = ?", arrayOf(name), MediaStore.Audio.Media.EXTERNAL_CONTENT_URI, StateLibrary.PROJECTION_VIDEO, "${MediaStore.Video.Media.DISPLAY_NAME} = ?", arrayOf(name),
null) ?: return null; null) ?: return null;
cursor.moveToFirst(); return cursor.use {
if(cursor.isAfterLast) cursor.moveToFirst();
return null; if(cursor.isAfterLast)
return videoFromCursor(cursor); return@use null;
return@use videoFromCursor(cursor);
}
} }
fun audioFromCursor(cursor: Cursor): IPlatformVideoDetails { fun audioFromCursor(cursor: Cursor): IPlatformVideoDetails {
@@ -484,12 +498,13 @@ class Artist {
val cursor = resolver.query(MediaStore.Audio.Artists.EXTERNAL_CONTENT_URI, val cursor = resolver.query(MediaStore.Audio.Artists.EXTERNAL_CONTENT_URI,
Artist.PROJECTION, Artist.PROJECTION,
"${MediaStore.Audio.Artists._ID} = ?", "${MediaStore.Audio.Artists._ID} = ?",
arrayOf(id.toString()), null) ?: arrayOf(id.toString()), null) ?: return null;
return null; return cursor.use {
cursor.moveToFirst(); cursor.moveToFirst();
if(cursor.isAfterLast) if(cursor.isAfterLast)
return null; return@use null;
return Artist.fromCursor(cursor); return@use Artist.fromCursor(cursor);
}
} }
fun getArtists(ordering: ArtistOrdering = ArtistOrdering.Alphabethic, query: String? = null, args: Array<String>? = null): List<Artist> { fun getArtists(ordering: ArtistOrdering = ArtistOrdering.Alphabethic, query: String? = null, args: Array<String>? = null): List<Artist> {
val ordering = when(ordering) { val ordering = when(ordering) {
@@ -503,13 +518,15 @@ class Artist {
query, query,
args, args,
ordering) ?: return listOf(); ordering) ?: return listOf();
cursor.moveToFirst(); return cursor.use {
val list = mutableListOf<Artist>() cursor.moveToFirst();
while(!cursor.isAfterLast) { val list = mutableListOf<Artist>()
list.add(fromCursor(cursor)); while(!cursor.isAfterLast) {
cursor.moveToNext(); list.add(fromCursor(cursor));
cursor.moveToNext();
}
return@use list;
} }
return list;
} }
fun getTracksPager(artistId: Long): List<IPlatformVideo> { fun getTracksPager(artistId: Long): List<IPlatformVideo> {
@@ -521,13 +538,15 @@ class Artist {
val cursor = resolver?.query( val cursor = resolver?.query(
MediaStore.Audio.Media.EXTERNAL_CONTENT_URI, StateLibrary.PROJECTION_MEDIA, "${MediaStore.Audio.Media.ARTIST_ID} = ?", arrayOf(artistId.toString()), MediaStore.Audio.Media.EXTERNAL_CONTENT_URI, StateLibrary.PROJECTION_MEDIA, "${MediaStore.Audio.Media.ARTIST_ID} = ?", arrayOf(artistId.toString()),
null) ?: return listOf(); null) ?: return listOf();
cursor.moveToFirst(); return cursor.use {
val list = mutableListOf<IPlatformVideo>() cursor.moveToFirst();
while(!cursor.isAfterLast) { val list = mutableListOf<IPlatformVideo>()
list.add(StateLibrary.audioFromCursor(cursor)); while(!cursor.isAfterLast) {
cursor.moveToNext(); list.add(StateLibrary.audioFromCursor(cursor));
cursor.moveToNext();
}
return@use list;
} }
return list;
} }
} }
} }
@@ -583,13 +602,15 @@ class Album {
val cursor = resolver?.query( val cursor = resolver?.query(
MediaStore.Audio.Media.EXTERNAL_CONTENT_URI, StateLibrary.PROJECTION_MEDIA, "${MediaStore.Audio.Media.ALBUM_ID} = ?", arrayOf(albumId.toString()), MediaStore.Audio.Media.EXTERNAL_CONTENT_URI, StateLibrary.PROJECTION_MEDIA, "${MediaStore.Audio.Media.ALBUM_ID} = ?", arrayOf(albumId.toString()),
null) ?: return listOf(); null) ?: return listOf();
cursor.moveToFirst(); return cursor.use {
val list = mutableListOf<IPlatformVideo>() cursor.moveToFirst();
while(!cursor.isAfterLast) { val list = mutableListOf<IPlatformVideo>()
list.add(StateLibrary.audioFromCursor(cursor)); while(!cursor.isAfterLast) {
cursor.moveToNext(); list.add(StateLibrary.audioFromCursor(cursor));
cursor.moveToNext();
}
return@use list;
} }
return list;
} }
fun getAlbum(id: Long): Album? { fun getAlbum(id: Long): Album? {
val resolver = StateApp.instance.contextOrNull?.contentResolver; val resolver = StateApp.instance.contextOrNull?.contentResolver;
@@ -600,12 +621,13 @@ class Album {
val cursor = resolver.query(MediaStore.Audio.Albums.EXTERNAL_CONTENT_URI, val cursor = resolver.query(MediaStore.Audio.Albums.EXTERNAL_CONTENT_URI,
PROJECTION, PROJECTION,
"${MediaStore.Audio.Albums.ALBUM_ID} = ?", "${MediaStore.Audio.Albums.ALBUM_ID} = ?",
arrayOf(id.toString()), null) ?: arrayOf(id.toString()), null) ?: return null;
return null; return cursor.use {
cursor.moveToFirst(); cursor.moveToFirst();
if(cursor.isAfterLast) if(cursor.isAfterLast)
return null; return@use null;
return fromCursor(cursor); return@use fromCursor(cursor);
}
} }
fun getAlbums(query: String? = null, args: Array<String>? = null): List<Album> { fun getAlbums(query: String? = null, args: Array<String>? = null): List<Album> {
val resolver = StateApp.instance.contextOrNull?.contentResolver; val resolver = StateApp.instance.contextOrNull?.contentResolver;
@@ -616,13 +638,15 @@ class Album {
val cursor = resolver?.query( val cursor = resolver?.query(
MediaStore.Audio.Albums.EXTERNAL_CONTENT_URI, PROJECTION, query, args, MediaStore.Audio.Albums.EXTERNAL_CONTENT_URI, PROJECTION, query, args,
MediaStore.Audio.Albums.ALBUM + " ASC") ?: return listOf(); MediaStore.Audio.Albums.ALBUM + " ASC") ?: return listOf();
cursor.moveToFirst(); return cursor.use {
val list = mutableListOf<Album>() cursor.moveToFirst();
while(!cursor.isAfterLast) { val list = mutableListOf<Album>()
list.add(fromCursor(cursor)); while(!cursor.isAfterLast) {
cursor.moveToNext(); list.add(fromCursor(cursor));
cursor.moveToNext();
}
return@use list;
} }
return list;
} }
fun getArtistAlbums(artistId: Long): List<Album> { fun getArtistAlbums(artistId: Long): List<Album> {
val resolver = StateApp.instance.contextOrNull?.contentResolver; val resolver = StateApp.instance.contextOrNull?.contentResolver;
@@ -633,13 +657,15 @@ class Album {
val cursor = resolver?.query( val cursor = resolver?.query(
MediaStore.Audio.Albums.EXTERNAL_CONTENT_URI, PROJECTION, "${MediaStore.Audio.Media.ARTIST_ID} = ?", arrayOf(artistId.toString()), MediaStore.Audio.Albums.EXTERNAL_CONTENT_URI, PROJECTION, "${MediaStore.Audio.Media.ARTIST_ID} = ?", arrayOf(artistId.toString()),
MediaStore.Audio.Albums.ALBUM + " ASC") ?: return listOf(); MediaStore.Audio.Albums.ALBUM + " ASC") ?: return listOf();
cursor.moveToFirst(); return cursor.use {
val list = mutableListOf<Album>() cursor.moveToFirst();
while(!cursor.isAfterLast) { val list = mutableListOf<Album>()
list.add(fromCursor(cursor)); while(!cursor.isAfterLast) {
cursor.moveToNext(); list.add(fromCursor(cursor));
cursor.moveToNext();
}
return@use list;
} }
return list;
} }
} }
} }