wip: Migrate to Trixnity
This commit is contained in:
@@ -12,9 +12,6 @@ import io.ktor.client.plugins.logging.LogLevel
|
||||
import io.ktor.client.plugins.logging.Logger
|
||||
import io.ktor.client.plugins.logging.Logging
|
||||
import net.folivo.trixnity.client.MatrixClient
|
||||
//import ru.risdeveau.pixeldragon.api.MatrixSyncService
|
||||
//import ru.risdeveau.pixeldragon.api.getMe
|
||||
import splitties.preferences.Preferences
|
||||
|
||||
val webClient = HttpClient {
|
||||
install(Logging) {
|
||||
@@ -30,24 +27,3 @@ val webClient = HttpClient {
|
||||
}
|
||||
|
||||
var client: MatrixClient? = null
|
||||
|
||||
object AccountData : Preferences("system_parameters") {
|
||||
var token by stringOrNullPref("token", null)
|
||||
var userId by stringOrNullPref("user_id", null)
|
||||
var homeserver by stringOrNullPref("homeserver", null)
|
||||
var syncLastBatch by stringOrNullPref("next_batch", null)
|
||||
var filter by stringOrNullPref("filter", null)
|
||||
}
|
||||
|
||||
//val syncService = MatrixSyncService()
|
||||
|
||||
//suspend fun initCheck(): Boolean {
|
||||
// Log.d("initCheck", "checking...")
|
||||
//
|
||||
// token = AccountData.token ?: return false
|
||||
// homeserver = AccountData.homeserver ?: return false
|
||||
//
|
||||
// baseUrl = "$homeserver/_matrix/client/v3"
|
||||
//
|
||||
// return getMe() != null
|
||||
//}
|
||||
|
||||
@@ -30,9 +30,13 @@ import androidx.navigation.compose.NavHost
|
||||
import androidx.navigation.compose.composable
|
||||
import androidx.navigation.compose.rememberNavController
|
||||
import androidx.navigation.navArgument
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.launch
|
||||
import net.folivo.trixnity.client.MatrixClient
|
||||
import net.folivo.trixnity.client.fromStore
|
||||
import ru.risdeveau.pixeldragon.client
|
||||
import ru.risdeveau.pixeldragon.ui.layout.RoomList
|
||||
import ru.risdeveau.pixeldragon.ui.theme.PixelDragonTheme
|
||||
import ru.risdeveau.pixeldragon.util.getMediaStore
|
||||
import ru.risdeveau.pixeldragon.util.getRoomStore
|
||||
@@ -70,9 +74,10 @@ class MainActivity : ComponentActivity() {
|
||||
) { innerPadding ->
|
||||
val navController = rememberNavController()
|
||||
|
||||
NavHost(navController = navController, startDestination = "none") {
|
||||
composable("none") { }
|
||||
composable("rooms") { /*RoomList(Modifier.padding(innerPadding), navController)*/ }
|
||||
NavHost(navController = navController, startDestination = "rooms") {
|
||||
composable("rooms") {
|
||||
RoomList(Modifier.padding(innerPadding), navController)
|
||||
}
|
||||
composable(
|
||||
"room/{rid}",
|
||||
arguments = listOf(navArgument("rid") { type = NavType.StringType })
|
||||
@@ -109,9 +114,17 @@ class MainActivity : ComponentActivity() {
|
||||
}
|
||||
|
||||
Log.i("MainActivity", "Log in as ${client!!.userId}")
|
||||
client!!.startSync()
|
||||
isClientReady = true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun onDestroy() {
|
||||
super.onDestroy()
|
||||
CoroutineScope(Dispatchers.Main).launch {
|
||||
client?.stopSync()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,3 +2,128 @@
|
||||
* Created by sweetbread
|
||||
* Copyright (c) 2026. All rights reserved.
|
||||
*/
|
||||
|
||||
package ru.risdeveau.pixeldragon.ui.item
|
||||
|
||||
import androidx.compose.foundation.Image
|
||||
import androidx.compose.foundation.layout.Box
|
||||
import androidx.compose.foundation.layout.fillMaxSize
|
||||
import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.outlined.Warning
|
||||
import androidx.compose.material3.CircularProgressIndicator
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.LaunchedEffect
|
||||
import androidx.compose.runtime.collectAsState
|
||||
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.layout.ContentScale
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import coil3.compose.rememberAsyncImagePainter
|
||||
import coil3.request.ImageRequest
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import net.folivo.trixnity.client.media
|
||||
import net.folivo.trixnity.clientserverapi.model.media.FileTransferProgress
|
||||
import ru.risdeveau.pixeldragon.client
|
||||
|
||||
enum class ImageLoadState {
|
||||
Loading, Success, Error
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun MXCImage(
|
||||
mxcUrl: String,
|
||||
modifier: Modifier = Modifier,
|
||||
contentScale: ContentScale = ContentScale.Fit,
|
||||
contentDescription: String = "",
|
||||
showProgress: Boolean = true
|
||||
) {
|
||||
val context = LocalContext.current
|
||||
var imageLoadState by remember { mutableStateOf(ImageLoadState.Loading) }
|
||||
var imageBytes by remember { mutableStateOf<ByteArray?>(null) }
|
||||
|
||||
val progressFlow = remember { MutableStateFlow<FileTransferProgress?>(null) }
|
||||
|
||||
LaunchedEffect(mxcUrl) {
|
||||
if (mxcUrl.isBlank()) {
|
||||
imageLoadState = ImageLoadState.Error
|
||||
return@LaunchedEffect
|
||||
}
|
||||
imageLoadState = ImageLoadState.Loading
|
||||
progressFlow.value = null
|
||||
|
||||
val result = client!!.media.getMedia(
|
||||
uri = mxcUrl,
|
||||
progress = progressFlow.takeIf { showProgress },
|
||||
saveToCache = true
|
||||
)
|
||||
|
||||
imageLoadState = result.fold(
|
||||
onSuccess = { media ->
|
||||
val bytes = media.toByteArray()
|
||||
if (bytes != null) {
|
||||
imageBytes = bytes
|
||||
ImageLoadState.Success
|
||||
} else {
|
||||
ImageLoadState.Error
|
||||
}
|
||||
},
|
||||
onFailure = {
|
||||
ImageLoadState.Error
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
val progress by progressFlow.collectAsState()
|
||||
|
||||
val showProgressIndicator = showProgress &&
|
||||
imageLoadState == ImageLoadState.Loading &&
|
||||
progress != null
|
||||
|
||||
val painter = rememberAsyncImagePainter(
|
||||
model = ImageRequest.Builder(context)
|
||||
.data(imageBytes)
|
||||
.build()
|
||||
)
|
||||
|
||||
Box(modifier = modifier, contentAlignment = Alignment.Center) {
|
||||
if (imageBytes != null) {
|
||||
Image(
|
||||
painter = painter,
|
||||
contentDescription = contentDescription,
|
||||
contentScale = contentScale,
|
||||
modifier = Modifier.fillMaxSize()
|
||||
)
|
||||
}
|
||||
|
||||
when {
|
||||
showProgressIndicator -> {
|
||||
progress?.let { p ->
|
||||
val percent = p.total?.let { p.transferred.toFloat() / it }
|
||||
if (percent == null) {
|
||||
CircularProgressIndicator(modifier = Modifier.align(Alignment.Center))
|
||||
} else {
|
||||
CircularProgressIndicator(
|
||||
progress = percent,
|
||||
modifier = Modifier.align(Alignment.Center)
|
||||
)
|
||||
}
|
||||
} ?: CircularProgressIndicator(modifier = Modifier.align(Alignment.Center))
|
||||
}
|
||||
imageLoadState == ImageLoadState.Loading -> {
|
||||
CircularProgressIndicator(modifier = Modifier.align(Alignment.Center))
|
||||
}
|
||||
imageLoadState == ImageLoadState.Error -> {
|
||||
Icon(
|
||||
Icons.Outlined.Warning,
|
||||
contentDescription = "Error",
|
||||
modifier = Modifier.align(Alignment.Center)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2,3 +2,127 @@
|
||||
* Created by sweetbread
|
||||
* Copyright (c) 2026. All rights reserved.
|
||||
*/
|
||||
|
||||
package ru.risdeveau.pixeldragon.ui.layout
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import android.util.Log
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.clickable
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.Row
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.height
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.layout.width
|
||||
import androidx.compose.foundation.lazy.LazyColumn
|
||||
import androidx.compose.foundation.lazy.items
|
||||
import androidx.compose.foundation.lazy.rememberLazyListState
|
||||
import androidx.compose.foundation.shape.CircleShape
|
||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.collectAsState
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.draw.clip
|
||||
import androidx.compose.ui.layout.ContentScale
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.navigation.NavController
|
||||
import kotlinx.coroutines.flow.map
|
||||
import net.folivo.trixnity.client.flattenValues
|
||||
import net.folivo.trixnity.client.room
|
||||
import net.folivo.trixnity.client.store.Room
|
||||
import net.folivo.trixnity.client.store.type
|
||||
import net.folivo.trixnity.core.model.events.m.room.CreateEventContent
|
||||
import ru.risdeveau.pixeldragon.client
|
||||
import ru.risdeveau.pixeldragon.ui.item.MXCImage
|
||||
|
||||
@SuppressLint("FlowOperatorInvokedInComposition")
|
||||
@Composable
|
||||
fun RoomList(modifier: Modifier = Modifier, navController: NavController) {
|
||||
val rooms by client!!.room.getAll().flattenValues().map { it.toList() }.collectAsState(initial = emptyList())
|
||||
|
||||
val listState = rememberLazyListState()
|
||||
|
||||
// if (itemState.scrollToTop) {
|
||||
// LaunchedEffect(coroutineScope) {
|
||||
// Log.e("TAG", "TopCoinsScreen: scrollToTop" )
|
||||
// listState.scrollToItem(0)
|
||||
// }
|
||||
// }
|
||||
|
||||
// LaunchedEffect(Unit) {
|
||||
// list = withContext(Dispatchers.IO) { Room.getJoined() }
|
||||
// }
|
||||
|
||||
LazyColumn(modifier = modifier, state = listState) {
|
||||
items(rooms) { room ->
|
||||
RoomItem(room = room, navController = navController )
|
||||
}
|
||||
|
||||
item {
|
||||
if (rooms.isEmpty()) {
|
||||
Text("You have no rooms")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun RoomItem(modifier: Modifier = Modifier, room: Room, navController: NavController) {
|
||||
val name = room.name
|
||||
val isSpace = room.type == CreateEventContent.RoomType.Space
|
||||
|
||||
|
||||
Row(
|
||||
modifier
|
||||
.padding(8.dp)
|
||||
.height((52 + 8 * 2).dp)
|
||||
.fillMaxWidth()
|
||||
.background(
|
||||
color =
|
||||
if (isSpace)
|
||||
MaterialTheme.colorScheme.tertiary
|
||||
else
|
||||
MaterialTheme.colorScheme.background
|
||||
)
|
||||
.clip(RoundedCornerShape(12.dp))
|
||||
.clickable {
|
||||
if (isSpace)
|
||||
navController.navigate("space/${room.roomId}")
|
||||
else
|
||||
navController.navigate("room/${room.roomId}")
|
||||
}
|
||||
.padding(8.dp)
|
||||
) {
|
||||
Log.v("RoomItem", room.avatarUrl.toString())
|
||||
room.avatarUrl?.let { mxc ->
|
||||
MXCImage(
|
||||
mxc,
|
||||
modifier = Modifier
|
||||
.padding(end = 4.dp)
|
||||
.height(52.dp)
|
||||
.width(52.dp)
|
||||
.let {
|
||||
if (isSpace)
|
||||
it.clip(RoundedCornerShape(12.dp))
|
||||
else
|
||||
it.clip(CircleShape)
|
||||
},
|
||||
ContentScale.Crop
|
||||
)
|
||||
}
|
||||
Column {
|
||||
(name?.explicitName ?: name?.heroes?.firstNotNullOf {it.localpart})?.let {
|
||||
Text(
|
||||
it,
|
||||
maxLines = 1,
|
||||
color = MaterialTheme.colorScheme.primary,
|
||||
fontSize = MaterialTheme.typography.titleLarge.fontSize
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,9 +15,7 @@ composeBom = "2025.02.00"
|
||||
navigationCompose = "2.8.8"
|
||||
room = "2.6.1"
|
||||
splittiesFunPackAndroidBase = "3.0.0"
|
||||
trixnityMessenger = "3.8.11"
|
||||
trixnityClient = "4.15.0"
|
||||
ksp = "2.0.21-1.0.27"
|
||||
trixnityClient = "4.22.7"
|
||||
|
||||
[libraries]
|
||||
androidx-core-ktx = { group = "androidx.core", name = "core-ktx", version.ref = "coreKtx" }
|
||||
@@ -27,7 +25,6 @@ androidx-navigation-dynamic-features-fragment = { module = "androidx.navigation:
|
||||
androidx-navigation-fragment = { module = "androidx.navigation:navigation-fragment", version.ref = "navigationCompose" }
|
||||
androidx-navigation-testing = { module = "androidx.navigation:navigation-testing", version.ref = "navigationCompose" }
|
||||
androidx-navigation-ui = { module = "androidx.navigation:navigation-ui", version.ref = "navigationCompose" }
|
||||
androidx-room-compiler = { module = "androidx.room:room-compiler", version.ref = "room" }
|
||||
androidx-room-ktx = { module = "androidx.room:room-ktx", version.ref = "room" }
|
||||
androidx-room-runtime = { module = "androidx.room:room-runtime", version.ref = "room" }
|
||||
coil-compose = { module = "io.coil-kt.coil3:coil-compose", version.ref = "coil" }
|
||||
@@ -46,7 +43,6 @@ androidx-ui-tooling-preview = { group = "androidx.compose.ui", name = "ui-toolin
|
||||
androidx-ui-test-manifest = { group = "androidx.compose.ui", name = "ui-test-manifest" }
|
||||
androidx-ui-test-junit4 = { group = "androidx.compose.ui", name = "ui-test-junit4" }
|
||||
androidx-material3 = { group = "androidx.compose.material3", name = "material3" }
|
||||
kotlinx-serialization-json = { module = "org.jetbrains.kotlinx:kotlinx-serialization-json", version.ref = "kotlinxSerializationJson" }
|
||||
ktor-client-okhttp = { module = "io.ktor:ktor-client-okhttp", version.ref = "ktor" }
|
||||
ktor-client-core = { module = "io.ktor:ktor-client-core", version.ref = "ktor" }
|
||||
ktor-client-logging = { module = "io.ktor:ktor-client-logging", version.ref = "ktor" }
|
||||
@@ -54,7 +50,6 @@ splitties-base = { module = "com.louiscad.splitties:splitties-fun-pack-android-b
|
||||
trixnity-client = { module = "net.folivo:trixnity-client", version.ref = "trixnityClient" }
|
||||
trixnity-client-media-okio = { module = "net.folivo:trixnity-client-media-okio", version.ref = "trixnityClient" }
|
||||
trixnity-client-repository-room = { module = "net.folivo:trixnity-client-repository-room", version.ref = "trixnityClient" }
|
||||
trixnity-messenger = { module = "de.connect2x:trixnity-messenger", version.ref = "trixnityMessenger" }
|
||||
|
||||
[plugins]
|
||||
android-application = { id = "com.android.application", version.ref = "agp" }
|
||||
|
||||
Reference in New Issue
Block a user