feat: Messages
This commit is contained in:
parent
bd87ca2729
commit
23780489f6
@ -1,7 +1,7 @@
|
|||||||
/*
|
/*
|
||||||
* Created by sweetbread on 22.02.2025, 15:45
|
* Created by sweetbread
|
||||||
* Copyright (c) 2025. All rights reserved.
|
* Copyright (c) 2025. All rights reserved.
|
||||||
* Last modified 22.02.2025, 14:56
|
* Last modified 03.03.2025, 16:46
|
||||||
*/
|
*/
|
||||||
|
|
||||||
plugins {
|
plugins {
|
||||||
@ -78,6 +78,13 @@ dependencies {
|
|||||||
implementation(libs.androidx.room.ktx)
|
implementation(libs.androidx.room.ktx)
|
||||||
ksp(libs.androidx.room.compiler)
|
ksp(libs.androidx.room.compiler)
|
||||||
|
|
||||||
|
// Navigation Compose
|
||||||
|
implementation(libs.androidx.navigation.compose)
|
||||||
|
implementation(libs.androidx.navigation.fragment)
|
||||||
|
implementation(libs.androidx.navigation.ui)
|
||||||
|
implementation(libs.androidx.navigation.dynamic.features.fragment)
|
||||||
|
androidTestImplementation(libs.androidx.navigation.testing)
|
||||||
|
|
||||||
// Others
|
// Others
|
||||||
implementation(libs.splitties.base) // Syntax sugar
|
implementation(libs.splitties.base) // Syntax sugar
|
||||||
}
|
}
|
56
app/src/main/java/ru/risdeveau/pixeldragon/api/Event.kt
Executable file
56
app/src/main/java/ru/risdeveau/pixeldragon/api/Event.kt
Executable file
@ -0,0 +1,56 @@
|
|||||||
|
/*
|
||||||
|
* Created by sweetbread
|
||||||
|
* Copyright (c) 2025. All rights reserved.
|
||||||
|
* Last modified 03.03.2025, 20:21
|
||||||
|
*/
|
||||||
|
|
||||||
|
package ru.risdeveau.pixeldragon.api
|
||||||
|
|
||||||
|
import io.ktor.client.request.bearerAuth
|
||||||
|
import io.ktor.client.request.get
|
||||||
|
import io.ktor.client.request.parameter
|
||||||
|
import io.ktor.client.statement.bodyAsText
|
||||||
|
import org.json.JSONObject
|
||||||
|
import ru.risdeveau.pixeldragon.baseUrl
|
||||||
|
import ru.risdeveau.pixeldragon.client
|
||||||
|
import ru.risdeveau.pixeldragon.token
|
||||||
|
|
||||||
|
class Event (
|
||||||
|
val id: String,
|
||||||
|
val rid: String,
|
||||||
|
val sender: String,
|
||||||
|
val type: String,
|
||||||
|
val content: JSONObject
|
||||||
|
) {
|
||||||
|
constructor(json: JSONObject) : this(
|
||||||
|
json.getString("event_id"),
|
||||||
|
json.getString("room_id"),
|
||||||
|
json.getString("sender"),
|
||||||
|
json.getString("type"),
|
||||||
|
json.getJSONObject("content")
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
data class EventsAround (
|
||||||
|
val base: Event,
|
||||||
|
val before: List<Event>,
|
||||||
|
val after: List<Event>
|
||||||
|
)
|
||||||
|
|
||||||
|
suspend fun getEventsAround(room: String, event: String): EventsAround {
|
||||||
|
val r = client.get("$baseUrl/rooms/$room/context/$event") {
|
||||||
|
bearerAuth(token)
|
||||||
|
parameter("limit", "50")
|
||||||
|
}
|
||||||
|
val json = JSONObject(r.bodyAsText())
|
||||||
|
|
||||||
|
return EventsAround(
|
||||||
|
Event(json.getJSONObject("event")),
|
||||||
|
if (json.has("events_before")) json.getJSONArray("events_before").let {
|
||||||
|
List<Event>(it.length()) { i -> Event(it.getJSONObject(i))}.reversed()
|
||||||
|
} else listOf(),
|
||||||
|
if (json.has("events_after")) json.getJSONArray("events_after").let {
|
||||||
|
List<Event>(it.length()) { i -> Event(it.getJSONObject(i))}
|
||||||
|
} else listOf()
|
||||||
|
)
|
||||||
|
}
|
@ -1,7 +1,7 @@
|
|||||||
/*
|
/*
|
||||||
* Created by sweetbread
|
* Created by sweetbread
|
||||||
* Copyright (c) 2025. All rights reserved.
|
* Copyright (c) 2025. All rights reserved.
|
||||||
* Last modified 22.02.2025, 19:52
|
* Last modified 03.03.2025, 18:28
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package ru.risdeveau.pixeldragon.api
|
package ru.risdeveau.pixeldragon.api
|
||||||
@ -55,3 +55,9 @@ private suspend fun getState(rid: String, state: String, key: String): String? {
|
|||||||
if (!json.has(key)) return null
|
if (!json.has(key)) return null
|
||||||
return json.getString(key)
|
return json.getString(key)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
suspend fun getAccountData(user: String, room: String, state: String): JSONObject? {
|
||||||
|
val r = client.get("$baseUrl/user/$user/rooms/$room/account_data/$state") { bearerAuth(token) }
|
||||||
|
if (r.status != HttpStatusCode.OK) return null
|
||||||
|
return JSONObject(r.bodyAsText())
|
||||||
|
}
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
/*
|
/*
|
||||||
* Created by sweetbread
|
* Created by sweetbread
|
||||||
* Copyright (c) 2025. All rights reserved.
|
* Copyright (c) 2025. All rights reserved.
|
||||||
* Last modified 03.03.2025, 15:53
|
* Last modified 03.03.2025, 20:22
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package ru.risdeveau.pixeldragon.ui.activity
|
package ru.risdeveau.pixeldragon.ui.activity
|
||||||
@ -10,52 +10,23 @@ import android.os.Bundle
|
|||||||
import androidx.activity.ComponentActivity
|
import androidx.activity.ComponentActivity
|
||||||
import androidx.activity.compose.setContent
|
import androidx.activity.compose.setContent
|
||||||
import androidx.activity.enableEdgeToEdge
|
import androidx.activity.enableEdgeToEdge
|
||||||
import androidx.compose.foundation.background
|
|
||||||
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.fillMaxWidth
|
|
||||||
import androidx.compose.foundation.layout.height
|
|
||||||
import androidx.compose.foundation.layout.padding
|
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.CircularProgressIndicator
|
|
||||||
import androidx.compose.material3.ExperimentalMaterial3Api
|
import androidx.compose.material3.ExperimentalMaterial3Api
|
||||||
import androidx.compose.material3.LinearProgressIndicator
|
|
||||||
import androidx.compose.material3.MaterialTheme
|
import androidx.compose.material3.MaterialTheme
|
||||||
import androidx.compose.material3.Scaffold
|
import androidx.compose.material3.Scaffold
|
||||||
import androidx.compose.material3.Text
|
import androidx.compose.material3.Text
|
||||||
import androidx.compose.material3.TopAppBar
|
import androidx.compose.material3.TopAppBar
|
||||||
import androidx.compose.material3.TopAppBarDefaults.topAppBarColors
|
import androidx.compose.material3.TopAppBarDefaults.topAppBarColors
|
||||||
import androidx.compose.runtime.Composable
|
|
||||||
import androidx.compose.runtime.LaunchedEffect
|
|
||||||
import androidx.compose.runtime.getValue
|
|
||||||
import androidx.compose.runtime.mutableStateOf
|
|
||||||
import androidx.compose.runtime.remember
|
|
||||||
import androidx.compose.runtime.rememberCoroutineScope
|
|
||||||
import androidx.compose.runtime.setValue
|
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
import androidx.compose.ui.draw.clip
|
import androidx.navigation.NavType
|
||||||
import androidx.compose.ui.layout.ContentScale
|
import androidx.navigation.compose.NavHost
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.navigation.compose.composable
|
||||||
import coil3.compose.SubcomposeAsyncImage
|
import androidx.navigation.compose.rememberNavController
|
||||||
import coil3.network.NetworkHeaders
|
import androidx.navigation.navArgument
|
||||||
import coil3.network.httpHeaders
|
import ru.risdeveau.pixeldragon.ui.layout.Room
|
||||||
import coil3.request.ImageRequest
|
import ru.risdeveau.pixeldragon.ui.layout.RoomList
|
||||||
import kotlinx.coroutines.Dispatchers
|
|
||||||
import kotlinx.coroutines.launch
|
|
||||||
import kotlinx.coroutines.withContext
|
|
||||||
import ru.risdeveau.pixeldragon.api.getRoom
|
|
||||||
import ru.risdeveau.pixeldragon.api.getRooms
|
|
||||||
import ru.risdeveau.pixeldragon.api.mxcToUrl
|
|
||||||
import ru.risdeveau.pixeldragon.db.Room
|
|
||||||
import ru.risdeveau.pixeldragon.token
|
|
||||||
import ru.risdeveau.pixeldragon.ui.theme.PixelDragonTheme
|
import ru.risdeveau.pixeldragon.ui.theme.PixelDragonTheme
|
||||||
import splitties.init.appCtx
|
|
||||||
|
|
||||||
class MainActivity : ComponentActivity() {
|
class MainActivity : ComponentActivity() {
|
||||||
@OptIn(ExperimentalMaterial3Api::class)
|
@OptIn(ExperimentalMaterial3Api::class)
|
||||||
@ -79,123 +50,24 @@ class MainActivity : ComponentActivity() {
|
|||||||
)
|
)
|
||||||
},
|
},
|
||||||
) { innerPadding ->
|
) { innerPadding ->
|
||||||
RoomList(Modifier.padding(innerPadding))
|
val navController = rememberNavController()
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Composable
|
NavHost(navController = navController, startDestination = "rooms") {
|
||||||
fun RoomList(modifier: Modifier = Modifier) {
|
composable("rooms") { RoomList(Modifier.padding(innerPadding), navController) }
|
||||||
var list by remember { mutableStateOf(listOf<String>()) }
|
composable(
|
||||||
val coroutineScope = rememberCoroutineScope()
|
"room/{rid}",
|
||||||
val listState = rememberLazyListState()
|
arguments = listOf(navArgument("rid") { type = NavType.StringType })
|
||||||
|
) { navBackStackEntry ->
|
||||||
// if (itemState.scrollToTop) {
|
Room(Modifier.padding(innerPadding).fillMaxSize(), navBackStackEntry.arguments!!.getString("rid")!!)
|
||||||
// LaunchedEffect(coroutineScope) {
|
|
||||||
// Log.e("TAG", "TopCoinsScreen: scrollToTop" )
|
|
||||||
// listState.scrollToItem(0)
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
LaunchedEffect(true) {
|
|
||||||
coroutineScope.launch {
|
|
||||||
withContext(Dispatchers.IO) {
|
|
||||||
list = getRooms()
|
|
||||||
}
|
}
|
||||||
}
|
composable(
|
||||||
}
|
"space/{rid}",
|
||||||
|
arguments = listOf(navArgument("rid") { type = NavType.StringType })
|
||||||
LazyColumn(modifier = modifier, state = listState) {
|
) { navBackStackEntry ->
|
||||||
items(list) { rid ->
|
Text(modifier = Modifier.padding(innerPadding), text = "Not implemented") }
|
||||||
RoomItem(rid = rid)
|
|
||||||
}
|
|
||||||
|
|
||||||
item {
|
|
||||||
if (list.isEmpty()) {
|
|
||||||
Text("You have no rooms")
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Composable
|
|
||||||
fun RoomItem(modifier: Modifier = Modifier, rid: String) {
|
|
||||||
var room by remember { mutableStateOf<Room?>(null) }
|
|
||||||
val scope = rememberCoroutineScope()
|
|
||||||
|
|
||||||
LaunchedEffect(true) {
|
|
||||||
scope.launch {
|
|
||||||
withContext(Dispatchers.IO) {
|
|
||||||
room = getRoom(rid)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
if (room != null) {
|
|
||||||
Row(
|
|
||||||
modifier
|
|
||||||
.padding(8.dp)
|
|
||||||
.height((52+8*2).dp)
|
|
||||||
.fillMaxWidth()
|
|
||||||
.background(MaterialTheme.colorScheme.background, RoundedCornerShape(16.dp))
|
|
||||||
.padding(8.dp)
|
|
||||||
) {
|
|
||||||
SubcomposeAsyncImage(
|
|
||||||
modifier = Modifier
|
|
||||||
.padding(end = 4.dp)
|
|
||||||
.height(52.dp)
|
|
||||||
.width(52.dp)
|
|
||||||
.let {
|
|
||||||
if (room!!.type == "m.space")
|
|
||||||
it.clip(RoundedCornerShape(12.dp))
|
|
||||||
else
|
|
||||||
it.clip(CircleShape)
|
|
||||||
},
|
|
||||||
model = ImageRequest.Builder(appCtx)
|
|
||||||
.data(mxcToUrl(room!!.avatarUrl ?: ""))
|
|
||||||
.httpHeaders(
|
|
||||||
NetworkHeaders.Builder()
|
|
||||||
.set("Authorization", "Bearer $token")
|
|
||||||
.set("Cache-Control", "max-age=86400")
|
|
||||||
.build()
|
|
||||||
)
|
|
||||||
.build(),
|
|
||||||
contentDescription = room!!.roomId,
|
|
||||||
contentScale = ContentScale.Crop,
|
|
||||||
loading = {
|
|
||||||
CircularProgressIndicator()
|
|
||||||
}
|
|
||||||
)
|
|
||||||
Column {
|
|
||||||
Text(
|
|
||||||
room!!.name ?: "Unnamed",
|
|
||||||
maxLines = 1,
|
|
||||||
color = MaterialTheme.colorScheme.primary,
|
|
||||||
fontSize = MaterialTheme.typography.titleLarge.fontSize
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
Row(
|
|
||||||
modifier
|
|
||||||
.padding(8.dp)
|
|
||||||
.height(80.dp)
|
|
||||||
.fillMaxWidth()
|
|
||||||
.background(MaterialTheme.colorScheme.background, RoundedCornerShape(16.dp))
|
|
||||||
.padding(8.dp)
|
|
||||||
) {
|
|
||||||
LinearProgressIndicator(Modifier.fillMaxWidth())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//@Preview(showBackground = true)
|
|
||||||
//@Composable
|
|
||||||
//fun GreetingPreview() {
|
|
||||||
// PixelDragonTheme {
|
|
||||||
// RoomItem()
|
|
||||||
// }
|
|
||||||
//}
|
|
||||||
|
|
||||||
|
90
app/src/main/java/ru/risdeveau/pixeldragon/ui/layout/Room.kt
Executable file
90
app/src/main/java/ru/risdeveau/pixeldragon/ui/layout/Room.kt
Executable file
@ -0,0 +1,90 @@
|
|||||||
|
/*
|
||||||
|
* Created by sweetbread
|
||||||
|
* Copyright (c) 2025. All rights reserved.
|
||||||
|
* Last modified 03.03.2025, 21:30
|
||||||
|
*/
|
||||||
|
|
||||||
|
package ru.risdeveau.pixeldragon.ui.layout
|
||||||
|
|
||||||
|
import androidx.compose.foundation.background
|
||||||
|
import androidx.compose.foundation.layout.Box
|
||||||
|
import androidx.compose.foundation.layout.Column
|
||||||
|
import androidx.compose.foundation.layout.fillMaxWidth
|
||||||
|
import androidx.compose.foundation.layout.padding
|
||||||
|
import androidx.compose.foundation.lazy.LazyColumn
|
||||||
|
import androidx.compose.foundation.lazy.items
|
||||||
|
import androidx.compose.foundation.lazy.rememberLazyListState
|
||||||
|
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.LaunchedEffect
|
||||||
|
import androidx.compose.runtime.getValue
|
||||||
|
import androidx.compose.runtime.mutableStateOf
|
||||||
|
import androidx.compose.runtime.remember
|
||||||
|
import androidx.compose.runtime.rememberCoroutineScope
|
||||||
|
import androidx.compose.runtime.setValue
|
||||||
|
import androidx.compose.ui.Alignment
|
||||||
|
import androidx.compose.ui.Modifier
|
||||||
|
import androidx.compose.ui.text.font.FontWeight
|
||||||
|
import androidx.compose.ui.unit.dp
|
||||||
|
import kotlinx.coroutines.Dispatchers
|
||||||
|
import kotlinx.coroutines.launch
|
||||||
|
import kotlinx.coroutines.withContext
|
||||||
|
import ru.risdeveau.pixeldragon.api.Event
|
||||||
|
import ru.risdeveau.pixeldragon.api.getAccountData
|
||||||
|
import ru.risdeveau.pixeldragon.api.getEventsAround
|
||||||
|
import ru.risdeveau.pixeldragon.api.getMe
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun Room(modifier: Modifier = Modifier, rid: String) {
|
||||||
|
var eventsId by remember { mutableStateOf(listOf<Event>()) }
|
||||||
|
val coroutineScope = rememberCoroutineScope()
|
||||||
|
val listState = rememberLazyListState()
|
||||||
|
|
||||||
|
LaunchedEffect(true) {
|
||||||
|
coroutineScope.launch {
|
||||||
|
withContext(Dispatchers.IO) {
|
||||||
|
val readMark = getAccountData(getMe()!!.userId, rid, "m.fully_read")
|
||||||
|
val eventsAround = getEventsAround(rid, readMark!!.getString("event_id")) //FIXME: Null check
|
||||||
|
eventsId = eventsAround.let {
|
||||||
|
it.before + listOf(it.base) + it.after
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
LazyColumn(modifier = modifier, state = listState, reverseLayout = true) {
|
||||||
|
items(eventsId.reversed()) { event ->
|
||||||
|
EventItem(event)
|
||||||
|
}
|
||||||
|
|
||||||
|
item {
|
||||||
|
if (eventsId.isEmpty()) {
|
||||||
|
Text("Empty room")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun EventItem(event: Event) {
|
||||||
|
Box (Modifier.fillMaxWidth()) {
|
||||||
|
when (event.type) {
|
||||||
|
"m.room.message" -> Column(
|
||||||
|
Modifier
|
||||||
|
.align(Alignment.CenterStart)
|
||||||
|
.padding(4.dp)
|
||||||
|
.background(
|
||||||
|
color = MaterialTheme.colorScheme.surfaceContainer,
|
||||||
|
shape = RoundedCornerShape(16.dp)
|
||||||
|
)
|
||||||
|
.padding(4.dp)
|
||||||
|
) {
|
||||||
|
Text(event.sender, maxLines = 1, fontWeight = FontWeight.Bold)
|
||||||
|
Text(event.content.getString("body"))
|
||||||
|
}
|
||||||
|
else -> Text(event.type, Modifier.padding(4.dp).background(MaterialTheme.colorScheme.errorContainer).padding(4.dp))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
161
app/src/main/java/ru/risdeveau/pixeldragon/ui/layout/Rooms.kt
Executable file
161
app/src/main/java/ru/risdeveau/pixeldragon/ui/layout/Rooms.kt
Executable file
@ -0,0 +1,161 @@
|
|||||||
|
/*
|
||||||
|
* Created by sweetbread
|
||||||
|
* Copyright (c) 2025. All rights reserved.
|
||||||
|
* Last modified 03.03.2025, 20:22
|
||||||
|
*/
|
||||||
|
|
||||||
|
package ru.risdeveau.pixeldragon.ui.layout
|
||||||
|
|
||||||
|
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.CircularProgressIndicator
|
||||||
|
import androidx.compose.material3.LinearProgressIndicator
|
||||||
|
import androidx.compose.material3.MaterialTheme
|
||||||
|
import androidx.compose.material3.Text
|
||||||
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.runtime.LaunchedEffect
|
||||||
|
import androidx.compose.runtime.getValue
|
||||||
|
import androidx.compose.runtime.mutableStateOf
|
||||||
|
import androidx.compose.runtime.remember
|
||||||
|
import androidx.compose.runtime.rememberCoroutineScope
|
||||||
|
import androidx.compose.runtime.setValue
|
||||||
|
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 coil3.compose.SubcomposeAsyncImage
|
||||||
|
import coil3.network.NetworkHeaders
|
||||||
|
import coil3.network.httpHeaders
|
||||||
|
import coil3.request.ImageRequest
|
||||||
|
import kotlinx.coroutines.Dispatchers
|
||||||
|
import kotlinx.coroutines.launch
|
||||||
|
import kotlinx.coroutines.withContext
|
||||||
|
import ru.risdeveau.pixeldragon.api.getRoom
|
||||||
|
import ru.risdeveau.pixeldragon.api.getRooms
|
||||||
|
import ru.risdeveau.pixeldragon.api.mxcToUrl
|
||||||
|
import ru.risdeveau.pixeldragon.db.Room
|
||||||
|
import ru.risdeveau.pixeldragon.token
|
||||||
|
import splitties.init.appCtx
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun RoomList(modifier: Modifier = Modifier, navController: NavController) {
|
||||||
|
var list by remember { mutableStateOf(listOf<String>()) }
|
||||||
|
val coroutineScope = rememberCoroutineScope()
|
||||||
|
val listState = rememberLazyListState()
|
||||||
|
|
||||||
|
// if (itemState.scrollToTop) {
|
||||||
|
// LaunchedEffect(coroutineScope) {
|
||||||
|
// Log.e("TAG", "TopCoinsScreen: scrollToTop" )
|
||||||
|
// listState.scrollToItem(0)
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
LaunchedEffect(true) {
|
||||||
|
coroutineScope.launch {
|
||||||
|
withContext(Dispatchers.IO) {
|
||||||
|
list = getRooms()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
LazyColumn(modifier = modifier, state = listState) {
|
||||||
|
items(list) { rid ->
|
||||||
|
RoomItem(rid = rid, navController = navController )
|
||||||
|
}
|
||||||
|
|
||||||
|
item {
|
||||||
|
if (list.isEmpty()) {
|
||||||
|
Text("You have no rooms")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun RoomItem(modifier: Modifier = Modifier, rid: String, navController: NavController) {
|
||||||
|
var room by remember { mutableStateOf<Room?>(null) }
|
||||||
|
val scope = rememberCoroutineScope()
|
||||||
|
|
||||||
|
LaunchedEffect(true) {
|
||||||
|
scope.launch {
|
||||||
|
withContext(Dispatchers.IO) {
|
||||||
|
room = getRoom(rid)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (room != null) {
|
||||||
|
Row(
|
||||||
|
modifier
|
||||||
|
.padding(8.dp)
|
||||||
|
.height((52 + 8 * 2).dp)
|
||||||
|
.fillMaxWidth()
|
||||||
|
.background(MaterialTheme.colorScheme.background, RoundedCornerShape(16.dp))
|
||||||
|
.padding(8.dp)
|
||||||
|
.clickable {
|
||||||
|
if (room!!.type == "m.space")
|
||||||
|
navController.navigate("space/$rid")
|
||||||
|
else
|
||||||
|
navController.navigate("room/$rid")
|
||||||
|
}
|
||||||
|
) {
|
||||||
|
SubcomposeAsyncImage(
|
||||||
|
modifier = Modifier
|
||||||
|
.padding(end = 4.dp)
|
||||||
|
.height(52.dp)
|
||||||
|
.width(52.dp)
|
||||||
|
.let {
|
||||||
|
if (room!!.type == "m.space")
|
||||||
|
it.clip(RoundedCornerShape(12.dp))
|
||||||
|
else
|
||||||
|
it.clip(CircleShape)
|
||||||
|
},
|
||||||
|
model = ImageRequest.Builder(appCtx)
|
||||||
|
.data(mxcToUrl(room!!.avatarUrl ?: ""))
|
||||||
|
.httpHeaders(
|
||||||
|
NetworkHeaders.Builder()
|
||||||
|
.set("Authorization", "Bearer $token")
|
||||||
|
.set("Cache-Control", "max-age=86400")
|
||||||
|
.build()
|
||||||
|
)
|
||||||
|
.build(),
|
||||||
|
contentDescription = room!!.roomId,
|
||||||
|
contentScale = ContentScale.Crop,
|
||||||
|
loading = {
|
||||||
|
CircularProgressIndicator()
|
||||||
|
}
|
||||||
|
)
|
||||||
|
Column {
|
||||||
|
Text(
|
||||||
|
room!!.name ?: "Unnamed",
|
||||||
|
maxLines = 1,
|
||||||
|
color = MaterialTheme.colorScheme.primary,
|
||||||
|
fontSize = MaterialTheme.typography.titleLarge.fontSize
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Row(
|
||||||
|
modifier
|
||||||
|
.padding(8.dp)
|
||||||
|
.height(80.dp)
|
||||||
|
.fillMaxWidth()
|
||||||
|
.background(MaterialTheme.colorScheme.background, RoundedCornerShape(16.dp))
|
||||||
|
.padding(8.dp)
|
||||||
|
) {
|
||||||
|
LinearProgressIndicator(Modifier.fillMaxWidth())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -6,16 +6,23 @@ coreKtx = "1.15.0"
|
|||||||
junit = "4.13.2"
|
junit = "4.13.2"
|
||||||
junitVersion = "1.2.1"
|
junitVersion = "1.2.1"
|
||||||
espressoCore = "3.6.1"
|
espressoCore = "3.6.1"
|
||||||
|
kotlinxSerializationJson = "1.7.3"
|
||||||
ktor = "3.1.0"
|
ktor = "3.1.0"
|
||||||
lifecycleRuntimeKtx = "2.8.7"
|
lifecycleRuntimeKtx = "2.8.7"
|
||||||
activityCompose = "1.10.0"
|
activityCompose = "1.10.0"
|
||||||
composeBom = "2025.02.00"
|
composeBom = "2025.02.00"
|
||||||
|
navigationCompose = "2.8.8"
|
||||||
room = "2.6.1"
|
room = "2.6.1"
|
||||||
splittiesFunPackAndroidBase = "3.0.0"
|
splittiesFunPackAndroidBase = "3.0.0"
|
||||||
|
|
||||||
[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" }
|
||||||
androidx-lifecycle-viewmodel-ktx = { module = "androidx.lifecycle:lifecycle-viewmodel-ktx", version.ref = "room" }
|
androidx-lifecycle-viewmodel-ktx = { module = "androidx.lifecycle:lifecycle-viewmodel-ktx", version.ref = "room" }
|
||||||
|
androidx-navigation-compose = { module = "androidx.navigation:navigation-compose", version.ref = "navigationCompose" }
|
||||||
|
androidx-navigation-dynamic-features-fragment = { module = "androidx.navigation:navigation-dynamic-features-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-ui = { module = "androidx.navigation:navigation-ui", version.ref = "navigationCompose" }
|
||||||
androidx-room-compiler = { module = "androidx.room:room-compiler", version.ref = "room" }
|
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" }
|
||||||
@ -34,6 +41,7 @@ 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" }
|
||||||
|
Loading…
x
Reference in New Issue
Block a user