Skip to content

Commit f8a96d7

Browse files
committed
Add generic custom user agent suggestions
1 parent ed185fe commit f8a96d7

3 files changed

Lines changed: 97 additions & 5 deletions

File tree

app/src/main/java/at/bitfire/icsdroid/Constants.kt

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,4 +14,13 @@ object Constants {
1414

1515
val USER_AGENT = "ICSx5/${BuildConfig.VERSION_NAME} (ical4j/${ical4jVersion} okhttp/${OkHttp.VERSION} Android/${Build.VERSION.RELEASE})"
1616

17+
/**
18+
* Suggested user agents to allow compatibility with user agent blocking servers
19+
*/
20+
val COMPATIBILITY_USER_AGENTS = mapOf(
21+
"Chrome Android" to "Mozilla/5.0 (Linux; Android 10; K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/134.0.0.0 Mobile Safari/537.3",
22+
"Firefox Android" to "Mozilla/5.0 (Android 16; Mobile; rv:142.0) Gecko/142.0 Firefox/142.0",
23+
"Safari iOS" to "Mozilla/5.0 (iPhone; CPU iPhone OS 18_3_2 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/18.3.1 Mobile/15E148 Safari/604."
24+
)
25+
1726
}

app/src/main/java/at/bitfire/icsdroid/ui/partials/CustomUserAgentInput.kt

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,17 @@
11
package at.bitfire.icsdroid.ui.partials
22

3-
import androidx.compose.foundation.layout.fillMaxWidth
43
import androidx.compose.foundation.text.KeyboardActions
5-
import androidx.compose.material3.OutlinedTextField
64
import androidx.compose.material3.Text
75
import androidx.compose.runtime.Composable
86
import androidx.compose.ui.Modifier
97
import androidx.compose.ui.res.stringResource
8+
import at.bitfire.icsdroid.Constants.COMPATIBILITY_USER_AGENTS
109
import at.bitfire.icsdroid.R
1110

1211
@Composable
1312
fun CustomUserAgentInput(
14-
onValueChange: (String?) -> Unit,
1513
value: String?,
14+
onValueChange: (String?) -> Unit,
1615
keyboardActions: KeyboardActions = KeyboardActions.Default
1716
) {
1817
ToggleContent(
@@ -21,11 +20,12 @@ fun CustomUserAgentInput(
2120
initialToggleState = value != null,
2221
onStateChange = { checked -> if (!checked) onValueChange(null) },
2322
) {
24-
OutlinedTextField(
23+
DropDownTextField(
2524
value = value ?: "",
2625
onValueChange = onValueChange,
26+
options = COMPATIBILITY_USER_AGENTS,
27+
modifier = Modifier,
2728
label = { Text(stringResource(R.string.add_calendar_custom_user_agent_label)) },
28-
modifier = Modifier.fillMaxWidth(),
2929
keyboardActions = keyboardActions
3030
)
3131
}
Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
package at.bitfire.icsdroid.ui.partials
2+
3+
import androidx.compose.foundation.clickable
4+
import androidx.compose.foundation.layout.Column
5+
import androidx.compose.foundation.layout.fillMaxWidth
6+
import androidx.compose.foundation.layout.width
7+
import androidx.compose.foundation.text.KeyboardActions
8+
import androidx.compose.material.icons.Icons
9+
import androidx.compose.material.icons.filled.KeyboardArrowDown
10+
import androidx.compose.material.icons.filled.KeyboardArrowUp
11+
import androidx.compose.material3.DropdownMenu
12+
import androidx.compose.material3.DropdownMenuItem
13+
import androidx.compose.material3.Icon
14+
import androidx.compose.material3.OutlinedTextField
15+
import androidx.compose.material3.Text
16+
import androidx.compose.runtime.Composable
17+
import androidx.compose.runtime.getValue
18+
import androidx.compose.runtime.mutableStateOf
19+
import androidx.compose.runtime.remember
20+
import androidx.compose.runtime.setValue
21+
import androidx.compose.ui.Modifier
22+
import androidx.compose.ui.geometry.Size
23+
import androidx.compose.ui.layout.onGloballyPositioned
24+
import androidx.compose.ui.platform.LocalDensity
25+
import androidx.compose.ui.unit.toSize
26+
27+
28+
@Composable
29+
fun DropDownTextField(
30+
value: String?,
31+
onValueChange: (String) -> Unit,
32+
options: Map<String, String>,
33+
modifier: Modifier = Modifier,
34+
label: @Composable (() -> Unit)? = null,
35+
keyboardActions: KeyboardActions = KeyboardActions.Default
36+
) {
37+
var expanded by remember { mutableStateOf(false) }
38+
var textFieldSize by remember { mutableStateOf(Size.Zero)}
39+
40+
Column {
41+
OutlinedTextField(
42+
value = value ?: "",
43+
onValueChange = onValueChange,
44+
keyboardActions = keyboardActions,
45+
modifier = modifier
46+
.fillMaxWidth()
47+
.onGloballyPositioned { coordinates ->
48+
// Remember text field size
49+
textFieldSize = coordinates.size.toSize()
50+
},
51+
label = label,
52+
trailingIcon = {
53+
// Open/Close dropdown icon
54+
Icon(
55+
imageVector = if (expanded)
56+
Icons.Filled.KeyboardArrowUp
57+
else
58+
Icons.Filled.KeyboardArrowDown,
59+
contentDescription = null,
60+
modifier = modifier.clickable { expanded = !expanded }
61+
)
62+
}
63+
)
64+
DropdownMenu(
65+
expanded = expanded,
66+
onDismissRequest = { expanded = false },
67+
modifier = modifier.width(with(LocalDensity.current) {
68+
// Make drop down menu same length as text field
69+
textFieldSize.width.toDp()
70+
})
71+
) {
72+
options.forEach { (label, option) ->
73+
DropdownMenuItem(
74+
text = { Text(text = label) },
75+
onClick = {
76+
onValueChange(option)
77+
expanded = false
78+
}
79+
)
80+
}
81+
}
82+
}
83+
}

0 commit comments

Comments
 (0)