Skip to content

Commit cedd4e2

Browse files
authored
Provide custom user agent suggestions (#678)
* Create generic toggle content composable and use in specific CustomUserAgentComposable * Add generic custom user agent suggestions * Rename variable and property * Missing space * Nullability
1 parent fa58f54 commit cedd4e2

7 files changed

Lines changed: 162 additions & 56 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
}
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
package at.bitfire.icsdroid.ui.partials
2+
3+
import androidx.compose.foundation.text.KeyboardActions
4+
import androidx.compose.material3.Text
5+
import androidx.compose.runtime.Composable
6+
import androidx.compose.ui.Modifier
7+
import androidx.compose.ui.res.stringResource
8+
import at.bitfire.icsdroid.Constants.COMPATIBILITY_USER_AGENTS
9+
import at.bitfire.icsdroid.R
10+
11+
@Composable
12+
fun CustomUserAgentInput(
13+
value: String?,
14+
onValueChange: (String?) -> Unit,
15+
keyboardActions: KeyboardActions = KeyboardActions.Default
16+
) {
17+
ToggleContent(
18+
title = stringResource(R.string.add_calendar_custom_user_agent_title),
19+
description = stringResource(R.string.add_calendar_custom_user_agent_description),
20+
initialToggleState = value != null,
21+
onToggle = { checked -> if (!checked) onValueChange(null) },
22+
) {
23+
DropDownTextField(
24+
value = value ?: "",
25+
onValueChange = onValueChange,
26+
options = COMPATIBILITY_USER_AGENTS,
27+
modifier = Modifier,
28+
label = { Text(stringResource(R.string.add_calendar_custom_user_agent_label)) },
29+
keyboardActions = keyboardActions
30+
)
31+
}
32+
}
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+
}
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
package at.bitfire.icsdroid.ui.partials
2+
3+
import androidx.compose.animation.AnimatedVisibility
4+
import androidx.compose.runtime.Composable
5+
import androidx.compose.runtime.getValue
6+
import androidx.compose.runtime.mutableStateOf
7+
import androidx.compose.runtime.saveable.rememberSaveable
8+
import androidx.compose.runtime.setValue
9+
10+
@Composable
11+
fun ToggleContent(
12+
title: String,
13+
description: String,
14+
initialToggleState: Boolean,
15+
onToggle: (Boolean) -> Unit,
16+
content: @Composable () -> Unit
17+
) {
18+
var showContent by rememberSaveable { mutableStateOf(initialToggleState) }
19+
SwitchSetting(
20+
title = title,
21+
description = description,
22+
checked = showContent,
23+
onCheckedChange = {
24+
showContent = !showContent
25+
onToggle(showContent)
26+
}
27+
)
28+
AnimatedVisibility(visible = showContent) {
29+
content()
30+
}
31+
}

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

Lines changed: 0 additions & 45 deletions
This file was deleted.

app/src/main/java/at/bitfire/icsdroid/ui/screen/EditSubscriptionScreen.kt

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ import at.bitfire.icsdroid.model.EditSubscriptionModel
3939
import at.bitfire.icsdroid.model.EditSubscriptionModel.EditSubscriptionModelFactory
4040
import at.bitfire.icsdroid.ui.partials.ExtendedTopAppBar
4141
import at.bitfire.icsdroid.ui.partials.GenericAlertDialog
42-
import at.bitfire.icsdroid.ui.partials.ToggleTextField
42+
import at.bitfire.icsdroid.ui.partials.CustomUserAgentInput
4343
import at.bitfire.icsdroid.ui.theme.AppTheme
4444
import at.bitfire.icsdroid.ui.views.LoginCredentialsComposable
4545
import at.bitfire.icsdroid.ui.views.SubscriptionSettingsComposable
@@ -174,11 +174,9 @@ fun EditSubscriptionScreen(
174174
)
175175

176176
// Custom User Agent
177-
ToggleTextField(
178-
title = stringResource(R.string.add_calendar_custom_user_agent_title),
179-
description = stringResource(R.string.add_calendar_custom_user_agent_description),
180-
onValueChange = customUserAgentChanged,
181-
value = customUserAgent
177+
CustomUserAgentInput(
178+
value = customUserAgent,
179+
onValueChange = customUserAgentChanged
182180
)
183181

184182
Spacer(modifier = Modifier.padding(12.dp))

app/src/main/java/at/bitfire/icsdroid/ui/views/EnterUrlComposable.kt

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@ import androidx.compose.ui.unit.em
5757
import at.bitfire.icsdroid.R
5858
import at.bitfire.icsdroid.ui.ResourceInfo
5959
import at.bitfire.icsdroid.ui.partials.AlertDialog
60-
import at.bitfire.icsdroid.ui.partials.ToggleTextField
60+
import at.bitfire.icsdroid.ui.partials.CustomUserAgentInput
6161
import kotlinx.coroutines.launch
6262

6363
@OptIn(ExperimentalFoundationApi::class)
@@ -287,11 +287,9 @@ private fun ColumnScope.SubscribeToUrl(
287287
)
288288

289289
// Custom User Agent
290-
ToggleTextField(
291-
title = stringResource(R.string.add_calendar_custom_user_agent_title),
292-
description = stringResource(R.string.add_calendar_custom_user_agent_description),
293-
onValueChange = onCustomUserAgentChange,
290+
CustomUserAgentInput(
294291
value = customUserAgent,
292+
onValueChange = onCustomUserAgentChange,
295293
keyboardActions = KeyboardActions { onSubmit() }
296294
)
297295
}

0 commit comments

Comments
 (0)