feat: discover screen

Signed-off-by: Infi <infi@infi.sh>
This commit is contained in:
Infi 2023-11-18 19:01:46 +01:00
parent 2507206ea3
commit 2a88d58cfa
7 changed files with 305 additions and 2 deletions

View File

@ -40,6 +40,7 @@ import chat.revolt.screens.register.OnboardingScreen
import chat.revolt.screens.register.RegisterDetailsScreen
import chat.revolt.screens.register.RegisterGreetingScreen
import chat.revolt.screens.register.RegisterVerifyScreen
import chat.revolt.screens.services.DiscoverScreen
import chat.revolt.screens.settings.AppearanceSettingsScreen
import chat.revolt.screens.settings.ChangelogsSettingsScreen
import chat.revolt.screens.settings.ClosedBetaUpdaterScreen
@ -145,6 +146,8 @@ fun AppEntrypoint(windowSizeClass: WindowSizeClass) {
composable("chat") { ChatRouterScreen(navController, windowSizeClass) }
composable("discover") { DiscoverScreen(navController) }
composable("settings") { SettingsScreen(navController) }
composable("settings/profile") { ProfileSettingsScreen(navController) }
composable("settings/sessions") { SessionSettingsScreen(navController) }

View File

@ -0,0 +1,109 @@
package chat.revolt.api.internals
import androidx.compose.material3.MaterialTheme
import androidx.compose.runtime.Composable
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.toArgb
import kotlinx.serialization.json.JsonObject
import kotlinx.serialization.json.JsonPrimitive
fun Color.asComponentJsonPrimitiveString(): JsonPrimitive {
val rgb = this.toArgb()
val r = rgb shr 16 and 0xFF
val g = rgb shr 8 and 0xFF
val b = rgb shr 0 and 0xFF
return JsonPrimitive("$r, $g, $b")
}
fun Color.asHexJsonPrimitiveString(): JsonPrimitive {
val rgb = this.toArgb()
val r = rgb shr 16 and 0xFF
val g = rgb shr 8 and 0xFF
val b = rgb shr 0 and 0xFF
return JsonPrimitive("#${r.toString(16)}${g.toString(16)}${b.toString(16)}")
}
object ThemeCompat {
@Composable
fun materialThemeAsDiscoverTheme(materialTheme: MaterialTheme): JsonObject {
// https://github.com/revoltchat/discover/blob/6effdf4a611e89b38b5e6bccefa1cd999e4b545f/styles/variables.scss
return JsonObject(
mapOf(
"accent" to materialTheme.colorScheme.primary.asHexJsonPrimitiveString(),
"accent-rgb" to materialTheme.colorScheme.primary.asComponentJsonPrimitiveString(),
"background" to materialTheme.colorScheme.background.asHexJsonPrimitiveString(),
"background-rgb" to materialTheme.colorScheme.background.asComponentJsonPrimitiveString(),
"foreground" to materialTheme.colorScheme.onBackground.asHexJsonPrimitiveString(),
"foreground-rgb" to materialTheme.colorScheme.onBackground.asComponentJsonPrimitiveString(),
"block" to materialTheme.colorScheme.surface.asHexJsonPrimitiveString(),
"block-rgb" to materialTheme.colorScheme.surface.asComponentJsonPrimitiveString(),
"message-box" to materialTheme.colorScheme.surface.asHexJsonPrimitiveString(),
"message-box-rgb" to materialTheme.colorScheme.surface.asComponentJsonPrimitiveString(),
"mention" to materialTheme.colorScheme.primary.copy(alpha = 0.1f)
.asHexJsonPrimitiveString(),
"mention-rgb" to materialTheme.colorScheme.primary.copy(alpha = 0.1f)
.asComponentJsonPrimitiveString(),
"success" to materialTheme.colorScheme.primary.asHexJsonPrimitiveString(),
"success-rgb" to materialTheme.colorScheme.primary.asComponentJsonPrimitiveString(),
"warning" to materialTheme.colorScheme.secondary.asHexJsonPrimitiveString(),
"warning-rgb" to materialTheme.colorScheme.secondary.asComponentJsonPrimitiveString(),
"error" to materialTheme.colorScheme.error.asHexJsonPrimitiveString(),
"error-rgb" to materialTheme.colorScheme.error.asComponentJsonPrimitiveString(),
"hover" to materialTheme.colorScheme.primary.copy(alpha = 0.1f)
.asHexJsonPrimitiveString(),
"hover-rgb" to materialTheme.colorScheme.primary.copy(alpha = 0.1f)
.asComponentJsonPrimitiveString(),
"scrollbar-thumb" to materialTheme.colorScheme.primary.asHexJsonPrimitiveString(),
"scrollbar-thumb-rgb" to materialTheme.colorScheme.primary.asComponentJsonPrimitiveString(),
"scrollbar-track" to materialTheme.colorScheme.background.asHexJsonPrimitiveString(),
"scrollbar-track-rgb" to materialTheme.colorScheme.background.asComponentJsonPrimitiveString(),
"primary-background" to materialTheme.colorScheme.background.asHexJsonPrimitiveString(),
"primary-background-rgb" to materialTheme.colorScheme.background.asComponentJsonPrimitiveString(),
"primary-header" to materialTheme.colorScheme.background.asHexJsonPrimitiveString(),
"primary-header-rgb" to materialTheme.colorScheme.background.asComponentJsonPrimitiveString(),
"secondary-background" to materialTheme.colorScheme.surface.asHexJsonPrimitiveString(),
"secondary-background-rgb" to materialTheme.colorScheme.surface.asComponentJsonPrimitiveString(),
"secondary-foreground" to materialTheme.colorScheme.onSurface.asHexJsonPrimitiveString(),
"secondary-foreground-rgb" to materialTheme.colorScheme.onSurface.asComponentJsonPrimitiveString(),
"secondary-header" to materialTheme.colorScheme.surface.asHexJsonPrimitiveString(),
"secondary-header-rgb" to materialTheme.colorScheme.surface.asComponentJsonPrimitiveString(),
"tertiary-background" to materialTheme.colorScheme.surface.asHexJsonPrimitiveString(),
"tertiary-background-rgb" to materialTheme.colorScheme.surface.asComponentJsonPrimitiveString(),
"tertiary-foreground" to materialTheme.colorScheme.onSurface.asHexJsonPrimitiveString(),
"tertiary-foreground-rgb" to materialTheme.colorScheme.onSurface.asComponentJsonPrimitiveString(),
"accent-contrast" to materialTheme.colorScheme.onPrimary.asHexJsonPrimitiveString(),
"accent-contrast-rgb" to materialTheme.colorScheme.onPrimary.asComponentJsonPrimitiveString(),
"background-contrast" to materialTheme.colorScheme.onBackground.asHexJsonPrimitiveString(),
"background-contrast-rgb" to materialTheme.colorScheme.onBackground.asComponentJsonPrimitiveString(),
"foreground-contrast" to materialTheme.colorScheme.inverseOnSurface.asHexJsonPrimitiveString(),
"foreground-contrast-rgb" to materialTheme.colorScheme.inverseOnSurface.asComponentJsonPrimitiveString(),
"block-contrast" to materialTheme.colorScheme.onSurface.asHexJsonPrimitiveString(),
"block-contrast-rgb" to materialTheme.colorScheme.onSurface.asComponentJsonPrimitiveString(),
"message-box-contrast" to materialTheme.colorScheme.onSurface.asHexJsonPrimitiveString(),
"message-box-contrast-rgb" to materialTheme.colorScheme.onSurface.asComponentJsonPrimitiveString(),
"mention-contrast" to materialTheme.colorScheme.onPrimary.asHexJsonPrimitiveString(),
"mention-contrast-rgb" to materialTheme.colorScheme.onPrimary.asComponentJsonPrimitiveString(),
"success-contrast" to materialTheme.colorScheme.onPrimary.asHexJsonPrimitiveString(),
"success-contrast-rgb" to materialTheme.colorScheme.onPrimary.asComponentJsonPrimitiveString(),
"warning-contrast" to materialTheme.colorScheme.onSecondary.asHexJsonPrimitiveString(),
"warning-contrast-rgb" to materialTheme.colorScheme.onSecondary.asComponentJsonPrimitiveString(),
"error-contrast" to materialTheme.colorScheme.onError.asHexJsonPrimitiveString(),
"error-contrast-rgb" to materialTheme.colorScheme.onError.asComponentJsonPrimitiveString(),
"primary-background-contrast" to materialTheme.colorScheme.onBackground.asHexJsonPrimitiveString(),
"primary-background-contrast-rgb" to materialTheme.colorScheme.onBackground.asComponentJsonPrimitiveString(),
"primary-header-contrast" to materialTheme.colorScheme.onBackground.asHexJsonPrimitiveString(),
"primary-header-contrast-rgb" to materialTheme.colorScheme.onBackground.asComponentJsonPrimitiveString(),
"secondary-background-contrast" to materialTheme.colorScheme.onSurface.asHexJsonPrimitiveString(),
"secondary-background-contrast-rgb" to materialTheme.colorScheme.onSurface.asComponentJsonPrimitiveString(),
"secondary-foreground-contrast" to materialTheme.colorScheme.inverseOnSurface.asHexJsonPrimitiveString(),
"secondary-foreground-contrast-rgb" to materialTheme.colorScheme.inverseOnSurface.asComponentJsonPrimitiveString(),
"secondary-header-contrast" to materialTheme.colorScheme.onSurface.asHexJsonPrimitiveString(),
"secondary-header-contrast-rgb" to materialTheme.colorScheme.onSurface.asComponentJsonPrimitiveString(),
"tertiary-background-contrast" to materialTheme.colorScheme.onSurface.asHexJsonPrimitiveString(),
"tertiary-background-contrast-rgb" to materialTheme.colorScheme.onSurface.asComponentJsonPrimitiveString(),
"tertiary-foreground-contrast" to materialTheme.colorScheme.inverseOnSurface.asHexJsonPrimitiveString(),
"tertiary-foreground-contrast-rgb" to materialTheme.colorScheme.inverseOnSurface.asComponentJsonPrimitiveString(),
)
)
}
}

View File

@ -0,0 +1,138 @@
package chat.revolt.components.screens.services
import android.annotation.SuppressLint
import android.content.Intent
import android.net.Uri
import android.webkit.WebResourceRequest
import android.webkit.WebView
import androidx.compose.animation.core.animateFloatAsState
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.ColumnScope
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.size
import androidx.compose.material3.CircularProgressIndicator
import androidx.compose.material3.MaterialTheme
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.alpha
import androidx.compose.ui.unit.dp
import androidx.compose.ui.viewinterop.AndroidView
import chat.revolt.activities.InviteActivity
import chat.revolt.api.REVOLT_APP
import chat.revolt.api.RevoltJson
import chat.revolt.api.buildUserAgent
import chat.revolt.api.internals.ThemeCompat
import kotlinx.serialization.json.JsonObject
import kotlinx.serialization.json.JsonPrimitive
@SuppressLint("SetJavaScriptEnabled")
@Composable
fun ColumnScope.DiscoverView() {
var showPlaceholder by remember { mutableStateOf(true) }
val animatedAlpha by animateFloatAsState(
targetValue = if (showPlaceholder) 1f else 0f,
label = "discoverViewPlaceholderAlpha"
)
val themeMap = ThemeCompat.materialThemeAsDiscoverTheme(MaterialTheme)
Box(
contentAlignment = Alignment.Center,
modifier = Modifier
.weight(1f)
) {
AndroidView(
factory = { context ->
WebView(context).apply {
settings.javaScriptEnabled = true
settings.domStorageEnabled = true
settings.userAgentString = buildUserAgent("DiscoverView")
settings.setSupportZoom(false)
settings.setSupportMultipleWindows(false)
loadUrl("https://rvlt.gg/discover/servers?embedded=true")
webViewClient = object : android.webkit.WebViewClient() {
override fun onPageFinished(view: WebView?, url: String?) {
super.onPageFinished(view, url)
val themeMessage = JsonObject(
mapOf(
"source" to JsonPrimitive("revolt"),
"type" to JsonPrimitive("theme"),
"theme" to themeMap
)
)
val themeMessageString =
RevoltJson.encodeToString(JsonObject.serializer(), themeMessage)
evaluateJavascript(
"""
window.postMessage($themeMessageString, "*")
window.addEventListener("message", event => {
try {
const data = JSON.parse(event.data)
if (data.source === "discover") {
switch (data.type) {
case "navigate":
// Cheap debounce
if (Date.now() - window.lastNavigateEvent < 500) {
return
}
window.lastNavigateEvent = Date.now()
window.location.href = data.url
break
}
}
} catch(e) {}
})
""".trimIndent(),
null
)
postDelayed({
showPlaceholder = false
}, 1000) // to prevent flickering
}
override fun shouldOverrideUrlLoading(
view: WebView?,
request: WebResourceRequest?
): Boolean {
if (request?.url?.host.equals(Uri.parse(REVOLT_APP).host)) {
val intent = Intent(
context,
InviteActivity::class.java
).setAction(Intent.ACTION_VIEW)
intent.data = request?.url
context.startActivity(intent)
return true
}
if (!request?.url?.host.equals("rvlt.gg")) {
return true
}
return false
}
}
}
},
update = {
},
modifier = Modifier
.fillMaxSize()
.alpha(1f - animatedAlpha)
)
CircularProgressIndicator(
modifier = Modifier
.size(48.dp)
.alpha(animatedAlpha)
)
}
}

View File

@ -700,6 +700,7 @@ fun ChatRouterScreen(
) {
Sidebar(
viewModel = viewModel,
topNav = topNav,
navController = navController,
onShowStatusSheet = {
showStatusSheet = true
@ -736,6 +737,7 @@ fun ChatRouterScreen(
) {
Sidebar(
viewModel = viewModel,
topNav = topNav,
navController = navController,
onShowStatusSheet = {
showStatusSheet = true
@ -777,6 +779,7 @@ fun ChatRouterScreen(
@Composable
fun Sidebar(
viewModel: ChatRouterViewModel,
topNav: NavController,
navController: NavHostController,
drawerState: DrawerState? = null,
onShowStatusSheet: () -> Unit,
@ -919,8 +922,6 @@ fun Sidebar(
server.id
),
onLongClick = {
/*serverContextSheetTarget = server.id
showServerContextSheet = true*/
onShowServerContextSheet(server.id)
}
) {
@ -940,6 +941,16 @@ fun Sidebar(
modifier = Modifier.padding(4.dp)
)
}
DrawerServerlikeIcon(
onClick = { topNav.navigate("discover") }
) {
Icon(
painter = painterResource(id = R.drawable.ic_compass_24dp),
contentDescription = stringResource(id = R.string.discover_alt),
modifier = Modifier.padding(4.dp)
)
}
}
Crossfade(

View File

@ -0,0 +1,30 @@
package chat.revolt.screens.services
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.safeDrawingPadding
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.res.stringResource
import androidx.navigation.NavController
import chat.revolt.R
import chat.revolt.components.generic.PageHeader
import chat.revolt.components.screens.services.DiscoverView
@Composable
fun DiscoverScreen(navController: NavController) {
Column(
Modifier
.fillMaxSize()
.safeDrawingPadding()
) {
PageHeader(
text = stringResource(R.string.discover),
showBackButton = true,
onBackButtonClicked = {
navController.popBackStack()
}
)
DiscoverView()
}
}

View File

@ -0,0 +1,9 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:height="24dp"
android:width="24dp"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:fillColor="#ffffff"
android:pathData="M14.19,14.19L6,18L9.81,9.81L18,6M12,2A10,10 0 0,0 2,12A10,10 0 0,0 12,22A10,10 0 0,0 22,12A10,10 0 0,0 12,2M12,10.9A1.1,1.1 0 0,0 10.9,12A1.1,1.1 0 0,0 12,13.1A1.1,1.1 0 0,0 13.1,12A1.1,1.1 0 0,0 12,10.9Z" />
</vector>

View File

@ -130,6 +130,7 @@
<string name="friends_deny_all_incoming">Clear all incoming requests</string>
<string name="server_plus_alt">Add server</string>
<string name="discover_alt">Discover</string>
<string name="no_channels_heading">Bit awkward.</string>
<string name="no_channels_body">There aren\'t any channels in this server. Not even a welcome channel. How rude.</string>
@ -300,6 +301,8 @@
<string name="add_server_sheet_create_new_modal_title">Create a new server</string>
<string name="add_server_sheet_create_new_modal_under_construction">This feature is currently under construction.</string>
<string name="discover">Discover Revolt</string>
<string name="report">Report</string>
<string name="report_cancel">Cancel</string>