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.Logger
|
||||||
import io.ktor.client.plugins.logging.Logging
|
import io.ktor.client.plugins.logging.Logging
|
||||||
import net.folivo.trixnity.client.MatrixClient
|
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 {
|
val webClient = HttpClient {
|
||||||
install(Logging) {
|
install(Logging) {
|
||||||
@@ -30,24 +27,3 @@ val webClient = HttpClient {
|
|||||||
}
|
}
|
||||||
|
|
||||||
var client: MatrixClient? = null
|
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.composable
|
||||||
import androidx.navigation.compose.rememberNavController
|
import androidx.navigation.compose.rememberNavController
|
||||||
import androidx.navigation.navArgument
|
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.MatrixClient
|
||||||
import net.folivo.trixnity.client.fromStore
|
import net.folivo.trixnity.client.fromStore
|
||||||
import ru.risdeveau.pixeldragon.client
|
import ru.risdeveau.pixeldragon.client
|
||||||
|
import ru.risdeveau.pixeldragon.ui.layout.RoomList
|
||||||
import ru.risdeveau.pixeldragon.ui.theme.PixelDragonTheme
|
import ru.risdeveau.pixeldragon.ui.theme.PixelDragonTheme
|
||||||
import ru.risdeveau.pixeldragon.util.getMediaStore
|
import ru.risdeveau.pixeldragon.util.getMediaStore
|
||||||
import ru.risdeveau.pixeldragon.util.getRoomStore
|
import ru.risdeveau.pixeldragon.util.getRoomStore
|
||||||
@@ -70,9 +74,10 @@ class MainActivity : ComponentActivity() {
|
|||||||
) { innerPadding ->
|
) { innerPadding ->
|
||||||
val navController = rememberNavController()
|
val navController = rememberNavController()
|
||||||
|
|
||||||
NavHost(navController = navController, startDestination = "none") {
|
NavHost(navController = navController, startDestination = "rooms") {
|
||||||
composable("none") { }
|
composable("rooms") {
|
||||||
composable("rooms") { /*RoomList(Modifier.padding(innerPadding), navController)*/ }
|
RoomList(Modifier.padding(innerPadding), navController)
|
||||||
|
}
|
||||||
composable(
|
composable(
|
||||||
"room/{rid}",
|
"room/{rid}",
|
||||||
arguments = listOf(navArgument("rid") { type = NavType.StringType })
|
arguments = listOf(navArgument("rid") { type = NavType.StringType })
|
||||||
@@ -109,9 +114,17 @@ class MainActivity : ComponentActivity() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Log.i("MainActivity", "Log in as ${client!!.userId}")
|
Log.i("MainActivity", "Log in as ${client!!.userId}")
|
||||||
|
client!!.startSync()
|
||||||
isClientReady = true
|
isClientReady = true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun onDestroy() {
|
||||||
|
super.onDestroy()
|
||||||
|
CoroutineScope(Dispatchers.Main).launch {
|
||||||
|
client?.stopSync()
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,3 +2,128 @@
|
|||||||
* Created by sweetbread
|
* Created by sweetbread
|
||||||
* Copyright (c) 2026. All rights reserved.
|
* 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
|
* Created by sweetbread
|
||||||
* Copyright (c) 2026. All rights reserved.
|
* 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"
|
navigationCompose = "2.8.8"
|
||||||
room = "2.6.1"
|
room = "2.6.1"
|
||||||
splittiesFunPackAndroidBase = "3.0.0"
|
splittiesFunPackAndroidBase = "3.0.0"
|
||||||
trixnityMessenger = "3.8.11"
|
trixnityClient = "4.22.7"
|
||||||
trixnityClient = "4.15.0"
|
|
||||||
ksp = "2.0.21-1.0.27"
|
|
||||||
|
|
||||||
[libraries]
|
[libraries]
|
||||||
androidx-core-ktx = { group = "androidx.core", name = "core-ktx", version.ref = "coreKtx" }
|
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-fragment = { module = "androidx.navigation:navigation-fragment", version.ref = "navigationCompose" }
|
||||||
androidx-navigation-testing = { module = "androidx.navigation:navigation-testing", 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-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-ktx = { module = "androidx.room:room-ktx", version.ref = "room" }
|
||||||
androidx-room-runtime = { module = "androidx.room:room-runtime", 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" }
|
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-manifest = { group = "androidx.compose.ui", name = "ui-test-manifest" }
|
||||||
androidx-ui-test-junit4 = { group = "androidx.compose.ui", name = "ui-test-junit4" }
|
androidx-ui-test-junit4 = { group = "androidx.compose.ui", name = "ui-test-junit4" }
|
||||||
androidx-material3 = { group = "androidx.compose.material3", name = "material3" }
|
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-okhttp = { module = "io.ktor:ktor-client-okhttp", version.ref = "ktor" }
|
||||||
ktor-client-core = { module = "io.ktor:ktor-client-core", 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" }
|
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 = { module = "net.folivo:trixnity-client", version.ref = "trixnityClient" }
|
||||||
trixnity-client-media-okio = { module = "net.folivo:trixnity-client-media-okio", 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-client-repository-room = { module = "net.folivo:trixnity-client-repository-room", version.ref = "trixnityClient" }
|
||||||
trixnity-messenger = { module = "de.connect2x:trixnity-messenger", version.ref = "trixnityMessenger" }
|
|
||||||
|
|
||||||
[plugins]
|
[plugins]
|
||||||
android-application = { id = "com.android.application", version.ref = "agp" }
|
android-application = { id = "com.android.application", version.ref = "agp" }
|
||||||
|
|||||||
Reference in New Issue
Block a user