Compare commits
No commits in common. "e70049f1f5feafd4389a93699df6ca0b9accc1b5" and "dc588a045d1076d82fc5de3cd522cf7f50749c24" have entirely different histories.
e70049f1f5
...
dc588a045d
6
.idea/copyright/profiles_settings.xml
generated
6
.idea/copyright/profiles_settings.xml
generated
@ -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>
|
8
.idea/deploymentTargetSelector.xml
generated
8
.idea/deploymentTargetSelector.xml
generated
@ -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
2
.idea/kotlinc.xml
generated
@ -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>
|
@ -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
|
||||||
}
|
}
|
@ -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>
|
@ -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()
|
|
@ -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)
|
|
||||||
}
|
|
@ -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]}"
|
|
||||||
}
|
|
@ -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
|
||||||
|
@ -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
|
|
||||||
}
|
|
@ -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?
|
|
||||||
)
|
|
@ -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,11 +119,12 @@ 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) }
|
||||||
|
|
||||||
|
if (loginSuccess) ok()
|
||||||
else err()
|
else err()
|
||||||
}
|
}
|
||||||
}
|
|
||||||
) {
|
) {
|
||||||
Text("Login")
|
Text("Login")
|
||||||
}
|
}
|
||||||
|
@ -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,7 +54,10 @@ class MainActivity : ComponentActivity() {
|
|||||||
)
|
)
|
||||||
},
|
},
|
||||||
) { innerPadding ->
|
) { innerPadding ->
|
||||||
RoomList(Modifier.padding(innerPadding))
|
Greeting(
|
||||||
|
name = "Android",
|
||||||
|
modifier = Modifier.padding(innerPadding)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -87,115 +65,17 @@ class MainActivity : ComponentActivity() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun RoomList(modifier: Modifier = Modifier) {
|
fun Greeting(name: String, 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(
|
Text(
|
||||||
room!!.name ?: "Unnamed",
|
text = "Hello $name!",
|
||||||
maxLines = 1,
|
modifier = modifier
|
||||||
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
|
|
||||||
//fun GreetingPreview() {
|
|
||||||
// PixelDragonTheme {
|
|
||||||
// RoomItem()
|
|
||||||
// }
|
|
||||||
//}
|
|
||||||
|
|
||||||
|
@Preview(showBackground = true)
|
||||||
|
@Composable
|
||||||
|
fun GreetingPreview() {
|
||||||
|
PixelDragonTheme {
|
||||||
|
Greeting("Android")
|
||||||
|
}
|
||||||
|
}
|
@ -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
|
|
||||||
}
|
}
|
@ -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]
|
||||||
|
Loading…
x
Reference in New Issue
Block a user