feat: retire PageHeader in favour of TopAppBar
- also make DisconnectionNotice borderless Signed-off-by: Infi <infi@infi.sh>
This commit is contained in:
parent
452d2b164d
commit
5736aec64d
|
|
@ -36,6 +36,7 @@ import androidx.compose.ui.Alignment
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
import androidx.compose.ui.draw.clip
|
import androidx.compose.ui.draw.clip
|
||||||
import androidx.compose.ui.graphics.Color
|
import androidx.compose.ui.graphics.Color
|
||||||
|
import androidx.compose.ui.graphics.toArgb
|
||||||
import androidx.compose.ui.layout.ContentScale
|
import androidx.compose.ui.layout.ContentScale
|
||||||
import androidx.compose.ui.platform.testTag
|
import androidx.compose.ui.platform.testTag
|
||||||
import androidx.compose.ui.res.stringResource
|
import androidx.compose.ui.res.stringResource
|
||||||
|
|
@ -70,6 +71,7 @@ class InviteActivity : ComponentActivity() {
|
||||||
|
|
||||||
val inviteCode = intent.data?.lastPathSegment
|
val inviteCode = intent.data?.lastPathSegment
|
||||||
|
|
||||||
|
window.statusBarColor = Color.Transparent.toArgb()
|
||||||
WindowCompat.setDecorFitsSystemWindows(window, false)
|
WindowCompat.setDecorFitsSystemWindows(window, false)
|
||||||
|
|
||||||
setContent {
|
setContent {
|
||||||
|
|
|
||||||
|
|
@ -25,6 +25,7 @@ import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.runtime.collectAsState
|
import androidx.compose.runtime.collectAsState
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
import androidx.compose.ui.graphics.Color
|
import androidx.compose.ui.graphics.Color
|
||||||
|
import androidx.compose.ui.graphics.toArgb
|
||||||
import androidx.compose.ui.unit.Dp
|
import androidx.compose.ui.unit.Dp
|
||||||
import androidx.compose.ui.unit.IntOffset
|
import androidx.compose.ui.unit.IntOffset
|
||||||
import androidx.core.splashscreen.SplashScreen.Companion.installSplashScreen
|
import androidx.core.splashscreen.SplashScreen.Companion.installSplashScreen
|
||||||
|
|
@ -212,6 +213,7 @@ class MainActivity : FragmentActivity() {
|
||||||
super.onResume()
|
super.onResume()
|
||||||
DynamicColors.applyToActivityIfAvailable(this)
|
DynamicColors.applyToActivityIfAvailable(this)
|
||||||
DynamicColors.applyToActivitiesIfAvailable(RevoltApplication.instance)
|
DynamicColors.applyToActivitiesIfAvailable(RevoltApplication.instance)
|
||||||
|
window.statusBarColor = Color.Transparent.toArgb()
|
||||||
}
|
}
|
||||||
|
|
||||||
@OptIn(ExperimentalMaterial3WindowSizeClassApi::class)
|
@OptIn(ExperimentalMaterial3WindowSizeClassApi::class)
|
||||||
|
|
@ -223,6 +225,7 @@ class MainActivity : FragmentActivity() {
|
||||||
options.release = BuildConfig.VERSION_NAME
|
options.release = BuildConfig.VERSION_NAME
|
||||||
}
|
}
|
||||||
|
|
||||||
|
window.statusBarColor = Color.Transparent.toArgb()
|
||||||
WindowCompat.setDecorFitsSystemWindows(window, false)
|
WindowCompat.setDecorFitsSystemWindows(window, false)
|
||||||
|
|
||||||
installSplashScreen().apply {
|
installSplashScreen().apply {
|
||||||
|
|
@ -273,7 +276,8 @@ fun AppEntrypoint(
|
||||||
colourOverrides = SyncedSettings.android.colourOverrides
|
colourOverrides = SyncedSettings.android.colourOverrides
|
||||||
) {
|
) {
|
||||||
Surface(
|
Surface(
|
||||||
modifier = Modifier.fillMaxSize(),
|
modifier = Modifier
|
||||||
|
.fillMaxSize(),
|
||||||
color = MaterialTheme.colorScheme.background
|
color = MaterialTheme.colorScheme.background
|
||||||
) {
|
) {
|
||||||
NavHost(
|
NavHost(
|
||||||
|
|
|
||||||
|
|
@ -12,12 +12,13 @@ import androidx.activity.compose.setContent
|
||||||
import androidx.activity.result.contract.ActivityResultContracts
|
import androidx.activity.result.contract.ActivityResultContracts
|
||||||
import androidx.compose.foundation.background
|
import androidx.compose.foundation.background
|
||||||
import androidx.compose.foundation.layout.Box
|
import androidx.compose.foundation.layout.Box
|
||||||
import androidx.compose.foundation.layout.Column
|
|
||||||
import androidx.compose.foundation.layout.Row
|
|
||||||
import androidx.compose.foundation.layout.fillMaxSize
|
import androidx.compose.foundation.layout.fillMaxSize
|
||||||
import androidx.compose.foundation.layout.padding
|
import androidx.compose.foundation.layout.padding
|
||||||
|
import androidx.compose.material.icons.Icons
|
||||||
|
import androidx.compose.material.icons.filled.ArrowBack
|
||||||
import androidx.compose.material3.DropdownMenu
|
import androidx.compose.material3.DropdownMenu
|
||||||
import androidx.compose.material3.DropdownMenuItem
|
import androidx.compose.material3.DropdownMenuItem
|
||||||
|
import androidx.compose.material3.ExperimentalMaterial3Api
|
||||||
import androidx.compose.material3.Icon
|
import androidx.compose.material3.Icon
|
||||||
import androidx.compose.material3.IconButton
|
import androidx.compose.material3.IconButton
|
||||||
import androidx.compose.material3.MaterialTheme
|
import androidx.compose.material3.MaterialTheme
|
||||||
|
|
@ -28,6 +29,7 @@ import androidx.compose.material3.SnackbarHostState
|
||||||
import androidx.compose.material3.SnackbarResult
|
import androidx.compose.material3.SnackbarResult
|
||||||
import androidx.compose.material3.Surface
|
import androidx.compose.material3.Surface
|
||||||
import androidx.compose.material3.Text
|
import androidx.compose.material3.Text
|
||||||
|
import androidx.compose.material3.TopAppBar
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.runtime.mutableStateOf
|
import androidx.compose.runtime.mutableStateOf
|
||||||
import androidx.compose.runtime.remember
|
import androidx.compose.runtime.remember
|
||||||
|
|
@ -38,6 +40,7 @@ import androidx.compose.ui.graphics.RectangleShape
|
||||||
import androidx.compose.ui.platform.LocalContext
|
import androidx.compose.ui.platform.LocalContext
|
||||||
import androidx.compose.ui.res.painterResource
|
import androidx.compose.ui.res.painterResource
|
||||||
import androidx.compose.ui.res.stringResource
|
import androidx.compose.ui.res.stringResource
|
||||||
|
import androidx.compose.ui.text.style.TextOverflow
|
||||||
import androidx.core.view.WindowCompat
|
import androidx.core.view.WindowCompat
|
||||||
import chat.revolt.R
|
import chat.revolt.R
|
||||||
import chat.revolt.api.REVOLT_FILES
|
import chat.revolt.api.REVOLT_FILES
|
||||||
|
|
@ -45,7 +48,6 @@ import chat.revolt.api.RevoltHttp
|
||||||
import chat.revolt.api.schemas.AutumnResource
|
import chat.revolt.api.schemas.AutumnResource
|
||||||
import chat.revolt.api.settings.GlobalState
|
import chat.revolt.api.settings.GlobalState
|
||||||
import chat.revolt.api.settings.SyncedSettings
|
import chat.revolt.api.settings.SyncedSettings
|
||||||
import chat.revolt.components.generic.PageHeader
|
|
||||||
import chat.revolt.provider.getAttachmentContentUri
|
import chat.revolt.provider.getAttachmentContentUri
|
||||||
import chat.revolt.ui.theme.RevoltTheme
|
import chat.revolt.ui.theme.RevoltTheme
|
||||||
import com.bumptech.glide.integration.compose.ExperimentalGlideComposeApi
|
import com.bumptech.glide.integration.compose.ExperimentalGlideComposeApi
|
||||||
|
|
@ -82,7 +84,7 @@ class ImageViewActivity : ComponentActivity() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@OptIn(ExperimentalGlideComposeApi::class)
|
@OptIn(ExperimentalGlideComposeApi::class, ExperimentalMaterial3Api::class)
|
||||||
@Composable
|
@Composable
|
||||||
fun ImageViewScreen(resource: AutumnResource, onClose: () -> Unit = {}) {
|
fun ImageViewScreen(resource: AutumnResource, onClose: () -> Unit = {}) {
|
||||||
val resourceUrl = "$REVOLT_FILES/attachments/${resource.id}/${resource.filename}"
|
val resourceUrl = "$REVOLT_FILES/attachments/${resource.id}/${resource.filename}"
|
||||||
|
|
@ -187,6 +189,81 @@ fun ImageViewScreen(resource: AutumnResource, onClose: () -> Unit = {}) {
|
||||||
colourOverrides = SyncedSettings.android.colourOverrides
|
colourOverrides = SyncedSettings.android.colourOverrides
|
||||||
) {
|
) {
|
||||||
Scaffold(
|
Scaffold(
|
||||||
|
topBar = {
|
||||||
|
TopAppBar(
|
||||||
|
title = {
|
||||||
|
Text(
|
||||||
|
text = stringResource(
|
||||||
|
id = R.string.media_viewer_title_image,
|
||||||
|
resource.filename ?: resource.id!!
|
||||||
|
),
|
||||||
|
maxLines = 1,
|
||||||
|
overflow = TextOverflow.Ellipsis,
|
||||||
|
)
|
||||||
|
},
|
||||||
|
navigationIcon = {
|
||||||
|
IconButton(onClick = {
|
||||||
|
onClose()
|
||||||
|
}) {
|
||||||
|
Icon(
|
||||||
|
imageVector = Icons.Default.ArrowBack,
|
||||||
|
contentDescription = stringResource(id = R.string.back)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
actions = {
|
||||||
|
IconButton(onClick = {
|
||||||
|
shareSubmenuIsOpen.value = true
|
||||||
|
}) {
|
||||||
|
Icon(
|
||||||
|
painter = painterResource(id = R.drawable.ic_share_24dp),
|
||||||
|
contentDescription = stringResource(id = R.string.share)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
DropdownMenu(
|
||||||
|
expanded = shareSubmenuIsOpen.value,
|
||||||
|
onDismissRequest = {
|
||||||
|
shareSubmenuIsOpen.value = false
|
||||||
|
}
|
||||||
|
) {
|
||||||
|
DropdownMenuItem(
|
||||||
|
onClick = {
|
||||||
|
shareUrl()
|
||||||
|
},
|
||||||
|
text = {
|
||||||
|
Text(
|
||||||
|
stringResource(id = R.string.media_viewer_share_url)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
DropdownMenuItem(
|
||||||
|
onClick = {
|
||||||
|
shareImage()
|
||||||
|
},
|
||||||
|
text = {
|
||||||
|
Text(
|
||||||
|
stringResource(
|
||||||
|
id = R.string.media_viewer_share_image
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
IconButton(onClick = {
|
||||||
|
saveToGallery()
|
||||||
|
}) {
|
||||||
|
Icon(
|
||||||
|
painter = painterResource(id = R.drawable.ic_download_24dp),
|
||||||
|
contentDescription = stringResource(
|
||||||
|
id = R.string.media_viewer_save
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
},
|
||||||
snackbarHost = { SnackbarHost(hostState = snackbarHostState) }
|
snackbarHost = { SnackbarHost(hostState = snackbarHostState) }
|
||||||
) { pv ->
|
) { pv ->
|
||||||
Surface(
|
Surface(
|
||||||
|
|
@ -195,87 +272,22 @@ fun ImageViewScreen(resource: AutumnResource, onClose: () -> Unit = {}) {
|
||||||
.background(MaterialTheme.colorScheme.background)
|
.background(MaterialTheme.colorScheme.background)
|
||||||
.fillMaxSize()
|
.fillMaxSize()
|
||||||
) {
|
) {
|
||||||
Column {
|
Box(
|
||||||
PageHeader(
|
modifier = Modifier
|
||||||
text = stringResource(
|
.clip(RectangleShape)
|
||||||
id = R.string.media_viewer_title_image,
|
.fillMaxSize()
|
||||||
resource.filename ?: resource.id!!
|
) {
|
||||||
|
ZoomableGlideImage(
|
||||||
|
model = resourceUrl,
|
||||||
|
contentDescription = null,
|
||||||
|
state = rememberZoomableImageState(
|
||||||
|
rememberZoomableState(
|
||||||
|
zoomSpec = ZoomSpec(maxZoomFactor = 10f)
|
||||||
|
)
|
||||||
),
|
),
|
||||||
showBackButton = true,
|
|
||||||
onBackButtonClicked = onClose,
|
|
||||||
maxLines = 1,
|
|
||||||
additionalButtons = {
|
|
||||||
Row {
|
|
||||||
IconButton(onClick = {
|
|
||||||
shareSubmenuIsOpen.value = true
|
|
||||||
}) {
|
|
||||||
Icon(
|
|
||||||
painter = painterResource(id = R.drawable.ic_share_24dp),
|
|
||||||
contentDescription = stringResource(id = R.string.share)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
DropdownMenu(
|
|
||||||
expanded = shareSubmenuIsOpen.value,
|
|
||||||
onDismissRequest = {
|
|
||||||
shareSubmenuIsOpen.value = false
|
|
||||||
}
|
|
||||||
) {
|
|
||||||
DropdownMenuItem(
|
|
||||||
onClick = {
|
|
||||||
shareUrl()
|
|
||||||
},
|
|
||||||
text = {
|
|
||||||
Text(
|
|
||||||
stringResource(id = R.string.media_viewer_share_url)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
)
|
|
||||||
DropdownMenuItem(
|
|
||||||
onClick = {
|
|
||||||
shareImage()
|
|
||||||
},
|
|
||||||
text = {
|
|
||||||
Text(
|
|
||||||
stringResource(
|
|
||||||
id = R.string.media_viewer_share_image
|
|
||||||
)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
IconButton(onClick = {
|
|
||||||
saveToGallery()
|
|
||||||
}) {
|
|
||||||
Icon(
|
|
||||||
painter = painterResource(id = R.drawable.ic_download_24dp),
|
|
||||||
contentDescription = stringResource(
|
|
||||||
id = R.string.media_viewer_save
|
|
||||||
)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
Box(
|
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.clip(RectangleShape)
|
|
||||||
.fillMaxSize()
|
.fillMaxSize()
|
||||||
) {
|
)
|
||||||
ZoomableGlideImage(
|
|
||||||
model = resourceUrl,
|
|
||||||
contentDescription = null,
|
|
||||||
state = rememberZoomableImageState(
|
|
||||||
rememberZoomableState(
|
|
||||||
zoomSpec = ZoomSpec(maxZoomFactor = 10f)
|
|
||||||
)
|
|
||||||
),
|
|
||||||
modifier = Modifier
|
|
||||||
.fillMaxSize()
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -12,12 +12,13 @@ import androidx.activity.compose.setContent
|
||||||
import androidx.activity.result.contract.ActivityResultContracts
|
import androidx.activity.result.contract.ActivityResultContracts
|
||||||
import androidx.compose.foundation.background
|
import androidx.compose.foundation.background
|
||||||
import androidx.compose.foundation.layout.Box
|
import androidx.compose.foundation.layout.Box
|
||||||
import androidx.compose.foundation.layout.Column
|
|
||||||
import androidx.compose.foundation.layout.Row
|
|
||||||
import androidx.compose.foundation.layout.fillMaxSize
|
import androidx.compose.foundation.layout.fillMaxSize
|
||||||
import androidx.compose.foundation.layout.padding
|
import androidx.compose.foundation.layout.padding
|
||||||
|
import androidx.compose.material.icons.Icons
|
||||||
|
import androidx.compose.material.icons.filled.ArrowBack
|
||||||
import androidx.compose.material3.DropdownMenu
|
import androidx.compose.material3.DropdownMenu
|
||||||
import androidx.compose.material3.DropdownMenuItem
|
import androidx.compose.material3.DropdownMenuItem
|
||||||
|
import androidx.compose.material3.ExperimentalMaterial3Api
|
||||||
import androidx.compose.material3.Icon
|
import androidx.compose.material3.Icon
|
||||||
import androidx.compose.material3.IconButton
|
import androidx.compose.material3.IconButton
|
||||||
import androidx.compose.material3.MaterialTheme
|
import androidx.compose.material3.MaterialTheme
|
||||||
|
|
@ -28,6 +29,7 @@ import androidx.compose.material3.SnackbarHostState
|
||||||
import androidx.compose.material3.SnackbarResult
|
import androidx.compose.material3.SnackbarResult
|
||||||
import androidx.compose.material3.Surface
|
import androidx.compose.material3.Surface
|
||||||
import androidx.compose.material3.Text
|
import androidx.compose.material3.Text
|
||||||
|
import androidx.compose.material3.TopAppBar
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.runtime.DisposableEffect
|
import androidx.compose.runtime.DisposableEffect
|
||||||
import androidx.compose.runtime.mutableStateOf
|
import androidx.compose.runtime.mutableStateOf
|
||||||
|
|
@ -39,6 +41,7 @@ import androidx.compose.ui.graphics.RectangleShape
|
||||||
import androidx.compose.ui.platform.LocalContext
|
import androidx.compose.ui.platform.LocalContext
|
||||||
import androidx.compose.ui.res.painterResource
|
import androidx.compose.ui.res.painterResource
|
||||||
import androidx.compose.ui.res.stringResource
|
import androidx.compose.ui.res.stringResource
|
||||||
|
import androidx.compose.ui.text.style.TextOverflow
|
||||||
import androidx.compose.ui.viewinterop.AndroidView
|
import androidx.compose.ui.viewinterop.AndroidView
|
||||||
import androidx.core.view.WindowCompat
|
import androidx.core.view.WindowCompat
|
||||||
import androidx.media3.common.MediaItem
|
import androidx.media3.common.MediaItem
|
||||||
|
|
@ -50,7 +53,6 @@ import chat.revolt.api.RevoltHttp
|
||||||
import chat.revolt.api.schemas.AutumnResource
|
import chat.revolt.api.schemas.AutumnResource
|
||||||
import chat.revolt.api.settings.GlobalState
|
import chat.revolt.api.settings.GlobalState
|
||||||
import chat.revolt.api.settings.SyncedSettings
|
import chat.revolt.api.settings.SyncedSettings
|
||||||
import chat.revolt.components.generic.PageHeader
|
|
||||||
import chat.revolt.provider.getAttachmentContentUri
|
import chat.revolt.provider.getAttachmentContentUri
|
||||||
import chat.revolt.ui.theme.RevoltTheme
|
import chat.revolt.ui.theme.RevoltTheme
|
||||||
import io.ktor.client.request.get
|
import io.ktor.client.request.get
|
||||||
|
|
@ -82,6 +84,7 @@ class VideoViewActivity : ComponentActivity() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@OptIn(ExperimentalMaterial3Api::class)
|
||||||
@androidx.annotation.OptIn(androidx.media3.common.util.UnstableApi::class)
|
@androidx.annotation.OptIn(androidx.media3.common.util.UnstableApi::class)
|
||||||
@Composable
|
@Composable
|
||||||
fun VideoViewScreen(resource: AutumnResource, onClose: () -> Unit = {}) {
|
fun VideoViewScreen(resource: AutumnResource, onClose: () -> Unit = {}) {
|
||||||
|
|
@ -199,6 +202,81 @@ fun VideoViewScreen(resource: AutumnResource, onClose: () -> Unit = {}) {
|
||||||
colourOverrides = SyncedSettings.android.colourOverrides
|
colourOverrides = SyncedSettings.android.colourOverrides
|
||||||
) {
|
) {
|
||||||
Scaffold(
|
Scaffold(
|
||||||
|
topBar = {
|
||||||
|
TopAppBar(
|
||||||
|
title = {
|
||||||
|
Text(
|
||||||
|
text = stringResource(
|
||||||
|
id = R.string.media_viewer_title_video,
|
||||||
|
resource.filename ?: resource.id!!
|
||||||
|
),
|
||||||
|
maxLines = 1,
|
||||||
|
overflow = TextOverflow.Ellipsis,
|
||||||
|
)
|
||||||
|
},
|
||||||
|
navigationIcon = {
|
||||||
|
IconButton(onClick = {
|
||||||
|
onClose()
|
||||||
|
}) {
|
||||||
|
Icon(
|
||||||
|
imageVector = Icons.Default.ArrowBack,
|
||||||
|
contentDescription = stringResource(id = R.string.back)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
actions = {
|
||||||
|
IconButton(onClick = {
|
||||||
|
shareSubmenuIsOpen.value = true
|
||||||
|
}) {
|
||||||
|
Icon(
|
||||||
|
painter = painterResource(id = R.drawable.ic_share_24dp),
|
||||||
|
contentDescription = stringResource(id = R.string.share)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
DropdownMenu(
|
||||||
|
expanded = shareSubmenuIsOpen.value,
|
||||||
|
onDismissRequest = {
|
||||||
|
shareSubmenuIsOpen.value = false
|
||||||
|
}
|
||||||
|
) {
|
||||||
|
DropdownMenuItem(
|
||||||
|
onClick = {
|
||||||
|
shareUrl()
|
||||||
|
},
|
||||||
|
text = {
|
||||||
|
Text(
|
||||||
|
stringResource(id = R.string.media_viewer_share_url)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
DropdownMenuItem(
|
||||||
|
onClick = {
|
||||||
|
shareVideo()
|
||||||
|
},
|
||||||
|
text = {
|
||||||
|
Text(
|
||||||
|
stringResource(
|
||||||
|
id = R.string.media_viewer_share_video
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
IconButton(onClick = {
|
||||||
|
saveToGallery()
|
||||||
|
}) {
|
||||||
|
Icon(
|
||||||
|
painter = painterResource(id = R.drawable.ic_download_24dp),
|
||||||
|
contentDescription = stringResource(
|
||||||
|
id = R.string.media_viewer_save
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
},
|
||||||
snackbarHost = { SnackbarHost(hostState = snackbarHostState) }
|
snackbarHost = { SnackbarHost(hostState = snackbarHostState) }
|
||||||
) { pv ->
|
) { pv ->
|
||||||
Surface(
|
Surface(
|
||||||
|
|
@ -207,89 +285,24 @@ fun VideoViewScreen(resource: AutumnResource, onClose: () -> Unit = {}) {
|
||||||
.background(MaterialTheme.colorScheme.background)
|
.background(MaterialTheme.colorScheme.background)
|
||||||
.fillMaxSize()
|
.fillMaxSize()
|
||||||
) {
|
) {
|
||||||
Column {
|
Box(
|
||||||
PageHeader(
|
modifier = Modifier
|
||||||
text = stringResource(
|
.clip(RectangleShape)
|
||||||
id = R.string.media_viewer_title_video,
|
.fillMaxSize()
|
||||||
resource.filename ?: resource.id!!
|
) {
|
||||||
),
|
AndroidView(
|
||||||
showBackButton = true,
|
factory = { context ->
|
||||||
onBackButtonClicked = onClose,
|
PlayerView(context).apply {
|
||||||
maxLines = 1,
|
setShowBuffering(PlayerView.SHOW_BUFFERING_ALWAYS)
|
||||||
additionalButtons = {
|
|
||||||
Row {
|
|
||||||
IconButton(onClick = {
|
|
||||||
shareSubmenuIsOpen.value = true
|
|
||||||
}) {
|
|
||||||
Icon(
|
|
||||||
painter = painterResource(id = R.drawable.ic_share_24dp),
|
|
||||||
contentDescription = stringResource(id = R.string.share)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
DropdownMenu(
|
|
||||||
expanded = shareSubmenuIsOpen.value,
|
|
||||||
onDismissRequest = {
|
|
||||||
shareSubmenuIsOpen.value = false
|
|
||||||
}
|
|
||||||
) {
|
|
||||||
DropdownMenuItem(
|
|
||||||
onClick = {
|
|
||||||
shareUrl()
|
|
||||||
},
|
|
||||||
text = {
|
|
||||||
Text(
|
|
||||||
stringResource(id = R.string.media_viewer_share_url)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
)
|
|
||||||
DropdownMenuItem(
|
|
||||||
onClick = {
|
|
||||||
shareVideo()
|
|
||||||
},
|
|
||||||
text = {
|
|
||||||
Text(
|
|
||||||
stringResource(
|
|
||||||
id = R.string.media_viewer_share_video
|
|
||||||
)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
IconButton(onClick = {
|
|
||||||
saveToGallery()
|
|
||||||
}) {
|
|
||||||
Icon(
|
|
||||||
painter = painterResource(id = R.drawable.ic_download_24dp),
|
|
||||||
contentDescription = stringResource(
|
|
||||||
id = R.string.media_viewer_save
|
|
||||||
)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
)
|
update = {
|
||||||
|
it.player = player
|
||||||
Box(
|
},
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.clip(RectangleShape)
|
|
||||||
.fillMaxSize()
|
.fillMaxSize()
|
||||||
) {
|
.background(MaterialTheme.colorScheme.background)
|
||||||
AndroidView(
|
)
|
||||||
factory = { context ->
|
|
||||||
PlayerView(context).apply {
|
|
||||||
setShowBuffering(PlayerView.SHOW_BUFFERING_ALWAYS)
|
|
||||||
}
|
|
||||||
},
|
|
||||||
update = {
|
|
||||||
it.player = player
|
|
||||||
},
|
|
||||||
modifier = Modifier
|
|
||||||
.fillMaxSize()
|
|
||||||
.background(MaterialTheme.colorScheme.background)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -2,9 +2,13 @@ package chat.revolt.components.chat
|
||||||
|
|
||||||
import androidx.compose.foundation.background
|
import androidx.compose.foundation.background
|
||||||
import androidx.compose.foundation.clickable
|
import androidx.compose.foundation.clickable
|
||||||
|
import androidx.compose.foundation.layout.Column
|
||||||
import androidx.compose.foundation.layout.Row
|
import androidx.compose.foundation.layout.Row
|
||||||
|
import androidx.compose.foundation.layout.WindowInsets
|
||||||
import androidx.compose.foundation.layout.fillMaxWidth
|
import androidx.compose.foundation.layout.fillMaxWidth
|
||||||
import androidx.compose.foundation.layout.padding
|
import androidx.compose.foundation.layout.padding
|
||||||
|
import androidx.compose.foundation.layout.statusBars
|
||||||
|
import androidx.compose.foundation.layout.windowInsetsPadding
|
||||||
import androidx.compose.material.icons.Icons
|
import androidx.compose.material.icons.Icons
|
||||||
import androidx.compose.material.icons.filled.Done
|
import androidx.compose.material.icons.filled.Done
|
||||||
import androidx.compose.material.icons.filled.Refresh
|
import androidx.compose.material.icons.filled.Refresh
|
||||||
|
|
@ -44,32 +48,35 @@ private fun DisconnectedNoticeBase(
|
||||||
canTapToRetry: Boolean = false,
|
canTapToRetry: Boolean = false,
|
||||||
onRetry: () -> Unit = {}
|
onRetry: () -> Unit = {}
|
||||||
) {
|
) {
|
||||||
Row(
|
Column {
|
||||||
modifier = Modifier
|
Row(
|
||||||
.clickable(enabled = canTapToRetry, onClick = onRetry)
|
modifier = Modifier
|
||||||
.fillMaxWidth()
|
.clickable(enabled = canTapToRetry, onClick = onRetry)
|
||||||
.background(background)
|
.fillMaxWidth()
|
||||||
.padding(vertical = 8.dp, horizontal = 16.dp),
|
.background(background)
|
||||||
verticalAlignment = Alignment.CenterVertically
|
.windowInsetsPadding(WindowInsets.statusBars)
|
||||||
) {
|
.padding(vertical = 8.dp, horizontal = 16.dp),
|
||||||
Icon(
|
verticalAlignment = Alignment.CenterVertically
|
||||||
modifier = Modifier.padding(end = 8.dp),
|
) {
|
||||||
imageVector = icon,
|
Icon(
|
||||||
tint = foreground,
|
modifier = Modifier.padding(end = 8.dp),
|
||||||
contentDescription = null
|
imageVector = icon,
|
||||||
)
|
tint = foreground,
|
||||||
Text(
|
contentDescription = null
|
||||||
text = text,
|
|
||||||
color = foreground,
|
|
||||||
fontWeight = FontWeight.Bold
|
|
||||||
)
|
|
||||||
if (canTapToRetry) {
|
|
||||||
Text(
|
|
||||||
text = stringResource(R.string.tap_to_reconnect),
|
|
||||||
color = foreground,
|
|
||||||
modifier = Modifier.padding(start = 8.dp),
|
|
||||||
fontWeight = FontWeight.Normal
|
|
||||||
)
|
)
|
||||||
|
Text(
|
||||||
|
text = text,
|
||||||
|
color = foreground,
|
||||||
|
fontWeight = FontWeight.Bold
|
||||||
|
)
|
||||||
|
if (canTapToRetry) {
|
||||||
|
Text(
|
||||||
|
text = stringResource(R.string.tap_to_reconnect),
|
||||||
|
color = foreground,
|
||||||
|
modifier = Modifier.padding(start = 8.dp),
|
||||||
|
fontWeight = FontWeight.Normal
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,88 +0,0 @@
|
||||||
package chat.revolt.components.generic
|
|
||||||
|
|
||||||
import androidx.compose.foundation.layout.Row
|
|
||||||
import androidx.compose.foundation.layout.padding
|
|
||||||
import androidx.compose.material.icons.Icons
|
|
||||||
import androidx.compose.material.icons.filled.ArrowBack
|
|
||||||
import androidx.compose.material.icons.filled.ArrowForward
|
|
||||||
import androidx.compose.material3.Icon
|
|
||||||
import androidx.compose.material3.IconButton
|
|
||||||
import androidx.compose.material3.MaterialTheme
|
|
||||||
import androidx.compose.material3.Text
|
|
||||||
import androidx.compose.runtime.Composable
|
|
||||||
import androidx.compose.ui.Alignment
|
|
||||||
import androidx.compose.ui.Modifier
|
|
||||||
import androidx.compose.ui.res.stringResource
|
|
||||||
import androidx.compose.ui.text.font.FontWeight
|
|
||||||
import androidx.compose.ui.text.style.TextAlign
|
|
||||||
import androidx.compose.ui.text.style.TextOverflow
|
|
||||||
import androidx.compose.ui.tooling.preview.Preview
|
|
||||||
import androidx.compose.ui.unit.dp
|
|
||||||
import androidx.compose.ui.unit.sp
|
|
||||||
import chat.revolt.R
|
|
||||||
|
|
||||||
@Composable
|
|
||||||
fun PageHeader(
|
|
||||||
text: String,
|
|
||||||
modifier: Modifier = Modifier,
|
|
||||||
showBackButton: Boolean = false,
|
|
||||||
onBackButtonClicked: () -> Unit = {},
|
|
||||||
startButtons: @Composable () -> Unit = {},
|
|
||||||
additionalButtons: @Composable () -> Unit = {},
|
|
||||||
maxLines: Int = Int.MAX_VALUE
|
|
||||||
) {
|
|
||||||
Row(
|
|
||||||
verticalAlignment = Alignment.CenterVertically
|
|
||||||
) {
|
|
||||||
if (showBackButton) {
|
|
||||||
IconButton(onClick = onBackButtonClicked) {
|
|
||||||
Icon(
|
|
||||||
modifier = modifier,
|
|
||||||
imageVector = Icons.Default.ArrowBack,
|
|
||||||
contentDescription = stringResource(id = R.string.back)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
startButtons()
|
|
||||||
Text(
|
|
||||||
text = text,
|
|
||||||
maxLines = maxLines,
|
|
||||||
overflow = TextOverflow.Ellipsis,
|
|
||||||
style = MaterialTheme.typography.displaySmall.copy(
|
|
||||||
fontWeight = FontWeight.Bold,
|
|
||||||
textAlign = TextAlign.Left,
|
|
||||||
fontSize = 24.sp
|
|
||||||
),
|
|
||||||
modifier = modifier
|
|
||||||
.padding(horizontal = 15.dp, vertical = 15.dp)
|
|
||||||
.weight(1f)
|
|
||||||
)
|
|
||||||
additionalButtons()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Preview(showBackground = true)
|
|
||||||
@Composable
|
|
||||||
fun PageHeaderPreview() {
|
|
||||||
PageHeader(text = "Page Header")
|
|
||||||
}
|
|
||||||
|
|
||||||
@Preview(showBackground = true)
|
|
||||||
@Composable
|
|
||||||
fun PageHeaderPreviewWithBackButton() {
|
|
||||||
PageHeader(text = "Page Header", showBackButton = true)
|
|
||||||
}
|
|
||||||
|
|
||||||
@Preview(showBackground = true)
|
|
||||||
@Composable
|
|
||||||
fun PageHeaderPreviewWithAdditionalButtons() {
|
|
||||||
PageHeader(text = "Page Header", showBackButton = true, additionalButtons = {
|
|
||||||
IconButton(onClick = {}) {
|
|
||||||
Icon(
|
|
||||||
modifier = Modifier,
|
|
||||||
imageVector = Icons.Default.ArrowForward,
|
|
||||||
contentDescription = null
|
|
||||||
)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
@ -0,0 +1,10 @@
|
||||||
|
package chat.revolt.internals.extensions
|
||||||
|
|
||||||
|
import androidx.compose.foundation.layout.WindowInsets
|
||||||
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.runtime.NonRestartableComposable
|
||||||
|
|
||||||
|
val WindowInsets.Companion.zero: WindowInsets
|
||||||
|
@Composable
|
||||||
|
@NonRestartableComposable
|
||||||
|
get() = WindowInsets(left = 0, right = 0, top = 0, bottom = 0)
|
||||||
|
|
@ -6,6 +6,8 @@ import androidx.compose.foundation.layout.fillMaxSize
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.runtime.LaunchedEffect
|
import androidx.compose.runtime.LaunchedEffect
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
|
import androidx.compose.ui.graphics.Color
|
||||||
|
import androidx.compose.ui.graphics.toArgb
|
||||||
import androidx.compose.ui.platform.LocalContext
|
import androidx.compose.ui.platform.LocalContext
|
||||||
import androidx.navigation.NavController
|
import androidx.navigation.NavController
|
||||||
import chat.revolt.RevoltApplication
|
import chat.revolt.RevoltApplication
|
||||||
|
|
@ -35,8 +37,10 @@ fun DefaultDestinationScreen(
|
||||||
nextDestination?.let {
|
nextDestination?.let {
|
||||||
// Fix for SDK >=31, where core-splashscreen accidentally removes dynamic colours
|
// Fix for SDK >=31, where core-splashscreen accidentally removes dynamic colours
|
||||||
// See the other one in MainActivity.kt
|
// See the other one in MainActivity.kt
|
||||||
DynamicColors.applyToActivityIfAvailable(context.getComponentActivity() as Activity)
|
val activity = context.getComponentActivity() as Activity
|
||||||
|
DynamicColors.applyToActivityIfAvailable(activity)
|
||||||
DynamicColors.applyToActivitiesIfAvailable(RevoltApplication.instance)
|
DynamicColors.applyToActivitiesIfAvailable(RevoltApplication.instance)
|
||||||
|
activity.window.statusBarColor = Color.Transparent.toArgb()
|
||||||
|
|
||||||
navController.popBackStack(navController.graph.startDestinationRoute!!, true)
|
navController.popBackStack(navController.graph.startDestinationRoute!!, true)
|
||||||
navController.navigate(it)
|
navController.navigate(it)
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,7 @@ import android.os.Build
|
||||||
import android.widget.Toast
|
import android.widget.Toast
|
||||||
import androidx.compose.foundation.Image
|
import androidx.compose.foundation.Image
|
||||||
import androidx.compose.foundation.layout.Arrangement
|
import androidx.compose.foundation.layout.Arrangement
|
||||||
|
import androidx.compose.foundation.layout.Box
|
||||||
import androidx.compose.foundation.layout.Column
|
import androidx.compose.foundation.layout.Column
|
||||||
import androidx.compose.foundation.layout.Row
|
import androidx.compose.foundation.layout.Row
|
||||||
import androidx.compose.foundation.layout.Spacer
|
import androidx.compose.foundation.layout.Spacer
|
||||||
|
|
@ -12,15 +13,21 @@ import androidx.compose.foundation.layout.fillMaxSize
|
||||||
import androidx.compose.foundation.layout.fillMaxWidth
|
import androidx.compose.foundation.layout.fillMaxWidth
|
||||||
import androidx.compose.foundation.layout.height
|
import androidx.compose.foundation.layout.height
|
||||||
import androidx.compose.foundation.layout.padding
|
import androidx.compose.foundation.layout.padding
|
||||||
import androidx.compose.foundation.layout.safeDrawingPadding
|
|
||||||
import androidx.compose.foundation.layout.size
|
import androidx.compose.foundation.layout.size
|
||||||
import androidx.compose.foundation.layout.width
|
import androidx.compose.foundation.layout.width
|
||||||
|
import androidx.compose.material.icons.Icons
|
||||||
|
import androidx.compose.material.icons.filled.ArrowBack
|
||||||
import androidx.compose.material3.CircularProgressIndicator
|
import androidx.compose.material3.CircularProgressIndicator
|
||||||
import androidx.compose.material3.ElevatedButton
|
import androidx.compose.material3.ElevatedButton
|
||||||
|
import androidx.compose.material3.ExperimentalMaterial3Api
|
||||||
|
import androidx.compose.material3.Icon
|
||||||
|
import androidx.compose.material3.IconButton
|
||||||
import androidx.compose.material3.LocalContentColor
|
import androidx.compose.material3.LocalContentColor
|
||||||
import androidx.compose.material3.MaterialTheme
|
import androidx.compose.material3.MaterialTheme
|
||||||
|
import androidx.compose.material3.Scaffold
|
||||||
import androidx.compose.material3.Text
|
import androidx.compose.material3.Text
|
||||||
import androidx.compose.material3.TextButton
|
import androidx.compose.material3.TextButton
|
||||||
|
import androidx.compose.material3.TopAppBar
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.runtime.getValue
|
import androidx.compose.runtime.getValue
|
||||||
import androidx.compose.runtime.mutableIntStateOf
|
import androidx.compose.runtime.mutableIntStateOf
|
||||||
|
|
@ -38,6 +45,7 @@ import androidx.compose.ui.res.stringResource
|
||||||
import androidx.compose.ui.text.AnnotatedString
|
import androidx.compose.ui.text.AnnotatedString
|
||||||
import androidx.compose.ui.text.font.FontWeight
|
import androidx.compose.ui.text.font.FontWeight
|
||||||
import androidx.compose.ui.text.style.TextAlign
|
import androidx.compose.ui.text.style.TextAlign
|
||||||
|
import androidx.compose.ui.text.style.TextOverflow
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
import androidx.lifecycle.ViewModel
|
import androidx.lifecycle.ViewModel
|
||||||
import androidx.lifecycle.viewModelScope
|
import androidx.lifecycle.viewModelScope
|
||||||
|
|
@ -49,7 +57,6 @@ import chat.revolt.api.REVOLT_BASE
|
||||||
import chat.revolt.api.RevoltJson
|
import chat.revolt.api.RevoltJson
|
||||||
import chat.revolt.api.routes.misc.Root
|
import chat.revolt.api.routes.misc.Root
|
||||||
import chat.revolt.api.routes.misc.getRootRoute
|
import chat.revolt.api.routes.misc.getRootRoute
|
||||||
import chat.revolt.components.generic.PageHeader
|
|
||||||
import chat.revolt.components.generic.PrimaryTabs
|
import chat.revolt.components.generic.PrimaryTabs
|
||||||
import chat.revolt.internals.Platform
|
import chat.revolt.internals.Platform
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
|
|
@ -126,6 +133,7 @@ fun DebugInfo(viewModel: AboutViewModel) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@OptIn(ExperimentalMaterial3Api::class)
|
||||||
@Composable
|
@Composable
|
||||||
fun AboutScreen(navController: NavController, viewModel: AboutViewModel = viewModel()) {
|
fun AboutScreen(navController: NavController, viewModel: AboutViewModel = viewModel()) {
|
||||||
val context = LocalContext.current
|
val context = LocalContext.current
|
||||||
|
|
@ -146,107 +154,126 @@ fun AboutScreen(navController: NavController, viewModel: AboutViewModel = viewMo
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Column(
|
Scaffold(
|
||||||
modifier = Modifier
|
topBar = {
|
||||||
.fillMaxSize()
|
TopAppBar(
|
||||||
.safeDrawingPadding(),
|
title = {
|
||||||
verticalArrangement = Arrangement.Center,
|
Text(
|
||||||
horizontalAlignment = Alignment.CenterHorizontally
|
text = stringResource(R.string.about),
|
||||||
) {
|
maxLines = 1,
|
||||||
PageHeader(
|
overflow = TextOverflow.Ellipsis,
|
||||||
text = stringResource(R.string.about),
|
)
|
||||||
showBackButton = true,
|
},
|
||||||
onBackButtonClicked = { navController.popBackStack() }
|
navigationIcon = {
|
||||||
)
|
IconButton(onClick = {
|
||||||
|
navController.popBackStack()
|
||||||
PrimaryTabs(
|
}) {
|
||||||
tabs = listOf(
|
Icon(
|
||||||
stringResource(R.string.about_tab_version),
|
imageVector = Icons.Default.ArrowBack,
|
||||||
stringResource(R.string.about_tab_details)
|
contentDescription = stringResource(id = R.string.back)
|
||||||
),
|
|
||||||
currentIndex = viewModel.selectedTabIndex,
|
|
||||||
onTabSelected = { viewModel.selectedTabIndex = it }
|
|
||||||
)
|
|
||||||
|
|
||||||
Column(
|
|
||||||
modifier = Modifier
|
|
||||||
.fillMaxWidth()
|
|
||||||
.fillMaxHeight()
|
|
||||||
.weight(1f),
|
|
||||||
verticalArrangement = Arrangement.Center,
|
|
||||||
horizontalAlignment = Alignment.CenterHorizontally
|
|
||||||
) {
|
|
||||||
if (viewModel.root == null) {
|
|
||||||
CircularProgressIndicator(
|
|
||||||
modifier = Modifier
|
|
||||||
.size(48.dp)
|
|
||||||
)
|
|
||||||
} else {
|
|
||||||
when (viewModel.selectedTabIndex) {
|
|
||||||
0 -> {
|
|
||||||
Image(
|
|
||||||
painter = painterResource(R.drawable.revolt_logo_wide),
|
|
||||||
contentDescription = stringResource(R.string.about_full_name),
|
|
||||||
colorFilter = ColorFilter.tint(LocalContentColor.current),
|
|
||||||
modifier = Modifier
|
|
||||||
.width(250.dp)
|
|
||||||
)
|
|
||||||
|
|
||||||
Spacer(modifier = Modifier.height(16.dp))
|
|
||||||
|
|
||||||
Text(
|
|
||||||
text = stringResource(R.string.about_full_name),
|
|
||||||
style = MaterialTheme.typography.titleMedium,
|
|
||||||
textAlign = TextAlign.Center
|
|
||||||
)
|
|
||||||
|
|
||||||
Spacer(modifier = Modifier.height(4.dp))
|
|
||||||
|
|
||||||
Text(
|
|
||||||
text = BuildConfig.VERSION_NAME,
|
|
||||||
style = MaterialTheme.typography.labelMedium.copy(
|
|
||||||
fontWeight = FontWeight.Normal
|
|
||||||
),
|
|
||||||
textAlign = TextAlign.Center
|
|
||||||
)
|
|
||||||
|
|
||||||
Spacer(modifier = Modifier.height(32.dp))
|
|
||||||
|
|
||||||
Text(
|
|
||||||
text = stringResource(R.string.about_brought_to_you_by),
|
|
||||||
style = MaterialTheme.typography.labelSmall.copy(
|
|
||||||
fontWeight = FontWeight.Light
|
|
||||||
),
|
|
||||||
color = LocalContentColor.current.copy(
|
|
||||||
alpha = 0.5f
|
|
||||||
),
|
|
||||||
textAlign = TextAlign.Center
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
},
|
||||||
|
) { pv ->
|
||||||
|
Box(Modifier.padding(pv)) {
|
||||||
|
Column(
|
||||||
|
modifier = Modifier
|
||||||
|
.fillMaxSize(),
|
||||||
|
verticalArrangement = Arrangement.Center,
|
||||||
|
horizontalAlignment = Alignment.CenterHorizontally
|
||||||
|
) {
|
||||||
|
PrimaryTabs(
|
||||||
|
tabs = listOf(
|
||||||
|
stringResource(R.string.about_tab_version),
|
||||||
|
stringResource(R.string.about_tab_details)
|
||||||
|
),
|
||||||
|
currentIndex = viewModel.selectedTabIndex,
|
||||||
|
onTabSelected = { viewModel.selectedTabIndex = it }
|
||||||
|
)
|
||||||
|
|
||||||
1 -> {
|
Column(
|
||||||
DebugInfo(viewModel)
|
modifier = Modifier
|
||||||
TextButton(onClick = ::copyDebugInformation) {
|
.fillMaxWidth()
|
||||||
Text(text = stringResource(id = R.string.copy))
|
.fillMaxHeight()
|
||||||
|
.weight(1f),
|
||||||
|
verticalArrangement = Arrangement.Center,
|
||||||
|
horizontalAlignment = Alignment.CenterHorizontally
|
||||||
|
) {
|
||||||
|
if (viewModel.root == null) {
|
||||||
|
CircularProgressIndicator(
|
||||||
|
modifier = Modifier
|
||||||
|
.size(48.dp)
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
when (viewModel.selectedTabIndex) {
|
||||||
|
0 -> {
|
||||||
|
Image(
|
||||||
|
painter = painterResource(R.drawable.revolt_logo_wide),
|
||||||
|
contentDescription = stringResource(R.string.about_full_name),
|
||||||
|
colorFilter = ColorFilter.tint(LocalContentColor.current),
|
||||||
|
modifier = Modifier
|
||||||
|
.width(250.dp)
|
||||||
|
)
|
||||||
|
|
||||||
|
Spacer(modifier = Modifier.height(16.dp))
|
||||||
|
|
||||||
|
Text(
|
||||||
|
text = stringResource(R.string.about_full_name),
|
||||||
|
style = MaterialTheme.typography.titleMedium,
|
||||||
|
textAlign = TextAlign.Center
|
||||||
|
)
|
||||||
|
|
||||||
|
Spacer(modifier = Modifier.height(4.dp))
|
||||||
|
|
||||||
|
Text(
|
||||||
|
text = BuildConfig.VERSION_NAME,
|
||||||
|
style = MaterialTheme.typography.labelMedium.copy(
|
||||||
|
fontWeight = FontWeight.Normal
|
||||||
|
),
|
||||||
|
textAlign = TextAlign.Center
|
||||||
|
)
|
||||||
|
|
||||||
|
Spacer(modifier = Modifier.height(32.dp))
|
||||||
|
|
||||||
|
Text(
|
||||||
|
text = stringResource(R.string.about_brought_to_you_by),
|
||||||
|
style = MaterialTheme.typography.labelSmall.copy(
|
||||||
|
fontWeight = FontWeight.Light
|
||||||
|
),
|
||||||
|
color = LocalContentColor.current.copy(
|
||||||
|
alpha = 0.5f
|
||||||
|
),
|
||||||
|
textAlign = TextAlign.Center
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
1 -> {
|
||||||
|
DebugInfo(viewModel)
|
||||||
|
TextButton(onClick = ::copyDebugInformation) {
|
||||||
|
Text(text = stringResource(id = R.string.copy))
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Column(
|
||||||
|
modifier = Modifier
|
||||||
|
.fillMaxWidth()
|
||||||
|
.padding(horizontal = 20.dp, vertical = 30.dp),
|
||||||
|
horizontalAlignment = Alignment.CenterHorizontally
|
||||||
|
) {
|
||||||
|
ElevatedButton(
|
||||||
|
onClick = { navController.navigate("about/oss") },
|
||||||
|
modifier = Modifier
|
||||||
|
.testTag("view_oss_attribution")
|
||||||
|
) {
|
||||||
|
Text(text = stringResource(id = R.string.oss_attribution))
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Column(
|
|
||||||
modifier = Modifier
|
|
||||||
.fillMaxWidth()
|
|
||||||
.padding(horizontal = 20.dp, vertical = 30.dp),
|
|
||||||
horizontalAlignment = Alignment.CenterHorizontally
|
|
||||||
) {
|
|
||||||
ElevatedButton(
|
|
||||||
onClick = { navController.navigate("about/oss") },
|
|
||||||
modifier = Modifier
|
|
||||||
.testTag("view_oss_attribution")
|
|
||||||
) {
|
|
||||||
Text(text = stringResource(id = R.string.oss_attribution))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -2,21 +2,28 @@ package chat.revolt.screens.about
|
||||||
|
|
||||||
import androidx.compose.foundation.background
|
import androidx.compose.foundation.background
|
||||||
import androidx.compose.foundation.layout.Arrangement
|
import androidx.compose.foundation.layout.Arrangement
|
||||||
|
import androidx.compose.foundation.layout.Box
|
||||||
import androidx.compose.foundation.layout.Column
|
import androidx.compose.foundation.layout.Column
|
||||||
import androidx.compose.foundation.layout.Spacer
|
import androidx.compose.foundation.layout.Spacer
|
||||||
import androidx.compose.foundation.layout.fillMaxWidth
|
import androidx.compose.foundation.layout.fillMaxWidth
|
||||||
import androidx.compose.foundation.layout.height
|
import androidx.compose.foundation.layout.height
|
||||||
import androidx.compose.foundation.layout.padding
|
import androidx.compose.foundation.layout.padding
|
||||||
import androidx.compose.foundation.layout.safeDrawingPadding
|
|
||||||
import androidx.compose.foundation.lazy.LazyColumn
|
import androidx.compose.foundation.lazy.LazyColumn
|
||||||
import androidx.compose.foundation.lazy.items
|
import androidx.compose.foundation.lazy.items
|
||||||
import androidx.compose.foundation.rememberScrollState
|
import androidx.compose.foundation.rememberScrollState
|
||||||
import androidx.compose.foundation.verticalScroll
|
import androidx.compose.foundation.verticalScroll
|
||||||
|
import androidx.compose.material.icons.Icons
|
||||||
|
import androidx.compose.material.icons.filled.ArrowBack
|
||||||
import androidx.compose.material3.ExperimentalMaterial3Api
|
import androidx.compose.material3.ExperimentalMaterial3Api
|
||||||
|
import androidx.compose.material3.Icon
|
||||||
|
import androidx.compose.material3.IconButton
|
||||||
|
import androidx.compose.material3.LargeTopAppBar
|
||||||
import androidx.compose.material3.LocalContentColor
|
import androidx.compose.material3.LocalContentColor
|
||||||
import androidx.compose.material3.MaterialTheme
|
import androidx.compose.material3.MaterialTheme
|
||||||
import androidx.compose.material3.ModalBottomSheet
|
import androidx.compose.material3.ModalBottomSheet
|
||||||
|
import androidx.compose.material3.Scaffold
|
||||||
import androidx.compose.material3.Text
|
import androidx.compose.material3.Text
|
||||||
|
import androidx.compose.material3.TopAppBarDefaults
|
||||||
import androidx.compose.material3.rememberModalBottomSheetState
|
import androidx.compose.material3.rememberModalBottomSheetState
|
||||||
import androidx.compose.material3.surfaceColorAtElevation
|
import androidx.compose.material3.surfaceColorAtElevation
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
|
|
@ -27,13 +34,14 @@ import androidx.compose.runtime.remember
|
||||||
import androidx.compose.runtime.setValue
|
import androidx.compose.runtime.setValue
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
import androidx.compose.ui.draw.clip
|
import androidx.compose.ui.draw.clip
|
||||||
|
import androidx.compose.ui.input.nestedscroll.nestedScroll
|
||||||
import androidx.compose.ui.platform.LocalContext
|
import androidx.compose.ui.platform.LocalContext
|
||||||
import androidx.compose.ui.res.stringResource
|
import androidx.compose.ui.res.stringResource
|
||||||
import androidx.compose.ui.text.style.TextAlign
|
import androidx.compose.ui.text.style.TextAlign
|
||||||
|
import androidx.compose.ui.text.style.TextOverflow
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
import androidx.navigation.NavController
|
import androidx.navigation.NavController
|
||||||
import chat.revolt.R
|
import chat.revolt.R
|
||||||
import chat.revolt.components.generic.PageHeader
|
|
||||||
import chat.revolt.components.screens.settings.AttributionItem
|
import chat.revolt.components.screens.settings.AttributionItem
|
||||||
import kotlinx.serialization.Serializable
|
import kotlinx.serialization.Serializable
|
||||||
import kotlinx.serialization.json.Json
|
import kotlinx.serialization.json.Json
|
||||||
|
|
@ -144,66 +152,85 @@ fun AttributionScreen(navController: NavController) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Column(
|
val scrollBehavior = TopAppBarDefaults.exitUntilCollapsedScrollBehavior()
|
||||||
modifier = Modifier
|
|
||||||
.safeDrawingPadding()
|
|
||||||
) {
|
|
||||||
PageHeader(
|
|
||||||
text = stringResource(R.string.oss_attribution),
|
|
||||||
showBackButton = true,
|
|
||||||
onBackButtonClicked = { navController.popBackStack() }
|
|
||||||
)
|
|
||||||
|
|
||||||
libraries?.let {
|
Scaffold(
|
||||||
LazyColumn {
|
modifier = Modifier.nestedScroll(scrollBehavior.nestedScrollConnection),
|
||||||
item {
|
topBar = {
|
||||||
Column(
|
LargeTopAppBar(
|
||||||
modifier = Modifier
|
scrollBehavior = scrollBehavior,
|
||||||
.padding(16.dp)
|
title = {
|
||||||
.clip(MaterialTheme.shapes.medium)
|
|
||||||
.background(MaterialTheme.colorScheme.surfaceColorAtElevation(2.dp))
|
|
||||||
.fillMaxWidth()
|
|
||||||
.padding(16.dp),
|
|
||||||
verticalArrangement = Arrangement.spacedBy(8.dp)
|
|
||||||
) {
|
|
||||||
Text(
|
|
||||||
text = stringResource(R.string.oss_attribution_body)
|
|
||||||
)
|
|
||||||
Text(
|
|
||||||
text = stringResource(R.string.oss_attribution_body_2)
|
|
||||||
)
|
|
||||||
Text(
|
|
||||||
text = stringResource(R.string.oss_attribution_warning),
|
|
||||||
color = MaterialTheme.colorScheme.error
|
|
||||||
)
|
|
||||||
|
|
||||||
Text(
|
|
||||||
text = stringResource(
|
|
||||||
R.string.oss_attribution_generation_date,
|
|
||||||
libraries?.metadata?.generated ?: ""
|
|
||||||
),
|
|
||||||
color = LocalContentColor.current.copy(alpha = 0.6f)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
items(
|
|
||||||
items = it.libraries.sortedBy { library -> library.name }
|
|
||||||
) { library ->
|
|
||||||
AttributionItem(library = library) {
|
|
||||||
licenceSheetOpen = true
|
|
||||||
licenseSheetTarget = library.licenses.first()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
item(key = "cat") {
|
|
||||||
Text(
|
Text(
|
||||||
text = "🐈",
|
text = stringResource(R.string.oss_attribution),
|
||||||
modifier = Modifier
|
maxLines = 1,
|
||||||
.fillMaxWidth()
|
overflow = TextOverflow.Ellipsis,
|
||||||
.padding(16.dp),
|
|
||||||
textAlign = TextAlign.Center
|
|
||||||
)
|
)
|
||||||
|
},
|
||||||
|
navigationIcon = {
|
||||||
|
IconButton(onClick = {
|
||||||
|
navController.popBackStack()
|
||||||
|
}) {
|
||||||
|
Icon(
|
||||||
|
imageVector = Icons.Default.ArrowBack,
|
||||||
|
contentDescription = stringResource(id = R.string.back)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
)
|
||||||
|
},
|
||||||
|
) { pv ->
|
||||||
|
Box(Modifier.padding(pv)) {
|
||||||
|
libraries?.let {
|
||||||
|
LazyColumn {
|
||||||
|
item {
|
||||||
|
Column(
|
||||||
|
modifier = Modifier
|
||||||
|
.padding(16.dp)
|
||||||
|
.clip(MaterialTheme.shapes.medium)
|
||||||
|
.background(MaterialTheme.colorScheme.surfaceColorAtElevation(2.dp))
|
||||||
|
.fillMaxWidth()
|
||||||
|
.padding(16.dp),
|
||||||
|
verticalArrangement = Arrangement.spacedBy(8.dp)
|
||||||
|
) {
|
||||||
|
Text(
|
||||||
|
text = stringResource(R.string.oss_attribution_body)
|
||||||
|
)
|
||||||
|
Text(
|
||||||
|
text = stringResource(R.string.oss_attribution_body_2)
|
||||||
|
)
|
||||||
|
Text(
|
||||||
|
text = stringResource(R.string.oss_attribution_warning),
|
||||||
|
color = MaterialTheme.colorScheme.error
|
||||||
|
)
|
||||||
|
|
||||||
|
Text(
|
||||||
|
text = stringResource(
|
||||||
|
R.string.oss_attribution_generation_date,
|
||||||
|
libraries?.metadata?.generated ?: ""
|
||||||
|
),
|
||||||
|
color = LocalContentColor.current.copy(alpha = 0.6f)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
items(
|
||||||
|
items = it.libraries.sortedBy { library -> library.name }
|
||||||
|
) { library ->
|
||||||
|
AttributionItem(library = library) {
|
||||||
|
licenceSheetOpen = true
|
||||||
|
licenseSheetTarget = library.licenses.first()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
item(key = "cat") {
|
||||||
|
Text(
|
||||||
|
text = "🐈",
|
||||||
|
modifier = Modifier
|
||||||
|
.fillMaxWidth()
|
||||||
|
.padding(16.dp),
|
||||||
|
textAlign = TextAlign.Center
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -12,13 +12,17 @@ import androidx.compose.animation.AnimatedVisibility
|
||||||
import androidx.compose.animation.Crossfade
|
import androidx.compose.animation.Crossfade
|
||||||
import androidx.compose.foundation.layout.Column
|
import androidx.compose.foundation.layout.Column
|
||||||
import androidx.compose.foundation.layout.Row
|
import androidx.compose.foundation.layout.Row
|
||||||
|
import androidx.compose.foundation.layout.Spacer
|
||||||
|
import androidx.compose.foundation.layout.WindowInsets
|
||||||
import androidx.compose.foundation.layout.aspectRatio
|
import androidx.compose.foundation.layout.aspectRatio
|
||||||
import androidx.compose.foundation.layout.fillMaxHeight
|
import androidx.compose.foundation.layout.fillMaxHeight
|
||||||
import androidx.compose.foundation.layout.fillMaxSize
|
import androidx.compose.foundation.layout.fillMaxSize
|
||||||
import androidx.compose.foundation.layout.fillMaxWidth
|
import androidx.compose.foundation.layout.fillMaxWidth
|
||||||
|
import androidx.compose.foundation.layout.navigationBars
|
||||||
import androidx.compose.foundation.layout.padding
|
import androidx.compose.foundation.layout.padding
|
||||||
import androidx.compose.foundation.layout.safeDrawingPadding
|
|
||||||
import androidx.compose.foundation.layout.size
|
import androidx.compose.foundation.layout.size
|
||||||
|
import androidx.compose.foundation.layout.statusBars
|
||||||
|
import androidx.compose.foundation.layout.windowInsetsPadding
|
||||||
import androidx.compose.foundation.rememberScrollState
|
import androidx.compose.foundation.rememberScrollState
|
||||||
import androidx.compose.foundation.verticalScroll
|
import androidx.compose.foundation.verticalScroll
|
||||||
import androidx.compose.material.icons.Icons
|
import androidx.compose.material.icons.Icons
|
||||||
|
|
@ -723,7 +727,6 @@ fun ChatRouterScreen(
|
||||||
Column(
|
Column(
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.fillMaxWidth()
|
.fillMaxWidth()
|
||||||
.safeDrawingPadding()
|
|
||||||
) {
|
) {
|
||||||
AnimatedVisibility(
|
AnimatedVisibility(
|
||||||
visible = RealtimeSocket.disconnectionState != DisconnectionState.Connected
|
visible = RealtimeSocket.disconnectionState != DisconnectionState.Connected
|
||||||
|
|
@ -737,10 +740,17 @@ fun ChatRouterScreen(
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
AnimatedVisibility(
|
||||||
|
visible = RealtimeSocket.disconnectionState == DisconnectionState.Connected
|
||||||
|
) {
|
||||||
|
Spacer(Modifier.windowInsetsPadding(WindowInsets.statusBars))
|
||||||
|
}
|
||||||
|
|
||||||
if (useTabletAwareUI) {
|
if (useTabletAwareUI) {
|
||||||
Row {
|
Row {
|
||||||
DismissibleDrawerSheet(
|
DismissibleDrawerSheet(
|
||||||
drawerContainerColor = Color.Transparent
|
drawerContainerColor = Color.Transparent,
|
||||||
|
windowInsets = WindowInsets.navigationBars
|
||||||
) {
|
) {
|
||||||
Sidebar(
|
Sidebar(
|
||||||
viewModel = viewModel,
|
viewModel = viewModel,
|
||||||
|
|
@ -781,7 +791,8 @@ fun ChatRouterScreen(
|
||||||
drawerState = drawerState,
|
drawerState = drawerState,
|
||||||
drawerContent = {
|
drawerContent = {
|
||||||
DismissibleDrawerSheet(
|
DismissibleDrawerSheet(
|
||||||
drawerContainerColor = Color.Transparent
|
drawerContainerColor = Color.Transparent,
|
||||||
|
windowInsets = WindowInsets.navigationBars
|
||||||
) {
|
) {
|
||||||
Sidebar(
|
Sidebar(
|
||||||
viewModel = viewModel,
|
viewModel = viewModel,
|
||||||
|
|
@ -1044,7 +1055,6 @@ fun Sidebar(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@OptIn(ExperimentalMaterial3Api::class)
|
|
||||||
@Composable
|
@Composable
|
||||||
fun ChannelNavigator(
|
fun ChannelNavigator(
|
||||||
navController: NavHostController,
|
navController: NavHostController,
|
||||||
|
|
@ -1111,7 +1121,7 @@ fun ChannelNavigator(
|
||||||
toggleDrawer()
|
toggleDrawer()
|
||||||
}
|
}
|
||||||
|
|
||||||
NoCurrentChannelScreen()
|
NoCurrentChannelScreen(useDrawer = useDrawer, onDrawerClicked = toggleDrawer)
|
||||||
}
|
}
|
||||||
|
|
||||||
dialog("report/message/{messageId}") { backStackEntry ->
|
dialog("report/message/{messageId}") { backStackEntry ->
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,9 @@ package chat.revolt.screens.chat.views
|
||||||
import androidx.compose.foundation.ExperimentalFoundationApi
|
import androidx.compose.foundation.ExperimentalFoundationApi
|
||||||
import androidx.compose.foundation.clickable
|
import androidx.compose.foundation.clickable
|
||||||
import androidx.compose.foundation.layout.Column
|
import androidx.compose.foundation.layout.Column
|
||||||
|
import androidx.compose.foundation.layout.WindowInsets
|
||||||
import androidx.compose.foundation.layout.fillMaxHeight
|
import androidx.compose.foundation.layout.fillMaxHeight
|
||||||
|
import androidx.compose.foundation.layout.padding
|
||||||
import androidx.compose.foundation.lazy.LazyColumn
|
import androidx.compose.foundation.lazy.LazyColumn
|
||||||
import androidx.compose.material.icons.Icons
|
import androidx.compose.material.icons.Icons
|
||||||
import androidx.compose.material.icons.filled.Menu
|
import androidx.compose.material.icons.filled.Menu
|
||||||
|
|
@ -12,7 +14,9 @@ import androidx.compose.material3.ExperimentalMaterial3Api
|
||||||
import androidx.compose.material3.Icon
|
import androidx.compose.material3.Icon
|
||||||
import androidx.compose.material3.IconButton
|
import androidx.compose.material3.IconButton
|
||||||
import androidx.compose.material3.ModalBottomSheet
|
import androidx.compose.material3.ModalBottomSheet
|
||||||
|
import androidx.compose.material3.Scaffold
|
||||||
import androidx.compose.material3.Text
|
import androidx.compose.material3.Text
|
||||||
|
import androidx.compose.material3.TopAppBar
|
||||||
import androidx.compose.material3.rememberModalBottomSheetState
|
import androidx.compose.material3.rememberModalBottomSheetState
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.runtime.getValue
|
import androidx.compose.runtime.getValue
|
||||||
|
|
@ -23,6 +27,7 @@ import androidx.compose.runtime.setValue
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
import androidx.compose.ui.res.painterResource
|
import androidx.compose.ui.res.painterResource
|
||||||
import androidx.compose.ui.res.stringResource
|
import androidx.compose.ui.res.stringResource
|
||||||
|
import androidx.compose.ui.text.style.TextOverflow
|
||||||
import chat.revolt.R
|
import chat.revolt.R
|
||||||
import chat.revolt.api.internals.FriendRequests
|
import chat.revolt.api.internals.FriendRequests
|
||||||
import chat.revolt.api.routes.user.unfriendUser
|
import chat.revolt.api.routes.user.unfriendUser
|
||||||
|
|
@ -30,8 +35,8 @@ import chat.revolt.callbacks.Action
|
||||||
import chat.revolt.callbacks.ActionChannel
|
import chat.revolt.callbacks.ActionChannel
|
||||||
import chat.revolt.components.chat.MemberListItem
|
import chat.revolt.components.chat.MemberListItem
|
||||||
import chat.revolt.components.generic.CountableListHeader
|
import chat.revolt.components.generic.CountableListHeader
|
||||||
import chat.revolt.components.generic.PageHeader
|
|
||||||
import chat.revolt.components.generic.SheetClickable
|
import chat.revolt.components.generic.SheetClickable
|
||||||
|
import chat.revolt.internals.extensions.zero
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
|
|
||||||
|
|
@ -86,154 +91,168 @@ fun FriendsScreen(useDrawer: Boolean, onDrawerClicked: () -> Unit) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Column(
|
Scaffold(
|
||||||
modifier = Modifier
|
topBar = {
|
||||||
.fillMaxHeight()
|
TopAppBar(
|
||||||
) {
|
title = {
|
||||||
PageHeader(
|
Text(
|
||||||
text = stringResource(R.string.friends),
|
text = stringResource(R.string.friends),
|
||||||
startButtons = {
|
maxLines = 1,
|
||||||
if (useDrawer) {
|
overflow = TextOverflow.Ellipsis,
|
||||||
IconButton(onClick = onDrawerClicked) {
|
)
|
||||||
|
},
|
||||||
|
navigationIcon = {
|
||||||
|
if (useDrawer) {
|
||||||
|
IconButton(onClick = {
|
||||||
|
onDrawerClicked()
|
||||||
|
}) {
|
||||||
|
Icon(
|
||||||
|
imageVector = Icons.Default.Menu,
|
||||||
|
contentDescription = stringResource(id = R.string.menu)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
actions = {
|
||||||
|
IconButton(onClick = {
|
||||||
|
optionsSheetShown = true
|
||||||
|
}) {
|
||||||
Icon(
|
Icon(
|
||||||
imageVector = Icons.Default.Menu,
|
imageVector = Icons.Default.MoreVert,
|
||||||
contentDescription = stringResource(R.string.menu)
|
contentDescription = stringResource(R.string.menu)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
},
|
windowInsets = WindowInsets.zero
|
||||||
additionalButtons = {
|
)
|
||||||
IconButton(onClick = {
|
},
|
||||||
optionsSheetShown = true
|
) { pv ->
|
||||||
}) {
|
Column(
|
||||||
Icon(
|
modifier = Modifier
|
||||||
imageVector = Icons.Default.MoreVert,
|
.padding(pv)
|
||||||
contentDescription = stringResource(R.string.menu)
|
.fillMaxHeight()
|
||||||
|
) {
|
||||||
|
LazyColumn {
|
||||||
|
stickyHeader(key = "incoming") {
|
||||||
|
CountableListHeader(
|
||||||
|
text = stringResource(id = R.string.friends_incoming_requests),
|
||||||
|
count = FriendRequests.getIncoming().size
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
LazyColumn {
|
items(FriendRequests.getIncoming().size) {
|
||||||
stickyHeader(key = "incoming") {
|
val item = FriendRequests.getIncoming()[it]
|
||||||
CountableListHeader(
|
MemberListItem(
|
||||||
text = stringResource(id = R.string.friends_incoming_requests),
|
member = null,
|
||||||
count = FriendRequests.getIncoming().size
|
user = item,
|
||||||
)
|
serverId = null,
|
||||||
}
|
userId = item.id ?: "",
|
||||||
|
modifier = Modifier.clickable {
|
||||||
items(FriendRequests.getIncoming().size) {
|
scope.launch {
|
||||||
val item = FriendRequests.getIncoming()[it]
|
item.id?.let { userId ->
|
||||||
MemberListItem(
|
ActionChannel.send(Action.OpenUserSheet(userId, null))
|
||||||
member = null,
|
}
|
||||||
user = item,
|
|
||||||
serverId = null,
|
|
||||||
userId = item.id ?: "",
|
|
||||||
modifier = Modifier.clickable {
|
|
||||||
scope.launch {
|
|
||||||
item.id?.let { userId ->
|
|
||||||
ActionChannel.send(Action.OpenUserSheet(userId, null))
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
)
|
||||||
)
|
}
|
||||||
}
|
|
||||||
|
|
||||||
stickyHeader(key = "outgoing") {
|
stickyHeader(key = "outgoing") {
|
||||||
CountableListHeader(
|
CountableListHeader(
|
||||||
text = stringResource(id = R.string.friends_outgoing_requests),
|
text = stringResource(id = R.string.friends_outgoing_requests),
|
||||||
count = FriendRequests.getOutgoing().size
|
count = FriendRequests.getOutgoing().size
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
items(FriendRequests.getOutgoing().size) {
|
items(FriendRequests.getOutgoing().size) {
|
||||||
val item = FriendRequests.getOutgoing()[it]
|
val item = FriendRequests.getOutgoing()[it]
|
||||||
MemberListItem(
|
MemberListItem(
|
||||||
member = null,
|
member = null,
|
||||||
user = item,
|
user = item,
|
||||||
serverId = null,
|
serverId = null,
|
||||||
userId = item.id ?: "",
|
userId = item.id ?: "",
|
||||||
modifier = Modifier.clickable {
|
modifier = Modifier.clickable {
|
||||||
scope.launch {
|
scope.launch {
|
||||||
item.id?.let { userId ->
|
item.id?.let { userId ->
|
||||||
ActionChannel.send(Action.OpenUserSheet(userId, null))
|
ActionChannel.send(Action.OpenUserSheet(userId, null))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
)
|
||||||
)
|
}
|
||||||
}
|
|
||||||
|
|
||||||
stickyHeader(key = "online") {
|
stickyHeader(key = "online") {
|
||||||
CountableListHeader(
|
CountableListHeader(
|
||||||
text = stringResource(id = R.string.status_online),
|
text = stringResource(id = R.string.status_online),
|
||||||
count = FriendRequests.getOnlineFriends().size
|
count = FriendRequests.getOnlineFriends().size
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
items(FriendRequests.getOnlineFriends().size) {
|
items(FriendRequests.getOnlineFriends().size) {
|
||||||
val item = FriendRequests.getOnlineFriends()[it]
|
val item = FriendRequests.getOnlineFriends()[it]
|
||||||
MemberListItem(
|
MemberListItem(
|
||||||
member = null,
|
member = null,
|
||||||
user = item,
|
user = item,
|
||||||
serverId = null,
|
serverId = null,
|
||||||
userId = item.id ?: "",
|
userId = item.id ?: "",
|
||||||
modifier = Modifier.clickable {
|
modifier = Modifier.clickable {
|
||||||
scope.launch {
|
scope.launch {
|
||||||
item.id?.let { userId ->
|
item.id?.let { userId ->
|
||||||
ActionChannel.send(Action.OpenUserSheet(userId, null))
|
ActionChannel.send(Action.OpenUserSheet(userId, null))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
)
|
||||||
)
|
}
|
||||||
}
|
|
||||||
|
|
||||||
stickyHeader(key = "not_online") {
|
stickyHeader(key = "not_online") {
|
||||||
CountableListHeader(
|
CountableListHeader(
|
||||||
text = stringResource(id = R.string.friends_all),
|
text = stringResource(id = R.string.friends_all),
|
||||||
count = FriendRequests.getFriends(true).size
|
count = FriendRequests.getFriends(true).size
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
items(FriendRequests.getFriends(true).size) {
|
items(FriendRequests.getFriends(true).size) {
|
||||||
val item = FriendRequests.getFriends(true)[it]
|
val item = FriendRequests.getFriends(true)[it]
|
||||||
MemberListItem(
|
MemberListItem(
|
||||||
member = null,
|
member = null,
|
||||||
user = item,
|
user = item,
|
||||||
serverId = null,
|
serverId = null,
|
||||||
userId = item.id ?: "",
|
userId = item.id ?: "",
|
||||||
modifier = Modifier.clickable {
|
modifier = Modifier.clickable {
|
||||||
scope.launch {
|
scope.launch {
|
||||||
item.id?.let { userId ->
|
item.id?.let { userId ->
|
||||||
ActionChannel.send(Action.OpenUserSheet(userId, null))
|
ActionChannel.send(Action.OpenUserSheet(userId, null))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
)
|
||||||
)
|
}
|
||||||
}
|
|
||||||
|
|
||||||
stickyHeader(key = "blocked") {
|
stickyHeader(key = "blocked") {
|
||||||
CountableListHeader(
|
CountableListHeader(
|
||||||
text = stringResource(id = R.string.friends_blocked),
|
text = stringResource(id = R.string.friends_blocked),
|
||||||
count = FriendRequests.getBlocked().size
|
count = FriendRequests.getBlocked().size
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
items(FriendRequests.getBlocked().size) {
|
items(FriendRequests.getBlocked().size) {
|
||||||
val item = FriendRequests.getBlocked()[it]
|
val item = FriendRequests.getBlocked()[it]
|
||||||
MemberListItem(
|
MemberListItem(
|
||||||
member = null,
|
member = null,
|
||||||
user = item,
|
user = item,
|
||||||
serverId = null,
|
serverId = null,
|
||||||
userId = item.id ?: "",
|
userId = item.id ?: "",
|
||||||
modifier = Modifier.clickable {
|
modifier = Modifier.clickable {
|
||||||
scope.launch {
|
scope.launch {
|
||||||
item.id?.let { userId ->
|
item.id?.let { userId ->
|
||||||
ActionChannel.send(Action.OpenUserSheet(userId, null))
|
ActionChannel.send(Action.OpenUserSheet(userId, null))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
)
|
||||||
)
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -10,15 +10,19 @@ import androidx.compose.animation.core.rememberInfiniteTransition
|
||||||
import androidx.compose.animation.core.tween
|
import androidx.compose.animation.core.tween
|
||||||
import androidx.compose.foundation.layout.Box
|
import androidx.compose.foundation.layout.Box
|
||||||
import androidx.compose.foundation.layout.Column
|
import androidx.compose.foundation.layout.Column
|
||||||
|
import androidx.compose.foundation.layout.WindowInsets
|
||||||
|
import androidx.compose.foundation.layout.fillMaxHeight
|
||||||
import androidx.compose.foundation.layout.fillMaxSize
|
import androidx.compose.foundation.layout.fillMaxSize
|
||||||
import androidx.compose.foundation.layout.padding
|
import androidx.compose.foundation.layout.padding
|
||||||
import androidx.compose.foundation.layout.safeDrawingPadding
|
|
||||||
import androidx.compose.material.icons.Icons
|
import androidx.compose.material.icons.Icons
|
||||||
import androidx.compose.material.icons.filled.Menu
|
import androidx.compose.material.icons.filled.Menu
|
||||||
import androidx.compose.material.icons.filled.Star
|
import androidx.compose.material.icons.filled.Star
|
||||||
|
import androidx.compose.material3.ExperimentalMaterial3Api
|
||||||
import androidx.compose.material3.Icon
|
import androidx.compose.material3.Icon
|
||||||
import androidx.compose.material3.IconButton
|
import androidx.compose.material3.IconButton
|
||||||
|
import androidx.compose.material3.Scaffold
|
||||||
import androidx.compose.material3.Text
|
import androidx.compose.material3.Text
|
||||||
|
import androidx.compose.material3.TopAppBar
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.runtime.getValue
|
import androidx.compose.runtime.getValue
|
||||||
import androidx.compose.ui.Alignment
|
import androidx.compose.ui.Alignment
|
||||||
|
|
@ -26,14 +30,16 @@ import androidx.compose.ui.Modifier
|
||||||
import androidx.compose.ui.draw.rotate
|
import androidx.compose.ui.draw.rotate
|
||||||
import androidx.compose.ui.platform.LocalContext
|
import androidx.compose.ui.platform.LocalContext
|
||||||
import androidx.compose.ui.res.stringResource
|
import androidx.compose.ui.res.stringResource
|
||||||
|
import androidx.compose.ui.text.style.TextOverflow
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
import androidx.compose.ui.unit.sp
|
import androidx.compose.ui.unit.sp
|
||||||
import androidx.navigation.NavController
|
import androidx.navigation.NavController
|
||||||
import chat.revolt.R
|
import chat.revolt.R
|
||||||
import chat.revolt.activities.InviteActivity
|
import chat.revolt.activities.InviteActivity
|
||||||
import chat.revolt.components.generic.PageHeader
|
|
||||||
import chat.revolt.components.screens.home.LinkOnHome
|
import chat.revolt.components.screens.home.LinkOnHome
|
||||||
|
import chat.revolt.internals.extensions.zero
|
||||||
|
|
||||||
|
@OptIn(ExperimentalMaterial3Api::class)
|
||||||
@Composable
|
@Composable
|
||||||
fun HomeScreen(navController: NavController, useDrawer: Boolean, onDrawerClicked: () -> Unit) {
|
fun HomeScreen(navController: NavController, useDrawer: Boolean, onDrawerClicked: () -> Unit) {
|
||||||
val context = LocalContext.current
|
val context = LocalContext.current
|
||||||
|
|
@ -49,59 +55,75 @@ fun HomeScreen(navController: NavController, useDrawer: Boolean, onDrawerClicked
|
||||||
label = "catRotation"
|
label = "catRotation"
|
||||||
)
|
)
|
||||||
|
|
||||||
Column(
|
Scaffold(
|
||||||
modifier = Modifier.safeDrawingPadding()
|
topBar = {
|
||||||
) {
|
TopAppBar(
|
||||||
PageHeader(
|
title = {
|
||||||
text = stringResource(id = R.string.home),
|
Text(
|
||||||
startButtons = {
|
text = stringResource(R.string.home),
|
||||||
if (useDrawer) {
|
maxLines = 1,
|
||||||
IconButton(onClick = onDrawerClicked) {
|
overflow = TextOverflow.Ellipsis,
|
||||||
Icon(
|
|
||||||
imageVector = Icons.Default.Menu,
|
|
||||||
contentDescription = stringResource(R.string.menu)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
)
|
|
||||||
Box(
|
|
||||||
modifier = Modifier
|
|
||||||
.weight(1f)
|
|
||||||
.fillMaxSize(),
|
|
||||||
contentAlignment = Alignment.Center
|
|
||||||
) {
|
|
||||||
Text(
|
|
||||||
text = "🐈",
|
|
||||||
fontSize = 100.sp,
|
|
||||||
modifier = Modifier.rotate(catRotation)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
Column(Modifier.padding(16.dp)) {
|
|
||||||
LinkOnHome(
|
|
||||||
icon = { modifier ->
|
|
||||||
Icon(
|
|
||||||
imageVector = Icons.Default.Star,
|
|
||||||
contentDescription = stringResource(id = R.string.home_join_jenvolt),
|
|
||||||
modifier = modifier
|
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
heading = { Text(text = stringResource(id = R.string.home_join_jenvolt)) },
|
navigationIcon = {
|
||||||
description = {
|
if (useDrawer) {
|
||||||
Text(
|
IconButton(onClick = {
|
||||||
text = stringResource(id = R.string.home_join_jenvolt_description)
|
onDrawerClicked()
|
||||||
|
}) {
|
||||||
|
Icon(
|
||||||
|
imageVector = Icons.Default.Menu,
|
||||||
|
contentDescription = stringResource(id = R.string.menu)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
windowInsets = WindowInsets.zero
|
||||||
|
)
|
||||||
|
},
|
||||||
|
) { pv ->
|
||||||
|
Column(
|
||||||
|
modifier = Modifier
|
||||||
|
.padding(pv)
|
||||||
|
.fillMaxHeight()
|
||||||
|
) {
|
||||||
|
Box(
|
||||||
|
modifier = Modifier
|
||||||
|
.weight(1f)
|
||||||
|
.fillMaxSize(),
|
||||||
|
contentAlignment = Alignment.Center
|
||||||
|
) {
|
||||||
|
Text(
|
||||||
|
text = "🐈",
|
||||||
|
fontSize = 100.sp,
|
||||||
|
modifier = Modifier.rotate(catRotation)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
Column(Modifier.padding(16.dp)) {
|
||||||
|
LinkOnHome(
|
||||||
|
icon = { modifier ->
|
||||||
|
Icon(
|
||||||
|
imageVector = Icons.Default.Star,
|
||||||
|
contentDescription = stringResource(id = R.string.home_join_jenvolt),
|
||||||
|
modifier = modifier
|
||||||
|
)
|
||||||
|
},
|
||||||
|
heading = { Text(text = stringResource(id = R.string.home_join_jenvolt)) },
|
||||||
|
description = {
|
||||||
|
Text(
|
||||||
|
text = stringResource(id = R.string.home_join_jenvolt_description)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
) {
|
||||||
|
context.startActivity(
|
||||||
|
Intent(
|
||||||
|
context,
|
||||||
|
InviteActivity::class.java
|
||||||
|
)
|
||||||
|
.setData(Uri.parse("https://rvlt.gg/jen"))
|
||||||
|
.setAction(Intent.ACTION_VIEW)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
) {
|
|
||||||
context.startActivity(
|
|
||||||
Intent(
|
|
||||||
context,
|
|
||||||
InviteActivity::class.java
|
|
||||||
)
|
|
||||||
.setData(Uri.parse("https://rvlt.gg/jen"))
|
|
||||||
.setAction(Intent.ACTION_VIEW)
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -2,10 +2,18 @@ package chat.revolt.screens.chat.views
|
||||||
|
|
||||||
import androidx.compose.foundation.layout.Arrangement
|
import androidx.compose.foundation.layout.Arrangement
|
||||||
import androidx.compose.foundation.layout.Column
|
import androidx.compose.foundation.layout.Column
|
||||||
|
import androidx.compose.foundation.layout.WindowInsets
|
||||||
import androidx.compose.foundation.layout.fillMaxSize
|
import androidx.compose.foundation.layout.fillMaxSize
|
||||||
import androidx.compose.foundation.layout.padding
|
import androidx.compose.foundation.layout.padding
|
||||||
|
import androidx.compose.material.icons.Icons
|
||||||
|
import androidx.compose.material.icons.filled.Menu
|
||||||
|
import androidx.compose.material3.ExperimentalMaterial3Api
|
||||||
|
import androidx.compose.material3.Icon
|
||||||
|
import androidx.compose.material3.IconButton
|
||||||
import androidx.compose.material3.MaterialTheme
|
import androidx.compose.material3.MaterialTheme
|
||||||
|
import androidx.compose.material3.Scaffold
|
||||||
import androidx.compose.material3.Text
|
import androidx.compose.material3.Text
|
||||||
|
import androidx.compose.material3.TopAppBar
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.ui.Alignment
|
import androidx.compose.ui.Alignment
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
|
|
@ -14,27 +22,51 @@ import androidx.compose.ui.text.style.TextAlign
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
import androidx.compose.ui.unit.sp
|
import androidx.compose.ui.unit.sp
|
||||||
import chat.revolt.R
|
import chat.revolt.R
|
||||||
|
import chat.revolt.internals.extensions.zero
|
||||||
|
|
||||||
|
@OptIn(ExperimentalMaterial3Api::class)
|
||||||
@Composable
|
@Composable
|
||||||
fun NoCurrentChannelScreen() {
|
fun NoCurrentChannelScreen(useDrawer: Boolean, onDrawerClicked: () -> Unit) {
|
||||||
Column(
|
Scaffold(
|
||||||
modifier = Modifier
|
topBar = {
|
||||||
.fillMaxSize()
|
TopAppBar(
|
||||||
.padding(64.dp),
|
title = {},
|
||||||
verticalArrangement = Arrangement.Center,
|
navigationIcon = {
|
||||||
horizontalAlignment = Alignment.CenterHorizontally
|
if (useDrawer) {
|
||||||
) {
|
IconButton(onClick = {
|
||||||
Text(
|
onDrawerClicked()
|
||||||
text = stringResource(R.string.no_active_channel),
|
}) {
|
||||||
style = MaterialTheme.typography.labelLarge,
|
Icon(
|
||||||
textAlign = TextAlign.Center,
|
imageVector = Icons.Default.Menu,
|
||||||
fontSize = 24.sp,
|
contentDescription = stringResource(id = R.string.menu)
|
||||||
modifier = Modifier.padding(bottom = 16.dp)
|
)
|
||||||
)
|
}
|
||||||
Text(
|
}
|
||||||
text = stringResource(R.string.no_active_channel_body),
|
},
|
||||||
style = MaterialTheme.typography.bodyMedium,
|
windowInsets = WindowInsets.zero
|
||||||
textAlign = TextAlign.Center
|
)
|
||||||
)
|
},
|
||||||
|
) { pv ->
|
||||||
|
Column(
|
||||||
|
modifier = Modifier
|
||||||
|
.padding(pv)
|
||||||
|
.fillMaxSize()
|
||||||
|
.padding(64.dp),
|
||||||
|
verticalArrangement = Arrangement.Center,
|
||||||
|
horizontalAlignment = Alignment.CenterHorizontally
|
||||||
|
) {
|
||||||
|
Text(
|
||||||
|
text = stringResource(R.string.no_active_channel),
|
||||||
|
style = MaterialTheme.typography.labelLarge,
|
||||||
|
textAlign = TextAlign.Center,
|
||||||
|
fontSize = 24.sp,
|
||||||
|
modifier = Modifier.padding(bottom = 16.dp)
|
||||||
|
)
|
||||||
|
Text(
|
||||||
|
text = stringResource(R.string.no_active_channel_body),
|
||||||
|
style = MaterialTheme.typography.bodyMedium,
|
||||||
|
textAlign = TextAlign.Center
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -20,12 +20,14 @@ import androidx.compose.foundation.background
|
||||||
import androidx.compose.foundation.layout.Box
|
import androidx.compose.foundation.layout.Box
|
||||||
import androidx.compose.foundation.layout.Column
|
import androidx.compose.foundation.layout.Column
|
||||||
import androidx.compose.foundation.layout.Spacer
|
import androidx.compose.foundation.layout.Spacer
|
||||||
|
import androidx.compose.foundation.layout.WindowInsets
|
||||||
import androidx.compose.foundation.layout.fillMaxHeight
|
import androidx.compose.foundation.layout.fillMaxHeight
|
||||||
import androidx.compose.foundation.layout.fillMaxWidth
|
import androidx.compose.foundation.layout.fillMaxWidth
|
||||||
import androidx.compose.foundation.layout.height
|
import androidx.compose.foundation.layout.height
|
||||||
import androidx.compose.foundation.layout.imePadding
|
import androidx.compose.foundation.layout.imePadding
|
||||||
|
import androidx.compose.foundation.layout.navigationBars
|
||||||
import androidx.compose.foundation.layout.padding
|
import androidx.compose.foundation.layout.padding
|
||||||
import androidx.compose.foundation.layout.safeDrawingPadding
|
import androidx.compose.foundation.layout.windowInsetsPadding
|
||||||
import androidx.compose.foundation.lazy.LazyColumn
|
import androidx.compose.foundation.lazy.LazyColumn
|
||||||
import androidx.compose.foundation.lazy.items
|
import androidx.compose.foundation.lazy.items
|
||||||
import androidx.compose.foundation.lazy.rememberLazyListState
|
import androidx.compose.foundation.lazy.rememberLazyListState
|
||||||
|
|
@ -258,7 +260,7 @@ fun ChannelScreen(
|
||||||
Column(
|
Column(
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.imePadding()
|
.imePadding()
|
||||||
.safeDrawingPadding()
|
.windowInsetsPadding(WindowInsets.navigationBars)
|
||||||
) {
|
) {
|
||||||
ChannelHeader(
|
ChannelHeader(
|
||||||
channel = channel ?: Channel(
|
channel = channel ?: Channel(
|
||||||
|
|
|
||||||
|
|
@ -2,29 +2,55 @@ package chat.revolt.screens.services
|
||||||
|
|
||||||
import androidx.compose.foundation.layout.Column
|
import androidx.compose.foundation.layout.Column
|
||||||
import androidx.compose.foundation.layout.fillMaxSize
|
import androidx.compose.foundation.layout.fillMaxSize
|
||||||
import androidx.compose.foundation.layout.safeDrawingPadding
|
import androidx.compose.foundation.layout.padding
|
||||||
|
import androidx.compose.material.icons.Icons
|
||||||
|
import androidx.compose.material.icons.filled.ArrowBack
|
||||||
|
import androidx.compose.material3.ExperimentalMaterial3Api
|
||||||
|
import androidx.compose.material3.Icon
|
||||||
|
import androidx.compose.material3.IconButton
|
||||||
|
import androidx.compose.material3.Scaffold
|
||||||
|
import androidx.compose.material3.Text
|
||||||
|
import androidx.compose.material3.TopAppBar
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
import androidx.compose.ui.res.stringResource
|
import androidx.compose.ui.res.stringResource
|
||||||
|
import androidx.compose.ui.text.style.TextOverflow
|
||||||
import androidx.navigation.NavController
|
import androidx.navigation.NavController
|
||||||
import chat.revolt.R
|
import chat.revolt.R
|
||||||
import chat.revolt.components.generic.PageHeader
|
|
||||||
import chat.revolt.components.screens.services.DiscoverView
|
import chat.revolt.components.screens.services.DiscoverView
|
||||||
|
|
||||||
|
@OptIn(ExperimentalMaterial3Api::class)
|
||||||
@Composable
|
@Composable
|
||||||
fun DiscoverScreen(navController: NavController) {
|
fun DiscoverScreen(navController: NavController) {
|
||||||
Column(
|
Scaffold(
|
||||||
Modifier
|
topBar = {
|
||||||
.fillMaxSize()
|
TopAppBar(
|
||||||
.safeDrawingPadding()
|
title = {
|
||||||
) {
|
Text(
|
||||||
PageHeader(
|
text = stringResource(R.string.discover),
|
||||||
text = stringResource(R.string.discover),
|
maxLines = 1,
|
||||||
showBackButton = true,
|
overflow = TextOverflow.Ellipsis,
|
||||||
onBackButtonClicked = {
|
)
|
||||||
navController.popBackStack()
|
},
|
||||||
}
|
navigationIcon = {
|
||||||
)
|
IconButton(onClick = {
|
||||||
DiscoverView()
|
navController.popBackStack()
|
||||||
|
}) {
|
||||||
|
Icon(
|
||||||
|
imageVector = Icons.Default.ArrowBack,
|
||||||
|
contentDescription = stringResource(id = R.string.back)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
) { pv ->
|
||||||
|
Column(
|
||||||
|
Modifier
|
||||||
|
.padding(pv)
|
||||||
|
.fillMaxSize()
|
||||||
|
) {
|
||||||
|
DiscoverView()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -10,6 +10,7 @@ import androidx.compose.animation.core.animateFloatAsState
|
||||||
import androidx.compose.foundation.clickable
|
import androidx.compose.foundation.clickable
|
||||||
import androidx.compose.foundation.isSystemInDarkTheme
|
import androidx.compose.foundation.isSystemInDarkTheme
|
||||||
import androidx.compose.foundation.layout.Arrangement
|
import androidx.compose.foundation.layout.Arrangement
|
||||||
|
import androidx.compose.foundation.layout.Box
|
||||||
import androidx.compose.foundation.layout.Column
|
import androidx.compose.foundation.layout.Column
|
||||||
import androidx.compose.foundation.layout.ExperimentalLayoutApi
|
import androidx.compose.foundation.layout.ExperimentalLayoutApi
|
||||||
import androidx.compose.foundation.layout.FlowRow
|
import androidx.compose.foundation.layout.FlowRow
|
||||||
|
|
@ -19,11 +20,11 @@ import androidx.compose.foundation.layout.fillMaxSize
|
||||||
import androidx.compose.foundation.layout.fillMaxWidth
|
import androidx.compose.foundation.layout.fillMaxWidth
|
||||||
import androidx.compose.foundation.layout.height
|
import androidx.compose.foundation.layout.height
|
||||||
import androidx.compose.foundation.layout.padding
|
import androidx.compose.foundation.layout.padding
|
||||||
import androidx.compose.foundation.layout.safeDrawingPadding
|
|
||||||
import androidx.compose.foundation.layout.width
|
import androidx.compose.foundation.layout.width
|
||||||
import androidx.compose.foundation.rememberScrollState
|
import androidx.compose.foundation.rememberScrollState
|
||||||
import androidx.compose.foundation.verticalScroll
|
import androidx.compose.foundation.verticalScroll
|
||||||
import androidx.compose.material.icons.Icons
|
import androidx.compose.material.icons.Icons
|
||||||
|
import androidx.compose.material.icons.filled.ArrowBack
|
||||||
import androidx.compose.material.icons.filled.Check
|
import androidx.compose.material.icons.filled.Check
|
||||||
import androidx.compose.material.icons.filled.Close
|
import androidx.compose.material.icons.filled.Close
|
||||||
import androidx.compose.material.icons.filled.Delete
|
import androidx.compose.material.icons.filled.Delete
|
||||||
|
|
@ -33,10 +34,14 @@ import androidx.compose.material.ripple.LocalRippleTheme
|
||||||
import androidx.compose.material3.Button
|
import androidx.compose.material3.Button
|
||||||
import androidx.compose.material3.ExperimentalMaterial3Api
|
import androidx.compose.material3.ExperimentalMaterial3Api
|
||||||
import androidx.compose.material3.Icon
|
import androidx.compose.material3.Icon
|
||||||
|
import androidx.compose.material3.IconButton
|
||||||
|
import androidx.compose.material3.LargeTopAppBar
|
||||||
import androidx.compose.material3.MaterialTheme
|
import androidx.compose.material3.MaterialTheme
|
||||||
import androidx.compose.material3.ModalBottomSheet
|
import androidx.compose.material3.ModalBottomSheet
|
||||||
|
import androidx.compose.material3.Scaffold
|
||||||
import androidx.compose.material3.Text
|
import androidx.compose.material3.Text
|
||||||
import androidx.compose.material3.TextButton
|
import androidx.compose.material3.TextButton
|
||||||
|
import androidx.compose.material3.TopAppBarDefaults
|
||||||
import androidx.compose.material3.dynamicDarkColorScheme
|
import androidx.compose.material3.dynamicDarkColorScheme
|
||||||
import androidx.compose.material3.rememberModalBottomSheetState
|
import androidx.compose.material3.rememberModalBottomSheetState
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
|
|
@ -51,11 +56,13 @@ import androidx.compose.ui.Modifier
|
||||||
import androidx.compose.ui.draw.rotate
|
import androidx.compose.ui.draw.rotate
|
||||||
import androidx.compose.ui.graphics.Color
|
import androidx.compose.ui.graphics.Color
|
||||||
import androidx.compose.ui.graphics.toArgb
|
import androidx.compose.ui.graphics.toArgb
|
||||||
|
import androidx.compose.ui.input.nestedscroll.nestedScroll
|
||||||
import androidx.compose.ui.platform.LocalContext
|
import androidx.compose.ui.platform.LocalContext
|
||||||
import androidx.compose.ui.platform.LocalLayoutDirection
|
import androidx.compose.ui.platform.LocalLayoutDirection
|
||||||
import androidx.compose.ui.platform.testTag
|
import androidx.compose.ui.platform.testTag
|
||||||
import androidx.compose.ui.res.painterResource
|
import androidx.compose.ui.res.painterResource
|
||||||
import androidx.compose.ui.res.stringResource
|
import androidx.compose.ui.res.stringResource
|
||||||
|
import androidx.compose.ui.text.style.TextOverflow
|
||||||
import androidx.compose.ui.unit.LayoutDirection
|
import androidx.compose.ui.unit.LayoutDirection
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
import androidx.hilt.navigation.compose.hiltViewModel
|
import androidx.hilt.navigation.compose.hiltViewModel
|
||||||
|
|
@ -68,7 +75,6 @@ import chat.revolt.api.RevoltJson
|
||||||
import chat.revolt.api.settings.GlobalState
|
import chat.revolt.api.settings.GlobalState
|
||||||
import chat.revolt.api.settings.SyncedSettings
|
import chat.revolt.api.settings.SyncedSettings
|
||||||
import chat.revolt.components.generic.ListHeader
|
import chat.revolt.components.generic.ListHeader
|
||||||
import chat.revolt.components.generic.PageHeader
|
|
||||||
import chat.revolt.components.screens.settings.appearance.ColourChip
|
import chat.revolt.components.screens.settings.appearance.ColourChip
|
||||||
import chat.revolt.ui.theme.ClearRippleTheme
|
import chat.revolt.ui.theme.ClearRippleTheme
|
||||||
import chat.revolt.ui.theme.OverridableColourScheme
|
import chat.revolt.ui.theme.OverridableColourScheme
|
||||||
|
|
@ -263,218 +269,234 @@ fun AppearanceSettingsScreen(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Column(
|
val scrollBehavior = TopAppBarDefaults.exitUntilCollapsedScrollBehavior()
|
||||||
modifier = Modifier
|
|
||||||
.fillMaxSize()
|
|
||||||
.safeDrawingPadding()
|
|
||||||
) {
|
|
||||||
PageHeader(
|
|
||||||
text = stringResource(id = R.string.settings_appearance),
|
|
||||||
showBackButton = true,
|
|
||||||
onBackButtonClicked = {
|
|
||||||
navController.popBackStack()
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
Column(
|
Scaffold(
|
||||||
modifier = Modifier
|
modifier = Modifier.nestedScroll(scrollBehavior.nestedScrollConnection),
|
||||||
.fillMaxSize()
|
topBar = {
|
||||||
.verticalScroll(rememberScrollState())
|
LargeTopAppBar(
|
||||||
) {
|
scrollBehavior = scrollBehavior,
|
||||||
ListHeader {
|
title = {
|
||||||
Text(stringResource(R.string.settings_appearance_theme))
|
Text(
|
||||||
}
|
text = stringResource(R.string.settings_appearance),
|
||||||
|
maxLines = 1,
|
||||||
FlowRow(
|
overflow = TextOverflow.Ellipsis,
|
||||||
horizontalArrangement = Arrangement.spacedBy(10.dp),
|
)
|
||||||
verticalArrangement = Arrangement.spacedBy(10.dp),
|
},
|
||||||
|
navigationIcon = {
|
||||||
|
IconButton(onClick = {
|
||||||
|
navController.popBackStack()
|
||||||
|
}) {
|
||||||
|
Icon(
|
||||||
|
imageVector = Icons.Default.ArrowBack,
|
||||||
|
contentDescription = stringResource(id = R.string.back)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
)
|
||||||
|
},
|
||||||
|
) { pv ->
|
||||||
|
Box(Modifier.padding(pv)) {
|
||||||
|
Column(
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.fillMaxWidth()
|
.fillMaxSize()
|
||||||
.padding(start = 20.dp, end = 20.dp)
|
.verticalScroll(rememberScrollState())
|
||||||
) {
|
) {
|
||||||
ColourChip(
|
ListHeader {
|
||||||
color = Color(0xff191919),
|
Text(stringResource(R.string.settings_appearance_theme))
|
||||||
text = stringResource(id = R.string.settings_appearance_theme_revolt),
|
|
||||||
selected = GlobalState.theme == Theme.Revolt,
|
|
||||||
modifier = Modifier
|
|
||||||
.weight(1f)
|
|
||||||
.testTag("set_theme_revolt")
|
|
||||||
) {
|
|
||||||
viewModel.saveNewTheme(Theme.Revolt)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ColourChip(
|
FlowRow(
|
||||||
color = Color(0xfff7f7f7),
|
horizontalArrangement = Arrangement.spacedBy(10.dp),
|
||||||
text = stringResource(id = R.string.settings_appearance_theme_light),
|
verticalArrangement = Arrangement.spacedBy(10.dp),
|
||||||
selected = GlobalState.theme == Theme.Light,
|
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.weight(1f)
|
.fillMaxWidth()
|
||||||
.testTag("set_theme_light")
|
.padding(start = 20.dp, end = 20.dp)
|
||||||
) {
|
) {
|
||||||
viewModel.saveNewTheme(Theme.Light)
|
|
||||||
}
|
|
||||||
|
|
||||||
ColourChip(
|
|
||||||
color = Color(0xff000000),
|
|
||||||
text = stringResource(id = R.string.settings_appearance_theme_amoled),
|
|
||||||
selected = GlobalState.theme == Theme.Amoled,
|
|
||||||
modifier = Modifier
|
|
||||||
.weight(1f)
|
|
||||||
.testTag("set_theme_amoled")
|
|
||||||
) {
|
|
||||||
viewModel.saveNewTheme(Theme.Amoled)
|
|
||||||
}
|
|
||||||
|
|
||||||
ColourChip(
|
|
||||||
color = if (isSystemInDarkTheme()) Color(0xff191919) else Color(0xfff7f7f7),
|
|
||||||
text = stringResource(id = R.string.settings_appearance_theme_none),
|
|
||||||
selected = GlobalState.theme == Theme.None,
|
|
||||||
modifier = Modifier
|
|
||||||
.weight(1f)
|
|
||||||
.testTag("set_theme_none")
|
|
||||||
) {
|
|
||||||
viewModel.saveNewTheme(Theme.None)
|
|
||||||
}
|
|
||||||
|
|
||||||
if (systemSupportsDynamicColors()) {
|
|
||||||
ColourChip(
|
ColourChip(
|
||||||
color = dynamicDarkColorScheme(LocalContext.current).primary,
|
color = Color(0xff191919),
|
||||||
text = stringResource(id = R.string.settings_appearance_theme_m3dynamic),
|
text = stringResource(id = R.string.settings_appearance_theme_revolt),
|
||||||
selected = GlobalState.theme == Theme.M3Dynamic,
|
selected = GlobalState.theme == Theme.Revolt,
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.weight(1f)
|
.weight(1f)
|
||||||
.testTag("set_theme_m3dynamic")
|
.testTag("set_theme_revolt")
|
||||||
) {
|
) {
|
||||||
viewModel.saveNewTheme(Theme.M3Dynamic)
|
viewModel.saveNewTheme(Theme.Revolt)
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
ColourChip(
|
ColourChip(
|
||||||
color = Color(0xffa0a0a0),
|
color = Color(0xfff7f7f7),
|
||||||
text = stringResource(
|
text = stringResource(id = R.string.settings_appearance_theme_light),
|
||||||
id = R.string.settings_appearance_theme_m3dynamic_unsupported
|
selected = GlobalState.theme == Theme.Light,
|
||||||
),
|
|
||||||
selected = false,
|
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.weight(1f)
|
.weight(1f)
|
||||||
.testTag("set_theme_m3dynamic_unsupported")
|
.testTag("set_theme_light")
|
||||||
) {
|
) {
|
||||||
Toast.makeText(
|
viewModel.saveNewTheme(Theme.Light)
|
||||||
context,
|
|
||||||
context.getString(
|
|
||||||
R.string.settings_appearance_theme_m3dynamic_unsupported_toast
|
|
||||||
),
|
|
||||||
Toast.LENGTH_SHORT
|
|
||||||
).show()
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Spacer(modifier = Modifier.height(20.dp))
|
ColourChip(
|
||||||
|
color = Color(0xff000000),
|
||||||
Row(
|
text = stringResource(id = R.string.settings_appearance_theme_amoled),
|
||||||
modifier = Modifier
|
selected = GlobalState.theme == Theme.Amoled,
|
||||||
.clickable {
|
|
||||||
viewModel.showColourOverrides = !viewModel.showColourOverrides
|
|
||||||
}
|
|
||||||
.fillMaxWidth()
|
|
||||||
.padding(vertical = 10.dp),
|
|
||||||
verticalAlignment = Alignment.CenterVertically
|
|
||||||
) {
|
|
||||||
if (LocalLayoutDirection.current == LayoutDirection.Ltr) {
|
|
||||||
Icon(
|
|
||||||
imageVector = Icons.Default.KeyboardArrowRight,
|
|
||||||
contentDescription = null,
|
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.padding(start = 20.dp, end = 4.dp)
|
.weight(1f)
|
||||||
.rotate(colourOverridesOpenerArrowRotation)
|
.testTag("set_theme_amoled")
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
Text(
|
|
||||||
text = stringResource(id = R.string.settings_appearance_colour_overrides),
|
|
||||||
style = MaterialTheme.typography.labelLarge,
|
|
||||||
modifier = Modifier
|
|
||||||
.weight(1f)
|
|
||||||
)
|
|
||||||
|
|
||||||
if (LocalLayoutDirection.current == LayoutDirection.Rtl) {
|
|
||||||
Icon(
|
|
||||||
imageVector = Icons.Default.KeyboardArrowLeft,
|
|
||||||
contentDescription = null,
|
|
||||||
modifier = Modifier
|
|
||||||
.padding(start = 4.dp, end = 20.dp)
|
|
||||||
.rotate(colourOverridesOpenerArrowRotation)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
AnimatedVisibility(viewModel.showColourOverrides) {
|
|
||||||
Column {
|
|
||||||
Spacer(modifier = Modifier.height(10.dp))
|
|
||||||
|
|
||||||
Row(
|
|
||||||
horizontalArrangement = Arrangement.spacedBy(4.dp),
|
|
||||||
modifier = Modifier
|
|
||||||
.fillMaxWidth()
|
|
||||||
.padding(horizontal = 20.dp)
|
|
||||||
) {
|
) {
|
||||||
TextButton(
|
viewModel.saveNewTheme(Theme.Amoled)
|
||||||
onClick = {
|
|
||||||
filePicker.launch(arrayOf("*/*"))
|
|
||||||
},
|
|
||||||
modifier = Modifier.weight(1f)
|
|
||||||
) {
|
|
||||||
Icon(
|
|
||||||
painter = painterResource(R.drawable.ic_folder_24dp),
|
|
||||||
contentDescription = null
|
|
||||||
)
|
|
||||||
|
|
||||||
Spacer(modifier = Modifier.width(8.dp))
|
|
||||||
|
|
||||||
Text(
|
|
||||||
text = stringResource(id = R.string.settings_appearance_colour_overrides_import)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
TextButton(
|
|
||||||
onClick = {
|
|
||||||
fileSaver.launch("${SyncedSettings.android.theme}-colours.rato")
|
|
||||||
},
|
|
||||||
modifier = Modifier.weight(1f)
|
|
||||||
) {
|
|
||||||
Icon(
|
|
||||||
painter = painterResource(R.drawable.ic_content_save_24dp),
|
|
||||||
contentDescription = null
|
|
||||||
)
|
|
||||||
|
|
||||||
Spacer(modifier = Modifier.width(8.dp))
|
|
||||||
|
|
||||||
Text(
|
|
||||||
text = stringResource(id = R.string.settings_appearance_colour_overrides_export)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Spacer(modifier = Modifier.height(10.dp))
|
ColourChip(
|
||||||
|
color = if (isSystemInDarkTheme()) Color(0xff191919) else Color(0xfff7f7f7),
|
||||||
OverridableColourScheme.fieldNames.forEach { fieldName ->
|
text = stringResource(id = R.string.settings_appearance_theme_none),
|
||||||
val value =
|
selected = GlobalState.theme == Theme.None,
|
||||||
SyncedSettings.android.colourOverrides?.getFieldByName(fieldName)
|
modifier = Modifier
|
||||||
?: MaterialTheme.colorScheme.getFieldByName(fieldName)
|
.weight(1f)
|
||||||
|
.testTag("set_theme_none")
|
||||||
|
) {
|
||||||
|
viewModel.saveNewTheme(Theme.None)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (systemSupportsDynamicColors()) {
|
||||||
ColourChip(
|
ColourChip(
|
||||||
color = Color(value ?: 0),
|
color = dynamicDarkColorScheme(LocalContext.current).primary,
|
||||||
text = OverridableColourScheme.fieldNameToResource[fieldName]
|
text = stringResource(id = R.string.settings_appearance_theme_m3dynamic),
|
||||||
?.let { context.getString(it) }
|
selected = GlobalState.theme == Theme.M3Dynamic,
|
||||||
?: fieldName,
|
modifier = Modifier
|
||||||
|
.weight(1f)
|
||||||
|
.testTag("set_theme_m3dynamic")
|
||||||
|
) {
|
||||||
|
viewModel.saveNewTheme(Theme.M3Dynamic)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
ColourChip(
|
||||||
|
color = Color(0xffa0a0a0),
|
||||||
|
text = stringResource(
|
||||||
|
id = R.string.settings_appearance_theme_m3dynamic_unsupported
|
||||||
|
),
|
||||||
|
selected = false,
|
||||||
|
modifier = Modifier
|
||||||
|
.weight(1f)
|
||||||
|
.testTag("set_theme_m3dynamic_unsupported")
|
||||||
|
) {
|
||||||
|
Toast.makeText(
|
||||||
|
context,
|
||||||
|
context.getString(
|
||||||
|
R.string.settings_appearance_theme_m3dynamic_unsupported_toast
|
||||||
|
),
|
||||||
|
Toast.LENGTH_SHORT
|
||||||
|
).show()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Spacer(modifier = Modifier.height(20.dp))
|
||||||
|
|
||||||
|
Row(
|
||||||
|
modifier = Modifier
|
||||||
|
.clickable {
|
||||||
|
viewModel.showColourOverrides = !viewModel.showColourOverrides
|
||||||
|
}
|
||||||
|
.fillMaxWidth()
|
||||||
|
.padding(vertical = 10.dp),
|
||||||
|
verticalAlignment = Alignment.CenterVertically
|
||||||
|
) {
|
||||||
|
if (LocalLayoutDirection.current == LayoutDirection.Ltr) {
|
||||||
|
Icon(
|
||||||
|
imageVector = Icons.Default.KeyboardArrowRight,
|
||||||
|
contentDescription = null,
|
||||||
|
modifier = Modifier
|
||||||
|
.padding(start = 20.dp, end = 4.dp)
|
||||||
|
.rotate(colourOverridesOpenerArrowRotation)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
Text(
|
||||||
|
text = stringResource(id = R.string.settings_appearance_colour_overrides),
|
||||||
|
style = MaterialTheme.typography.labelLarge,
|
||||||
|
modifier = Modifier
|
||||||
|
.weight(1f)
|
||||||
|
)
|
||||||
|
|
||||||
|
if (LocalLayoutDirection.current == LayoutDirection.Rtl) {
|
||||||
|
Icon(
|
||||||
|
imageVector = Icons.Default.KeyboardArrowLeft,
|
||||||
|
contentDescription = null,
|
||||||
|
modifier = Modifier
|
||||||
|
.padding(start = 4.dp, end = 20.dp)
|
||||||
|
.rotate(colourOverridesOpenerArrowRotation)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
AnimatedVisibility(viewModel.showColourOverrides) {
|
||||||
|
Column {
|
||||||
|
Spacer(modifier = Modifier.height(10.dp))
|
||||||
|
|
||||||
|
Row(
|
||||||
|
horizontalArrangement = Arrangement.spacedBy(4.dp),
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.fillMaxWidth()
|
.fillMaxWidth()
|
||||||
.padding(start = 20.dp, end = 20.dp)
|
.padding(horizontal = 20.dp)
|
||||||
.testTag("set_colour_override_$fieldName")
|
|
||||||
) {
|
) {
|
||||||
viewModel.selectedOverrideName = fieldName
|
TextButton(
|
||||||
viewModel.selectedOverrideInitialValue = value
|
onClick = {
|
||||||
viewModel.overridePickerSheetVisible = true
|
filePicker.launch(arrayOf("*/*"))
|
||||||
|
},
|
||||||
|
modifier = Modifier.weight(1f)
|
||||||
|
) {
|
||||||
|
Icon(
|
||||||
|
painter = painterResource(R.drawable.ic_folder_24dp),
|
||||||
|
contentDescription = null
|
||||||
|
)
|
||||||
|
|
||||||
|
Spacer(modifier = Modifier.width(8.dp))
|
||||||
|
|
||||||
|
Text(
|
||||||
|
text = stringResource(id = R.string.settings_appearance_colour_overrides_import)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
TextButton(
|
||||||
|
onClick = {
|
||||||
|
fileSaver.launch("${SyncedSettings.android.theme}-colours.rato")
|
||||||
|
},
|
||||||
|
modifier = Modifier.weight(1f)
|
||||||
|
) {
|
||||||
|
Icon(
|
||||||
|
painter = painterResource(R.drawable.ic_content_save_24dp),
|
||||||
|
contentDescription = null
|
||||||
|
)
|
||||||
|
|
||||||
|
Spacer(modifier = Modifier.width(8.dp))
|
||||||
|
|
||||||
|
Text(
|
||||||
|
text = stringResource(id = R.string.settings_appearance_colour_overrides_export)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Spacer(modifier = Modifier.height(10.dp))
|
||||||
|
|
||||||
|
OverridableColourScheme.fieldNames.forEach { fieldName ->
|
||||||
|
val value =
|
||||||
|
SyncedSettings.android.colourOverrides?.getFieldByName(fieldName)
|
||||||
|
?: MaterialTheme.colorScheme.getFieldByName(fieldName)
|
||||||
|
|
||||||
|
ColourChip(
|
||||||
|
color = Color(value ?: 0),
|
||||||
|
text = OverridableColourScheme.fieldNameToResource[fieldName]
|
||||||
|
?.let { context.getString(it) }
|
||||||
|
?: fieldName,
|
||||||
|
modifier = Modifier
|
||||||
|
.fillMaxWidth()
|
||||||
|
.padding(start = 20.dp, end = 20.dp)
|
||||||
|
.testTag("set_colour_override_$fieldName")
|
||||||
|
) {
|
||||||
|
viewModel.selectedOverrideName = fieldName
|
||||||
|
viewModel.selectedOverrideInitialValue = value
|
||||||
|
viewModel.overridePickerSheetVisible = true
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -5,14 +5,21 @@ import androidx.compose.foundation.clickable
|
||||||
import androidx.compose.foundation.layout.Column
|
import androidx.compose.foundation.layout.Column
|
||||||
import androidx.compose.foundation.layout.fillMaxSize
|
import androidx.compose.foundation.layout.fillMaxSize
|
||||||
import androidx.compose.foundation.layout.fillMaxWidth
|
import androidx.compose.foundation.layout.fillMaxWidth
|
||||||
import androidx.compose.foundation.layout.safeDrawingPadding
|
import androidx.compose.foundation.layout.padding
|
||||||
import androidx.compose.foundation.lazy.LazyColumn
|
import androidx.compose.foundation.lazy.LazyColumn
|
||||||
|
import androidx.compose.material.icons.Icons
|
||||||
|
import androidx.compose.material.icons.filled.ArrowBack
|
||||||
import androidx.compose.material3.Divider
|
import androidx.compose.material3.Divider
|
||||||
import androidx.compose.material3.ExperimentalMaterial3Api
|
import androidx.compose.material3.ExperimentalMaterial3Api
|
||||||
|
import androidx.compose.material3.Icon
|
||||||
|
import androidx.compose.material3.IconButton
|
||||||
|
import androidx.compose.material3.LargeTopAppBar
|
||||||
import androidx.compose.material3.ListItem
|
import androidx.compose.material3.ListItem
|
||||||
import androidx.compose.material3.MaterialTheme
|
import androidx.compose.material3.MaterialTheme
|
||||||
import androidx.compose.material3.ModalBottomSheet
|
import androidx.compose.material3.ModalBottomSheet
|
||||||
|
import androidx.compose.material3.Scaffold
|
||||||
import androidx.compose.material3.Text
|
import androidx.compose.material3.Text
|
||||||
|
import androidx.compose.material3.TopAppBarDefaults
|
||||||
import androidx.compose.material3.rememberModalBottomSheetState
|
import androidx.compose.material3.rememberModalBottomSheetState
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.runtime.getValue
|
import androidx.compose.runtime.getValue
|
||||||
|
|
@ -20,12 +27,13 @@ import androidx.compose.runtime.mutableStateOf
|
||||||
import androidx.compose.runtime.remember
|
import androidx.compose.runtime.remember
|
||||||
import androidx.compose.runtime.setValue
|
import androidx.compose.runtime.setValue
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
|
import androidx.compose.ui.input.nestedscroll.nestedScroll
|
||||||
import androidx.compose.ui.res.stringResource
|
import androidx.compose.ui.res.stringResource
|
||||||
|
import androidx.compose.ui.text.style.TextOverflow
|
||||||
import androidx.hilt.navigation.compose.hiltViewModel
|
import androidx.hilt.navigation.compose.hiltViewModel
|
||||||
import androidx.lifecycle.ViewModel
|
import androidx.lifecycle.ViewModel
|
||||||
import androidx.navigation.NavController
|
import androidx.navigation.NavController
|
||||||
import chat.revolt.R
|
import chat.revolt.R
|
||||||
import chat.revolt.components.generic.PageHeader
|
|
||||||
import chat.revolt.internals.Changelogs
|
import chat.revolt.internals.Changelogs
|
||||||
import chat.revolt.persistence.KVStorage
|
import chat.revolt.persistence.KVStorage
|
||||||
import chat.revolt.sheets.ChangelogSheet
|
import chat.revolt.sheets.ChangelogSheet
|
||||||
|
|
@ -65,49 +73,69 @@ fun ChangelogsSettingsScreen(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Column(
|
val scrollBehavior = TopAppBarDefaults.exitUntilCollapsedScrollBehavior()
|
||||||
modifier = Modifier
|
|
||||||
.fillMaxSize()
|
|
||||||
.safeDrawingPadding()
|
|
||||||
) {
|
|
||||||
PageHeader(
|
|
||||||
text = stringResource(R.string.settings_changelogs),
|
|
||||||
showBackButton = true,
|
|
||||||
onBackButtonClicked = {
|
|
||||||
navController.popBackStack()
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
LazyColumn {
|
Scaffold(
|
||||||
items(
|
modifier = Modifier.nestedScroll(scrollBehavior.nestedScrollConnection),
|
||||||
viewModel.list.size,
|
topBar = {
|
||||||
key = { viewModel.list.keys.elementAt(it) }
|
LargeTopAppBar(
|
||||||
) { index ->
|
scrollBehavior = scrollBehavior,
|
||||||
val version = viewModel.list.keys.elementAt(index)
|
title = {
|
||||||
val changelog = viewModel.list[version]!!
|
Text(
|
||||||
|
text = stringResource(R.string.settings_changelogs),
|
||||||
Column(
|
maxLines = 1,
|
||||||
modifier = Modifier
|
overflow = TextOverflow.Ellipsis,
|
||||||
.clickable {
|
|
||||||
currentChangelog = version
|
|
||||||
sheetOpen = true
|
|
||||||
}
|
|
||||||
.fillMaxWidth()
|
|
||||||
) {
|
|
||||||
ListItem(
|
|
||||||
headlineContent = {
|
|
||||||
Text(
|
|
||||||
text = changelog.version,
|
|
||||||
style = MaterialTheme.typography.headlineSmall
|
|
||||||
)
|
|
||||||
},
|
|
||||||
supportingContent = {
|
|
||||||
Text(
|
|
||||||
text = changelog.summary,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
)
|
)
|
||||||
Divider()
|
},
|
||||||
|
navigationIcon = {
|
||||||
|
IconButton(onClick = {
|
||||||
|
navController.popBackStack()
|
||||||
|
}) {
|
||||||
|
Icon(
|
||||||
|
imageVector = Icons.Default.ArrowBack,
|
||||||
|
contentDescription = stringResource(id = R.string.back)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
)
|
||||||
|
},
|
||||||
|
) { pv ->
|
||||||
|
Column(
|
||||||
|
modifier = Modifier
|
||||||
|
.padding(pv)
|
||||||
|
.fillMaxSize()
|
||||||
|
) {
|
||||||
|
LazyColumn {
|
||||||
|
items(
|
||||||
|
viewModel.list.size,
|
||||||
|
key = { viewModel.list.keys.elementAt(it) }
|
||||||
|
) { index ->
|
||||||
|
val version = viewModel.list.keys.elementAt(index)
|
||||||
|
val changelog = viewModel.list[version]!!
|
||||||
|
|
||||||
|
Column(
|
||||||
|
modifier = Modifier
|
||||||
|
.clickable {
|
||||||
|
currentChangelog = version
|
||||||
|
sheetOpen = true
|
||||||
|
}
|
||||||
|
.fillMaxWidth()
|
||||||
|
) {
|
||||||
|
ListItem(
|
||||||
|
headlineContent = {
|
||||||
|
Text(
|
||||||
|
text = changelog.version,
|
||||||
|
style = MaterialTheme.typography.headlineSmall
|
||||||
|
)
|
||||||
|
},
|
||||||
|
supportingContent = {
|
||||||
|
Text(
|
||||||
|
text = changelog.summary,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
Divider()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -5,15 +5,16 @@ import android.util.Log
|
||||||
import androidx.browser.customtabs.CustomTabsIntent
|
import androidx.browser.customtabs.CustomTabsIntent
|
||||||
import androidx.compose.animation.AnimatedVisibility
|
import androidx.compose.animation.AnimatedVisibility
|
||||||
import androidx.compose.foundation.layout.Arrangement
|
import androidx.compose.foundation.layout.Arrangement
|
||||||
|
import androidx.compose.foundation.layout.Box
|
||||||
import androidx.compose.foundation.layout.Column
|
import androidx.compose.foundation.layout.Column
|
||||||
import androidx.compose.foundation.layout.Spacer
|
import androidx.compose.foundation.layout.Spacer
|
||||||
import androidx.compose.foundation.layout.fillMaxSize
|
import androidx.compose.foundation.layout.fillMaxSize
|
||||||
import androidx.compose.foundation.layout.fillMaxWidth
|
import androidx.compose.foundation.layout.fillMaxWidth
|
||||||
import androidx.compose.foundation.layout.height
|
import androidx.compose.foundation.layout.height
|
||||||
import androidx.compose.foundation.layout.padding
|
import androidx.compose.foundation.layout.padding
|
||||||
import androidx.compose.foundation.layout.safeDrawingPadding
|
|
||||||
import androidx.compose.foundation.layout.size
|
import androidx.compose.foundation.layout.size
|
||||||
import androidx.compose.material.icons.Icons
|
import androidx.compose.material.icons.Icons
|
||||||
|
import androidx.compose.material.icons.filled.ArrowBack
|
||||||
import androidx.compose.material.icons.filled.Check
|
import androidx.compose.material.icons.filled.Check
|
||||||
import androidx.compose.material.icons.filled.Close
|
import androidx.compose.material.icons.filled.Close
|
||||||
import androidx.compose.material.icons.filled.Refresh
|
import androidx.compose.material.icons.filled.Refresh
|
||||||
|
|
@ -21,9 +22,14 @@ import androidx.compose.material.icons.filled.Search
|
||||||
import androidx.compose.material.icons.filled.Settings
|
import androidx.compose.material.icons.filled.Settings
|
||||||
import androidx.compose.material3.Button
|
import androidx.compose.material3.Button
|
||||||
import androidx.compose.material3.ElevatedButton
|
import androidx.compose.material3.ElevatedButton
|
||||||
|
import androidx.compose.material3.ExperimentalMaterial3Api
|
||||||
import androidx.compose.material3.Icon
|
import androidx.compose.material3.Icon
|
||||||
|
import androidx.compose.material3.IconButton
|
||||||
import androidx.compose.material3.MaterialTheme
|
import androidx.compose.material3.MaterialTheme
|
||||||
|
import androidx.compose.material3.Scaffold
|
||||||
import androidx.compose.material3.Text
|
import androidx.compose.material3.Text
|
||||||
|
import androidx.compose.material3.TopAppBar
|
||||||
|
import androidx.compose.material3.TopAppBarDefaults
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.runtime.getValue
|
import androidx.compose.runtime.getValue
|
||||||
import androidx.compose.runtime.mutableIntStateOf
|
import androidx.compose.runtime.mutableIntStateOf
|
||||||
|
|
@ -32,21 +38,24 @@ import androidx.compose.runtime.setValue
|
||||||
import androidx.compose.ui.Alignment
|
import androidx.compose.ui.Alignment
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
import androidx.compose.ui.graphics.Color
|
import androidx.compose.ui.graphics.Color
|
||||||
|
import androidx.compose.ui.input.nestedscroll.nestedScroll
|
||||||
import androidx.compose.ui.platform.LocalContext
|
import androidx.compose.ui.platform.LocalContext
|
||||||
|
import androidx.compose.ui.res.stringResource
|
||||||
import androidx.compose.ui.text.AnnotatedString
|
import androidx.compose.ui.text.AnnotatedString
|
||||||
import androidx.compose.ui.text.SpanStyle
|
import androidx.compose.ui.text.SpanStyle
|
||||||
import androidx.compose.ui.text.font.FontWeight
|
import androidx.compose.ui.text.font.FontWeight
|
||||||
import androidx.compose.ui.text.style.TextAlign
|
import androidx.compose.ui.text.style.TextAlign
|
||||||
|
import androidx.compose.ui.text.style.TextOverflow
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
import androidx.lifecycle.ViewModel
|
import androidx.lifecycle.ViewModel
|
||||||
import androidx.lifecycle.viewModelScope
|
import androidx.lifecycle.viewModelScope
|
||||||
import androidx.lifecycle.viewmodel.compose.viewModel
|
import androidx.lifecycle.viewmodel.compose.viewModel
|
||||||
import androidx.navigation.NavController
|
import androidx.navigation.NavController
|
||||||
import chat.revolt.BuildConfig
|
import chat.revolt.BuildConfig
|
||||||
|
import chat.revolt.R
|
||||||
import chat.revolt.api.RevoltAPI
|
import chat.revolt.api.RevoltAPI
|
||||||
import chat.revolt.api.RevoltHttp
|
import chat.revolt.api.RevoltHttp
|
||||||
import chat.revolt.api.RevoltJson
|
import chat.revolt.api.RevoltJson
|
||||||
import chat.revolt.components.generic.PageHeader
|
|
||||||
import io.ktor.client.request.post
|
import io.ktor.client.request.post
|
||||||
import io.ktor.client.request.setBody
|
import io.ktor.client.request.setBody
|
||||||
import io.ktor.client.statement.bodyAsText
|
import io.ktor.client.statement.bodyAsText
|
||||||
|
|
@ -135,6 +144,7 @@ class ClosedBetaUpdaterScreenViewModel : ViewModel() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@OptIn(ExperimentalMaterial3Api::class)
|
||||||
@Composable
|
@Composable
|
||||||
fun ClosedBetaUpdaterScreen(
|
fun ClosedBetaUpdaterScreen(
|
||||||
navController: NavController,
|
navController: NavController,
|
||||||
|
|
@ -142,165 +152,181 @@ fun ClosedBetaUpdaterScreen(
|
||||||
) {
|
) {
|
||||||
val context = LocalContext.current
|
val context = LocalContext.current
|
||||||
|
|
||||||
Column(
|
val scrollBehavior = TopAppBarDefaults.pinnedScrollBehavior()
|
||||||
modifier = Modifier
|
|
||||||
.fillMaxSize()
|
|
||||||
.safeDrawingPadding()
|
|
||||||
) {
|
|
||||||
PageHeader(
|
|
||||||
text = "Closed Beta Updater",
|
|
||||||
showBackButton = true,
|
|
||||||
onBackButtonClicked = {
|
|
||||||
navController.popBackStack()
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
Column(
|
Scaffold(
|
||||||
modifier = Modifier.fillMaxSize(),
|
modifier = Modifier.nestedScroll(scrollBehavior.nestedScrollConnection),
|
||||||
horizontalAlignment = Alignment.CenterHorizontally
|
topBar = {
|
||||||
) {
|
TopAppBar(
|
||||||
Column(
|
scrollBehavior = scrollBehavior,
|
||||||
modifier = Modifier
|
title = {
|
||||||
.weight(1f)
|
Text(
|
||||||
.fillMaxWidth(),
|
text = "Closed Beta Updater",
|
||||||
verticalArrangement = Arrangement.Center,
|
maxLines = 1,
|
||||||
horizontalAlignment = Alignment.CenterHorizontally
|
overflow = TextOverflow.Ellipsis,
|
||||||
) {
|
)
|
||||||
Text(
|
},
|
||||||
text = "Revolt ${BuildConfig.VERSION_NAME}/${BuildConfig.VERSION_CODE}",
|
navigationIcon = {
|
||||||
style = MaterialTheme.typography.headlineSmall,
|
IconButton(onClick = {
|
||||||
modifier = Modifier.padding(bottom = 10.dp)
|
navController.popBackStack()
|
||||||
)
|
}) {
|
||||||
|
|
||||||
when (viewModel.updateState) {
|
|
||||||
UpdateState.NotChecked -> Column(
|
|
||||||
horizontalAlignment = Alignment.CenterHorizontally
|
|
||||||
) {
|
|
||||||
Icon(
|
Icon(
|
||||||
imageVector = Icons.Default.Search,
|
imageVector = Icons.Default.ArrowBack,
|
||||||
contentDescription = null,
|
contentDescription = stringResource(id = R.string.back)
|
||||||
tint = Color(0xFF585858),
|
|
||||||
modifier = Modifier.size(100.dp)
|
|
||||||
)
|
|
||||||
Text(
|
|
||||||
text = "Not yet checked for updates",
|
|
||||||
style = MaterialTheme.typography.bodyMedium,
|
|
||||||
modifier = Modifier.padding(vertical = 10.dp)
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
)
|
||||||
|
},
|
||||||
|
) { pv ->
|
||||||
|
Box(Modifier.padding(pv)) {
|
||||||
|
Column(
|
||||||
|
modifier = Modifier.fillMaxSize(),
|
||||||
|
horizontalAlignment = Alignment.CenterHorizontally
|
||||||
|
) {
|
||||||
|
Column(
|
||||||
|
modifier = Modifier
|
||||||
|
.weight(1f)
|
||||||
|
.fillMaxWidth(),
|
||||||
|
verticalArrangement = Arrangement.Center,
|
||||||
|
horizontalAlignment = Alignment.CenterHorizontally
|
||||||
|
) {
|
||||||
|
Text(
|
||||||
|
text = "Revolt ${BuildConfig.VERSION_NAME}/${BuildConfig.VERSION_CODE}",
|
||||||
|
style = MaterialTheme.typography.headlineSmall,
|
||||||
|
modifier = Modifier.padding(bottom = 10.dp)
|
||||||
|
)
|
||||||
|
|
||||||
UpdateState.UpdateAvailable -> Column(
|
when (viewModel.updateState) {
|
||||||
horizontalAlignment = Alignment.CenterHorizontally
|
UpdateState.NotChecked -> Column(
|
||||||
) {
|
horizontalAlignment = Alignment.CenterHorizontally
|
||||||
Icon(
|
|
||||||
imageVector = Icons.Default.Close,
|
|
||||||
contentDescription = null,
|
|
||||||
tint = Color(0xFFFF5252),
|
|
||||||
modifier = Modifier.size(100.dp)
|
|
||||||
)
|
|
||||||
Text(
|
|
||||||
text = AnnotatedString.Builder().apply {
|
|
||||||
append("You are out of date\n\nBuild ")
|
|
||||||
pushStyle(SpanStyle(fontWeight = FontWeight.Bold))
|
|
||||||
append("${viewModel.newestBuild}")
|
|
||||||
pop()
|
|
||||||
append(" is available")
|
|
||||||
}.toAnnotatedString(),
|
|
||||||
style = MaterialTheme.typography.bodyMedium,
|
|
||||||
textAlign = TextAlign.Center,
|
|
||||||
modifier = Modifier.padding(vertical = 10.dp)
|
|
||||||
)
|
|
||||||
|
|
||||||
AnimatedVisibility(
|
|
||||||
visible = viewModel.updateState == UpdateState.UpdateAvailable
|
|
||||||
) {
|
) {
|
||||||
ElevatedButton(onClick = {
|
Icon(
|
||||||
viewUrlInBrowser(
|
imageVector = Icons.Default.Search,
|
||||||
ctx = context,
|
contentDescription = null,
|
||||||
url = "${BuildConfig.ANALYSIS_BASEURL}/api/distribution/android/download?build=${viewModel.newestBuild}&token=${viewModel.newestDownloadToken}"
|
tint = Color(0xFF585858),
|
||||||
)
|
modifier = Modifier.size(100.dp)
|
||||||
}) {
|
)
|
||||||
Text(text = "Download")
|
Text(
|
||||||
|
text = "Not yet checked for updates",
|
||||||
|
style = MaterialTheme.typography.bodyMedium,
|
||||||
|
modifier = Modifier.padding(vertical = 10.dp)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
UpdateState.UpdateAvailable -> Column(
|
||||||
|
horizontalAlignment = Alignment.CenterHorizontally
|
||||||
|
) {
|
||||||
|
Icon(
|
||||||
|
imageVector = Icons.Default.Close,
|
||||||
|
contentDescription = null,
|
||||||
|
tint = Color(0xFFFF5252),
|
||||||
|
modifier = Modifier.size(100.dp)
|
||||||
|
)
|
||||||
|
Text(
|
||||||
|
text = AnnotatedString.Builder().apply {
|
||||||
|
append("You are out of date\n\nBuild ")
|
||||||
|
pushStyle(SpanStyle(fontWeight = FontWeight.Bold))
|
||||||
|
append("${viewModel.newestBuild}")
|
||||||
|
pop()
|
||||||
|
append(" is available")
|
||||||
|
}.toAnnotatedString(),
|
||||||
|
style = MaterialTheme.typography.bodyMedium,
|
||||||
|
textAlign = TextAlign.Center,
|
||||||
|
modifier = Modifier.padding(vertical = 10.dp)
|
||||||
|
)
|
||||||
|
|
||||||
|
AnimatedVisibility(
|
||||||
|
visible = viewModel.updateState == UpdateState.UpdateAvailable
|
||||||
|
) {
|
||||||
|
ElevatedButton(onClick = {
|
||||||
|
viewUrlInBrowser(
|
||||||
|
ctx = context,
|
||||||
|
url = "${BuildConfig.ANALYSIS_BASEURL}/api/distribution/android/download?build=${viewModel.newestBuild}&token=${viewModel.newestDownloadToken}"
|
||||||
|
)
|
||||||
|
}) {
|
||||||
|
Text(text = "Download")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
UpdateState.Checking -> Column(
|
||||||
|
horizontalAlignment = Alignment.CenterHorizontally
|
||||||
|
) {
|
||||||
|
Icon(
|
||||||
|
imageVector = Icons.Default.Refresh,
|
||||||
|
contentDescription = null,
|
||||||
|
tint = Color(0xFFEEFF41),
|
||||||
|
modifier = Modifier.size(100.dp)
|
||||||
|
)
|
||||||
|
Text(
|
||||||
|
text = "Checking for updates...",
|
||||||
|
style = MaterialTheme.typography.bodyMedium,
|
||||||
|
modifier = Modifier.padding(vertical = 10.dp)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
UpdateState.UpToDate -> Column(
|
||||||
|
horizontalAlignment = Alignment.CenterHorizontally
|
||||||
|
) {
|
||||||
|
Icon(
|
||||||
|
imageVector = Icons.Default.Check,
|
||||||
|
contentDescription = null,
|
||||||
|
tint = Color(0xFF00E676),
|
||||||
|
modifier = Modifier.size(100.dp)
|
||||||
|
)
|
||||||
|
Text(
|
||||||
|
text = "Up to date",
|
||||||
|
style = MaterialTheme.typography.bodyMedium,
|
||||||
|
modifier = Modifier.padding(vertical = 10.dp)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
UpdateState.ErrorChecking -> Column(
|
||||||
|
horizontalAlignment = Alignment.CenterHorizontally
|
||||||
|
) {
|
||||||
|
Icon(
|
||||||
|
imageVector = Icons.Default.Close,
|
||||||
|
contentDescription = null,
|
||||||
|
tint = Color(0xFFFF5252),
|
||||||
|
modifier = Modifier.size(100.dp)
|
||||||
|
)
|
||||||
|
Text(
|
||||||
|
text = "Error checking for updates",
|
||||||
|
style = MaterialTheme.typography.bodyMedium,
|
||||||
|
modifier = Modifier.padding(vertical = 10.dp)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
UpdateState.RequestingUpdateToken -> Column(
|
||||||
|
horizontalAlignment = Alignment.CenterHorizontally
|
||||||
|
) {
|
||||||
|
Icon(
|
||||||
|
imageVector = Icons.Default.Settings,
|
||||||
|
contentDescription = null,
|
||||||
|
tint = Color(0xFFEEFF41),
|
||||||
|
modifier = Modifier.size(100.dp)
|
||||||
|
)
|
||||||
|
Text(
|
||||||
|
text = "Requesting update token...",
|
||||||
|
style = MaterialTheme.typography.bodyMedium,
|
||||||
|
modifier = Modifier.padding(vertical = 10.dp)
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
UpdateState.Checking -> Column(
|
Spacer(modifier = Modifier.height(10.dp))
|
||||||
horizontalAlignment = Alignment.CenterHorizontally
|
|
||||||
) {
|
|
||||||
Icon(
|
|
||||||
imageVector = Icons.Default.Refresh,
|
|
||||||
contentDescription = null,
|
|
||||||
tint = Color(0xFFEEFF41),
|
|
||||||
modifier = Modifier.size(100.dp)
|
|
||||||
)
|
|
||||||
Text(
|
|
||||||
text = "Checking for updates...",
|
|
||||||
style = MaterialTheme.typography.bodyMedium,
|
|
||||||
modifier = Modifier.padding(vertical = 10.dp)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
UpdateState.UpToDate -> Column(
|
|
||||||
horizontalAlignment = Alignment.CenterHorizontally
|
|
||||||
) {
|
|
||||||
Icon(
|
|
||||||
imageVector = Icons.Default.Check,
|
|
||||||
contentDescription = null,
|
|
||||||
tint = Color(0xFF00E676),
|
|
||||||
modifier = Modifier.size(100.dp)
|
|
||||||
)
|
|
||||||
Text(
|
|
||||||
text = "Up to date",
|
|
||||||
style = MaterialTheme.typography.bodyMedium,
|
|
||||||
modifier = Modifier.padding(vertical = 10.dp)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
UpdateState.ErrorChecking -> Column(
|
|
||||||
horizontalAlignment = Alignment.CenterHorizontally
|
|
||||||
) {
|
|
||||||
Icon(
|
|
||||||
imageVector = Icons.Default.Close,
|
|
||||||
contentDescription = null,
|
|
||||||
tint = Color(0xFFFF5252),
|
|
||||||
modifier = Modifier.size(100.dp)
|
|
||||||
)
|
|
||||||
Text(
|
|
||||||
text = "Error checking for updates",
|
|
||||||
style = MaterialTheme.typography.bodyMedium,
|
|
||||||
modifier = Modifier.padding(vertical = 10.dp)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
UpdateState.RequestingUpdateToken -> Column(
|
|
||||||
horizontalAlignment = Alignment.CenterHorizontally
|
|
||||||
) {
|
|
||||||
Icon(
|
|
||||||
imageVector = Icons.Default.Settings,
|
|
||||||
contentDescription = null,
|
|
||||||
tint = Color(0xFFEEFF41),
|
|
||||||
modifier = Modifier.size(100.dp)
|
|
||||||
)
|
|
||||||
Text(
|
|
||||||
text = "Requesting update token...",
|
|
||||||
style = MaterialTheme.typography.bodyMedium,
|
|
||||||
modifier = Modifier.padding(vertical = 10.dp)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Spacer(modifier = Modifier.height(10.dp))
|
Button(
|
||||||
}
|
onClick = {
|
||||||
|
viewModel.checkForUpdates()
|
||||||
Button(
|
},
|
||||||
onClick = {
|
modifier = Modifier
|
||||||
viewModel.checkForUpdates()
|
.padding(bottom = 10.dp)
|
||||||
},
|
) {
|
||||||
modifier = Modifier
|
Text(text = "Check for updates")
|
||||||
.padding(bottom = 10.dp)
|
}
|
||||||
) {
|
|
||||||
Text(text = "Check for updates")
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -5,25 +5,35 @@ import androidx.compose.foundation.layout.Column
|
||||||
import androidx.compose.foundation.layout.Row
|
import androidx.compose.foundation.layout.Row
|
||||||
import androidx.compose.foundation.layout.fillMaxSize
|
import androidx.compose.foundation.layout.fillMaxSize
|
||||||
import androidx.compose.foundation.layout.padding
|
import androidx.compose.foundation.layout.padding
|
||||||
import androidx.compose.foundation.layout.safeDrawingPadding
|
|
||||||
import androidx.compose.foundation.rememberScrollState
|
import androidx.compose.foundation.rememberScrollState
|
||||||
import androidx.compose.foundation.verticalScroll
|
import androidx.compose.foundation.verticalScroll
|
||||||
|
import androidx.compose.material.icons.Icons
|
||||||
|
import androidx.compose.material.icons.filled.ArrowBack
|
||||||
import androidx.compose.material3.ElevatedButton
|
import androidx.compose.material3.ElevatedButton
|
||||||
|
import androidx.compose.material3.ExperimentalMaterial3Api
|
||||||
|
import androidx.compose.material3.Icon
|
||||||
|
import androidx.compose.material3.IconButton
|
||||||
|
import androidx.compose.material3.LargeTopAppBar
|
||||||
import androidx.compose.material3.MaterialTheme
|
import androidx.compose.material3.MaterialTheme
|
||||||
|
import androidx.compose.material3.Scaffold
|
||||||
import androidx.compose.material3.Text
|
import androidx.compose.material3.Text
|
||||||
import androidx.compose.material3.TextButton
|
import androidx.compose.material3.TextButton
|
||||||
|
import androidx.compose.material3.TopAppBarDefaults
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
|
import androidx.compose.ui.input.nestedscroll.nestedScroll
|
||||||
|
import androidx.compose.ui.res.stringResource
|
||||||
|
import androidx.compose.ui.text.style.TextOverflow
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
import androidx.hilt.navigation.compose.hiltViewModel
|
import androidx.hilt.navigation.compose.hiltViewModel
|
||||||
import androidx.lifecycle.ViewModel
|
import androidx.lifecycle.ViewModel
|
||||||
import androidx.lifecycle.viewModelScope
|
import androidx.lifecycle.viewModelScope
|
||||||
import androidx.navigation.NavController
|
import androidx.navigation.NavController
|
||||||
import chat.revolt.components.generic.PageHeader
|
import chat.revolt.R
|
||||||
import chat.revolt.persistence.KVStorage
|
import chat.revolt.persistence.KVStorage
|
||||||
import dagger.hilt.android.lifecycle.HiltViewModel
|
import dagger.hilt.android.lifecycle.HiltViewModel
|
||||||
import javax.inject.Inject
|
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
|
import javax.inject.Inject
|
||||||
|
|
||||||
@HiltViewModel
|
@HiltViewModel
|
||||||
class DebugSettingsScreenViewModel @Inject constructor(
|
class DebugSettingsScreenViewModel @Inject constructor(
|
||||||
|
|
@ -46,56 +56,77 @@ class DebugSettingsScreenViewModel @Inject constructor(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@OptIn(ExperimentalMaterial3Api::class)
|
||||||
@Composable
|
@Composable
|
||||||
fun DebugSettingsScreen(
|
fun DebugSettingsScreen(
|
||||||
navController: NavController,
|
navController: NavController,
|
||||||
viewModel: DebugSettingsScreenViewModel = hiltViewModel()
|
viewModel: DebugSettingsScreenViewModel = hiltViewModel()
|
||||||
) {
|
) {
|
||||||
Column(
|
val scrollBehavior = TopAppBarDefaults.exitUntilCollapsedScrollBehavior()
|
||||||
modifier = Modifier
|
|
||||||
.fillMaxSize()
|
|
||||||
.safeDrawingPadding()
|
|
||||||
) {
|
|
||||||
PageHeader(
|
|
||||||
text = "Debug",
|
|
||||||
showBackButton = true,
|
|
||||||
onBackButtonClicked = {
|
|
||||||
navController.popBackStack()
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
|
Scaffold(
|
||||||
|
modifier = Modifier.nestedScroll(scrollBehavior.nestedScrollConnection),
|
||||||
|
topBar = {
|
||||||
|
LargeTopAppBar(
|
||||||
|
scrollBehavior = scrollBehavior,
|
||||||
|
title = {
|
||||||
|
Text(
|
||||||
|
text = "Debug",
|
||||||
|
maxLines = 1,
|
||||||
|
overflow = TextOverflow.Ellipsis,
|
||||||
|
)
|
||||||
|
},
|
||||||
|
navigationIcon = {
|
||||||
|
IconButton(onClick = {
|
||||||
|
navController.popBackStack()
|
||||||
|
}) {
|
||||||
|
Icon(
|
||||||
|
imageVector = Icons.Default.ArrowBack,
|
||||||
|
contentDescription = stringResource(id = R.string.back)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
)
|
||||||
|
},
|
||||||
|
) { pv ->
|
||||||
Column(
|
Column(
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
|
.padding(pv)
|
||||||
.fillMaxSize()
|
.fillMaxSize()
|
||||||
.verticalScroll(rememberScrollState())
|
|
||||||
.padding(20.dp)
|
|
||||||
) {
|
) {
|
||||||
Text(
|
Column(
|
||||||
text = "Sparks",
|
modifier = Modifier
|
||||||
style = MaterialTheme.typography.headlineSmall,
|
.fillMaxSize()
|
||||||
modifier = Modifier.padding(bottom = 10.dp)
|
.verticalScroll(rememberScrollState())
|
||||||
)
|
.padding(20.dp)
|
||||||
Row(
|
|
||||||
modifier = Modifier.horizontalScroll(rememberScrollState())
|
|
||||||
) {
|
) {
|
||||||
TextButton(onClick = { viewModel.forgetSidebarSparkShown() }) {
|
Text(
|
||||||
Text("Forget sidebar spark")
|
text = "Sparks",
|
||||||
|
style = MaterialTheme.typography.headlineSmall,
|
||||||
|
modifier = Modifier.padding(bottom = 10.dp)
|
||||||
|
)
|
||||||
|
Row(
|
||||||
|
modifier = Modifier.horizontalScroll(rememberScrollState())
|
||||||
|
) {
|
||||||
|
TextButton(onClick = { viewModel.forgetSidebarSparkShown() }) {
|
||||||
|
Text("Forget sidebar spark")
|
||||||
|
}
|
||||||
|
ElevatedButton(onClick = { viewModel.forgetAllSparks() }) {
|
||||||
|
Text("Forget all sparks")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
ElevatedButton(onClick = { viewModel.forgetAllSparks() }) {
|
|
||||||
Text("Forget all sparks")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Text(
|
Text(
|
||||||
text = "Changelogs",
|
text = "Changelogs",
|
||||||
style = MaterialTheme.typography.headlineSmall,
|
style = MaterialTheme.typography.headlineSmall,
|
||||||
modifier = Modifier.padding(bottom = 10.dp)
|
modifier = Modifier.padding(bottom = 10.dp)
|
||||||
)
|
)
|
||||||
Row(
|
Row(
|
||||||
modifier = Modifier.horizontalScroll(rememberScrollState())
|
modifier = Modifier.horizontalScroll(rememberScrollState())
|
||||||
) {
|
) {
|
||||||
ElevatedButton(onClick = { viewModel.forgetLatestChangelog() }) {
|
ElevatedButton(onClick = { viewModel.forgetLatestChangelog() }) {
|
||||||
Text("Mark latest changelog as unread")
|
Text("Mark latest changelog as unread")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,7 @@ import android.content.Context
|
||||||
import android.net.Uri
|
import android.net.Uri
|
||||||
import androidx.compose.animation.AnimatedVisibility
|
import androidx.compose.animation.AnimatedVisibility
|
||||||
import androidx.compose.foundation.layout.Arrangement
|
import androidx.compose.foundation.layout.Arrangement
|
||||||
|
import androidx.compose.foundation.layout.Box
|
||||||
import androidx.compose.foundation.layout.Column
|
import androidx.compose.foundation.layout.Column
|
||||||
import androidx.compose.foundation.layout.ExperimentalLayoutApi
|
import androidx.compose.foundation.layout.ExperimentalLayoutApi
|
||||||
import androidx.compose.foundation.layout.FlowRow
|
import androidx.compose.foundation.layout.FlowRow
|
||||||
|
|
@ -12,20 +13,25 @@ import androidx.compose.foundation.layout.fillMaxSize
|
||||||
import androidx.compose.foundation.layout.fillMaxWidth
|
import androidx.compose.foundation.layout.fillMaxWidth
|
||||||
import androidx.compose.foundation.layout.height
|
import androidx.compose.foundation.layout.height
|
||||||
import androidx.compose.foundation.layout.padding
|
import androidx.compose.foundation.layout.padding
|
||||||
import androidx.compose.foundation.layout.safeDrawingPadding
|
|
||||||
import androidx.compose.foundation.layout.size
|
import androidx.compose.foundation.layout.size
|
||||||
import androidx.compose.foundation.layout.width
|
import androidx.compose.foundation.layout.width
|
||||||
import androidx.compose.foundation.rememberScrollState
|
import androidx.compose.foundation.rememberScrollState
|
||||||
import androidx.compose.foundation.verticalScroll
|
import androidx.compose.foundation.verticalScroll
|
||||||
import androidx.compose.material.icons.Icons
|
import androidx.compose.material.icons.Icons
|
||||||
|
import androidx.compose.material.icons.filled.ArrowBack
|
||||||
import androidx.compose.material.icons.filled.Check
|
import androidx.compose.material.icons.filled.Check
|
||||||
import androidx.compose.material3.CircularProgressIndicator
|
import androidx.compose.material3.CircularProgressIndicator
|
||||||
|
import androidx.compose.material3.ExperimentalMaterial3Api
|
||||||
import androidx.compose.material3.Icon
|
import androidx.compose.material3.Icon
|
||||||
|
import androidx.compose.material3.IconButton
|
||||||
|
import androidx.compose.material3.LargeTopAppBar
|
||||||
import androidx.compose.material3.LinearProgressIndicator
|
import androidx.compose.material3.LinearProgressIndicator
|
||||||
import androidx.compose.material3.MaterialTheme
|
import androidx.compose.material3.MaterialTheme
|
||||||
import androidx.compose.material3.OutlinedTextField
|
import androidx.compose.material3.OutlinedTextField
|
||||||
|
import androidx.compose.material3.Scaffold
|
||||||
import androidx.compose.material3.Text
|
import androidx.compose.material3.Text
|
||||||
import androidx.compose.material3.TextButton
|
import androidx.compose.material3.TextButton
|
||||||
|
import androidx.compose.material3.TopAppBarDefaults
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.runtime.getValue
|
import androidx.compose.runtime.getValue
|
||||||
import androidx.compose.runtime.mutableFloatStateOf
|
import androidx.compose.runtime.mutableFloatStateOf
|
||||||
|
|
@ -33,7 +39,9 @@ import androidx.compose.runtime.mutableStateOf
|
||||||
import androidx.compose.runtime.setValue
|
import androidx.compose.runtime.setValue
|
||||||
import androidx.compose.ui.Alignment
|
import androidx.compose.ui.Alignment
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
|
import androidx.compose.ui.input.nestedscroll.nestedScroll
|
||||||
import androidx.compose.ui.res.stringResource
|
import androidx.compose.ui.res.stringResource
|
||||||
|
import androidx.compose.ui.text.style.TextOverflow
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
import androidx.hilt.navigation.compose.hiltViewModel
|
import androidx.hilt.navigation.compose.hiltViewModel
|
||||||
import androidx.lifecycle.ViewModel
|
import androidx.lifecycle.ViewModel
|
||||||
|
|
@ -46,7 +54,6 @@ import chat.revolt.api.routes.user.fetchUserProfile
|
||||||
import chat.revolt.api.routes.user.patchSelf
|
import chat.revolt.api.routes.user.patchSelf
|
||||||
import chat.revolt.api.schemas.Profile
|
import chat.revolt.api.schemas.Profile
|
||||||
import chat.revolt.components.generic.InlineMediaPicker
|
import chat.revolt.components.generic.InlineMediaPicker
|
||||||
import chat.revolt.components.generic.PageHeader
|
|
||||||
import chat.revolt.components.screens.settings.RawUserOverview
|
import chat.revolt.components.screens.settings.RawUserOverview
|
||||||
import dagger.hilt.android.lifecycle.HiltViewModel
|
import dagger.hilt.android.lifecycle.HiltViewModel
|
||||||
import dagger.hilt.android.qualifiers.ApplicationContext
|
import dagger.hilt.android.qualifiers.ApplicationContext
|
||||||
|
|
@ -226,159 +233,90 @@ class ProfileSettingsScreenViewModel @Inject constructor(@ApplicationContext val
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@OptIn(ExperimentalLayoutApi::class)
|
@OptIn(ExperimentalLayoutApi::class, ExperimentalMaterial3Api::class)
|
||||||
@Composable
|
@Composable
|
||||||
fun ProfileSettingsScreen(
|
fun ProfileSettingsScreen(
|
||||||
navController: NavController,
|
navController: NavController,
|
||||||
viewModel: ProfileSettingsScreenViewModel = hiltViewModel()
|
viewModel: ProfileSettingsScreenViewModel = hiltViewModel()
|
||||||
) {
|
) {
|
||||||
Column(
|
val scrollBehavior = TopAppBarDefaults.exitUntilCollapsedScrollBehavior()
|
||||||
modifier = Modifier
|
|
||||||
.fillMaxSize()
|
|
||||||
.safeDrawingPadding()
|
|
||||||
) {
|
|
||||||
PageHeader(
|
|
||||||
text = stringResource(id = R.string.settings_profile),
|
|
||||||
showBackButton = true,
|
|
||||||
onBackButtonClicked = {
|
|
||||||
navController.popBackStack()
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
val scrollState = rememberScrollState()
|
Scaffold(
|
||||||
Column(
|
modifier = Modifier.nestedScroll(scrollBehavior.nestedScrollConnection),
|
||||||
modifier = Modifier
|
topBar = {
|
||||||
.fillMaxSize()
|
LargeTopAppBar(
|
||||||
.then(
|
scrollBehavior = scrollBehavior,
|
||||||
if (viewModel.isLoading) {
|
title = {
|
||||||
Modifier
|
|
||||||
} else {
|
|
||||||
Modifier.verticalScroll(scrollState)
|
|
||||||
}
|
|
||||||
),
|
|
||||||
verticalArrangement = if (viewModel.isLoading) {
|
|
||||||
Arrangement.Center
|
|
||||||
} else {
|
|
||||||
Arrangement.Top
|
|
||||||
},
|
|
||||||
horizontalAlignment = if (viewModel.isLoading) {
|
|
||||||
Alignment.CenterHorizontally
|
|
||||||
} else {
|
|
||||||
Alignment.Start
|
|
||||||
}
|
|
||||||
) {
|
|
||||||
if (viewModel.isLoading) {
|
|
||||||
CircularProgressIndicator(
|
|
||||||
modifier = Modifier
|
|
||||||
.size(48.dp)
|
|
||||||
)
|
|
||||||
} else {
|
|
||||||
RevoltAPI.userCache[RevoltAPI.selfId]?.let {
|
|
||||||
RawUserOverview(
|
|
||||||
it,
|
|
||||||
viewModel.pendingProfile,
|
|
||||||
viewModel.pfpModel?.toString(),
|
|
||||||
viewModel.backgroundModel?.toString()
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
AnimatedVisibility(visible = viewModel.uploadProgress > 0f) {
|
|
||||||
LinearProgressIndicator(
|
|
||||||
progress = viewModel.uploadProgress,
|
|
||||||
modifier = Modifier
|
|
||||||
.fillMaxSize()
|
|
||||||
.padding(start = 20.dp, end = 20.dp, top = 20.dp, bottom = 0.dp)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
AnimatedVisibility(visible = viewModel.uploadError != null) {
|
|
||||||
Text(
|
Text(
|
||||||
text = viewModel.uploadError ?: "",
|
text = stringResource(R.string.settings_profile),
|
||||||
style = MaterialTheme.typography.labelLarge.copy(
|
maxLines = 1,
|
||||||
color = MaterialTheme.colorScheme.error
|
overflow = TextOverflow.Ellipsis,
|
||||||
),
|
|
||||||
modifier = Modifier
|
|
||||||
.padding(start = 20.dp, end = 20.dp, top = 20.dp, bottom = 0.dp)
|
|
||||||
)
|
)
|
||||||
}
|
},
|
||||||
|
navigationIcon = {
|
||||||
FlowRow(
|
IconButton(onClick = {
|
||||||
horizontalArrangement = Arrangement.spacedBy(10.dp),
|
navController.popBackStack()
|
||||||
) {
|
}) {
|
||||||
Column(
|
Icon(
|
||||||
modifier = Modifier
|
imageVector = Icons.Default.ArrowBack,
|
||||||
.padding(start = 20.dp, end = 20.dp, top = 20.dp, bottom = 0.dp)
|
contentDescription = stringResource(id = R.string.back)
|
||||||
) {
|
|
||||||
Text(
|
|
||||||
text = stringResource(id = R.string.settings_profile_profile_picture),
|
|
||||||
style = MaterialTheme.typography.labelLarge
|
|
||||||
)
|
)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
)
|
||||||
|
},
|
||||||
|
) { pv ->
|
||||||
|
Box(Modifier.padding(pv)) {
|
||||||
|
|
||||||
Spacer(Modifier.height(10.dp))
|
val scrollState = rememberScrollState()
|
||||||
|
Column(
|
||||||
InlineMediaPicker(
|
modifier = Modifier
|
||||||
currentModel = viewModel.pfpModel,
|
.fillMaxSize()
|
||||||
circular = true,
|
.then(
|
||||||
onPick = {
|
if (viewModel.isLoading) {
|
||||||
viewModel.pfpModel = it.toString()
|
Modifier
|
||||||
viewModel.saveNewPfp()
|
} else {
|
||||||
},
|
Modifier.verticalScroll(scrollState)
|
||||||
canRemove = true,
|
}
|
||||||
onRemove = {
|
),
|
||||||
viewModel.removePfp()
|
verticalArrangement = if (viewModel.isLoading) {
|
||||||
}
|
Arrangement.Center
|
||||||
|
} else {
|
||||||
|
Arrangement.Top
|
||||||
|
},
|
||||||
|
horizontalAlignment = if (viewModel.isLoading) {
|
||||||
|
Alignment.CenterHorizontally
|
||||||
|
} else {
|
||||||
|
Alignment.Start
|
||||||
|
}
|
||||||
|
) {
|
||||||
|
if (viewModel.isLoading) {
|
||||||
|
CircularProgressIndicator(
|
||||||
|
modifier = Modifier
|
||||||
|
.size(48.dp)
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
RevoltAPI.userCache[RevoltAPI.selfId]?.let {
|
||||||
|
RawUserOverview(
|
||||||
|
it,
|
||||||
|
viewModel.pendingProfile,
|
||||||
|
viewModel.pfpModel?.toString(),
|
||||||
|
viewModel.backgroundModel?.toString()
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
Column(
|
AnimatedVisibility(visible = viewModel.uploadProgress > 0f) {
|
||||||
modifier = Modifier
|
LinearProgressIndicator(
|
||||||
.padding(20.dp)
|
progress = viewModel.uploadProgress,
|
||||||
) {
|
modifier = Modifier
|
||||||
Text(
|
.fillMaxSize()
|
||||||
text = stringResource(id = R.string.settings_profile_custom_background),
|
.padding(start = 20.dp, end = 20.dp, top = 20.dp, bottom = 0.dp)
|
||||||
style = MaterialTheme.typography.labelLarge,
|
|
||||||
)
|
|
||||||
|
|
||||||
Spacer(Modifier.height(10.dp))
|
|
||||||
|
|
||||||
InlineMediaPicker(
|
|
||||||
currentModel = viewModel.backgroundModel,
|
|
||||||
onPick = {
|
|
||||||
viewModel.backgroundModel = it.toString()
|
|
||||||
viewModel.saveNewBackground()
|
|
||||||
},
|
|
||||||
canRemove = true,
|
|
||||||
onRemove = {
|
|
||||||
viewModel.removeBackground()
|
|
||||||
}
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
|
||||||
Column(
|
|
||||||
modifier = Modifier
|
|
||||||
.padding(start = 20.dp, end = 20.dp, top = 0.dp, bottom = 20.dp)
|
|
||||||
) {
|
|
||||||
OutlinedTextField(
|
|
||||||
value = viewModel.pendingProfile?.content ?: "",
|
|
||||||
onValueChange = { value ->
|
|
||||||
viewModel.pendingProfile?.let {
|
|
||||||
viewModel.pendingProfile = it.copy(content = value)
|
|
||||||
}
|
|
||||||
},
|
|
||||||
label = {
|
|
||||||
Text(
|
|
||||||
text = stringResource(id = R.string.user_info_sheet_category_bio),
|
|
||||||
style = MaterialTheme.typography.labelLarge,
|
|
||||||
)
|
|
||||||
},
|
|
||||||
modifier = Modifier.fillMaxWidth(),
|
|
||||||
)
|
|
||||||
|
|
||||||
AnimatedVisibility(visible = viewModel.bioError != null) {
|
|
||||||
Spacer(Modifier.height(8.dp))
|
|
||||||
|
|
||||||
|
AnimatedVisibility(visible = viewModel.uploadError != null) {
|
||||||
Text(
|
Text(
|
||||||
text = viewModel.bioError ?: "",
|
text = viewModel.uploadError ?: "",
|
||||||
style = MaterialTheme.typography.labelLarge.copy(
|
style = MaterialTheme.typography.labelLarge.copy(
|
||||||
color = MaterialTheme.colorScheme.error
|
color = MaterialTheme.colorScheme.error
|
||||||
),
|
),
|
||||||
|
|
@ -387,26 +325,112 @@ fun ProfileSettingsScreen(
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
Spacer(Modifier.height(8.dp))
|
FlowRow(
|
||||||
|
horizontalArrangement = Arrangement.spacedBy(10.dp),
|
||||||
TextButton(
|
|
||||||
onClick = {
|
|
||||||
viewModel.saveBio()
|
|
||||||
},
|
|
||||||
enabled = viewModel.pendingProfile?.content != viewModel.currentProfile?.content,
|
|
||||||
modifier = Modifier.fillMaxWidth()
|
|
||||||
) {
|
) {
|
||||||
Icon(
|
Column(
|
||||||
imageVector = Icons.Default.Check,
|
modifier = Modifier
|
||||||
contentDescription = null
|
.padding(start = 20.dp, end = 20.dp, top = 20.dp, bottom = 0.dp)
|
||||||
|
) {
|
||||||
|
Text(
|
||||||
|
text = stringResource(id = R.string.settings_profile_profile_picture),
|
||||||
|
style = MaterialTheme.typography.labelLarge
|
||||||
|
)
|
||||||
|
|
||||||
|
Spacer(Modifier.height(10.dp))
|
||||||
|
|
||||||
|
InlineMediaPicker(
|
||||||
|
currentModel = viewModel.pfpModel,
|
||||||
|
circular = true,
|
||||||
|
onPick = {
|
||||||
|
viewModel.pfpModel = it.toString()
|
||||||
|
viewModel.saveNewPfp()
|
||||||
|
},
|
||||||
|
canRemove = true,
|
||||||
|
onRemove = {
|
||||||
|
viewModel.removePfp()
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
Column(
|
||||||
|
modifier = Modifier
|
||||||
|
.padding(20.dp)
|
||||||
|
) {
|
||||||
|
Text(
|
||||||
|
text = stringResource(id = R.string.settings_profile_custom_background),
|
||||||
|
style = MaterialTheme.typography.labelLarge,
|
||||||
|
)
|
||||||
|
|
||||||
|
Spacer(Modifier.height(10.dp))
|
||||||
|
|
||||||
|
InlineMediaPicker(
|
||||||
|
currentModel = viewModel.backgroundModel,
|
||||||
|
onPick = {
|
||||||
|
viewModel.backgroundModel = it.toString()
|
||||||
|
viewModel.saveNewBackground()
|
||||||
|
},
|
||||||
|
canRemove = true,
|
||||||
|
onRemove = {
|
||||||
|
viewModel.removeBackground()
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Column(
|
||||||
|
modifier = Modifier
|
||||||
|
.padding(start = 20.dp, end = 20.dp, top = 0.dp, bottom = 20.dp)
|
||||||
|
) {
|
||||||
|
OutlinedTextField(
|
||||||
|
value = viewModel.pendingProfile?.content ?: "",
|
||||||
|
onValueChange = { value ->
|
||||||
|
viewModel.pendingProfile?.let {
|
||||||
|
viewModel.pendingProfile = it.copy(content = value)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
label = {
|
||||||
|
Text(
|
||||||
|
text = stringResource(id = R.string.user_info_sheet_category_bio),
|
||||||
|
style = MaterialTheme.typography.labelLarge,
|
||||||
|
)
|
||||||
|
},
|
||||||
|
modifier = Modifier.fillMaxWidth(),
|
||||||
)
|
)
|
||||||
|
|
||||||
Spacer(modifier = Modifier.width(8.dp))
|
AnimatedVisibility(visible = viewModel.bioError != null) {
|
||||||
|
Spacer(Modifier.height(8.dp))
|
||||||
|
|
||||||
Text(
|
Text(
|
||||||
text = stringResource(id = R.string.settings_profile_save),
|
text = viewModel.bioError ?: "",
|
||||||
style = MaterialTheme.typography.bodySmall
|
style = MaterialTheme.typography.labelLarge.copy(
|
||||||
)
|
color = MaterialTheme.colorScheme.error
|
||||||
|
),
|
||||||
|
modifier = Modifier
|
||||||
|
.padding(start = 20.dp, end = 20.dp, top = 20.dp, bottom = 0.dp)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
Spacer(Modifier.height(8.dp))
|
||||||
|
|
||||||
|
TextButton(
|
||||||
|
onClick = {
|
||||||
|
viewModel.saveBio()
|
||||||
|
},
|
||||||
|
enabled = viewModel.pendingProfile?.content != viewModel.currentProfile?.content,
|
||||||
|
modifier = Modifier.fillMaxWidth()
|
||||||
|
) {
|
||||||
|
Icon(
|
||||||
|
imageVector = Icons.Default.Check,
|
||||||
|
contentDescription = null
|
||||||
|
)
|
||||||
|
|
||||||
|
Spacer(modifier = Modifier.width(8.dp))
|
||||||
|
|
||||||
|
Text(
|
||||||
|
text = stringResource(id = R.string.settings_profile_save),
|
||||||
|
style = MaterialTheme.typography.bodySmall
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,7 @@ import android.util.Log
|
||||||
import androidx.compose.foundation.ExperimentalFoundationApi
|
import androidx.compose.foundation.ExperimentalFoundationApi
|
||||||
import androidx.compose.foundation.background
|
import androidx.compose.foundation.background
|
||||||
import androidx.compose.foundation.layout.Arrangement
|
import androidx.compose.foundation.layout.Arrangement
|
||||||
|
import androidx.compose.foundation.layout.Box
|
||||||
import androidx.compose.foundation.layout.Column
|
import androidx.compose.foundation.layout.Column
|
||||||
import androidx.compose.foundation.layout.Row
|
import androidx.compose.foundation.layout.Row
|
||||||
import androidx.compose.foundation.layout.Spacer
|
import androidx.compose.foundation.layout.Spacer
|
||||||
|
|
@ -11,16 +12,23 @@ import androidx.compose.foundation.layout.fillMaxSize
|
||||||
import androidx.compose.foundation.layout.fillMaxWidth
|
import androidx.compose.foundation.layout.fillMaxWidth
|
||||||
import androidx.compose.foundation.layout.height
|
import androidx.compose.foundation.layout.height
|
||||||
import androidx.compose.foundation.layout.padding
|
import androidx.compose.foundation.layout.padding
|
||||||
import androidx.compose.foundation.layout.safeDrawingPadding
|
|
||||||
import androidx.compose.foundation.layout.size
|
import androidx.compose.foundation.layout.size
|
||||||
import androidx.compose.foundation.lazy.LazyColumn
|
import androidx.compose.foundation.lazy.LazyColumn
|
||||||
|
import androidx.compose.material.icons.Icons
|
||||||
|
import androidx.compose.material.icons.filled.ArrowBack
|
||||||
import androidx.compose.material3.AlertDialog
|
import androidx.compose.material3.AlertDialog
|
||||||
import androidx.compose.material3.Button
|
import androidx.compose.material3.Button
|
||||||
import androidx.compose.material3.CircularProgressIndicator
|
import androidx.compose.material3.CircularProgressIndicator
|
||||||
|
import androidx.compose.material3.ExperimentalMaterial3Api
|
||||||
import androidx.compose.material3.FilledTonalButton
|
import androidx.compose.material3.FilledTonalButton
|
||||||
|
import androidx.compose.material3.Icon
|
||||||
|
import androidx.compose.material3.IconButton
|
||||||
|
import androidx.compose.material3.LargeTopAppBar
|
||||||
import androidx.compose.material3.MaterialTheme
|
import androidx.compose.material3.MaterialTheme
|
||||||
|
import androidx.compose.material3.Scaffold
|
||||||
import androidx.compose.material3.Text
|
import androidx.compose.material3.Text
|
||||||
import androidx.compose.material3.TextButton
|
import androidx.compose.material3.TextButton
|
||||||
|
import androidx.compose.material3.TopAppBarDefaults
|
||||||
import androidx.compose.material3.surfaceColorAtElevation
|
import androidx.compose.material3.surfaceColorAtElevation
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.runtime.LaunchedEffect
|
import androidx.compose.runtime.LaunchedEffect
|
||||||
|
|
@ -31,8 +39,10 @@ import androidx.compose.runtime.setValue
|
||||||
import androidx.compose.ui.Alignment
|
import androidx.compose.ui.Alignment
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
import androidx.compose.ui.draw.clip
|
import androidx.compose.ui.draw.clip
|
||||||
|
import androidx.compose.ui.input.nestedscroll.nestedScroll
|
||||||
import androidx.compose.ui.res.stringResource
|
import androidx.compose.ui.res.stringResource
|
||||||
import androidx.compose.ui.text.font.FontWeight
|
import androidx.compose.ui.text.font.FontWeight
|
||||||
|
import androidx.compose.ui.text.style.TextOverflow
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
import androidx.lifecycle.ViewModel
|
import androidx.lifecycle.ViewModel
|
||||||
import androidx.lifecycle.viewModelScope
|
import androidx.lifecycle.viewModelScope
|
||||||
|
|
@ -45,7 +55,6 @@ import chat.revolt.api.routes.auth.logoutAllSessions
|
||||||
import chat.revolt.api.routes.auth.logoutSessionById
|
import chat.revolt.api.routes.auth.logoutSessionById
|
||||||
import chat.revolt.api.schemas.Session
|
import chat.revolt.api.schemas.Session
|
||||||
import chat.revolt.components.generic.ListHeader
|
import chat.revolt.components.generic.ListHeader
|
||||||
import chat.revolt.components.generic.PageHeader
|
|
||||||
import chat.revolt.components.generic.UIMarkdown
|
import chat.revolt.components.generic.UIMarkdown
|
||||||
import chat.revolt.components.settings.sessions.SessionItem
|
import chat.revolt.components.settings.sessions.SessionItem
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
|
|
@ -84,7 +93,7 @@ class SessionSettingsScreenViewModel : ViewModel() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@OptIn(ExperimentalFoundationApi::class)
|
@OptIn(ExperimentalFoundationApi::class, ExperimentalMaterial3Api::class)
|
||||||
@Composable
|
@Composable
|
||||||
fun SessionSettingsScreen(
|
fun SessionSettingsScreen(
|
||||||
navController: NavController,
|
navController: NavController,
|
||||||
|
|
@ -126,125 +135,147 @@ fun SessionSettingsScreen(
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
Column(
|
|
||||||
modifier = Modifier
|
|
||||||
.fillMaxSize()
|
|
||||||
.safeDrawingPadding()
|
|
||||||
) {
|
|
||||||
PageHeader(
|
|
||||||
text = stringResource(id = R.string.settings_sessions),
|
|
||||||
showBackButton = true,
|
|
||||||
onBackButtonClicked = {
|
|
||||||
navController.popBackStack()
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
if (viewModel.isLoading) {
|
val scrollBehavior = TopAppBarDefaults.exitUntilCollapsedScrollBehavior()
|
||||||
|
|
||||||
|
Scaffold(
|
||||||
|
modifier = Modifier.nestedScroll(scrollBehavior.nestedScrollConnection),
|
||||||
|
topBar = {
|
||||||
|
LargeTopAppBar(
|
||||||
|
scrollBehavior = scrollBehavior,
|
||||||
|
title = {
|
||||||
|
Text(
|
||||||
|
text = stringResource(R.string.settings_sessions),
|
||||||
|
maxLines = 1,
|
||||||
|
overflow = TextOverflow.Ellipsis,
|
||||||
|
)
|
||||||
|
},
|
||||||
|
navigationIcon = {
|
||||||
|
IconButton(onClick = {
|
||||||
|
navController.popBackStack()
|
||||||
|
}) {
|
||||||
|
Icon(
|
||||||
|
imageVector = Icons.Default.ArrowBack,
|
||||||
|
contentDescription = stringResource(id = R.string.back)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
)
|
||||||
|
},
|
||||||
|
) { pv ->
|
||||||
|
Box(Modifier.padding(pv)) {
|
||||||
Column(
|
Column(
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.fillMaxSize(),
|
.fillMaxSize()
|
||||||
horizontalAlignment = Alignment.CenterHorizontally,
|
|
||||||
verticalArrangement = Arrangement.Center
|
|
||||||
) {
|
) {
|
||||||
CircularProgressIndicator(
|
if (viewModel.isLoading) {
|
||||||
modifier = Modifier
|
Column(
|
||||||
.size(48.dp)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
LazyColumn {
|
|
||||||
stickyHeader(key = "thisDevice") {
|
|
||||||
ListHeader {
|
|
||||||
Text(stringResource(id = R.string.settings_sessions_this_device))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
viewModel.currentSession?.let {
|
|
||||||
item(key = it.id) {
|
|
||||||
Spacer(Modifier.height(8.dp))
|
|
||||||
SessionItem(
|
|
||||||
session = it,
|
|
||||||
currentSession = true,
|
|
||||||
onLogout = {},
|
|
||||||
modifier = Modifier.padding(horizontal = 8.dp)
|
|
||||||
)
|
|
||||||
Spacer(Modifier.height(8.dp))
|
|
||||||
}
|
|
||||||
} ?: run {
|
|
||||||
item(key = "noCurrentSession") {
|
|
||||||
UIMarkdown(
|
|
||||||
text = stringResource(id = R.string.settings_sessions_this_device_unavailable),
|
|
||||||
modifier = Modifier
|
|
||||||
.fillMaxWidth()
|
|
||||||
.background(MaterialTheme.colorScheme.background)
|
|
||||||
.padding(10.dp)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
stickyHeader(key = "otherSessions") {
|
|
||||||
ListHeader {
|
|
||||||
Text(stringResource(id = R.string.settings_sessions_other_sessions))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
item(key = "logoutOtherSessions") {
|
|
||||||
Row(
|
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.padding(vertical = 8.dp, horizontal = 16.dp)
|
.fillMaxSize(),
|
||||||
.fillMaxWidth()
|
horizontalAlignment = Alignment.CenterHorizontally,
|
||||||
.clip(shape = MaterialTheme.shapes.medium)
|
verticalArrangement = Arrangement.Center
|
||||||
.background(
|
|
||||||
color = MaterialTheme.colorScheme.surfaceColorAtElevation(6.dp)
|
|
||||||
)
|
|
||||||
.padding(16.dp),
|
|
||||||
verticalAlignment = Alignment.CenterVertically,
|
|
||||||
horizontalArrangement = Arrangement.SpaceBetween
|
|
||||||
) {
|
) {
|
||||||
Column(
|
CircularProgressIndicator(
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.weight(1f)
|
.size(48.dp)
|
||||||
.padding(end = 16.dp)
|
)
|
||||||
) {
|
}
|
||||||
Text(
|
} else {
|
||||||
text = stringResource(R.string.settings_sessions_log_out_other),
|
LazyColumn {
|
||||||
style = MaterialTheme.typography.labelLarge
|
stickyHeader(key = "thisDevice") {
|
||||||
)
|
ListHeader {
|
||||||
|
Text(stringResource(id = R.string.settings_sessions_this_device))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Text(
|
viewModel.currentSession?.let {
|
||||||
text = stringResource(
|
item(key = it.id) {
|
||||||
R.string.settings_sessions_log_out_other_description
|
Spacer(Modifier.height(8.dp))
|
||||||
),
|
SessionItem(
|
||||||
style = MaterialTheme.typography.bodySmall.copy(
|
session = it,
|
||||||
fontWeight = FontWeight.Normal
|
currentSession = true,
|
||||||
|
onLogout = {},
|
||||||
|
modifier = Modifier.padding(horizontal = 8.dp)
|
||||||
)
|
)
|
||||||
|
Spacer(Modifier.height(8.dp))
|
||||||
|
}
|
||||||
|
} ?: run {
|
||||||
|
item(key = "noCurrentSession") {
|
||||||
|
UIMarkdown(
|
||||||
|
text = stringResource(id = R.string.settings_sessions_this_device_unavailable),
|
||||||
|
modifier = Modifier
|
||||||
|
.fillMaxWidth()
|
||||||
|
.background(MaterialTheme.colorScheme.background)
|
||||||
|
.padding(10.dp)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
stickyHeader(key = "otherSessions") {
|
||||||
|
ListHeader {
|
||||||
|
Text(stringResource(id = R.string.settings_sessions_other_sessions))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
item(key = "logoutOtherSessions") {
|
||||||
|
Row(
|
||||||
|
modifier = Modifier
|
||||||
|
.padding(vertical = 8.dp, horizontal = 16.dp)
|
||||||
|
.fillMaxWidth()
|
||||||
|
.clip(shape = MaterialTheme.shapes.medium)
|
||||||
|
.background(
|
||||||
|
color = MaterialTheme.colorScheme.surfaceColorAtElevation(6.dp)
|
||||||
|
)
|
||||||
|
.padding(16.dp),
|
||||||
|
verticalAlignment = Alignment.CenterVertically,
|
||||||
|
horizontalArrangement = Arrangement.SpaceBetween
|
||||||
|
) {
|
||||||
|
Column(
|
||||||
|
modifier = Modifier
|
||||||
|
.weight(1f)
|
||||||
|
.padding(end = 16.dp)
|
||||||
|
) {
|
||||||
|
Text(
|
||||||
|
text = stringResource(R.string.settings_sessions_log_out_other),
|
||||||
|
style = MaterialTheme.typography.labelLarge
|
||||||
|
)
|
||||||
|
|
||||||
|
Text(
|
||||||
|
text = stringResource(
|
||||||
|
R.string.settings_sessions_log_out_other_description
|
||||||
|
),
|
||||||
|
style = MaterialTheme.typography.bodySmall.copy(
|
||||||
|
fontWeight = FontWeight.Normal
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
FilledTonalButton(onClick = {
|
||||||
|
viewModel.showLogoutOtherConfirmation = true
|
||||||
|
}) {
|
||||||
|
Text(stringResource(R.string.logout))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Spacer(Modifier.height(8.dp))
|
||||||
|
}
|
||||||
|
|
||||||
|
items(viewModel.sessions.size) {
|
||||||
|
val item = viewModel.sessions[it]
|
||||||
|
|
||||||
|
if (item.isCurrent()) {
|
||||||
|
return@items
|
||||||
|
}
|
||||||
|
|
||||||
|
SessionItem(
|
||||||
|
session = item,
|
||||||
|
onLogout = { session ->
|
||||||
|
viewModel.logoutSession(session.id)
|
||||||
|
},
|
||||||
|
modifier = Modifier.padding(horizontal = 8.dp)
|
||||||
)
|
)
|
||||||
}
|
Spacer(Modifier.height(16.dp))
|
||||||
|
|
||||||
FilledTonalButton(onClick = {
|
|
||||||
viewModel.showLogoutOtherConfirmation = true
|
|
||||||
}) {
|
|
||||||
Text(stringResource(R.string.logout))
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Spacer(Modifier.height(8.dp))
|
|
||||||
}
|
|
||||||
|
|
||||||
items(viewModel.sessions.size) {
|
|
||||||
val item = viewModel.sessions[it]
|
|
||||||
|
|
||||||
if (item.isCurrent()) {
|
|
||||||
return@items
|
|
||||||
}
|
|
||||||
|
|
||||||
SessionItem(
|
|
||||||
session = item,
|
|
||||||
onLogout = { session ->
|
|
||||||
viewModel.logoutSession(session.id)
|
|
||||||
},
|
|
||||||
modifier = Modifier.padding(horizontal = 8.dp)
|
|
||||||
)
|
|
||||||
Spacer(Modifier.height(16.dp))
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,29 +1,37 @@
|
||||||
package chat.revolt.screens.settings
|
package chat.revolt.screens.settings
|
||||||
|
|
||||||
import androidx.compose.foundation.clickable
|
import androidx.compose.foundation.clickable
|
||||||
|
import androidx.compose.foundation.layout.Box
|
||||||
import androidx.compose.foundation.layout.Column
|
import androidx.compose.foundation.layout.Column
|
||||||
import androidx.compose.foundation.layout.fillMaxSize
|
import androidx.compose.foundation.layout.fillMaxSize
|
||||||
import androidx.compose.foundation.layout.padding
|
import androidx.compose.foundation.layout.padding
|
||||||
import androidx.compose.foundation.layout.safeDrawingPadding
|
|
||||||
import androidx.compose.foundation.rememberScrollState
|
import androidx.compose.foundation.rememberScrollState
|
||||||
import androidx.compose.foundation.verticalScroll
|
import androidx.compose.foundation.verticalScroll
|
||||||
import androidx.compose.material.icons.Icons
|
import androidx.compose.material.icons.Icons
|
||||||
|
import androidx.compose.material.icons.filled.ArrowBack
|
||||||
import androidx.compose.material.icons.filled.ArrowForward
|
import androidx.compose.material.icons.filled.ArrowForward
|
||||||
import androidx.compose.material.icons.filled.Close
|
import androidx.compose.material.icons.filled.Close
|
||||||
import androidx.compose.material.icons.filled.DateRange
|
import androidx.compose.material.icons.filled.DateRange
|
||||||
import androidx.compose.material.icons.filled.Info
|
import androidx.compose.material.icons.filled.Info
|
||||||
import androidx.compose.material.icons.filled.Settings
|
import androidx.compose.material.icons.filled.Settings
|
||||||
|
import androidx.compose.material3.ExperimentalMaterial3Api
|
||||||
import androidx.compose.material3.Icon
|
import androidx.compose.material3.Icon
|
||||||
|
import androidx.compose.material3.IconButton
|
||||||
|
import androidx.compose.material3.LargeTopAppBar
|
||||||
import androidx.compose.material3.ListItem
|
import androidx.compose.material3.ListItem
|
||||||
import androidx.compose.material3.LocalContentColor
|
import androidx.compose.material3.LocalContentColor
|
||||||
import androidx.compose.material3.MaterialTheme
|
import androidx.compose.material3.MaterialTheme
|
||||||
|
import androidx.compose.material3.Scaffold
|
||||||
import androidx.compose.material3.Text
|
import androidx.compose.material3.Text
|
||||||
|
import androidx.compose.material3.TopAppBarDefaults
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.runtime.CompositionLocalProvider
|
import androidx.compose.runtime.CompositionLocalProvider
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
|
import androidx.compose.ui.input.nestedscroll.nestedScroll
|
||||||
import androidx.compose.ui.platform.testTag
|
import androidx.compose.ui.platform.testTag
|
||||||
import androidx.compose.ui.res.painterResource
|
import androidx.compose.ui.res.painterResource
|
||||||
import androidx.compose.ui.res.stringResource
|
import androidx.compose.ui.res.stringResource
|
||||||
|
import androidx.compose.ui.text.style.TextOverflow
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
import androidx.hilt.navigation.compose.hiltViewModel
|
import androidx.hilt.navigation.compose.hiltViewModel
|
||||||
import androidx.lifecycle.ViewModel
|
import androidx.lifecycle.ViewModel
|
||||||
|
|
@ -35,7 +43,6 @@ import chat.revolt.api.settings.FeatureFlags
|
||||||
import chat.revolt.api.settings.GlobalState
|
import chat.revolt.api.settings.GlobalState
|
||||||
import chat.revolt.api.settings.LabsAccessControlVariates
|
import chat.revolt.api.settings.LabsAccessControlVariates
|
||||||
import chat.revolt.components.generic.ListHeader
|
import chat.revolt.components.generic.ListHeader
|
||||||
import chat.revolt.components.generic.PageHeader
|
|
||||||
import chat.revolt.components.screens.settings.SelfUserOverview
|
import chat.revolt.components.screens.settings.SelfUserOverview
|
||||||
import chat.revolt.persistence.KVStorage
|
import chat.revolt.persistence.KVStorage
|
||||||
import dagger.hilt.android.lifecycle.HiltViewModel
|
import dagger.hilt.android.lifecycle.HiltViewModel
|
||||||
|
|
@ -55,152 +62,188 @@ class SettingsScreenViewModel @Inject constructor(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@OptIn(ExperimentalMaterial3Api::class)
|
||||||
@Composable
|
@Composable
|
||||||
fun SettingsScreen(
|
fun SettingsScreen(
|
||||||
navController: NavController,
|
navController: NavController,
|
||||||
viewModel: SettingsScreenViewModel = hiltViewModel()
|
viewModel: SettingsScreenViewModel = hiltViewModel()
|
||||||
) {
|
) {
|
||||||
Column(
|
val scrollBehavior = TopAppBarDefaults.exitUntilCollapsedScrollBehavior()
|
||||||
modifier = Modifier
|
|
||||||
.fillMaxSize()
|
|
||||||
.safeDrawingPadding()
|
|
||||||
) {
|
|
||||||
PageHeader(
|
|
||||||
text = stringResource(id = R.string.settings),
|
|
||||||
showBackButton = true,
|
|
||||||
onBackButtonClicked = {
|
|
||||||
navController.popBackStack()
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
Column(
|
|
||||||
modifier = Modifier
|
|
||||||
.fillMaxSize()
|
|
||||||
.verticalScroll(rememberScrollState())
|
|
||||||
) {
|
|
||||||
SelfUserOverview()
|
|
||||||
|
|
||||||
|
Scaffold(
|
||||||
|
modifier = Modifier.nestedScroll(scrollBehavior.nestedScrollConnection),
|
||||||
|
topBar = {
|
||||||
|
LargeTopAppBar(
|
||||||
|
scrollBehavior = scrollBehavior,
|
||||||
|
title = {
|
||||||
|
Text(
|
||||||
|
text = stringResource(R.string.settings),
|
||||||
|
maxLines = 1,
|
||||||
|
overflow = TextOverflow.Ellipsis,
|
||||||
|
)
|
||||||
|
},
|
||||||
|
navigationIcon = {
|
||||||
|
IconButton(onClick = {
|
||||||
|
navController.popBackStack()
|
||||||
|
}) {
|
||||||
|
Icon(
|
||||||
|
imageVector = Icons.Default.ArrowBack,
|
||||||
|
contentDescription = stringResource(id = R.string.back)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
)
|
||||||
|
},
|
||||||
|
) { pv ->
|
||||||
|
Box(Modifier.padding(pv)) {
|
||||||
Column(
|
Column(
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.fillMaxSize()
|
.fillMaxSize()
|
||||||
.padding(vertical = 10.dp)
|
.verticalScroll(rememberScrollState())
|
||||||
) {
|
) {
|
||||||
ListHeader {
|
SelfUserOverview()
|
||||||
Text(stringResource(R.string.settings_category_account))
|
|
||||||
}
|
|
||||||
|
|
||||||
ListItem(
|
Column(
|
||||||
headlineContent = {
|
|
||||||
Text(
|
|
||||||
text = stringResource(id = R.string.settings_profile)
|
|
||||||
)
|
|
||||||
},
|
|
||||||
leadingContent = {
|
|
||||||
Icon(
|
|
||||||
painter = painterResource(R.drawable.ic_card_account_details_24dp),
|
|
||||||
contentDescription = null,
|
|
||||||
)
|
|
||||||
},
|
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.testTag("settings_view_profile")
|
.fillMaxSize()
|
||||||
.clickable {
|
.padding(vertical = 10.dp)
|
||||||
navController.navigate("settings/profile")
|
) {
|
||||||
}
|
ListHeader {
|
||||||
)
|
Text(stringResource(R.string.settings_category_account))
|
||||||
|
}
|
||||||
|
|
||||||
ListItem(
|
|
||||||
headlineContent = {
|
|
||||||
Text(
|
|
||||||
text = stringResource(id = R.string.settings_sessions)
|
|
||||||
)
|
|
||||||
},
|
|
||||||
leadingContent = {
|
|
||||||
Icon(
|
|
||||||
painter = painterResource(R.drawable.ic_tablet_cellphone_24dp),
|
|
||||||
contentDescription = null,
|
|
||||||
)
|
|
||||||
},
|
|
||||||
modifier = Modifier
|
|
||||||
.testTag("settings_view_sessions")
|
|
||||||
.clickable {
|
|
||||||
navController.navigate("settings/sessions")
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
ListHeader {
|
|
||||||
Text(stringResource(R.string.settings_category_general))
|
|
||||||
}
|
|
||||||
|
|
||||||
ListItem(
|
|
||||||
headlineContent = {
|
|
||||||
Text(
|
|
||||||
text = stringResource(id = R.string.settings_appearance)
|
|
||||||
)
|
|
||||||
},
|
|
||||||
leadingContent = {
|
|
||||||
Icon(
|
|
||||||
painter = painterResource(R.drawable.ic_palette_24dp),
|
|
||||||
contentDescription = null,
|
|
||||||
)
|
|
||||||
},
|
|
||||||
modifier = Modifier
|
|
||||||
.testTag("settings_view_appearance")
|
|
||||||
.clickable {
|
|
||||||
navController.navigate("settings/appearance")
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
ListHeader {
|
|
||||||
Text(stringResource(R.string.settings_category_miscellaneous))
|
|
||||||
}
|
|
||||||
|
|
||||||
ListItem(
|
|
||||||
headlineContent = {
|
|
||||||
Text(
|
|
||||||
text = stringResource(id = R.string.about)
|
|
||||||
)
|
|
||||||
},
|
|
||||||
leadingContent = {
|
|
||||||
Icon(
|
|
||||||
imageVector = Icons.Default.Info,
|
|
||||||
contentDescription = null,
|
|
||||||
)
|
|
||||||
},
|
|
||||||
modifier = Modifier
|
|
||||||
.testTag("settings_view_about")
|
|
||||||
.clickable {
|
|
||||||
navController.navigate("about")
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
if (BuildConfig.DEBUG) {
|
|
||||||
ListItem(
|
ListItem(
|
||||||
headlineContent = {
|
headlineContent = {
|
||||||
Text(
|
Text(
|
||||||
text = "Debug"
|
text = stringResource(id = R.string.settings_profile)
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
leadingContent = {
|
leadingContent = {
|
||||||
Icon(
|
Icon(
|
||||||
imageVector = Icons.Default.Settings,
|
painter = painterResource(R.drawable.ic_card_account_details_24dp),
|
||||||
contentDescription = null,
|
contentDescription = null,
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.testTag("settings_view_debug")
|
.testTag("settings_view_profile")
|
||||||
.clickable {
|
.clickable {
|
||||||
navController.navigate("settings/debug")
|
navController.navigate("settings/profile")
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
}
|
|
||||||
|
|
||||||
if (FeatureFlags.labsAccessControl is LabsAccessControlVariates.Restricted &&
|
|
||||||
(FeatureFlags.labsAccessControl as LabsAccessControlVariates.Restricted).predicate()
|
|
||||||
) {
|
|
||||||
ListItem(
|
ListItem(
|
||||||
headlineContent = {
|
headlineContent = {
|
||||||
Text(
|
Text(
|
||||||
text = "Labs"
|
text = stringResource(id = R.string.settings_sessions)
|
||||||
|
)
|
||||||
|
},
|
||||||
|
leadingContent = {
|
||||||
|
Icon(
|
||||||
|
painter = painterResource(R.drawable.ic_tablet_cellphone_24dp),
|
||||||
|
contentDescription = null,
|
||||||
|
)
|
||||||
|
},
|
||||||
|
modifier = Modifier
|
||||||
|
.testTag("settings_view_sessions")
|
||||||
|
.clickable {
|
||||||
|
navController.navigate("settings/sessions")
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
ListHeader {
|
||||||
|
Text(stringResource(R.string.settings_category_general))
|
||||||
|
}
|
||||||
|
|
||||||
|
ListItem(
|
||||||
|
headlineContent = {
|
||||||
|
Text(
|
||||||
|
text = stringResource(id = R.string.settings_appearance)
|
||||||
|
)
|
||||||
|
},
|
||||||
|
leadingContent = {
|
||||||
|
Icon(
|
||||||
|
painter = painterResource(R.drawable.ic_palette_24dp),
|
||||||
|
contentDescription = null,
|
||||||
|
)
|
||||||
|
},
|
||||||
|
modifier = Modifier
|
||||||
|
.testTag("settings_view_appearance")
|
||||||
|
.clickable {
|
||||||
|
navController.navigate("settings/appearance")
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
ListHeader {
|
||||||
|
Text(stringResource(R.string.settings_category_miscellaneous))
|
||||||
|
}
|
||||||
|
|
||||||
|
ListItem(
|
||||||
|
headlineContent = {
|
||||||
|
Text(
|
||||||
|
text = stringResource(id = R.string.about)
|
||||||
|
)
|
||||||
|
},
|
||||||
|
leadingContent = {
|
||||||
|
Icon(
|
||||||
|
imageVector = Icons.Default.Info,
|
||||||
|
contentDescription = null,
|
||||||
|
)
|
||||||
|
},
|
||||||
|
modifier = Modifier
|
||||||
|
.testTag("settings_view_about")
|
||||||
|
.clickable {
|
||||||
|
navController.navigate("about")
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
if (BuildConfig.DEBUG) {
|
||||||
|
ListItem(
|
||||||
|
headlineContent = {
|
||||||
|
Text(
|
||||||
|
text = "Debug"
|
||||||
|
)
|
||||||
|
},
|
||||||
|
leadingContent = {
|
||||||
|
Icon(
|
||||||
|
imageVector = Icons.Default.Settings,
|
||||||
|
contentDescription = null,
|
||||||
|
)
|
||||||
|
},
|
||||||
|
modifier = Modifier
|
||||||
|
.testTag("settings_view_debug")
|
||||||
|
.clickable {
|
||||||
|
navController.navigate("settings/debug")
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (FeatureFlags.labsAccessControl is LabsAccessControlVariates.Restricted &&
|
||||||
|
(FeatureFlags.labsAccessControl as LabsAccessControlVariates.Restricted).predicate()
|
||||||
|
) {
|
||||||
|
ListItem(
|
||||||
|
headlineContent = {
|
||||||
|
Text(
|
||||||
|
text = "Labs"
|
||||||
|
)
|
||||||
|
},
|
||||||
|
leadingContent = {
|
||||||
|
Icon(
|
||||||
|
imageVector = Icons.Default.ArrowForward,
|
||||||
|
contentDescription = null,
|
||||||
|
)
|
||||||
|
},
|
||||||
|
modifier = Modifier
|
||||||
|
.testTag("settings_view_labs")
|
||||||
|
.clickable {
|
||||||
|
navController.navigate("labs")
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
ListItem(
|
||||||
|
headlineContent = {
|
||||||
|
Text(
|
||||||
|
text = "Closed Beta Updater"
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
leadingContent = {
|
leadingContent = {
|
||||||
|
|
@ -210,101 +253,87 @@ fun SettingsScreen(
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.testTag("settings_view_labs")
|
.testTag("settings_view_updater")
|
||||||
.clickable {
|
.clickable {
|
||||||
navController.navigate("labs")
|
navController.navigate("settings/updater")
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
ListHeader {
|
||||||
|
Text(
|
||||||
|
stringResource(
|
||||||
|
R.string.settings_category_last,
|
||||||
|
BuildConfig.VERSION_NAME
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
ListItem(
|
||||||
|
headlineContent = {
|
||||||
|
Text(
|
||||||
|
text = stringResource(id = R.string.settings_changelogs)
|
||||||
|
)
|
||||||
|
},
|
||||||
|
leadingContent = {
|
||||||
|
Icon(
|
||||||
|
imageVector = Icons.Default.DateRange,
|
||||||
|
contentDescription = null,
|
||||||
|
)
|
||||||
|
},
|
||||||
|
modifier = Modifier
|
||||||
|
.testTag("settings_view_changelogs")
|
||||||
|
.clickable {
|
||||||
|
navController.navigate("settings/changelogs")
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
ListItem(
|
||||||
|
headlineContent = {
|
||||||
|
Text(
|
||||||
|
text = stringResource(id = R.string.settings_feedback)
|
||||||
|
)
|
||||||
|
},
|
||||||
|
leadingContent = {
|
||||||
|
Icon(
|
||||||
|
imageVector = Icons.Default.ArrowForward,
|
||||||
|
contentDescription = null,
|
||||||
|
)
|
||||||
|
},
|
||||||
|
modifier = Modifier
|
||||||
|
.testTag("settings_view_feedback")
|
||||||
|
.clickable {
|
||||||
|
navController.navigate("settings/feedback")
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
ListItem(
|
||||||
|
headlineContent = {
|
||||||
|
CompositionLocalProvider(LocalContentColor provides MaterialTheme.colorScheme.error) {
|
||||||
|
Text(
|
||||||
|
text = stringResource(id = R.string.logout)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
leadingContent = {
|
||||||
|
CompositionLocalProvider(LocalContentColor provides MaterialTheme.colorScheme.error) {
|
||||||
|
Icon(
|
||||||
|
imageVector = Icons.Default.Close,
|
||||||
|
contentDescription = null,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
modifier = Modifier
|
||||||
|
.testTag("settings_view_logout")
|
||||||
|
.clickable {
|
||||||
|
viewModel.logout()
|
||||||
|
navController.navigate("login/greeting") {
|
||||||
|
popUpTo("chat") {
|
||||||
|
inclusive = true
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
ListItem(
|
|
||||||
headlineContent = {
|
|
||||||
Text(
|
|
||||||
text = "Closed Beta Updater"
|
|
||||||
)
|
|
||||||
},
|
|
||||||
leadingContent = {
|
|
||||||
Icon(
|
|
||||||
imageVector = Icons.Default.ArrowForward,
|
|
||||||
contentDescription = null,
|
|
||||||
)
|
|
||||||
},
|
|
||||||
modifier = Modifier
|
|
||||||
.testTag("settings_view_updater")
|
|
||||||
.clickable {
|
|
||||||
navController.navigate("settings/updater")
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
ListHeader {
|
|
||||||
Text(stringResource(R.string.settings_category_last, BuildConfig.VERSION_NAME))
|
|
||||||
}
|
|
||||||
|
|
||||||
ListItem(
|
|
||||||
headlineContent = {
|
|
||||||
Text(
|
|
||||||
text = stringResource(id = R.string.settings_changelogs)
|
|
||||||
)
|
|
||||||
},
|
|
||||||
leadingContent = {
|
|
||||||
Icon(
|
|
||||||
imageVector = Icons.Default.DateRange,
|
|
||||||
contentDescription = null,
|
|
||||||
)
|
|
||||||
},
|
|
||||||
modifier = Modifier
|
|
||||||
.testTag("settings_view_changelogs")
|
|
||||||
.clickable {
|
|
||||||
navController.navigate("settings/changelogs")
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
ListItem(
|
|
||||||
headlineContent = {
|
|
||||||
Text(
|
|
||||||
text = stringResource(id = R.string.settings_feedback)
|
|
||||||
)
|
|
||||||
},
|
|
||||||
leadingContent = {
|
|
||||||
Icon(
|
|
||||||
imageVector = Icons.Default.ArrowForward,
|
|
||||||
contentDescription = null,
|
|
||||||
)
|
|
||||||
},
|
|
||||||
modifier = Modifier
|
|
||||||
.testTag("settings_view_feedback")
|
|
||||||
.clickable {
|
|
||||||
navController.navigate("settings/feedback")
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
ListItem(
|
|
||||||
headlineContent = {
|
|
||||||
CompositionLocalProvider(LocalContentColor provides MaterialTheme.colorScheme.error) {
|
|
||||||
Text(
|
|
||||||
text = stringResource(id = R.string.logout)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
},
|
|
||||||
leadingContent = {
|
|
||||||
CompositionLocalProvider(LocalContentColor provides MaterialTheme.colorScheme.error) {
|
|
||||||
Icon(
|
|
||||||
imageVector = Icons.Default.Close,
|
|
||||||
contentDescription = null,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
},
|
|
||||||
modifier = Modifier
|
|
||||||
.testTag("settings_view_logout")
|
|
||||||
.clickable {
|
|
||||||
viewModel.logout()
|
|
||||||
navController.navigate("login/greeting") {
|
|
||||||
popUpTo("chat") {
|
|
||||||
inclusive = true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -17,6 +17,7 @@ import androidx.compose.material.icons.filled.ExitToApp
|
||||||
import androidx.compose.material3.AlertDialog
|
import androidx.compose.material3.AlertDialog
|
||||||
import androidx.compose.material3.Icon
|
import androidx.compose.material3.Icon
|
||||||
import androidx.compose.material3.ListItem
|
import androidx.compose.material3.ListItem
|
||||||
|
import androidx.compose.material3.MaterialTheme
|
||||||
import androidx.compose.material3.Text
|
import androidx.compose.material3.Text
|
||||||
import androidx.compose.material3.TextButton
|
import androidx.compose.material3.TextButton
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
|
|
@ -31,7 +32,6 @@ import chat.revolt.R
|
||||||
import chat.revolt.activities.InviteActivity
|
import chat.revolt.activities.InviteActivity
|
||||||
import chat.revolt.api.REVOLT_APP
|
import chat.revolt.api.REVOLT_APP
|
||||||
import chat.revolt.components.generic.FormTextField
|
import chat.revolt.components.generic.FormTextField
|
||||||
import chat.revolt.components.generic.PageHeader
|
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun AddServerSheet() {
|
fun AddServerSheet() {
|
||||||
|
|
@ -53,8 +53,9 @@ fun AddServerSheet() {
|
||||||
|
|
||||||
Spacer(modifier = Modifier.height(4.dp))
|
Spacer(modifier = Modifier.height(4.dp))
|
||||||
|
|
||||||
PageHeader(
|
Text(
|
||||||
text = stringResource(id = R.string.add_server_sheet_title)
|
text = stringResource(id = R.string.add_server_sheet_title),
|
||||||
|
style = MaterialTheme.typography.headlineMedium
|
||||||
)
|
)
|
||||||
|
|
||||||
Spacer(modifier = Modifier.height(4.dp))
|
Spacer(modifier = Modifier.height(4.dp))
|
||||||
|
|
|
||||||
|
|
@ -10,6 +10,8 @@ import androidx.compose.foundation.layout.padding
|
||||||
import androidx.compose.foundation.rememberScrollState
|
import androidx.compose.foundation.rememberScrollState
|
||||||
import androidx.compose.foundation.verticalScroll
|
import androidx.compose.foundation.verticalScroll
|
||||||
import androidx.compose.material3.CircularProgressIndicator
|
import androidx.compose.material3.CircularProgressIndicator
|
||||||
|
import androidx.compose.material3.MaterialTheme
|
||||||
|
import androidx.compose.material3.Text
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.runtime.LaunchedEffect
|
import androidx.compose.runtime.LaunchedEffect
|
||||||
import androidx.compose.runtime.getValue
|
import androidx.compose.runtime.getValue
|
||||||
|
|
@ -23,7 +25,6 @@ import androidx.compose.ui.unit.dp
|
||||||
import androidx.hilt.navigation.compose.hiltViewModel
|
import androidx.hilt.navigation.compose.hiltViewModel
|
||||||
import androidx.lifecycle.ViewModel
|
import androidx.lifecycle.ViewModel
|
||||||
import chat.revolt.R
|
import chat.revolt.R
|
||||||
import chat.revolt.components.generic.PageHeader
|
|
||||||
import chat.revolt.components.generic.WebMarkdown
|
import chat.revolt.components.generic.WebMarkdown
|
||||||
import chat.revolt.internals.Changelog
|
import chat.revolt.internals.Changelog
|
||||||
import chat.revolt.internals.Changelogs
|
import chat.revolt.internals.Changelogs
|
||||||
|
|
@ -67,8 +68,8 @@ fun ChangelogSheet(
|
||||||
}
|
}
|
||||||
|
|
||||||
Column {
|
Column {
|
||||||
PageHeader(
|
Text(
|
||||||
if (new) {
|
text = if (new) {
|
||||||
stringResource(R.string.settings_changelogs_new_header)
|
stringResource(R.string.settings_changelogs_new_header)
|
||||||
} else {
|
} else {
|
||||||
stringResource(
|
stringResource(
|
||||||
|
|
@ -76,7 +77,8 @@ fun ChangelogSheet(
|
||||||
viewModel.changelog?.version
|
viewModel.changelog?.version
|
||||||
?: stringResource(R.string.settings_changelogs_historical_version_header_placeholder)
|
?: stringResource(R.string.settings_changelogs_historical_version_header_placeholder)
|
||||||
)
|
)
|
||||||
}
|
},
|
||||||
|
style = MaterialTheme.typography.headlineMedium
|
||||||
)
|
)
|
||||||
|
|
||||||
if (viewModel.changelogContents == null) {
|
if (viewModel.changelogContents == null) {
|
||||||
|
|
|
||||||
|
|
@ -14,6 +14,7 @@ import androidx.compose.material3.CircularProgressIndicator
|
||||||
import androidx.compose.material3.ExperimentalMaterial3Api
|
import androidx.compose.material3.ExperimentalMaterial3Api
|
||||||
import androidx.compose.material3.MaterialTheme
|
import androidx.compose.material3.MaterialTheme
|
||||||
import androidx.compose.material3.ModalBottomSheet
|
import androidx.compose.material3.ModalBottomSheet
|
||||||
|
import androidx.compose.material3.Text
|
||||||
import androidx.compose.material3.rememberModalBottomSheetState
|
import androidx.compose.material3.rememberModalBottomSheetState
|
||||||
import androidx.compose.material3.surfaceColorAtElevation
|
import androidx.compose.material3.surfaceColorAtElevation
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
|
|
@ -42,7 +43,6 @@ import chat.revolt.api.schemas.Member
|
||||||
import chat.revolt.api.schemas.User
|
import chat.revolt.api.schemas.User
|
||||||
import chat.revolt.components.chat.MemberListItem
|
import chat.revolt.components.chat.MemberListItem
|
||||||
import chat.revolt.components.generic.CountableListHeader
|
import chat.revolt.components.generic.CountableListHeader
|
||||||
import chat.revolt.components.generic.PageHeader
|
|
||||||
import chat.revolt.components.generic.Presence
|
import chat.revolt.components.generic.Presence
|
||||||
import chat.revolt.components.generic.presenceFromStatus
|
import chat.revolt.components.generic.presenceFromStatus
|
||||||
import dagger.hilt.android.lifecycle.HiltViewModel
|
import dagger.hilt.android.lifecycle.HiltViewModel
|
||||||
|
|
@ -254,7 +254,10 @@ fun MemberListSheet(
|
||||||
}
|
}
|
||||||
|
|
||||||
Column {
|
Column {
|
||||||
PageHeader(text = stringResource(R.string.channel_info_sheet_options_members))
|
Text(
|
||||||
|
text = stringResource(R.string.channel_info_sheet_options_members),
|
||||||
|
style = MaterialTheme.typography.headlineMedium
|
||||||
|
)
|
||||||
|
|
||||||
LazyColumn {
|
LazyColumn {
|
||||||
viewModel.fullItemList.forEachIndexed { index, item ->
|
viewModel.fullItemList.forEachIndexed { index, item ->
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue