Merge remote-tracking branch 'origin/master' into ab/self-chat

This commit is contained in:
IC Rainbow 2024-01-09 12:11:51 +02:00
commit e43ed1ca43
49 changed files with 147 additions and 103 deletions

View File

@ -3,11 +3,12 @@ package chat.simplex.app
import android.content.Context
import android.util.Log
import androidx.work.*
import chat.simplex.app.*
import chat.simplex.app.SimplexService.Companion.showPassphraseNotification
import chat.simplex.common.model.ChatController
import chat.simplex.common.views.helpers.DBMigrationResult
import chat.simplex.app.BuildConfig
import chat.simplex.common.platform.chatModel
import chat.simplex.common.platform.initChatControllerAndRunMigrations
import chat.simplex.common.views.helpers.DatabaseUtils
import kotlinx.coroutines.*
import java.util.Date
import java.util.concurrent.TimeUnit
@ -57,6 +58,10 @@ class MessagesFetcherWork(
val durationSeconds = inputData.getInt(INPUT_DATA_DURATION, 60)
var shouldReschedule = true
try {
// In case of self-destruct is enabled the initialization process will not start in SimplexApp, Let's start it here
if (DatabaseUtils.ksSelfDestructPassword.get() != null && chatModel.chatDbStatus.value == null) {
initChatControllerAndRunMigrations()
}
withTimeout(durationSeconds * 1000L) {
val chatController = ChatController
SimplexService.waitDbMigrationEnds(chatController)

View File

@ -26,6 +26,7 @@ import kotlinx.coroutines.sync.withLock
import java.io.*
import java.util.*
import java.util.concurrent.TimeUnit
import kotlin.system.exitProcess
const val TAG = "SIMPLEX"
@ -46,8 +47,8 @@ class SimplexApp: Application(), LifecycleEventObserver {
try {
Looper.loop()
} catch (e: Throwable) {
if (e.message != null && e.message!!.startsWith("Unable to start activity")) {
android.os.Process.killProcess(android.os.Process.myPid())
if (e is UnsatisfiedLinkError || e.message?.startsWith("Unable to start activity") == true) {
Process.killProcess(Process.myPid())
break
} else {
// Send it to our exception handled because it will not get the exception otherwise
@ -63,7 +64,9 @@ class SimplexApp: Application(), LifecycleEventObserver {
tmpDir.deleteRecursively()
tmpDir.mkdir()
initChatControllerAndRunMigrations(false)
if (DatabaseUtils.ksSelfDestructPassword.get() == null) {
initChatControllerAndRunMigrations()
}
ProcessLifecycleOwner.get().lifecycle.addObserver(this@SimplexApp)
}

View File

@ -72,6 +72,10 @@ class SimplexService: Service() {
stopSelf()
} else {
isServiceStarted = true
// In case of self-destruct is enabled the initialization process will not start in SimplexApp, Let's start it here
if (DatabaseUtils.ksSelfDestructPassword.get() != null && chatModel.chatDbStatus.value == null) {
initChatControllerAndRunMigrations()
}
}
}

View File

@ -97,7 +97,8 @@ fun IncomingCallActivityView(m: ChatModel) {
Surface(
Modifier
.fillMaxSize(),
color = MaterialTheme.colors.background
color = MaterialTheme.colors.background,
contentColor = LocalContentColor.current
) {
if (showCallView) {
Box {
@ -200,7 +201,8 @@ private fun SimpleXLogo() {
private fun LockScreenCallButton(text: String, icon: Painter, color: Color, action: () -> Unit) {
Surface(
shape = RoundedCornerShape(10.dp),
color = Color.Transparent
color = Color.Transparent,
contentColor = LocalContentColor.current
) {
Column(
Modifier
@ -227,7 +229,8 @@ fun PreviewIncomingCallLockScreenAlert() {
Surface(
Modifier
.fillMaxSize(),
color = MaterialTheme.colors.background
color = MaterialTheme.colors.background,
contentColor = LocalContentColor.current
) {
IncomingCallLockScreenAlertLayout(
invitation = RcvCallInvitation(

View File

@ -44,7 +44,7 @@ data class SettingsViewState(
fun AppScreen() {
SimpleXTheme {
ProvideWindowInsets(windowInsetsAnimationsEnabled = true) {
Surface(color = MaterialTheme.colors.background) {
Surface(color = MaterialTheme.colors.background, contentColor = LocalContentColor.current) {
MainScreen()
}
}
@ -85,7 +85,7 @@ fun MainScreen() {
@Composable
fun AuthView() {
Surface(color = MaterialTheme.colors.background) {
Surface(color = MaterialTheme.colors.background, contentColor = LocalContentColor.current) {
Box(
Modifier.fillMaxSize(),
contentAlignment = Alignment.Center

View File

@ -1,8 +1,7 @@
package chat.simplex.common
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.material.MaterialTheme
import androidx.compose.material.Surface
import androidx.compose.material.*
import androidx.compose.runtime.mutableStateOf
import androidx.compose.ui.Modifier
import chat.simplex.common.model.*
@ -107,7 +106,7 @@ object AppLock {
private fun setPasscode() {
val appPrefs = ChatController.appPrefs
ModalManager.fullscreen.showCustomModal { close ->
Surface(Modifier.fillMaxSize(), color = MaterialTheme.colors.background) {
Surface(Modifier.fillMaxSize(), color = MaterialTheme.colors.background, contentColor = LocalContentColor.current) {
SetAppPasscodeView(
submit = {
ChatModel.performLA.value = true

View File

@ -41,21 +41,20 @@ val appPreferences: AppPreferences
val chatController: ChatController = ChatController
fun initChatControllerAndRunMigrations(ignoreSelfDestruct: Boolean) {
if (ignoreSelfDestruct || DatabaseUtils.ksSelfDestructPassword.get() == null) {
withBGApi {
if (appPreferences.chatStopped.get() && appPreferences.storeDBPassphrase.get() && ksDatabasePassword.get() != null) {
initChatController(startChat = ::showStartChatAfterRestartAlert)
} else {
initChatController()
}
runMigrations()
fun initChatControllerAndRunMigrations() {
withBGApi {
if (appPreferences.chatStopped.get() && appPreferences.storeDBPassphrase.get() && ksDatabasePassword.get() != null) {
initChatController(startChat = ::showStartChatAfterRestartAlert)
} else {
initChatController()
}
runMigrations()
}
}
suspend fun initChatController(useKey: String? = null, confirmMigrations: MigrationConfirmation? = null, startChat: () -> CompletableDeferred<Boolean> = { CompletableDeferred(true) }) {
try {
if (chatModel.ctrlInitInProgress.value) return
chatModel.ctrlInitInProgress.value = true
val dbKey = useKey ?: DatabaseUtils.useDatabaseKey()
val confirm = confirmMigrations ?: if (appPreferences.confirmDBUpgrades.get()) MigrationConfirmation.Error else MigrationConfirmation.YesUp

View File

@ -1,5 +1,7 @@
package chat.simplex.common.ui.theme
import androidx.compose.material.LocalContentColor
import androidx.compose.runtime.Composable
import androidx.compose.ui.graphics.Color
val Purple200 = Color(0xFFBB86FC)
@ -25,4 +27,5 @@ val WarningOrange = Color(255, 127, 0, 255)
val WarningYellow = Color(255, 192, 0, 255)
val FileLight = Color(183, 190, 199, 255)
val FileDark = Color(101, 101, 106, 255)
val MenuTextColorDark = Color.White.copy(alpha = 0.8f)
val MenuTextColor: Color @Composable get () = if (isInDarkTheme()) LocalContentColor.current.copy(alpha = 0.8f) else Color.Black

View File

@ -283,27 +283,10 @@ fun SimpleXTheme(darkTheme: Boolean? = null, content: @Composable () -> Unit) {
val theme by CurrentColors.collectAsState()
MaterialTheme(
colors = theme.colors,
typography = Typography.copy(
h1 = Typography.h1.copy(color = theme.colors.onBackground),
h2 = Typography.h2.copy(color = theme.colors.onBackground),
h3 = Typography.h3.copy(color = theme.colors.onBackground),
h4 = Typography.h4.copy(color = theme.colors.onBackground),
h5 = Typography.h5.copy(color = theme.colors.onBackground),
h6 = Typography.h6.copy(color = theme.colors.onBackground),
subtitle1 = Typography.subtitle1.copy(color = theme.colors.onBackground),
subtitle2 = Typography.subtitle2.copy(color = theme.colors.onBackground),
body1 = Typography.body1.copy(color = theme.colors.onBackground),
body2 = Typography.body2.copy(color = theme.colors.onBackground),
button = Typography.button.copy(color = theme.colors.onBackground),
caption = Typography.caption.copy(color = theme.colors.onBackground),
overline = Typography.overline.copy(color = theme.colors.onBackground)
),
typography = Typography,
shapes = Shapes,
content = {
ProvideTextStyle(
value = TextStyle(color = theme.colors.onBackground),
content = content
)
CompositionLocalProvider(LocalContentColor provides MaterialTheme.colors.onBackground, content = content)
}
)
}

View File

@ -1,8 +1,7 @@
package chat.simplex.common.views
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.material.MaterialTheme
import androidx.compose.material.Surface
import androidx.compose.material.*
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
@ -11,7 +10,8 @@ fun SplashView() {
Surface(
Modifier
.fillMaxSize(),
color = MaterialTheme.colors.background
color = MaterialTheme.colors.background,
contentColor = LocalContentColor.current
) {
// Image(
// painter = painterResource(MR.images.logo),

View File

@ -101,13 +101,16 @@ fun TerminalLayout(
)
}
},
contentColor = LocalContentColor.current,
drawerContentColor = LocalContentColor.current,
modifier = Modifier.navigationBarsWithImePadding()
) { contentPadding ->
Surface(
modifier = Modifier
.padding(contentPadding)
.fillMaxWidth(),
color = MaterialTheme.colors.background
color = MaterialTheme.colors.background,
contentColor = LocalContentColor.current
) {
TerminalLog()
}

View File

@ -239,7 +239,7 @@ fun OnboardingButtons(displayName: MutableState<String>, close: () -> Unit) {
val enabled = canCreateProfile(displayName.value)
val createModifier: Modifier = Modifier.clickable(enabled) { createProfileOnboarding(chatModel, displayName.value, close) }.padding(8.dp)
val createColor: Color = if (enabled) MaterialTheme.colors.primary else MaterialTheme.colors.secondary
Surface(shape = RoundedCornerShape(20.dp), color = Color.Transparent) {
Surface(shape = RoundedCornerShape(20.dp), color = Color.Transparent, contentColor = LocalContentColor.current) {
Row(verticalAlignment = Alignment.CenterVertically, modifier = createModifier) {
Text(stringResource(MR.strings.create_profile_button), style = MaterialTheme.typography.caption, color = createColor, fontWeight = FontWeight.Medium)
Icon(painterResource(MR.images.ic_arrow_forward_ios), stringResource(MR.strings.create_profile_button), tint = createColor)

View File

@ -85,7 +85,8 @@ fun IncomingCallInfo(invitation: RcvCallInvitation, chatModel: ChatModel) {
private fun CallButton(text: String, icon: Painter, color: Color, action: () -> Unit) {
Surface(
shape = RoundedCornerShape(10.dp),
color = Color.Transparent
color = Color.Transparent,
contentColor = LocalContentColor.current
) {
Column(
Modifier

View File

@ -570,6 +570,8 @@ fun ChatLayout(
bottomBar = composeView,
modifier = Modifier.navigationBarsWithImePadding(),
floatingActionButton = { floatingButton.value() },
contentColor = LocalContentColor.current,
drawerContentColor = LocalContentColor.current,
) { contentPadding ->
BoxWithConstraints(Modifier
.fillMaxHeight()

View File

@ -258,7 +258,8 @@ private fun CustomDisappearingMessageDialog(
DefaultDialog(onDismissRequest = { setShowDialog(false) }) {
Surface(
shape = RoundedCornerShape(corner = CornerSize(25.dp))
shape = RoundedCornerShape(corner = CornerSize(25.dp)),
contentColor = LocalContentColor.current
) {
Box(
contentAlignment = Alignment.Center

View File

@ -131,7 +131,8 @@ fun CIFileView(
Surface(
Modifier.drawRingModifier(angle, strokeColor, strokeWidth),
color = Color.Transparent,
shape = MaterialTheme.shapes.small.copy(CornerSize(percent = 50))
shape = MaterialTheme.shapes.small.copy(CornerSize(percent = 50)),
contentColor = LocalContentColor.current
) {
Box(Modifier.size(32.dp))
}

View File

@ -88,6 +88,7 @@ fun CIGroupInvitationView(
}) else Modifier,
shape = RoundedCornerShape(18.dp),
color = if (sent) sentColor else receivedColor,
contentColor = LocalContentColor.current
) {
Box(
Modifier

View File

@ -142,6 +142,7 @@ fun DecryptionErrorItemFixButton(
Modifier.clickable(onClick = onClick),
shape = RoundedCornerShape(18.dp),
color = receivedColor,
contentColor = LocalContentColor.current
) {
Box(
Modifier.padding(vertical = 6.dp, horizontal = 12.dp),
@ -188,6 +189,7 @@ fun DecryptionErrorItem(
Modifier.clickable(onClick = onClick),
shape = RoundedCornerShape(18.dp),
color = receivedColor,
contentColor = LocalContentColor.current
) {
Box(
Modifier.padding(vertical = 6.dp, horizontal = 12.dp),

View File

@ -153,7 +153,8 @@ private fun BoxScope.PlayButton(error: Boolean = false, onLongClick: () -> Unit,
Surface(
Modifier.align(Alignment.Center),
color = Color.Black.copy(alpha = 0.25f),
shape = RoundedCornerShape(percent = 50)
shape = RoundedCornerShape(percent = 50),
contentColor = LocalContentColor.current
) {
Box(
Modifier
@ -264,7 +265,8 @@ private fun progressCircle(progress: Long, total: Long) {
Surface(
Modifier.drawRingModifier(angle, strokeColor, strokeWidth),
color = Color.Transparent,
shape = MaterialTheme.shapes.small.copy(CornerSize(percent = 50))
shape = MaterialTheme.shapes.small.copy(CornerSize(percent = 50)),
contentColor = LocalContentColor.current
) {
Box(Modifier.size(16.dp))
}

View File

@ -225,7 +225,8 @@ private fun PlayPauseButton(
Surface(
Modifier.drawRingModifier(angle, strokeColor, strokeWidth),
color = if (sent) sentColor else receivedColor,
shape = MaterialTheme.shapes.small.copy(CornerSize(percent = 50))
shape = MaterialTheme.shapes.small.copy(CornerSize(percent = 50)),
contentColor = LocalContentColor.current
) {
Box(
Modifier

View File

@ -613,7 +613,7 @@ private fun ShrinkItemAction(revealed: MutableState<Boolean>, showMenu: MutableS
@Composable
fun ItemAction(text: String, icon: Painter, color: Color = Color.Unspecified, onClick: () -> Unit) {
val finalColor = if (color == Color.Unspecified) {
if (isInDarkTheme()) MenuTextColorDark else Color.Black
MenuTextColor
} else color
DropdownMenuItem(onClick, contentPadding = PaddingValues(horizontal = DEFAULT_PADDING * 1.5f)) {
Row(verticalAlignment = Alignment.CenterVertically) {
@ -633,7 +633,7 @@ fun ItemAction(text: String, icon: Painter, color: Color = Color.Unspecified, on
@Composable
fun ItemAction(text: String, icon: ImageVector, onClick: () -> Unit, color: Color = Color.Unspecified) {
val finalColor = if (color == Color.Unspecified) {
if (isInDarkTheme()) MenuTextColorDark else Color.Black
MenuTextColor
} else color
DropdownMenuItem(onClick, contentPadding = PaddingValues(horizontal = DEFAULT_PADDING * 1.5f)) {
Row(verticalAlignment = Alignment.CenterVertically) {

View File

@ -23,6 +23,7 @@ fun DeletedItemView(ci: ChatItem, timedMessagesTTL: Int?) {
Surface(
shape = RoundedCornerShape(18.dp),
color = if (sent) sentColor else receivedColor,
contentColor = LocalContentColor.current
) {
Row(
Modifier.padding(horizontal = 12.dp, vertical = 6.dp),

View File

@ -56,6 +56,7 @@ fun CIMsgError(ci: ChatItem, timedMessagesTTL: Int?, onClick: () -> Unit) {
Modifier.clickable(onClick = onClick),
shape = RoundedCornerShape(18.dp),
color = receivedColor,
contentColor = LocalContentColor.current
) {
Row(
Modifier.padding(horizontal = 12.dp, vertical = 6.dp),

View File

@ -26,6 +26,7 @@ fun MarkedDeletedItemView(ci: ChatItem, timedMessagesTTL: Int?, revealed: Mutabl
Surface(
shape = RoundedCornerShape(18.dp),
color = if (ci.chatDir.sent) sentColor else receivedColor,
contentColor = LocalContentColor.current
) {
Row(
Modifier.padding(horizontal = 12.dp, vertical = 6.dp),

View File

@ -75,6 +75,8 @@ fun ChatListView(chatModel: ChatModel, settingsState: SettingsViewState, setPerf
SettingsView(chatModel, setPerformLA, scaffoldState.drawerState)
}
},
contentColor = LocalContentColor.current,
drawerContentColor = LocalContentColor.current,
drawerScrimColor = MaterialTheme.colors.onSurface.copy(alpha = if (isInDarkTheme()) 0.16f else 0.32f),
drawerGesturesEnabled = appPlatform.isAndroid,
floatingActionButton = {

View File

@ -30,6 +30,8 @@ fun ShareListView(chatModel: ChatModel, settingsState: SettingsViewState, stoppe
val endPadding = if (appPlatform.isDesktop) 56.dp else 0.dp
Scaffold(
Modifier.padding(end = endPadding),
contentColor = LocalContentColor.current,
drawerContentColor = LocalContentColor.current,
scaffoldState = scaffoldState,
topBar = { Column { ShareListToolbar(chatModel, userPickerState, stopped) { searchInList = it.trim() } } },
) {

View File

@ -31,7 +31,6 @@ import chat.simplex.common.views.remote.*
import chat.simplex.common.views.usersettings.doWithAuth
import chat.simplex.res.MR
import dev.icerock.moko.resources.compose.stringResource
import kotlinx.coroutines.delay
import kotlinx.coroutines.flow.*
import kotlinx.coroutines.launch
import kotlin.math.roundToInt
@ -303,7 +302,7 @@ fun UserProfileRow(u: User) {
u.displayName,
modifier = Modifier
.padding(start = 10.dp, end = 8.dp),
color = if (isInDarkTheme()) MenuTextColorDark else Color.Black,
color = MenuTextColor,
fontWeight = if (u.activeUser) FontWeight.Medium else FontWeight.Normal
)
}
@ -346,7 +345,7 @@ fun RemoteHostRow(h: RemoteHostInfo) {
Text(
h.hostDeviceName,
modifier = Modifier.padding(start = 26.dp, end = 8.dp),
color = if (h.activeHost) MaterialTheme.colors.onBackground else if (isInDarkTheme()) MenuTextColorDark else Color.Black,
color = if (h.activeHost) MaterialTheme.colors.onBackground else MenuTextColor,
fontSize = 14.sp,
)
}
@ -387,7 +386,7 @@ fun LocalDeviceRow(active: Boolean) {
Text(
stringResource(MR.strings.this_device),
modifier = Modifier.padding(start = 26.dp, end = 8.dp),
color = if (active) MaterialTheme.colors.onBackground else if (isInDarkTheme()) MenuTextColorDark else Color.Black,
color = if (active) MaterialTheme.colors.onBackground else MenuTextColor,
fontSize = 14.sp,
)
}
@ -399,7 +398,7 @@ private fun UseFromDesktopPickerItem(onClick: () -> Unit) {
val text = generalGetString(MR.strings.settings_section_title_use_from_desktop).lowercase().capitalize(Locale.current)
Icon(painterResource(MR.images.ic_desktop), text, Modifier.size(20.dp), tint = MaterialTheme.colors.onBackground)
Spacer(Modifier.width(DEFAULT_PADDING + 6.dp))
Text(text, color = if (isInDarkTheme()) MenuTextColorDark else Color.Black)
Text(text, color = MenuTextColor)
}
}
@ -409,7 +408,7 @@ private fun LinkAMobilePickerItem(onClick: () -> Unit) {
val text = generalGetString(MR.strings.link_a_mobile)
Icon(painterResource(MR.images.ic_smartphone_300), text, Modifier.size(20.dp), tint = MaterialTheme.colors.onBackground)
Spacer(Modifier.width(DEFAULT_PADDING + 6.dp))
Text(text, color = if (isInDarkTheme()) MenuTextColorDark else Color.Black)
Text(text, color = MenuTextColor)
}
}
@ -419,7 +418,7 @@ private fun CreateInitialProfile(onClick: () -> Unit) {
val text = generalGetString(MR.strings.create_chat_profile)
Icon(painterResource(MR.images.ic_manage_accounts), text, Modifier.size(20.dp), tint = MaterialTheme.colors.onBackground)
Spacer(Modifier.width(DEFAULT_PADDING + 6.dp))
Text(text, color = if (isInDarkTheme()) MenuTextColorDark else Color.Black)
Text(text, color = MenuTextColor)
}
}
@ -429,7 +428,7 @@ private fun SettingsPickerItem(onClick: () -> Unit) {
val text = generalGetString(MR.strings.settings_section_title_settings).lowercase().capitalize(Locale.current)
Icon(painterResource(MR.images.ic_settings), text, Modifier.size(20.dp), tint = MaterialTheme.colors.onBackground)
Spacer(Modifier.width(DEFAULT_PADDING + 6.dp))
Text(text, color = if (isInDarkTheme()) MenuTextColorDark else Color.Black)
Text(text, color = MenuTextColor)
}
}
@ -439,7 +438,7 @@ private fun CancelPickerItem(onClick: () -> Unit) {
val text = generalGetString(MR.strings.cancel_verb)
Icon(painterResource(MR.images.ic_close), text, Modifier.size(20.dp), tint = MaterialTheme.colors.onBackground)
Spacer(Modifier.width(DEFAULT_PADDING + 6.dp))
Text(text, color = if (isInDarkTheme()) MenuTextColorDark else Color.Black)
Text(text, color = MenuTextColor)
}
}

View File

@ -460,10 +460,10 @@ suspend fun deleteChatAsync(m: ChatModel) {
m.controller.apiDeleteStorage()
DatabaseUtils.ksDatabasePassword.remove()
m.controller.appPrefs.storeDBPassphrase.set(true)
deleteChatDatabaseFiles()
deleteAppDatabaseAndFiles()
}
fun deleteChatDatabaseFiles() {
fun deleteAppDatabaseAndFiles() {
val chat = File(dataDir, chatDatabaseFileName)
val chatBak = File(dataDir, "$chatDatabaseFileName.bak")
val agent = File(dataDir, agentDatabaseFileName)
@ -473,6 +473,7 @@ fun deleteChatDatabaseFiles() {
agent.delete()
agentBak.delete()
filesDir.deleteRecursively()
filesDir.mkdir()
remoteHostsDir.deleteRecursively()
tmpDir.deleteRecursively()
tmpDir.mkdir()

View File

@ -152,7 +152,8 @@ fun CustomTimePickerDialog(
) {
DefaultDialog(onDismissRequest = cancel) {
Surface(
shape = RoundedCornerShape(corner = CornerSize(25.dp))
shape = RoundedCornerShape(corner = CornerSize(25.dp)),
contentColor = LocalContentColor.current
) {
Box(
contentAlignment = Alignment.Center

View File

@ -17,7 +17,7 @@ object DatabaseUtils {
val ksAppPassword = KeyStoreItem(APP_PASSWORD_ALIAS, appPreferences.encryptedAppPassphrase, appPreferences.initializationVectorAppPassphrase)
val ksSelfDestructPassword = KeyStoreItem(SELF_DESTRUCT_PASSWORD_ALIAS, appPreferences.encryptedSelfDestructPassphrase, appPreferences.initializationVectorSelfDestructPassphrase)
class KeyStoreItem(val alias: String, val passphrase: SharedPreference<String?>, val initVector: SharedPreference<String?>) {
class KeyStoreItem(private val alias: String, val passphrase: SharedPreference<String?>, val initVector: SharedPreference<String?>) {
fun get(): String? {
return cryptor.decryptData(
passphrase.get()?.toByteArrayFromBase64ForPassphrase() ?: return null,

View File

@ -70,7 +70,7 @@ fun <T> ExposedDropDownSetting(
selectionOption.second + (if (label != null) " $label" else ""),
maxLines = 1,
overflow = TextOverflow.Ellipsis,
color = if (isInDarkTheme()) MenuTextColorDark else Color.Black,
color = MenuTextColor,
fontSize = fontSize,
)
}

View File

@ -1,8 +1,7 @@
package chat.simplex.common.views.helpers
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.material.MaterialTheme
import androidx.compose.material.Surface
import androidx.compose.material.*
import androidx.compose.ui.Modifier
import chat.simplex.common.model.ChatController
import chat.simplex.common.model.ChatModel
@ -50,7 +49,7 @@ fun authenticateWithPasscode(
close()
completed(LAResult.Error(generalGetString(MR.strings.authentication_cancelled)))
}
Surface(Modifier.fillMaxSize(), color = MaterialTheme.colors.background) {
Surface(Modifier.fillMaxSize(), color = MaterialTheme.colors.background, contentColor = LocalContentColor.current) {
LocalAuthView(ChatModel, LocalAuthRequest(promptTitle, promptSubtitle, password, selfDestruct && ChatController.appPrefs.selfDestruct.get()) {
close()
completed(it)

View File

@ -26,7 +26,7 @@ fun ModalView(
if (showClose) {
BackHandler(onBack = close)
}
Surface(Modifier.fillMaxSize()) {
Surface(Modifier.fillMaxSize(), contentColor = LocalContentColor.current) {
Column(if (background != MaterialTheme.colors.background) Modifier.background(background) else Modifier.themedBackground()) {
CloseSheetBar(close, showClose, endButtons)
Box(modifier) { content() }

View File

@ -34,7 +34,7 @@ fun LocalAuthView(m: ChatModel, authRequest: LocalAuthRequest) {
} else {
val r: LAResult = if (passcode.value == authRequest.password) {
if (authRequest.selfDestruct && sdPassword != null && controller.ctrl == -1L) {
initChatControllerAndRunMigrations(true)
initChatControllerAndRunMigrations()
}
LAResult.Success
} else {
@ -67,8 +67,8 @@ private fun deleteStorageAndRestart(m: ChatModel, password: String, completed: (
* */
chatCloseStore(ctrl)
}
deleteChatDatabaseFiles()
// Clear sensitive data on screen just in case ModalManager will fail to prevent hiding its modals while database encrypts itself
deleteAppDatabaseAndFiles()
// Clear sensitive data on screen just in case ModalManager fails to hide its modals while new database is created
m.chatId.value = null
m.chatItems.clear()
m.chats.clear()

View File

@ -12,6 +12,7 @@ import chat.simplex.res.MR
@Composable
fun SetAppPasscodeView(
passcodeKeychain: DatabaseUtils.KeyStoreItem = ksAppPassword,
prohibitedPasscodeKeychain: DatabaseUtils.KeyStoreItem = ksSelfDestructPassword,
title: String = generalGetString(MR.strings.new_passcode),
reason: String? = null,
submit: () -> Unit,
@ -51,7 +52,7 @@ fun SetAppPasscodeView(
} else {
SetPasswordView(title, generalGetString(MR.strings.save_verb),
// Do not allow to set app passcode == selfDestruct passcode
submitEnabled = { pwd -> pwd != (if (passcodeKeychain.alias == ksSelfDestructPassword.alias) ksAppPassword else ksSelfDestructPassword).get() }) {
submitEnabled = { pwd -> pwd != prohibitedPasscodeKeychain.get() }) {
enteredPassword = passcode.value
passcode.value = ""
confirming = true

View File

@ -175,7 +175,7 @@ fun ActionButton(
disabled: Boolean = false,
click: () -> Unit = {}
) {
Surface(shape = RoundedCornerShape(18.dp), color = Color.Transparent) {
Surface(shape = RoundedCornerShape(18.dp), color = Color.Transparent, contentColor = LocalContentColor.current) {
Column(
Modifier
.clickable(onClick = click)
@ -220,7 +220,7 @@ fun ActionButton(
disabled: Boolean = false,
click: () -> Unit = {}
) {
Surface(modifier, shape = RoundedCornerShape(18.dp)) {
Surface(modifier, shape = RoundedCornerShape(18.dp), contentColor = LocalContentColor.current) {
Column(
Modifier
.fillMaxWidth()

View File

@ -380,7 +380,8 @@ fun SettingsSectionFooter(revert: () -> Unit, save: () -> Unit, disabled: Boolea
fun FooterButton(icon: Painter, title: String, action: () -> Unit, disabled: Boolean) {
Surface(
shape = RoundedCornerShape(20.dp),
color = Color.Black.copy(alpha = 0f)
color = Color.Black.copy(alpha = 0f),
contentColor = LocalContentColor.current
) {
val modifier = if (disabled) Modifier else Modifier.clickable { action() }
Row(

View File

@ -383,7 +383,7 @@ fun SimplexLockView(
}
LAMode.PASSCODE -> {
ModalManager.fullscreen.showCustomModal { close ->
Surface(Modifier.fillMaxSize(), color = MaterialTheme.colors.background) {
Surface(Modifier.fillMaxSize(), color = MaterialTheme.colors.background, contentColor = LocalContentColor.current) {
SetAppPasscodeView(
submit = {
laLockDelay.set(30)
@ -427,7 +427,7 @@ fun SimplexLockView(
when (laResult) {
LAResult.Success -> {
ModalManager.fullscreen.showCustomModal { close ->
Surface(Modifier.fillMaxSize(), color = MaterialTheme.colors.background) {
Surface(Modifier.fillMaxSize(), color = MaterialTheme.colors.background, contentColor = LocalContentColor.current) {
SetAppPasscodeView(
reason = generalGetString(MR.strings.la_app_passcode),
submit = {
@ -451,9 +451,10 @@ fun SimplexLockView(
when (laResult) {
LAResult.Success -> {
ModalManager.fullscreen.showCustomModal { close ->
Surface(Modifier.fillMaxSize(), color = MaterialTheme.colors.background) {
Surface(Modifier.fillMaxSize(), color = MaterialTheme.colors.background, contentColor = LocalContentColor.current) {
SetAppPasscodeView(
passcodeKeychain = ksSelfDestructPassword,
prohibitedPasscodeKeychain = ksAppPassword,
reason = generalGetString(MR.strings.self_destruct),
submit = {
selfDestructPasscodeAlert(generalGetString(MR.strings.self_destruct_passcode_changed))
@ -487,7 +488,7 @@ fun SimplexLockView(
}
LAMode.PASSCODE -> {
ModalManager.fullscreen.showCustomModal { close ->
Surface(Modifier.fillMaxSize(), color = MaterialTheme.colors.background) {
Surface(Modifier.fillMaxSize(), color = MaterialTheme.colors.background, contentColor = LocalContentColor.current) {
SetAppPasscodeView(
submit = {
laLockDelay.set(30)
@ -598,9 +599,9 @@ private fun EnableSelfDestruct(
selfDestruct: SharedPreference<Boolean>,
close: () -> Unit
) {
Surface(Modifier.fillMaxSize(), color = MaterialTheme.colors.background) {
Surface(Modifier.fillMaxSize(), color = MaterialTheme.colors.background, contentColor = LocalContentColor.current) {
SetAppPasscodeView(
passcodeKeychain = ksSelfDestructPassword, title = generalGetString(MR.strings.set_passcode), reason = generalGetString(MR.strings.enabled_self_destruct_passcode),
passcodeKeychain = ksSelfDestructPassword, prohibitedPasscodeKeychain = ksAppPassword, title = generalGetString(MR.strings.set_passcode), reason = generalGetString(MR.strings.enabled_self_destruct_passcode),
submit = {
selfDestruct.set(true)
selfDestructPasscodeAlert(generalGetString(MR.strings.self_destruct_passcode_enabled))

View File

@ -155,7 +155,8 @@ fun RTCServersLayout(
.height(160.dp)
.fillMaxWidth(),
shape = RoundedCornerShape(10.dp),
border = BorderStroke(1.dp, MaterialTheme.colors.secondaryVariant)
border = BorderStroke(1.dp, MaterialTheme.colors.secondaryVariant),
contentColor = LocalContentColor.current
) {
SelectionContainer(
Modifier.verticalScroll(rememberScrollState())

View File

@ -155,7 +155,7 @@ fun UserAddressView(
contentAlignment = Alignment.Center
) {
if (userAddress.value != null) {
Surface(Modifier.size(50.dp), color = MaterialTheme.colors.background.copy(0.9f), shape = RoundedCornerShape(50)){}
Surface(Modifier.size(50.dp), color = MaterialTheme.colors.background.copy(0.9f), contentColor = LocalContentColor.current, shape = RoundedCornerShape(50)){}
}
CircularProgressIndicator(
Modifier

View File

@ -24,7 +24,9 @@ fun initApp() {
override fun cancelAllNotifications() = chat.simplex.common.model.NtfManager.cancelAllNotifications()
}
applyAppLocale()
initChatControllerAndRunMigrations(false)
if (DatabaseUtils.ksSelfDestructPassword.get() == null) {
initChatControllerAndRunMigrations()
}
// LALAL
//testCrypto()
}

View File

@ -167,7 +167,8 @@ actual fun PlatformTextField(
decorationBox = { innerTextField ->
Surface(
shape = RoundedCornerShape(18.dp),
border = BorderStroke(1.dp, MaterialTheme.colors.secondary)
border = BorderStroke(1.dp, MaterialTheme.colors.secondary),
contentColor = LocalContentColor.current
) {
Row(
Modifier.background(MaterialTheme.colors.background),

View File

@ -2,8 +2,7 @@ package chat.simplex.common.views.helpers
import androidx.compose.foundation.*
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material.MaterialTheme
import androidx.compose.material.Surface
import androidx.compose.material.*
import androidx.compose.runtime.*
import androidx.compose.ui.Modifier
import androidx.compose.ui.input.key.*
@ -39,7 +38,8 @@ actual fun DefaultDialog(
) {
Surface(
Modifier
.border(border = BorderStroke(1.dp, MaterialTheme.colors.secondary.copy(alpha = 0.3F)), shape = RoundedCornerShape(8))
.border(border = BorderStroke(1.dp, MaterialTheme.colors.secondary.copy(alpha = 0.3F)), shape = RoundedCornerShape(8)),
contentColor = LocalContentColor.current
) {
content()
}

View File

@ -12,7 +12,7 @@ constraints: zip +disable-bzip2 +disable-zstd
source-repository-package
type: git
location: https://github.com/simplex-chat/simplexmq.git
tag: 6d4834f306963e2d3f2f62af212fe855ea9c7595
tag: fa794d7878c82c370f1547f01e76f9691d229b92
source-repository-package
type: git

View File

@ -8,9 +8,9 @@ u="$USER"
tmp="$(mktemp -d -t)"
folder="$tmp/simplex-chat"
nix_ver="nix-2.15.1"
nix_ver="nix-2.19.2"
nix_url="https://releases.nixos.org/nix/$nix_ver/install"
nix_hash="67aa37f0115195d8ddf32b5d6f471f1e60ecca0fdb3e98bcf54bc147c3078640"
nix_hash="435f0d7e11f7c7dffeeab0ec9cc55723f6d3c03352379d785633cf4ddb5caf90"
nix_config="sandbox = true
max-jobs = auto
experimental-features = nix-command flakes"
@ -102,8 +102,19 @@ build() {
sed -i.bak '/android {/a lint {abortOnError = false}' "$folder/apps/multiplatform/android/build.gradle.kts"
for arch in $arches; do
android_simplex_lib="${folder}#hydraJobs.${arch}-android:lib:simplex-chat.x86_64-linux"
android_support_lib="${folder}#hydraJobs.${arch}-android:lib:support.x86_64-linux"
tag_full="$(git tag --points-at HEAD)"
tag_version="${tag_full%%-*}"
if [ "$arch" = "armv7a" ] && [ -n "$tag_full" ] ; then
git checkout "${tag_version}-armv7a"
android_simplex_lib="${folder}#hydraJobs.${arch}-android:lib:simplex-chat.x86_64-linux"
android_support_lib="${folder}#hydraJobs.${arch}-android:lib:support.x86_64-linux"
else
android_simplex_lib="${folder}#hydraJobs.x86_64-linux.${arch}-android:lib:simplex-chat"
android_support_lib="${folder}#hydraJobs.x86_64-linux.${arch}-android:lib:support"
fi
android_simplex_lib_output="${PWD}/result/pkg-${arch}-android-libsimplex.zip"
android_support_lib_output="${PWD}/result/pkg-${arch}-android-libsupport.zip"
@ -139,6 +150,10 @@ build() {
zipalign -p -f 4 "$tmp/$android_apk_output_final" "$PWD/$android_apk_output_final"
rm -rf "$libs_folder/$android_arch"
if [ "$arch" = "armv7a" ] && [ -n "$tag_full" ] ; then
git checkout "${tag_full}"
fi
done
}

View File

@ -1,5 +1,5 @@
{
"https://github.com/simplex-chat/simplexmq.git"."6d4834f306963e2d3f2f62af212fe855ea9c7595" = "1603nlzkncrl8kg9xb8yi4kjbk8d8gmyw7wzvlni7lgbf0hjrffz";
"https://github.com/simplex-chat/simplexmq.git"."fa794d7878c82c370f1547f01e76f9691d229b92" = "0fmgq7yy42rlpf4a0agz3149iqkw5cri85xppwgicl4i9c7bs9gi";
"https://github.com/simplex-chat/hs-socks.git"."a30cc7a79a08d8108316094f8f2f82a0c5e1ac51" = "0yasvnr7g91k76mjkamvzab2kvlb1g5pspjyjn2fr6v83swjhj38";
"https://github.com/simplex-chat/direct-sqlcipher.git"."f814ee68b16a9447fbb467ccc8f29bdd3546bfd9" = "1ql13f4kfwkbaq7nygkxgw84213i0zm7c1a8hwvramayxl38dq5d";
"https://github.com/simplex-chat/sqlcipher-simple.git"."a46bd361a19376c5211f1058908fc0ae6bf42446" = "1z0r78d8f0812kxbgsm735qf6xx8lvaz27k1a0b4a2m0sshpd5gl";

View File

@ -3,7 +3,7 @@
module Simplex.Chat.Mobile.Shared where
import qualified Data.ByteString as B
import Data.ByteString.Internal (ByteString (..), memcpy)
import Data.ByteString.Internal (ByteString (..))
import qualified Data.ByteString.Lazy as LB
import qualified Data.ByteString.Lazy.Internal as LB
import Foreign
@ -21,7 +21,7 @@ getByteString ptr len = do
putByteString :: Ptr Word8 -> ByteString -> IO ()
putByteString ptr (PS fp offset len) =
withForeignPtr fp $ \p -> memcpy ptr (p `plusPtr` offset) len
withForeignPtr fp $ \p -> copyBytes ptr (p `plusPtr` offset) len
{-# INLINE putByteString #-}
putLazyByteString :: Ptr Word8 -> LB.ByteString -> IO ()

View File

@ -415,6 +415,7 @@ xftpServerConfig =
logStatsStartTime = 0,
serverStatsLogFile = "tests/tmp/xftp-server-stats.daily.log",
serverStatsBackupFile = Nothing,
controlPort = Nothing,
transportConfig = defaultTransportServerConfig
}

View File

@ -16,11 +16,12 @@ import qualified Data.Aeson.TH as JQ
import Data.ByteString (ByteString)
import qualified Data.ByteString as B
import qualified Data.ByteString.Char8 as BS
import Data.ByteString.Internal (create, memcpy)
import Data.ByteString.Internal (create)
import qualified Data.ByteString.Lazy.Char8 as LB
import Data.Word (Word8, Word32)
import Foreign.C
import Foreign.Marshal.Alloc (mallocBytes)
import Foreign.Marshal.Utils (copyBytes)
import Foreign.Ptr
import Foreign.StablePtr
import Foreign.Storable (peek)
@ -291,7 +292,7 @@ testFileCApi fileName tmp = do
peek ptr' `shouldReturn` (0 :: Word8)
sz :: Word32 <- peek (ptr' `plusPtr` 1)
let sz' = fromIntegral sz
contents <- create sz' $ \toPtr -> memcpy toPtr (ptr' `plusPtr` 5) sz'
contents <- create sz' $ \toPtr -> copyBytes toPtr (ptr' `plusPtr` 5) sz'
contents `shouldBe` src
sz' `shouldBe` fromIntegral len