Files
Void-Client/app/src/main/java/com/sffteam/voidclient/preferences/SecurityActivity.kt
2026-03-02 18:49:17 +02:00

409 lines
22 KiB
Kotlin
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
package com.sffteam.voidclient.preferences
import android.os.Bundle
import android.widget.Toast
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.activity.enableEdgeToEdge
import androidx.compose.foundation.background
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.automirrored.filled.ArrowBackIos
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.Icon
import androidx.compose.material3.IconButton
import androidx.compose.material3.MaterialTheme.colorScheme
import androidx.compose.material3.Scaffold
import androidx.compose.material3.Switch
import androidx.compose.material3.Text
import androidx.compose.material3.TopAppBar
import androidx.compose.material3.TopAppBarDefaults
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.rememberCoroutineScope
import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.size
import androidx.compose.material.icons.outlined.Lock
import androidx.compose.material3.ModalBottomSheet
import androidx.compose.material3.rememberModalBottomSheetState
import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.platform.LocalContext
import com.sffteam.voidclient.AccountManager
import com.sffteam.voidclient.OPCode
import com.sffteam.voidclient.SocketManager
import com.sffteam.voidclient.ui.theme.AppTheme
import kotlinx.coroutines.launch
import kotlinx.serialization.json.JsonObject
import kotlinx.serialization.json.JsonPrimitive
import kotlinx.serialization.json.jsonArray
import kotlinx.serialization.json.jsonObject
class SecurityActivity : ComponentActivity() {
@OptIn(ExperimentalMaterial3Api::class)
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
enableEdgeToEdge()
val forSettings = mapOf(
"HIDDEN" to mapOf("Контакты" to false, "Никто" to true),
"CONTENT_LEVEL_ACCESS" to mapOf("Весь" to false, "Безопасный" to true),
"CHATS_INVITE" to mapOf("Все" to "ALL", "Контакты" to "CONTACTS"),
"SEARCH_BY_PHONE" to mapOf("Все" to "ALL", "Контакты" to "CONTACTS"),
"INCOMING_CALL" to mapOf("Все" to "ALL", "Контакты" to "CONTACTS"),
)
setContent {
val coroutineScope = rememberCoroutineScope()
val settings by AccountManager.settings.collectAsState()
val sheetState = rememberModalBottomSheetState()
val safeMode = remember { mutableStateOf(settings.safeMode) }
val context = LocalContext.current
var showBottomSheet by remember { mutableStateOf(false) }
val selectedSettings = remember { mutableStateOf("") }
if (AccountManager.sessionsList.value.isEmpty()) {
val packet =
SocketManager.packPacket(OPCode.SESSIONS.opcode, JsonObject(emptyMap()))
coroutineScope.launch {
SocketManager.sendPacket(packet, { packet ->
if (packet.payload is JsonObject) {
AccountManager.processSession(packet.payload["sessions"]!!.jsonArray)
}
})
}
}
AppTheme {
LaunchedEffect(settings) {
safeMode.value = settings.safeMode
}
if (showBottomSheet) {
ModalBottomSheet(
onDismissRequest = {
showBottomSheet = false
}, sheetState = sheetState
) {
Column(
verticalArrangement = Arrangement.spacedBy(16.dp),
modifier = Modifier.padding(start = 8.dp)
) {
forSettings[selectedSettings.value]?.forEach { (index, value) ->
Text(index, modifier = Modifier.clickable {
val packet = SocketManager.packPacket(OPCode.SETTINGS_CHANGE.opcode, JsonObject(
mapOf(
"settings" to JsonObject(
mapOf(
"user" to JsonObject(
mapOf(
if (value is String) {
selectedSettings.value to JsonPrimitive(value)
} else if (value is Boolean) {
selectedSettings.value to JsonPrimitive(value)
} else {
selectedSettings.value to JsonPrimitive("")
}
)
)
)
)
)
))
coroutineScope.launch {
SocketManager.sendPacket(packet, { packet ->
if (packet.payload is JsonObject) {
AccountManager.processSettings(packet.payload["user"]!!.jsonObject)
}
})
}
showBottomSheet = false
}
.padding(8.dp), fontSize = 24.sp)
}
}
}
}
Scaffold(
topBar = {
TopAppBar(
colors = TopAppBarDefaults.topAppBarColors(
containerColor = colorScheme.surfaceContainer,
),
title = {
Text("Безопасность")
},
navigationIcon = {
IconButton({ finish() }) {
Icon(
Icons.AutoMirrored.Filled.ArrowBackIos,
contentDescription = "Меню"
)
}
},
)
}) {
Box(
modifier = Modifier
.padding(it)
.fillMaxSize()
) {
LazyColumn(
modifier = Modifier
.fillMaxSize()
.padding(12.dp),
verticalArrangement = Arrangement.spacedBy(12.dp),
) {
item() {
Box(
modifier = Modifier
.background(
colorScheme.secondaryContainer,
shape = RoundedCornerShape(20.dp)
)
.fillMaxWidth()
.padding(start = 4.dp, top = 4.dp, end = 4.dp)
) {
Column(modifier = Modifier
.padding(bottom = 8.dp),
verticalArrangement = Arrangement.spacedBy(12.dp)) {
Row(verticalAlignment = Alignment.CenterVertically) {
Icon(
Icons.Outlined.Lock,
contentDescription = "lol",
modifier = Modifier.size(40.dp).padding(start = 8.dp)
)
Text("Безопасный режим", fontSize = 24.sp, modifier = Modifier.padding(start = 8.dp))
Spacer(modifier = Modifier.weight(1f))
Switch(
checked = safeMode.value,
onCheckedChange = {
val packet = SocketManager.packPacket(OPCode.SETTINGS_CHANGE.opcode, JsonObject(
mapOf(
"settings" to JsonObject(
mapOf(
"user" to JsonObject(
mapOf(
"SAFE_MODE" to JsonPrimitive(it)
)
)
)
)
)
))
coroutineScope.launch {
SocketManager.sendPacket(packet, { packet ->
if (packet.payload is JsonObject) {
AccountManager.processSettings(packet.payload["user"]!!.jsonObject)
}
})
}
},
modifier = Modifier.padding(end = 4.dp)
)
}
Row(modifier = Modifier
.clickable {
if (settings.safeMode) {
Toast.makeText(
context,
"Отключите безопасный режим, чтобы изменить эту настройку",
Toast.LENGTH_SHORT
).show()
} else {
selectedSettings.value = "SEARCH_BY_PHONE"
showBottomSheet = true
}
}) {
Text("Найти меня по номеру", fontSize = 20.sp, modifier = Modifier.padding(start = 8.dp))
val whoCan = if (settings.searchByPhone == "ALL") {
"Все"
} else {
"Контакты"
}
Spacer(modifier = Modifier.weight(1f))
if (settings.safeMode) {
Icon(
Icons.Outlined.Lock,
contentDescription = "lol",
modifier = Modifier.size(25.dp).padding(start = 4.dp, end = 4.dp)
)
}
Text(whoCan, fontSize = 20.sp, modifier = Modifier.padding(end = 8.dp))
}
Row(modifier = Modifier
.clickable {
if (settings.safeMode) {
Toast.makeText(
context,
"Отключите безопасный режим, чтобы изменить эту настройку",
Toast.LENGTH_SHORT
).show()
} else {
selectedSettings.value = "INCOMING_CALL"
showBottomSheet = true
}
}) {
Text("Позвонить", fontSize = 20.sp, modifier = Modifier.padding(start = 8.dp))
val whoCan = if (settings.incomingCall == "ALL") {
"Все"
} else {
"Контакты"
}
Spacer(modifier = Modifier.weight(1f))
if (settings.safeMode) {
Icon(
Icons.Outlined.Lock,
contentDescription = "lol",
modifier = Modifier.size(25.dp).padding(start = 4.dp, end = 4.dp)
)
}
Text(whoCan, fontSize = 20.sp, modifier = Modifier.padding(end = 8.dp))
}
Row(modifier = Modifier
.clickable {
if (settings.safeMode) {
Toast.makeText(
context,
"Отключите безопасный режим, чтобы изменить эту настройку",
Toast.LENGTH_SHORT
).show()
} else {
selectedSettings.value = "CHATS_INVITE"
showBottomSheet = true
}
}) {
Text("Приглашения в чат", fontSize = 20.sp, modifier = Modifier.padding(start = 8.dp))
val whoCan = if (settings.chatsInvite == "ALL") {
"Все"
} else {
"Контакты"
}
Spacer(modifier = Modifier.weight(1f))
if (settings.safeMode) {
Icon(
Icons.Outlined.Lock,
contentDescription = "lol",
modifier = Modifier.size(25.dp).padding(start = 4.dp, end = 4.dp)
)
}
Text(whoCan, fontSize = 20.sp, modifier = Modifier.padding(end = 8.dp))
}
Row(modifier = Modifier
.clickable {
if (settings.safeMode) {
Toast.makeText(
context,
"Отключите безопасный режим, чтобы изменить эту настройку",
Toast.LENGTH_SHORT
).show()
} else {
selectedSettings.value = "CONTENT_LEVEL_ACCESS"
showBottomSheet = true
}
}) {
Text("Показывать контент", fontSize = 20.sp, modifier = Modifier.padding(start = 8.dp))
val content = if (!settings.contentLevelAccess) {
"Весь"
} else {
"Безопасный"
}
Spacer(modifier = Modifier.weight(1f))
if (settings.safeMode) {
Icon(
Icons.Outlined.Lock,
contentDescription = "lol",
modifier = Modifier.size(25.dp).padding(start = 4.dp, end = 4.dp)
)
}
Text(content, fontSize = 20.sp, modifier = Modifier.padding(end = 8.dp))
}
}
}
}
item() {
Box(
modifier = Modifier
.background(
colorScheme.secondaryContainer,
shape = RoundedCornerShape(20.dp)
)
.fillMaxWidth()
.padding(start = 4.dp, top = 4.dp, end = 4.dp)
) {
Column() {
Text(
"Информация",
fontSize = 22.sp,
color = colorScheme.primary,
modifier = Modifier.padding(start = 8.dp, bottom = 8.dp)
)
Row(modifier = Modifier
.clickable {
selectedSettings.value = "HIDDEN"
showBottomSheet = true
}
.padding(bottom = 8.dp)) {
Text("Статус \"В сети\"", fontSize = 20.sp, modifier = Modifier.padding(start = 8.dp))
val hidden = if (settings.hidden) {
"Никто"
} else {
"Контакты"
}
Spacer(modifier = Modifier.weight(1f))
Text(hidden, fontSize = 20.sp, modifier = Modifier.padding(end = 8.dp))
}
}
}
}
item() {}
}
}
}
}
}
}
}