Compare commits

..

No commits in common. "e70049f1f5feafd4389a93699df6ca0b9accc1b5" and "dc588a045d1076d82fc5de3cd522cf7f50749c24" have entirely different histories.

15 changed files with 82 additions and 408 deletions

View File

@ -1,3 +1,7 @@
<component name="CopyrightManager"> <component name="CopyrightManager">
<settings default="My" /> <settings default="My">
<module2copyright>
<element module="All" copyright="My" />
</module2copyright>
</settings>
</component> </component>

View File

@ -4,14 +4,6 @@
<selectionStates> <selectionStates>
<SelectionState runConfigName="app"> <SelectionState runConfigName="app">
<option name="selectionMode" value="DROPDOWN" /> <option name="selectionMode" value="DROPDOWN" />
<DropdownSelection timestamp="2025-02-22T11:46:39.159466074Z">
<Target type="DEFAULT_BOOT">
<handle>
<DeviceId pluginId="PhysicalDevice" identifier="serial=22163a3c" />
</handle>
</Target>
</DropdownSelection>
<DialogSelection />
</SelectionState> </SelectionState>
</selectionStates> </selectionStates>
</component> </component>

2
.idea/kotlinc.xml generated
View File

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<project version="4"> <project version="4">
<component name="KotlinJpsPluginSettings"> <component name="KotlinJpsPluginSettings">
<option name="version" value="2.0.21" /> <option name="version" value="2.0.0" />
</component> </component>
</project> </project>

View File

@ -1,14 +1,13 @@
/* /*
* Created by sweetbread on 22.02.2025, 15:45 * Created by sweetbread on 21.02.2025, 12:01
* Copyright (c) 2025. All rights reserved. * Copyright (c) 2025. All rights reserved.
* Last modified 22.02.2025, 14:56 * Last modified 21.02.2025, 12:01
*/ */
plugins { plugins {
alias(libs.plugins.android.application) alias(libs.plugins.android.application)
alias(libs.plugins.kotlin.android) alias(libs.plugins.kotlin.android)
alias(libs.plugins.kotlin.compose) alias(libs.plugins.kotlin.compose)
id("com.google.devtools.ksp")
} }
android { android {
@ -35,11 +34,11 @@ android {
} }
} }
compileOptions { compileOptions {
sourceCompatibility = JavaVersion.VERSION_17 sourceCompatibility = JavaVersion.VERSION_1_8
targetCompatibility = JavaVersion.VERSION_17 targetCompatibility = JavaVersion.VERSION_1_8
} }
kotlinOptions { kotlinOptions {
jvmTarget = "17" jvmTarget = "1.8"
} }
buildFeatures { buildFeatures {
compose = true compose = true
@ -65,19 +64,12 @@ dependencies {
// Ktor - web client // Ktor - web client
implementation(libs.ktor.client.core) implementation(libs.ktor.client.core)
implementation(libs.ktor.client.okhttp) implementation(libs.ktor.client.cio)
implementation(libs.ktor.client.logging)
// Coil - image loader // Coil - image loader
implementation(libs.coil.compose) implementation(libs.coil.compose)
implementation(libs.coil.network.okhttp) implementation(libs.coil.network.okhttp)
// Room - database
implementation(libs.androidx.room.runtime)
implementation(libs.androidx.lifecycle.viewmodel.ktx)
implementation(libs.androidx.room.ktx)
ksp(libs.androidx.room.compiler)
// Others // Others
implementation(libs.splitties.base) // Syntax sugar implementation(libs.splitties.base) // Syntax sugar
} }

View File

@ -1,8 +1,8 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<!-- <!--
~ Created by sweetbread on 22.02.2025, 15:45 ~ Created by sweetbread on 21.02.2025, 12:08
~ Copyright (c) 2025. All rights reserved. ~ Copyright (c) 2025. All rights reserved.
~ Last modified 22.02.2025, 14:00 ~ Last modified 21.02.2025, 12:07
--> -->
<manifest xmlns:android="http://schemas.android.com/apk/res/android" <manifest xmlns:android="http://schemas.android.com/apk/res/android"
@ -22,7 +22,13 @@
tools:targetApi="31"> tools:targetApi="31">
<activity <activity
android:name=".ui.activity.Login" android:name=".ui.activity.Login"
android:exported="false"
android:label="@string/title_activity_login"
android:theme="@style/Theme.PixelDragon" />
<activity
android:name=".ui.activity.MainActivity"
android:exported="true" android:exported="true"
android:label="@string/app_name"
android:theme="@style/Theme.PixelDragon"> android:theme="@style/Theme.PixelDragon">
<intent-filter> <intent-filter>
<action android:name="android.intent.action.MAIN" /> <action android:name="android.intent.action.MAIN" />
@ -30,11 +36,6 @@
<category android:name="android.intent.category.LAUNCHER" /> <category android:name="android.intent.category.LAUNCHER" />
</intent-filter> </intent-filter>
</activity> </activity>
<activity
android:name=".ui.activity.MainActivity"
android:exported="false"
android:theme="@style/Theme.PixelDragon" />
</application> </application>
</manifest> </manifest>

View File

@ -1,55 +1,43 @@
/* /*
* Created by sweetbread on 22.02.2025, 15:45 * Created by sweetbread on 21.02.2025, 12:01
* Copyright (c) 2025. All rights reserved. * Copyright (c) 2025. All rights reserved.
* Last modified 22.02.2025, 15:45 * Last modified 21.02.2025, 12:01
*/ */
package ru.risdeveau.pixeldragon package ru.risdeveau.pixeldragon
import android.content.Context import android.content.Context
import android.util.Log
import androidx.room.Room
import io.ktor.client.HttpClient import io.ktor.client.HttpClient
import io.ktor.client.engine.cio.CIO
import io.ktor.client.engine.cio.endpoint
import io.ktor.client.plugins.cache.HttpCache import io.ktor.client.plugins.cache.HttpCache
import io.ktor.client.plugins.logging.LogLevel
import io.ktor.client.plugins.logging.Logger
import io.ktor.client.plugins.logging.Logging
import ru.risdeveau.pixeldragon.api.getMe import ru.risdeveau.pixeldragon.api.getMe
import ru.risdeveau.pixeldragon.db.AppDatabase
import splitties.init.appCtx import splitties.init.appCtx
val client = HttpClient { val client = HttpClient(CIO) {
install(Logging) { engine {
logger = object : Logger { endpoint {
override fun log(message: String) { maxConnectionsPerRoute = 100
Log.i("Ktor", message) pipelineMaxSize = 20
} keepAliveTime = 30000
connectTimeout = 15000
connectAttempts = 5
} }
level = LogLevel.ALL
} }
install(HttpCache) install(HttpCache)
} }
val accountData = appCtx.getSharedPreferences("settings", Context.MODE_PRIVATE) val accountData = appCtx.getSharedPreferences("settings", Context.MODE_PRIVATE)
lateinit var homeserver: String lateinit var urlBase: String
lateinit var baseUrl: String
lateinit var token: String lateinit var token: String
suspend fun initCheck(): Boolean { suspend fun initCheck(): Boolean {
Log.d("initCheck", "checking...")
if (!accountData.contains("token")) return false if (!accountData.contains("token")) return false
if (!accountData.contains("homeserver")) return false if (!accountData.contains("homeserver")) return false
token = accountData.getString("token", "").toString() token = accountData.getString("token", "").toString()
homeserver = accountData.getString("homeserver", "").toString() urlBase = "https://${accountData.getString("homeserver", "")}/_matrix/client/v3"
baseUrl = "https://$homeserver/_matrix/client/v3"
return getMe() != null return getMe() != null
} }
val db = Room.databaseBuilder(
appCtx,
AppDatabase::class.java, "database"
).build()

View File

@ -1,57 +0,0 @@
/*
* Created by sweetbread
* Copyright (c) 2025. All rights reserved.
* Last modified 22.02.2025, 19:52
*/
package ru.risdeveau.pixeldragon.api
import io.ktor.client.request.bearerAuth
import io.ktor.client.request.get
import io.ktor.client.statement.bodyAsText
import io.ktor.http.HttpStatusCode
import org.json.JSONObject
import ru.risdeveau.pixeldragon.baseUrl
import ru.risdeveau.pixeldragon.client
import ru.risdeveau.pixeldragon.db
import ru.risdeveau.pixeldragon.db.Room
import ru.risdeveau.pixeldragon.token
//fun getRooms(): List<Room> {
// return db.roomDoa().getAllJoined()
//}
//
//fun updateRooms(): List<Room> {
//
//}
suspend fun getRooms(): List<String> {
val r = client.get("$baseUrl/joined_rooms")
{ bearerAuth(token) }
val rooms = JSONObject(r.bodyAsText()).getJSONArray("joined_rooms")
return List<String>(
rooms.length()
) { i -> rooms.getString(i) }
}
suspend fun getRoom(rid: String): Room {
var room = db.roomDoa().getById(rid)
if (room == null) {
val name = getState(rid, "m.room.name", "name")
val type = getState(rid, "m.room.create", "type") ?: "m.room"
val creator = getState(rid, "m.room.create", "creator")
val avatar = getState(rid, "m.room.avatar", "url")
room = Room(rid, name, type, creator, null, avatar, null, true)
db.roomDoa().insert(room)
}
return room
}
private suspend fun getState(rid: String, state: String, key: String): String? {
val r = client.get("$baseUrl/rooms/$rid/state/$state") { bearerAuth(token) }
if (r.status != HttpStatusCode.OK) return null
val json = JSONObject(r.bodyAsText())
if (!json.has(key)) return null
return json.getString(key)
}

View File

@ -1,7 +1,7 @@
/* /*
* Created by sweetbread on 22.02.2025, 17:28 * Created by sweetbread on 21.02.2025, 12:01
* Copyright (c) 2025. All rights reserved. * Copyright (c) 2025. All rights reserved.
* Last modified 22.02.2025, 17:28 * Last modified 21.02.2025, 12:01
*/ */
package ru.risdeveau.pixeldragon.api package ru.risdeveau.pixeldragon.api
@ -11,7 +11,6 @@ import io.ktor.client.statement.bodyAsText
import org.json.JSONException import org.json.JSONException
import org.json.JSONObject import org.json.JSONObject
import ru.risdeveau.pixeldragon.client import ru.risdeveau.pixeldragon.client
import ru.risdeveau.pixeldragon.homeserver
suspend fun isMatrixServer(url: String): Boolean { suspend fun isMatrixServer(url: String): Boolean {
val r = try { client.get("https://$url/.well-known/matrix/client") } val r = try { client.get("https://$url/.well-known/matrix/client") }
@ -22,10 +21,3 @@ suspend fun isMatrixServer(url: String): Boolean {
return true return true
} }
fun mxcToUrl(mxc: String): String {
val pattern = Regex("mxc://([-a-zA-Z0-9@:%._+~#=]{1,256}\\.[a-zA-Z0-9()]{1,6})/([a-zA-Z]+)")
val match = pattern.find(mxc)
return "https://$homeserver/_matrix/client/v1/media/download/${match?.groupValues[1]}/${match?.groupValues[2]}"
}

View File

@ -1,7 +1,7 @@
/* /*
* Created by sweetbread on 22.02.2025, 15:45 * Created by sweetbread on 21.02.2025, 12:09
* Copyright (c) 2025. All rights reserved. * Copyright (c) 2025. All rights reserved.
* Last modified 22.02.2025, 15:45 * Last modified 21.02.2025, 12:01
*/ */
package ru.risdeveau.pixeldragon.api package ru.risdeveau.pixeldragon.api
@ -18,10 +18,10 @@ import io.ktor.http.HttpStatusCode
import io.ktor.http.contentType import io.ktor.http.contentType
import org.json.JSONObject import org.json.JSONObject
import ru.risdeveau.pixeldragon.accountData import ru.risdeveau.pixeldragon.accountData
import ru.risdeveau.pixeldragon.baseUrl
import ru.risdeveau.pixeldragon.client import ru.risdeveau.pixeldragon.client
import ru.risdeveau.pixeldragon.initCheck import ru.risdeveau.pixeldragon.initCheck
import ru.risdeveau.pixeldragon.token import ru.risdeveau.pixeldragon.token
import ru.risdeveau.pixeldragon.urlBase
import splitties.init.appCtx import splitties.init.appCtx
data class Me (val userId: String, val deviceId: String) data class Me (val userId: String, val deviceId: String)
@ -30,7 +30,7 @@ data class Me (val userId: String, val deviceId: String)
* This func is to validate the token * This func is to validate the token
*/ */
suspend fun getMe(): Me? { suspend fun getMe(): Me? {
val r = client.get("$baseUrl/account/whoami") { bearerAuth(token) } val r = client.get("$urlBase/account/whoami") { bearerAuth(token) }
if (r.status != HttpStatusCode.OK) { if (r.status != HttpStatusCode.OK) {
Log.e("getMe", r.bodyAsText()) Log.e("getMe", r.bodyAsText())
return null return null

View File

@ -1,81 +0,0 @@
/*
* Created by sweetbread
* Copyright (c) 2025. All rights reserved.
* Last modified 22.02.2025, 19:49
*/
package ru.risdeveau.pixeldragon.db
import androidx.room.Dao
import androidx.room.Database
import androidx.room.Delete
import androidx.room.Embedded
import androidx.room.Entity
import androidx.room.Insert
import androidx.room.Junction
import androidx.room.PrimaryKey
import androidx.room.Query
import androidx.room.Relation
import androidx.room.RoomDatabase
@Entity
data class Room(
@PrimaryKey val roomId: String,
val name: String?,
val type: String,
val creatorId: String?,
val createTime: Long?,
val avatarUrl: String?,
val members: Int?,
val joined: Boolean
)
@Dao
interface RoomDao {
// @Query("SELECT * FROM room")
// fun getAll(): List<User>
// @Query("SELECT * FROM user WHERE uid IN (:userIds)")
// fun loadAllByIds(userIds: IntArray): List<User>
// @Query("SELECT * FROM user WHERE first_name LIKE :first AND " +
// "last_name LIKE :last LIMIT 1")
// fun findByName(first: String, last: String): User
@Query("SELECT * FROM room WHERE roomId LIKE :rid LIMIT 1")
fun getById(rid: String): Room?
// @Transaction
// @Query("SELECT * FROM room WHERE ")
// fun getSpace(rid: String): Space
@Query("SELECT * FROM room WHERE joined = 1 AND roomId NOT IN (SELECT roomId FROM SpaceToRoom)")
fun getAllJoined(): List<Room>
@Insert
fun insert(vararg rooms: Room)
@Delete
fun delete(room: Room)
}
@Entity(primaryKeys = ["spaceId", "roomId"])
data class SpaceToRoom(
val spaceId: String,
val roomId: String
)
data class Space(
@Embedded val space: Room,
@Relation(
parentColumn = "spaceId",
entityColumn = "roomId",
associateBy = Junction(SpaceToRoom::class)
)
val children: List<Room>
)
@Database(entities = [Room::class, SpaceToRoom::class, User::class], version = 1)
abstract class AppDatabase : RoomDatabase() {
abstract fun roomDoa(): RoomDao
}

View File

@ -1,18 +0,0 @@
/*
* Created by sweetbread on 22.02.2025, 15:45
* Copyright (c) 2025. All rights reserved.
* Last modified 21.02.2025, 13:38
*/
package ru.risdeveau.pixeldragon.db
import androidx.room.ColumnInfo
import androidx.room.Entity
import androidx.room.PrimaryKey
@Entity
data class User(
@PrimaryKey val uid: String,
@ColumnInfo(name = "name") val name: String?,
@ColumnInfo(name = "avatar") val avatar: String?
)

View File

@ -1,7 +1,7 @@
/* /*
* Created by sweetbread on 22.02.2025, 15:45 * Created by sweetbread on 21.02.2025, 12:08
* Copyright (c) 2025. All rights reserved. * Copyright (c) 2025. All rights reserved.
* Last modified 22.02.2025, 15:45 * Last modified 21.02.2025, 12:08
*/ */
package ru.risdeveau.pixeldragon.ui.activity package ru.risdeveau.pixeldragon.ui.activity
@ -35,25 +35,15 @@ import androidx.compose.ui.Modifier
import androidx.compose.ui.text.input.KeyboardType import androidx.compose.ui.text.input.KeyboardType
import androidx.compose.ui.text.input.PasswordVisualTransformation import androidx.compose.ui.text.input.PasswordVisualTransformation
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import kotlinx.coroutines.DelicateCoroutinesApi
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import ru.risdeveau.pixeldragon.api.isMatrixServer import ru.risdeveau.pixeldragon.api.isMatrixServer
import ru.risdeveau.pixeldragon.api.login import ru.risdeveau.pixeldragon.api.login
import ru.risdeveau.pixeldragon.initCheck
import ru.risdeveau.pixeldragon.ui.theme.PixelDragonTheme import ru.risdeveau.pixeldragon.ui.theme.PixelDragonTheme
import splitties.activities.start import splitties.activities.start
class Login : ComponentActivity() { class Login : ComponentActivity() {
@OptIn(DelicateCoroutinesApi::class)
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
GlobalScope.launch {
if (initCheck()) start<MainActivity>()
}
enableEdgeToEdge() enableEdgeToEdge()
setContent { setContent {
PixelDragonTheme { PixelDragonTheme {
@ -66,10 +56,7 @@ class Login : ComponentActivity() {
SnackbarHost(hostState = snackbarHostState) SnackbarHost(hostState = snackbarHostState)
} }
) { innerPadding -> ) { innerPadding ->
Box( Box(Modifier.fillMaxSize().padding(innerPadding)) {
Modifier
.fillMaxSize()
.padding(innerPadding)) {
LoginField( LoginField(
Modifier.align(Alignment.Center), Modifier.align(Alignment.Center),
{ start<MainActivity>() }, { start<MainActivity>() },
@ -132,10 +119,11 @@ fun LoginField(modifier: Modifier = Modifier, ok: () -> Unit, err: () -> Unit) {
Button( Button(
enabled = hmsValid && !login.isEmpty() && !pass.isEmpty(), enabled = hmsValid && !login.isEmpty() && !pass.isEmpty(),
onClick = { onClick = {
scope.launch { var loginSuccess = false
if (login(homeserver, login, pass)) ok() scope.launch { loginSuccess = login(homeserver, login, pass) }
else err()
} if (loginSuccess) ok()
else err()
} }
) { ) {
Text("Login") Text("Login")

View File

@ -1,7 +1,7 @@
/* /*
* Created by sweetbread * Created by sweetbread on 21.02.2025, 12:08
* Copyright (c) 2025. All rights reserved. * Copyright (c) 2025. All rights reserved.
* Last modified 22.02.2025, 20:24 * Last modified 21.02.2025, 12:07
*/ */
package ru.risdeveau.pixeldragon.ui.activity package ru.risdeveau.pixeldragon.ui.activity
@ -10,56 +10,31 @@ 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.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.compose.ui.tooling.preview.Preview
import androidx.compose.ui.layout.ContentScale import kotlinx.coroutines.DelicateCoroutinesApi
import androidx.compose.ui.unit.dp import kotlinx.coroutines.GlobalScope
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.launch
import kotlinx.coroutines.withContext import ru.risdeveau.pixeldragon.initCheck
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 import splitties.activities.start
class MainActivity : ComponentActivity() { class MainActivity : ComponentActivity() {
@OptIn(ExperimentalMaterial3Api::class) @OptIn(ExperimentalMaterial3Api::class, DelicateCoroutinesApi::class)
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
GlobalScope.launch {
if (!initCheck()) start<Login>()
}
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
enableEdgeToEdge() enableEdgeToEdge()
@ -79,123 +54,28 @@ class MainActivity : ComponentActivity() {
) )
}, },
) { innerPadding -> ) { innerPadding ->
RoomList(Modifier.padding(innerPadding)) Greeting(
} name = "Android",
} modifier = Modifier.padding(innerPadding)
}
}
}
@Composable
fun RoomList(modifier: Modifier = Modifier) {
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)
}
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(80.dp)
.fillMaxWidth()
.background(MaterialTheme.colorScheme.primaryContainer, RoundedCornerShape(16.dp))
.padding(8.dp)
) {
SubcomposeAsyncImage(
modifier = Modifier
.padding(end = 4.dp)
.height(64.dp)
.width(64.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.primaryContainer, RoundedCornerShape(16.dp))
.padding(8.dp)
) {
LinearProgressIndicator(Modifier.fillMaxWidth())
}
} }
} }
//@Preview(showBackground = true) @Composable
//@Composable fun Greeting(name: String, modifier: Modifier = Modifier) {
//fun GreetingPreview() { Text(
// PixelDragonTheme { text = "Hello $name!",
// RoomItem() modifier = modifier
// } )
//} }
@Preview(showBackground = true)
@Composable
fun GreetingPreview() {
PixelDragonTheme {
Greeting("Android")
}
}

View File

@ -1,7 +1,7 @@
/* /*
* Created by sweetbread on 22.02.2025, 15:45 * Created by sweetbread on 21.02.2025, 12:00
* Copyright (c) 2025. All rights reserved. * Copyright (c) 2025. All rights reserved.
* Last modified 21.02.2025, 12:21 * Last modified 21.02.2025, 12:00
*/ */
// Top-level build file where you can add configuration options common to all sub-projects/modules. // Top-level build file where you can add configuration options common to all sub-projects/modules.
@ -9,5 +9,4 @@ plugins {
alias(libs.plugins.android.application) apply false alias(libs.plugins.android.application) apply false
alias(libs.plugins.kotlin.android) apply false alias(libs.plugins.kotlin.android) apply false
alias(libs.plugins.kotlin.compose) apply false alias(libs.plugins.kotlin.compose) apply false
id("com.google.devtools.ksp") version "2.0.21-1.0.27" apply false
} }

View File

@ -1,7 +1,7 @@
[versions] [versions]
agp = "8.7.3" agp = "8.7.3"
coil = "3.1.0" coil = "3.1.0"
kotlin = "2.0.21" kotlin = "2.0.0"
coreKtx = "1.15.0" coreKtx = "1.15.0"
junit = "4.13.2" junit = "4.13.2"
junitVersion = "1.2.1" junitVersion = "1.2.1"
@ -10,15 +10,10 @@ 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"
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-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" } coil-compose = { module = "io.coil-kt.coil3:coil-compose", version.ref = "coil" }
coil-network-okhttp = { module = "io.coil-kt.coil3:coil-network-okhttp", version.ref = "coil" } coil-network-okhttp = { module = "io.coil-kt.coil3:coil-network-okhttp", version.ref = "coil" }
junit = { group = "junit", name = "junit", version.ref = "junit" } junit = { group = "junit", name = "junit", version.ref = "junit" }
@ -34,9 +29,8 @@ 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" }
ktor-client-okhttp = { module = "io.ktor:ktor-client-okhttp", version.ref = "ktor" } ktor-client-cio = { module = "io.ktor:ktor-client-cio", 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" }
splitties-base = { module = "com.louiscad.splitties:splitties-fun-pack-android-base", version.ref = "splittiesFunPackAndroidBase" } splitties-base = { module = "com.louiscad.splitties:splitties-fun-pack-android-base", version.ref = "splittiesFunPackAndroidBase" }
[plugins] [plugins]