Skip to content

Commit a915a8d

Browse files
Add external links
1 parent 05a456b commit a915a8d

File tree

9 files changed

+123
-131
lines changed

9 files changed

+123
-131
lines changed

app/src/main/kotlin/app/fyreplace/fyreplace/ui/screens/SettingsScreen.kt

+44-10
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,20 @@
11
package app.fyreplace.fyreplace.ui.screens
22

3+
import androidx.compose.foundation.clickable
34
import androidx.compose.foundation.layout.Arrangement
45
import androidx.compose.foundation.layout.Column
56
import androidx.compose.foundation.layout.fillMaxWidth
67
import androidx.compose.foundation.rememberScrollState
78
import androidx.compose.foundation.verticalScroll
89
import androidx.compose.material.icons.Icons
9-
import androidx.compose.material.icons.automirrored.filled.Logout
10+
import androidx.compose.material.icons.automirrored.outlined.Logout
11+
import androidx.compose.material.icons.outlined.Code
12+
import androidx.compose.material.icons.outlined.Info
13+
import androidx.compose.material.icons.outlined.Lock
14+
import androidx.compose.material.icons.outlined.Shield
1015
import androidx.compose.material3.Icon
16+
import androidx.compose.material3.ListItem
17+
import androidx.compose.material3.Text
1118
import androidx.compose.runtime.Composable
1219
import androidx.compose.runtime.getValue
1320
import androidx.compose.ui.Modifier
@@ -24,8 +31,8 @@ import app.fyreplace.fyreplace.fakes.FakeEventBus
2431
import app.fyreplace.fyreplace.fakes.FakeStoreResolver
2532
import app.fyreplace.fyreplace.fakes.placeholder
2633
import app.fyreplace.fyreplace.ui.theme.AppTheme
27-
import app.fyreplace.fyreplace.ui.views.settings.AvatarPreference
28-
import app.fyreplace.fyreplace.ui.views.settings.Preference
34+
import app.fyreplace.fyreplace.ui.views.settings.AvatarListItem
35+
import app.fyreplace.fyreplace.ui.views.settings.LinkListItem
2936
import app.fyreplace.fyreplace.ui.views.settings.Section
3037
import app.fyreplace.fyreplace.viewmodels.screens.SettingsViewModel
3138

@@ -39,18 +46,45 @@ fun SettingsScreen(viewModel: SettingsViewModel = hiltViewModel()) {
3946
) {
4047
val currentUser by viewModel.currentUser.collectAsStateWithLifecycle()
4148

42-
Section(stringResource(R.string.settings_header_profile)) {
43-
AvatarPreference(
49+
Section(stringResource(R.string.settings_profile_header)) {
50+
AvatarListItem(
4451
user = currentUser,
4552
onUpdateAvatar = viewModel::updateAvatar,
4653
onRemoveAvatar = viewModel::removeAvatar
4754
)
4855

49-
Preference(
50-
title = stringResource(R.string.settings_logout),
51-
summary = stringResource(R.string.settings_logout_summary),
52-
icon = { Icon(Icons.AutoMirrored.Filled.Logout, null) },
53-
onClick = viewModel::logout
56+
57+
ListItem(
58+
headlineContent = { Text(stringResource(R.string.settings_profile_logout)) },
59+
supportingContent = { Text(stringResource(R.string.settings_profile_logout_summary)) },
60+
leadingContent = { Icon(Icons.AutoMirrored.Outlined.Logout, null) },
61+
modifier = Modifier.clickable(onClick = viewModel::logout)
62+
)
63+
}
64+
65+
Section(stringResource(R.string.settings_about_header)) {
66+
LinkListItem(
67+
title = stringResource(R.string.settings_about_website),
68+
uri = stringResource(R.string.info_url_website),
69+
icon = Icons.Outlined.Info
70+
)
71+
72+
LinkListItem(
73+
title = stringResource(R.string.settings_about_terms_of_service),
74+
uri = stringResource(R.string.info_url_terms_of_service),
75+
icon = Icons.Outlined.Shield
76+
)
77+
78+
LinkListItem(
79+
title = stringResource(R.string.settings_about_privacy_policy),
80+
uri = stringResource(R.string.info_url_privacy_policy),
81+
icon = Icons.Outlined.Lock
82+
)
83+
84+
LinkListItem(
85+
title = stringResource(R.string.settings_about_source_code),
86+
uri = stringResource(R.string.info_url_source_code),
87+
icon = Icons.Outlined.Code
5488
)
5589
}
5690
}

app/src/main/kotlin/app/fyreplace/fyreplace/ui/views/bars/TopBar.kt

+13-17
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@ import androidx.compose.animation.SharedTransitionLayout
77
import androidx.compose.animation.SharedTransitionScope
88
import androidx.compose.material3.CenterAlignedTopAppBar
99
import androidx.compose.material3.ExperimentalMaterial3Api
10-
import androidx.compose.material3.LargeTopAppBar
1110
import androidx.compose.material3.SegmentedButton
1211
import androidx.compose.material3.SegmentedButtonDefaults
1312
import androidx.compose.material3.SingleChoiceSegmentedButtonRow
@@ -29,16 +28,9 @@ fun TopBar(
2928
selectedDestination: Destination.Singleton?,
3029
enabled: Boolean,
3130
onClickDestination: (Destination.Singleton) -> Unit
32-
) {
33-
@Composable
34-
fun MaybeTitle() {
35-
if (selectedDestination != null) {
36-
Text(stringResource(selectedDestination.labelRes))
37-
}
38-
}
39-
40-
if (destinations.isNotEmpty()) {
41-
CenterAlignedTopAppBar(title = {
31+
) = if (destinations.isNotEmpty()) {
32+
CenterAlignedTopAppBar(
33+
title = {
4234
SharedTransitionLayout {
4335
AnimatedContent(destinations, label = "Top bar segments") {
4436
SegmentedChoice(
@@ -50,12 +42,16 @@ fun TopBar(
5042
)
5143
}
5244
}
53-
})
54-
} else if (selectedDestination?.hasLargeTitle == true) {
55-
LargeTopAppBar(title = { MaybeTitle() })
56-
} else {
57-
TopAppBar(title = { MaybeTitle() })
58-
}
45+
}
46+
)
47+
} else {
48+
TopAppBar(
49+
title = {
50+
if (selectedDestination != null) {
51+
Text(stringResource(selectedDestination.labelRes))
52+
}
53+
}
54+
)
5955
}
6056

6157
@Preview

app/src/main/kotlin/app/fyreplace/fyreplace/ui/views/navigation/Destination.kt

-2
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,6 @@ sealed interface Destination {
4040
val activeIcon: ImageVector
4141
val inactiveIcon: ImageVector
4242
val requiresAuthentication: Boolean
43-
val hasLargeTitle: Boolean get() = false
4443

4544
@get:StringRes
4645
val labelRes: Int
@@ -124,7 +123,6 @@ sealed interface Destination {
124123
override val inactiveIcon = Icons.Outlined.Settings
125124
override val labelRes = R.string.main_destination_settings
126125
override val requiresAuthentication = false
127-
override val hasLargeTitle = true
128126
}
129127

130128
@Serializable

app/src/main/kotlin/app/fyreplace/fyreplace/ui/views/settings/AvatarPreference.kt app/src/main/kotlin/app/fyreplace/fyreplace/ui/views/settings/AvatarListItem.kt

+24-18
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package app.fyreplace.fyreplace.ui.views.settings
22

33
import androidx.compose.foundation.ExperimentalFoundationApi
44
import androidx.compose.foundation.background
5+
import androidx.compose.foundation.combinedClickable
56
import androidx.compose.foundation.draganddrop.dragAndDropTarget
67
import androidx.compose.foundation.layout.Box
78
import androidx.compose.foundation.layout.size
@@ -11,6 +12,7 @@ import androidx.compose.material.icons.outlined.Upload
1112
import androidx.compose.material3.DropdownMenu
1213
import androidx.compose.material3.DropdownMenuItem
1314
import androidx.compose.material3.Icon
15+
import androidx.compose.material3.ListItem
1416
import androidx.compose.material3.Text
1517
import androidx.compose.runtime.Composable
1618
import androidx.compose.runtime.getValue
@@ -34,7 +36,7 @@ import java.time.format.FormatStyle
3436

3537
@OptIn(ExperimentalFoundationApi::class)
3638
@Composable
37-
fun AvatarPreference(
39+
fun AvatarListItem(
3840
user: User?,
3941
onUpdateAvatar: (File) -> Unit,
4042
onRemoveAvatar: () -> Unit
@@ -64,30 +66,34 @@ fun AvatarPreference(
6466
}
6567

6668
Box(modifier = dropModifier) {
67-
Preference(
68-
title = user?.username ?: stringResource(R.string.loading),
69-
summary = when (dateJoined) {
70-
null -> stringResource(R.string.loading)
71-
else -> stringResource(
72-
R.string.settings_date_joined,
73-
dateFormatter.format(dateJoined)
69+
ListItem(
70+
headlineContent = { Text(user?.username ?: stringResource(R.string.loading)) },
71+
supportingContent = {
72+
Text(
73+
when (dateJoined) {
74+
null -> stringResource(R.string.loading)
75+
else -> stringResource(
76+
R.string.settings_profile_date_joined,
77+
dateFormatter.format(dateJoined)
78+
)
79+
}
7480
)
7581
},
76-
icon = {
77-
Avatar(user = user, modifier = Modifier.size(64.dp))
78-
},
79-
onClick = ::selectImage,
80-
onLongClick = {
81-
haptics.performHapticFeedback(HapticFeedbackType.LongPress)
82-
isAvatarMenuExpanded = true
83-
}
82+
leadingContent = { Avatar(user = user, modifier = Modifier.size(56.dp)) },
83+
modifier = Modifier.combinedClickable(
84+
onClick = ::selectImage,
85+
onLongClick = {
86+
haptics.performHapticFeedback(HapticFeedbackType.LongPress)
87+
isAvatarMenuExpanded = true
88+
}
89+
)
8490
)
8591

8692
DropdownMenu(
8793
isAvatarMenuExpanded,
8894
onDismissRequest = { isAvatarMenuExpanded = false }) {
8995
DropdownMenuItem(
90-
text = { Text(stringResource(R.string.settings_avatar_change)) },
96+
text = { Text(stringResource(R.string.settings_profile_avatar_change)) },
9197
leadingIcon = { Icon(Icons.Outlined.Upload, null) },
9298
onClick = {
9399
selectImage()
@@ -96,7 +102,7 @@ fun AvatarPreference(
96102
)
97103
DropdownMenuItem(
98104
enabled = !user?.avatar.isNullOrEmpty(),
99-
text = { Text(stringResource(R.string.settings_avatar_remove)) },
105+
text = { Text(stringResource(R.string.settings_profile_avatar_remove)) },
100106
leadingIcon = { Icon(Icons.Outlined.Delete, null) },
101107
onClick = {
102108
onRemoveAvatar()
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
package app.fyreplace.fyreplace.ui.views.settings
2+
3+
import androidx.compose.foundation.clickable
4+
import androidx.compose.material3.Icon
5+
import androidx.compose.material3.ListItem
6+
import androidx.compose.material3.Text
7+
import androidx.compose.runtime.Composable
8+
import androidx.compose.ui.Modifier
9+
import androidx.compose.ui.graphics.vector.ImageVector
10+
import androidx.compose.ui.platform.LocalUriHandler
11+
12+
@Composable
13+
fun LinkListItem(
14+
title: String,
15+
uri: String,
16+
icon: ImageVector
17+
) {
18+
val uriHandler = LocalUriHandler.current
19+
ListItem(
20+
headlineContent = { Text(title) },
21+
supportingContent = { Text(uri) },
22+
leadingContent = { Icon(icon, null) },
23+
modifier = Modifier.clickable(onClick = { uriHandler.openUri(uri) })
24+
)
25+
}

app/src/main/kotlin/app/fyreplace/fyreplace/ui/views/settings/Preference.kt

-77
This file was deleted.

app/src/main/kotlin/app/fyreplace/fyreplace/ui/views/settings/Section.kt

+5-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
package app.fyreplace.fyreplace.ui.views.settings
22

33
import androidx.compose.foundation.layout.Column
4+
import androidx.compose.foundation.layout.Spacer
5+
import androidx.compose.foundation.layout.height
46
import androidx.compose.foundation.layout.padding
57
import androidx.compose.material3.MaterialTheme
68
import androidx.compose.material3.Text
@@ -12,12 +14,14 @@ import app.fyreplace.fyreplace.R
1214
@Composable
1315
fun Section(header: String, content: @Composable () -> Unit) {
1416
Column {
17+
Spacer(modifier = Modifier.height(dimensionResource(R.dimen.spacing_medium)))
1518
Text(
1619
text = header,
17-
style = MaterialTheme.typography.titleSmall,
20+
style = MaterialTheme.typography.titleMedium,
1821
modifier = Modifier.padding(start = dimensionResource(R.dimen.spacing_medium))
1922
)
2023

24+
Spacer(modifier = Modifier.height(dimensionResource(R.dimen.spacing_small)))
2125
content()
2226
}
2327
}

app/src/main/res/values/strings.xml

+11-6
Original file line numberDiff line numberDiff line change
@@ -16,12 +16,17 @@
1616
<string name="main_destination_login">Login</string>
1717
<string name="main_destination_register">Sign up</string>
1818

19-
<string name="settings_header_profile">Profile</string>
20-
<string name="settings_date_joined">Joined: %1$s</string>
21-
<string name="settings_avatar_change">Change avatar</string>
22-
<string name="settings_avatar_remove">Remove avatar</string>
23-
<string name="settings_logout">Logout</string>
24-
<string name="settings_logout_summary">Disconnect from this account</string>
19+
<string name="settings_profile_header">Profile</string>
20+
<string name="settings_profile_date_joined">Joined: %1$s</string>
21+
<string name="settings_profile_avatar_change">Change avatar</string>
22+
<string name="settings_profile_avatar_remove">Remove avatar</string>
23+
<string name="settings_profile_logout">Logout</string>
24+
<string name="settings_profile_logout_summary">Disconnect from this account</string>
25+
<string name="settings_about_header">About</string>
26+
<string name="settings_about_website">Website</string>
27+
<string name="settings_about_terms_of_service">Terms of service</string>
28+
<string name="settings_about_privacy_policy">Privacy policy</string>
29+
<string name="settings_about_source_code">Source code</string>
2530
<string name="settings_error_413_title">File too large</string>
2631
<string name="settings_error_413_message">This file is too heavy; please select a file under 1M.</string>
2732
<string name="settings_error_415_title">Unsupported file format</string>

app/src/main/res/values/urls.xml

+1
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
<string name="info_url_website" translatable="false">https://fyreplace.net</string>
77
<string name="info_url_terms_of_service" translatable="false">https://fyreplace.net/terms-of-service</string>
88
<string name="info_url_privacy_policy" translatable="false">https://fyreplace.net/privacy-policy</string>
9+
<string name="info_url_source_code" translatable="false">https://github.com/fyreplace</string>
910
<string name="deep_link_host_main" translatable="false">fyreplace.app</string>
1011
<string name="deep_link_host_dev" translatable="false">dev.fyreplace.app</string>
1112
<string name="deep_link_path_login" translatable="false">/login</string>

0 commit comments

Comments
 (0)