Skip to content

Commit 6a9034f

Browse files
Remember search query after reconfiguration,
Use any found serializer to save and restore an route, Pass an exception to the source if it is failed to load Signed-off-by: MrBoom <[email protected]>
1 parent b157c4f commit 6a9034f

File tree

9 files changed

+205
-185
lines changed

9 files changed

+205
-185
lines changed

gradle.properties

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -10,18 +10,18 @@
1010
# This option should only be used with decoupled projects. For more details, visit
1111
# https://developer.android.com/r/tools/gradle-multi-project-decoupled-projects
1212
# org.gradle.parallel=true
13-
#Tue Dec 31 22:14:21 WAT 2024
13+
#Sun Feb 23 01:23:38 YEKT 2025
1414
android.enableJetifier=false
1515
android.nonFinalResIds=true
1616
android.nonTransitiveRClass=true
1717
android.useAndroidX=true
1818
awery.app.version=1.0.5.4
1919
awery.ext.version=1.0.2
20+
awery.packageName=com.mrboomdev.awery
2021
awery.sdk.min=25
2122
awery.sdk.target=35
22-
awery.packageName=com.mrboomdev.awery
2323
kotlin.mpp.androidSourceSetLayoutVersion=2
2424
org.gradle.caching=true
25-
org.gradle.jvmargs=-Xmx1536M -Dkotlin.daemon.jvm.options\="-Xmx1536M" -Dfile.encoding\=UTF-8
25+
org.gradle.jvmargs=-Xmx1024M -Dkotlin.daemon.jvm.options\="-Xmx1024M" -Dfile.encoding\=UTF-8
2626
org.gradle.parallel=true
27-
org.gradle.unsafe.configuration-cache=true
27+
org.gradle.unsafe.configuration-cache=true

shared/build.gradle.kts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,7 @@ kotlin {
7373
// Core
7474
implementation(projects.resources)
7575
implementation(projects.ext)
76+
implementation(kotlin("reflect"))
7677

7778
// Yomi
7879
implementation(libs.bundles.yomi)

shared/src/androidMain/AndroidManifest.xml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,8 @@
22
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
33

44
<uses-permission android:name="android.permission.ENFORCE_UPDATE_OWNERSHIP" />
5-
5+
<uses-permission android:name="android.permission.REQUEST_DELETE_PACKAGES" />
6+
67
<application>
78
<activity
89
android:name="com.mrboomdev.awery.platform.ExecutorActivity"

shared/src/androidMain/kotlin/com/mrboomdev/awery/sources/yomi/YomiManager.kt

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -114,8 +114,8 @@ abstract class YomiManager<S>(
114114
createSource(pkg.packageName, GlobalId(context.id, pkg.packageName).isEnabled)
115115
}
116116
}
117-
} catch(_: Throwable) {
118-
createSource(pkg.packageName, false)
117+
} catch(t: Throwable) {
118+
createSource(pkg.packageName, false, t)
119119
}
120120

121121
progress.increment()
@@ -133,8 +133,12 @@ abstract class YomiManager<S>(
133133

134134
abstract fun getSourceLongId(source: S): Long
135135

136-
private fun createSource(packageName: String, init: Boolean): Source {
137-
var throwable: Throwable? = null
136+
private fun createSource(
137+
packageName: String,
138+
init: Boolean,
139+
throwable: Throwable? = null
140+
): Source {
141+
var t = throwable
138142

139143
val packageInfo = Platform.packageManager.getPackageInfo(
140144
packageName, PackageManager.GET_CONFIGURATIONS or PackageManager.GET_META_DATA
@@ -143,16 +147,16 @@ abstract class YomiManager<S>(
143147
val sources = if(!init) null else try {
144148
checkSupportedVersionBounds(packageInfo.versionName!!)
145149
instantiateMains(packageInfo)
146-
} catch(t: Throwable) {
147-
throwable = t
150+
} catch(th: Throwable) {
151+
t = th
148152
null
149153
}
150154

151155
return createSourceWrapper(
152156
isNsfw = packageInfo.applicationInfo!!.metaData.getInt(nsfwMeta, 0) == 1,
153157
packageInfo = packageInfo,
154158
sources = sources,
155-
exception = throwable,
159+
exception = t,
156160

157161
label = packageInfo.applicationInfo!!.loadLabel(Platform.packageManager).let { appLabel ->
158162
if(appLabel.startsWith(appLabelPrefix)) {

shared/src/commonMain/kotlin/com/mrboomdev/awery/ui/routes/BaseRoute.kt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,12 @@ package com.mrboomdev.awery.ui.routes
22

33
import cafe.adriel.voyager.core.screen.Screen
44
import com.mrboomdev.awery.ui.utils.UniqueIdGenerator
5+
import kotlinx.serialization.Serializable
56

67
/**
78
* Uses an unique key for every instance, so no crashes should happen 😅
89
*/
10+
@Serializable
911
abstract class BaseRoute: Screen {
1012
override val key = uniqueIdGenerator.long.toString()
1113

Lines changed: 155 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,173 @@
11
package com.mrboomdev.awery.ui.routes
22

3+
import androidx.compose.foundation.ExperimentalFoundationApi
4+
import androidx.compose.foundation.clickable
5+
import androidx.compose.foundation.layout.Column
6+
import androidx.compose.foundation.layout.Row
7+
import androidx.compose.foundation.layout.WindowInsets
8+
import androidx.compose.foundation.layout.WindowInsetsSides
9+
import androidx.compose.foundation.layout.asPaddingValues
10+
import androidx.compose.foundation.layout.fillMaxWidth
11+
import androidx.compose.foundation.layout.only
12+
import androidx.compose.foundation.layout.padding
13+
import androidx.compose.foundation.layout.safeDrawing
14+
import androidx.compose.foundation.layout.size
15+
import androidx.compose.foundation.layout.windowInsetsPadding
16+
import androidx.compose.foundation.lazy.LazyColumn
17+
import androidx.compose.foundation.lazy.items
18+
import androidx.compose.foundation.text.BasicTextField
19+
import androidx.compose.foundation.text.input.TextFieldLineLimits
20+
import androidx.compose.foundation.text.input.TextFieldState
21+
import androidx.compose.material3.Icon
22+
import androidx.compose.material3.IconButton
23+
import androidx.compose.material3.MaterialTheme
24+
import androidx.compose.material3.Text
325
import androidx.compose.runtime.Composable
26+
import androidx.compose.runtime.LaunchedEffect
27+
import androidx.compose.runtime.derivedStateOf
28+
import androidx.compose.runtime.getValue
29+
import androidx.compose.runtime.remember
30+
import androidx.compose.ui.Alignment
31+
import androidx.compose.ui.Modifier
32+
import androidx.compose.ui.focus.FocusRequester
33+
import androidx.compose.ui.focus.focusRequester
34+
import androidx.compose.ui.graphics.SolidColor
35+
import androidx.compose.ui.text.TextStyle
36+
import androidx.compose.ui.text.style.TextAlign
37+
import androidx.compose.ui.unit.dp
38+
import androidx.compose.ui.unit.sp
39+
import cafe.adriel.voyager.core.model.ScreenModel
40+
import cafe.adriel.voyager.core.model.rememberScreenModel
441
import cafe.adriel.voyager.navigator.LocalNavigator
542
import cafe.adriel.voyager.navigator.currentOrThrow
643
import com.mrboomdev.awery.ext.data.Setting
7-
import com.mrboomdev.awery.ui.screens.SearchScreen
44+
import com.mrboomdev.awery.generated.*
45+
import com.mrboomdev.awery.sources.ExtensionsManager
46+
import com.mrboomdev.awery.ui.utils.LocalToaster
847
import kotlinx.serialization.Contextual
948
import kotlinx.serialization.Serializable
49+
import org.jetbrains.compose.resources.painterResource
50+
import org.jetbrains.compose.resources.stringResource
1051

11-
@Serializable
1252
class SearchRoute(
53+
initialFilters: List<@Contextual Setting>? = null
54+
): DefaultSearchRoute(initialFilters)
55+
56+
@Serializable
57+
open class DefaultSearchRoute(
1358
private val initialFilters: List<@Contextual Setting>? = null
1459
): BaseRoute() {
60+
@OptIn(ExperimentalFoundationApi::class)
1561
@Composable
1662
override fun Content() {
1763
val navigation = LocalNavigator.currentOrThrow
64+
val model = rememberScreenModel { SearchModel() }
65+
val queryFocusRequested = remember { FocusRequester() }
1866

19-
SearchScreen(
20-
onBack = { navigation.pop() },
21-
initialFilters = initialFilters
22-
)
67+
val foundSources by remember { derivedStateOf {
68+
ExtensionsManager.allSources.filter { source ->
69+
model.query.text.trim().let { text ->
70+
source.context.name?.contains(text) == true || source.context.id.contains(text)
71+
}
72+
}.sortedBy { it.context.name ?: it.context.id }
73+
} }
74+
75+
LaunchedEffect(true) {
76+
queryFocusRequested.requestFocus()
77+
}
78+
79+
Column {
80+
Row(
81+
modifier = Modifier.windowInsetsPadding(
82+
WindowInsets.safeDrawing.only(
83+
WindowInsetsSides.Horizontal + WindowInsetsSides.Top
84+
)
85+
),
86+
verticalAlignment = Alignment.CenterVertically
87+
) {
88+
IconButton(
89+
onClick = { navigation.pop() }
90+
) {
91+
Icon(
92+
modifier = Modifier
93+
.size(64.dp)
94+
.padding(9.dp),
95+
painter = painterResource(Res.drawable.ic_back),
96+
contentDescription = stringResource(Res.string.back)
97+
)
98+
}
99+
100+
BasicTextField(
101+
modifier = Modifier
102+
.focusRequester(queryFocusRequested)
103+
.padding(4.dp)
104+
.fillMaxWidth(),
105+
106+
state = model.query,
107+
lineLimits = TextFieldLineLimits.SingleLine,
108+
cursorBrush = SolidColor(MaterialTheme.colorScheme.onSurface),
109+
110+
textStyle = TextStyle(
111+
color = MaterialTheme.colorScheme.onSurface,
112+
fontSize = 16.sp
113+
)
114+
)
115+
}
116+
117+
LazyColumn(
118+
modifier = Modifier.fillMaxWidth(),
119+
contentPadding = WindowInsets.safeDrawing.only(
120+
WindowInsetsSides.Horizontal + WindowInsetsSides.Bottom
121+
).asPaddingValues()
122+
) {
123+
items(
124+
items = foundSources,
125+
key = { it.context.manager.context.id + it.context.id }
126+
) { source ->
127+
val toaster = LocalToaster.current
128+
129+
Row(
130+
modifier = Modifier
131+
.fillMaxWidth()
132+
.clickable {
133+
toaster.show("This action isn't done yet!")
134+
}.padding(8.dp)
135+
.animateItemPlacement()
136+
) {
137+
Text(
138+
style = MaterialTheme.typography.bodyLarge,
139+
text = source.context.name ?: source.context.id
140+
)
141+
}
142+
}
143+
144+
if(foundSources.isEmpty()) {
145+
item("empty") {
146+
Column(
147+
modifier = Modifier
148+
.fillMaxWidth()
149+
.padding(32.dp, 64.dp)
150+
.animateItemPlacement(),
151+
horizontalAlignment = Alignment.CenterHorizontally
152+
) {
153+
Text(
154+
style = MaterialTheme.typography.headlineSmall,
155+
text = stringResource(Res.string.nothing_found)
156+
)
157+
158+
Text(
159+
modifier = Modifier.padding(8.dp),
160+
textAlign = TextAlign.Center,
161+
text = stringResource(Res.string.no_media_found)
162+
)
163+
}
164+
}
165+
}
166+
}
167+
}
23168
}
169+
}
170+
171+
private class SearchModel: ScreenModel {
172+
val query = TextFieldState()
24173
}

0 commit comments

Comments
 (0)