Skip to content

Commit 874b43b

Browse files
Fixed crash when trying to use a bubble navigation,
Fixed crash when trying to open any other screen from new settings, Fixed bug when settings would give old values, Show empty new settings screen with an header, Better dependency management, Use black background in new settings for an amoled theme, Allow setting string, int, float and enum values in new settings Signed-off-by: MrBoom <[email protected]>
1 parent 41f104d commit 874b43b

File tree

20 files changed

+471
-119
lines changed

20 files changed

+471
-119
lines changed

app/src/main/assets/app_settings.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@
2828
"to": 10,
2929
"value": 0,
3030
"title": "media_columns_count_land",
31-
"description": "Auto if is 0"
31+
"placeholder": "Leave blank to use an automatic value"
3232
},
3333

3434
{
@@ -38,7 +38,7 @@
3838
"to": 10,
3939
"value": 0,
4040
"title": "media_columns_count_port",
41-
"description": "Auto if is 0",
41+
"placeholder": "Leave blank to use an automatic value",
4242
"show_if": ["!tv"]
4343
},
4444

app/src/main/java/com/mrboomdev/awery/ext/ResourcesProvider.kt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,10 @@ import java.io.File
66

77
object ResourcesProvider {
88
fun getFile(source: Source, path: String): File {
9-
throw UnsupportedOperationException("Stub1!")
9+
throw NotImplementedError("TODO: Implement an Android implementation.")
1010
}
1111

1212
fun createImage(file: File): Image {
13-
throw UnsupportedOperationException("Stub1!")
13+
throw NotImplementedError("TODO: Implement an Android implementation.")
1414
}
1515
}

app/src/main/java/com/mrboomdev/awery/ui/mobile/components/MobileSetting.kt

Lines changed: 245 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -3,32 +3,51 @@ package com.mrboomdev.awery.ui.mobile.components
33
import androidx.compose.foundation.layout.Column
44
import androidx.compose.foundation.layout.Row
55
import androidx.compose.foundation.layout.Spacer
6+
import androidx.compose.foundation.layout.fillMaxWidth
7+
import androidx.compose.foundation.layout.height
68
import androidx.compose.foundation.layout.padding
9+
import androidx.compose.foundation.selection.selectable
10+
import androidx.compose.foundation.selection.selectableGroup
711
import androidx.compose.foundation.shape.RoundedCornerShape
12+
import androidx.compose.foundation.text.KeyboardActions
13+
import androidx.compose.foundation.text.KeyboardOptions
14+
import androidx.compose.material3.ExperimentalMaterial3Api
815
import androidx.compose.material3.MaterialTheme
16+
import androidx.compose.material3.OutlinedTextField
17+
import androidx.compose.material3.RadioButton
918
import androidx.compose.material3.Surface
1019
import androidx.compose.material3.Switch
1120
import androidx.compose.material3.Text
21+
import androidx.compose.material3.TextButton
1222
import androidx.compose.material3.TriStateCheckbox
1323
import androidx.compose.material3.contentColorFor
1424
import androidx.compose.runtime.Composable
25+
import androidx.compose.runtime.derivedStateOf
1526
import androidx.compose.runtime.getValue
1627
import androidx.compose.runtime.mutableStateOf
1728
import androidx.compose.runtime.remember
1829
import androidx.compose.runtime.setValue
1930
import androidx.compose.ui.Alignment
2031
import androidx.compose.ui.Modifier
32+
import androidx.compose.ui.draw.clip
2133
import androidx.compose.ui.graphics.Color
2234
import androidx.compose.ui.platform.LocalContext
35+
import androidx.compose.ui.res.stringResource
36+
import androidx.compose.ui.semantics.Role
2337
import androidx.compose.ui.state.ToggleableState
38+
import androidx.compose.ui.text.input.ImeAction
39+
import androidx.compose.ui.text.input.KeyboardType
2440
import androidx.compose.ui.unit.dp
2541
import com.mrboomdev.awery.R
26-
import com.mrboomdev.awery.app.App.Companion.i18n
27-
import com.mrboomdev.awery.app.App.Companion.toast
2842
import com.mrboomdev.awery.ext.data.Setting
43+
import com.mrboomdev.awery.platform.PlatformResources.i18n
2944
import com.mrboomdev.awery.platform.PlatformSetting
3045
import com.mrboomdev.awery.platform.PlatformSettingHandler
46+
import com.mrboomdev.awery.ui.components.MaterialDialog
47+
import com.mrboomdev.awery.utils.compareTo
48+
import com.mrboomdev.awery.utils.toStrippedString
3149

50+
@OptIn(ExperimentalMaterial3Api::class)
3251
@Composable
3352
fun MobileSetting(
3453
setting: Setting,
@@ -37,6 +56,7 @@ fun MobileSetting(
3756
) {
3857
var triState by remember { mutableStateOf(setting.value as? Setting.TriState ?: Setting.TriState.EMPTY) }
3958
var isChecked by remember { mutableStateOf(setting.value == true) }
59+
var isDialogShown by remember { mutableStateOf(false) }
4060
val context = LocalContext.current
4161

4262
Surface(
@@ -67,14 +87,13 @@ fun MobileSetting(
6787

6888
Setting.Type.BOOLEAN -> isChecked = !isChecked
6989
Setting.Type.TRI_STATE -> triState = triState.next()
70-
71-
Setting.Type.FLOAT -> toast("This action isn't done yet!")
72-
Setting.Type.STRING -> toast("This action isn't done yet!")
73-
Setting.Type.SELECT -> toast("This action isn't done yet!")
74-
Setting.Type.INTEGER -> toast("This action isn't done yet!")
75-
Setting.Type.MULTISELECT -> toast("This action isn't done yet!")
76-
7790
Setting.Type.CATEGORY, null -> {}
91+
92+
Setting.Type.FLOAT,
93+
Setting.Type.STRING,
94+
Setting.Type.SELECT,
95+
Setting.Type.INTEGER,
96+
Setting.Type.MULTISELECT -> isDialogShown = true
7897
}
7998
}
8099
) {
@@ -90,9 +109,7 @@ fun MobileSetting(
90109
(setting.title ?: (if(setting.description == null) setting.key else null))?.let { title ->
91110
Text(
92111
style = MaterialTheme.typography.bodyLarge,
93-
text = setting.takeIf { it is PlatformSetting }?.let {
94-
i18n<R.string>(title)
95-
} ?: title
112+
text = setting.takeIf { it is PlatformSetting }?.let { i18n(title) } ?: title
96113
)
97114
}
98115

@@ -104,10 +121,7 @@ fun MobileSetting(
104121
Text(
105122
style = if(setting.title == null) MaterialTheme.typography.bodyMedium else MaterialTheme.typography.bodySmall,
106123
color = if(setting.type == Setting.Type.CATEGORY) MaterialTheme.colorScheme.primary else Color.Unspecified,
107-
108-
text = setting.takeIf { it is PlatformSetting }?.let {
109-
i18n<R.string>(description)
110-
} ?: description
124+
text = setting.takeIf { it is PlatformSetting }?.let { i18n(description) } ?: description
111125
)
112126
}
113127
}
@@ -133,6 +147,221 @@ fun MobileSetting(
133147
}
134148
}
135149
}
150+
151+
if(isDialogShown) {
152+
var newValue by remember { mutableStateOf(setting.value) }
153+
154+
val isValidValue by remember { derivedStateOf {
155+
when(setting.type) {
156+
Setting.Type.STRING -> {
157+
setting.from?.also { from ->
158+
if(((newValue as? String?)?.length ?: 0) < from) {
159+
return@derivedStateOf false to "This text is too short! Minimum length is ${from.toStrippedString()}."
160+
}
161+
}
162+
163+
setting.to?.also { to ->
164+
if(((newValue as? String?)?.length ?: 0) > to) {
165+
return@derivedStateOf false to "This text is too long! Maximum length is ${to.toStrippedString()}."
166+
}
167+
}
168+
169+
true to ""
170+
}
171+
172+
Setting.Type.INTEGER, Setting.Type.FLOAT -> {
173+
setting.from?.also { from ->
174+
if((newValue as? Number? ?: 0) < from) {
175+
return@derivedStateOf false to "This number is too short! Minimum length is ${from.toStrippedString()}."
176+
}
177+
}
178+
179+
setting.to?.also { to ->
180+
if((newValue as? Number? ?: 0) > to) {
181+
return@derivedStateOf false to "This number is too long! Maximum length is ${to.toStrippedString()}."
182+
}
183+
}
184+
185+
if(newValue != null && newValue !is Number) {
186+
return@derivedStateOf false to "This is not a number!"
187+
}
188+
189+
true to ""
190+
}
191+
192+
else -> true to "No checks can be made on this type."
193+
}
194+
}}
195+
196+
MaterialDialog(
197+
modifier = Modifier.padding(horizontal = 8.dp),
198+
onDismissRequest = { isDialogShown = false },
199+
200+
title = setting.title?.let { title -> {
201+
Text(
202+
style = MaterialTheme.typography.headlineMedium,
203+
text = setting.takeIf { it is PlatformSetting }?.let { i18n(title) } ?: title
204+
)
205+
}},
206+
207+
dismissButton = {
208+
TextButton(onClick = this@MaterialDialog::requestDismiss) {
209+
Text(text = stringResource(R.string.cancel))
210+
}
211+
},
212+
213+
confirmButton = {
214+
TextButton(onClick = {
215+
if(!isValidValue.first) return@TextButton
216+
setting.value = newValue
217+
requestDismiss()
218+
}) {
219+
Text(text = stringResource(R.string.confirm))
220+
}
221+
}
222+
) {
223+
Column {
224+
if(setting.description != null) {
225+
val description = setting.description!!
226+
227+
Text(
228+
text = setting.takeIf { it is PlatformSetting }
229+
?.let { i18n(description) } ?: description
230+
)
231+
}
232+
233+
when(setting.type) {
234+
Setting.Type.STRING -> {
235+
OutlinedTextField(
236+
isError = isValidValue.first,
237+
label = if(isValidValue.first) null else {{
238+
Text(isValidValue.second)
239+
}},
240+
241+
placeholder = if(setting is PlatformSetting && setting.placeholder != null) {{
242+
Text(setting.placeholder!!)
243+
}} else null,
244+
245+
singleLine = true,
246+
value = newValue?.toString() ?: "",
247+
onValueChange = { newValue = it },
248+
keyboardOptions = KeyboardOptions(imeAction = ImeAction.Done),
249+
keyboardActions = KeyboardActions(onDone = {
250+
if(!isValidValue.first) return@KeyboardActions
251+
setting.value = newValue
252+
requestDismiss()
253+
})
254+
)
255+
}
256+
257+
Setting.Type.INTEGER -> {
258+
OutlinedTextField(
259+
isError = !isValidValue.first,
260+
label = if(isValidValue.first) null else {{
261+
Text(isValidValue.second)
262+
}},
263+
264+
placeholder = if(setting is PlatformSetting && setting.placeholder != null) {{
265+
Text(setting.placeholder!!)
266+
}} else null,
267+
268+
singleLine = true,
269+
value = newValue?.toString() ?: "",
270+
271+
onValueChange = {
272+
newValue = if(it.isBlank()) null else try {
273+
it.toInt()
274+
} catch(e: NumberFormatException) { it }
275+
},
276+
277+
keyboardOptions = KeyboardOptions(
278+
keyboardType = KeyboardType.Phone,
279+
imeAction = ImeAction.Done
280+
),
281+
282+
keyboardActions = KeyboardActions(onDone = {
283+
if(!isValidValue.first) return@KeyboardActions
284+
setting.value = newValue
285+
requestDismiss()
286+
})
287+
)
288+
}
289+
290+
Setting.Type.FLOAT -> {
291+
OutlinedTextField(
292+
isError = !isValidValue.first,
293+
label = if(isValidValue.first) null else {{
294+
Text(isValidValue.second)
295+
}},
296+
297+
placeholder = if(setting is PlatformSetting && setting.placeholder != null) {{
298+
Text(setting.placeholder!!)
299+
}} else null,
300+
301+
singleLine = true,
302+
value = newValue?.toString() ?: "",
303+
304+
onValueChange = {
305+
newValue = if(it.isBlank()) null else try {
306+
it.toFloat()
307+
} catch(e: NumberFormatException) { it }
308+
},
309+
310+
keyboardOptions = KeyboardOptions(
311+
keyboardType = KeyboardType.Decimal,
312+
imeAction = ImeAction.Done
313+
),
314+
315+
keyboardActions = KeyboardActions(onDone = {
316+
setting.value = newValue
317+
requestDismiss()
318+
})
319+
)
320+
}
321+
322+
Setting.Type.SELECT -> {
323+
Column(modifier = Modifier.selectableGroup()) {
324+
for(item in setting.items!!) {
325+
Row(modifier = Modifier
326+
.clip(RoundedCornerShape(8.dp))
327+
.fillMaxWidth()
328+
.height(56.dp)
329+
.selectable(
330+
selected = newValue == item.key,
331+
onClick = { newValue = item.key },
332+
role = Role.RadioButton
333+
),
334+
verticalAlignment = Alignment.CenterVertically
335+
) {
336+
RadioButton(
337+
selected = newValue == item.key,
338+
onClick = null
339+
)
340+
341+
Text(
342+
text = item.title?.let { title ->
343+
setting.takeIf { it is PlatformSetting }?.let { i18n(title) } ?: title
344+
} ?: item.key ?: "No title",
345+
346+
style = MaterialTheme.typography.bodyLarge,
347+
modifier = Modifier.padding(start = 16.dp)
348+
)
349+
}
350+
}
351+
}
352+
}
353+
354+
else -> {
355+
Text(
356+
style = MaterialTheme.typography.bodyLarge,
357+
color = Color.Red,
358+
text = "Unsupported setting type!"
359+
)
360+
}
361+
}
362+
}
363+
}
364+
}
136365
}
137366

138367
private fun Setting.TriState.asToggleableState() = when(this) {

app/src/main/java/com/mrboomdev/awery/ui/mobile/screens/catalog/MainActivity.kt

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -248,10 +248,9 @@ class MainActivity : AppCompatActivity() {
248248

249249
(fun(tab: Int) {
250250
binding!!.pages.setCurrentItem(tab, false)
251-
(binding!!.pages.adapter as? FeedsAdapter)?.fragments?.get(tab)?.get()?.onFocus()
251+
(binding!!.pages.adapter as? FeedsAdapter)?.fragments?.getOrNull(tab)?.get()?.onFocus()
252252
}).let {
253253
binding!!.navbarBubble.onTabSelected = { tab -> it(tab.id) }
254-
255254
binding!!.navbarMaterial.setOnItemSelectedListener { tab ->
256255
it(tab.itemId)
257256
true

app/src/main/java/com/mrboomdev/awery/ui/mobile/screens/settings/SettingsActivity2.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,7 @@ class SettingsActivity2: ComponentActivity() {
7272
}
7373
} catch(_: CancellationException) {}
7474
}
75-
75+
7676
Row(Modifier.fillMaxSize()) {
7777
Spacer(Modifier.windowInsetsStartWidth(WindowInsets.safeContent))
7878

0 commit comments

Comments
 (0)