Merge branch 'stable'

This commit is contained in:
Evgeny Poberezkin
2024-12-25 23:18:41 +00:00
8 changed files with 113 additions and 81 deletions
@@ -53,7 +53,7 @@ struct OperatorView: View {
ServersErrorView(errStr: errStr)
} else {
switch (userServers[operatorIndex].operator_.conditionsAcceptance) {
case let .accepted(acceptedAt):
case let .accepted(acceptedAt, _):
if let acceptedAt = acceptedAt {
Text("Conditions accepted on: \(conditionsTimestamp(acceptedAt)).")
.foregroundColor(theme.colors.secondary)
+20 -20
View File
@@ -1935,7 +1935,7 @@
CLANG_TIDY_MISC_REDUNDANT_EXPRESSION = YES;
CODE_SIGN_ENTITLEMENTS = "SimpleX (iOS).entitlements";
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 256;
CURRENT_PROJECT_VERSION = 257;
DEAD_CODE_STRIPPING = YES;
DEVELOPMENT_TEAM = 5NN7GUYB6T;
ENABLE_BITCODE = NO;
@@ -1960,7 +1960,7 @@
"@executable_path/Frameworks",
);
LLVM_LTO = YES_THIN;
MARKETING_VERSION = 6.2.2;
MARKETING_VERSION = 6.2.3;
PRODUCT_BUNDLE_IDENTIFIER = chat.simplex.app;
PRODUCT_NAME = SimpleX;
SDKROOT = iphoneos;
@@ -1984,7 +1984,7 @@
CLANG_TIDY_MISC_REDUNDANT_EXPRESSION = YES;
CODE_SIGN_ENTITLEMENTS = "SimpleX (iOS).entitlements";
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 256;
CURRENT_PROJECT_VERSION = 257;
DEAD_CODE_STRIPPING = YES;
DEVELOPMENT_TEAM = 5NN7GUYB6T;
ENABLE_BITCODE = NO;
@@ -2009,7 +2009,7 @@
"@executable_path/Frameworks",
);
LLVM_LTO = YES;
MARKETING_VERSION = 6.2.2;
MARKETING_VERSION = 6.2.3;
PRODUCT_BUNDLE_IDENTIFIER = chat.simplex.app;
PRODUCT_NAME = SimpleX;
SDKROOT = iphoneos;
@@ -2025,11 +2025,11 @@
buildSettings = {
ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 256;
CURRENT_PROJECT_VERSION = 257;
DEVELOPMENT_TEAM = 5NN7GUYB6T;
GENERATE_INFOPLIST_FILE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 15.0;
MARKETING_VERSION = 6.2.2;
MARKETING_VERSION = 6.2.3;
PRODUCT_BUNDLE_IDENTIFIER = "chat.simplex.Tests-iOS";
PRODUCT_NAME = "$(TARGET_NAME)";
SDKROOT = iphoneos;
@@ -2045,11 +2045,11 @@
buildSettings = {
ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 256;
CURRENT_PROJECT_VERSION = 257;
DEVELOPMENT_TEAM = 5NN7GUYB6T;
GENERATE_INFOPLIST_FILE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 15.0;
MARKETING_VERSION = 6.2.2;
MARKETING_VERSION = 6.2.3;
PRODUCT_BUNDLE_IDENTIFIER = "chat.simplex.Tests-iOS";
PRODUCT_NAME = "$(TARGET_NAME)";
SDKROOT = iphoneos;
@@ -2070,7 +2070,7 @@
CODE_SIGN_ENTITLEMENTS = "SimpleX NSE/SimpleX NSE.entitlements";
CODE_SIGN_IDENTITY = "Apple Development";
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 256;
CURRENT_PROJECT_VERSION = 257;
DEVELOPMENT_TEAM = 5NN7GUYB6T;
ENABLE_BITCODE = NO;
GCC_OPTIMIZATION_LEVEL = s;
@@ -2085,7 +2085,7 @@
"@executable_path/../../Frameworks",
);
LLVM_LTO = YES;
MARKETING_VERSION = 6.2.2;
MARKETING_VERSION = 6.2.3;
PRODUCT_BUNDLE_IDENTIFIER = "chat.simplex.app.SimpleX-NSE";
PRODUCT_NAME = "$(TARGET_NAME)";
PROVISIONING_PROFILE_SPECIFIER = "";
@@ -2107,7 +2107,7 @@
CODE_SIGN_ENTITLEMENTS = "SimpleX NSE/SimpleX NSE.entitlements";
CODE_SIGN_IDENTITY = "Apple Development";
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 256;
CURRENT_PROJECT_VERSION = 257;
DEVELOPMENT_TEAM = 5NN7GUYB6T;
ENABLE_BITCODE = NO;
ENABLE_CODE_COVERAGE = NO;
@@ -2122,7 +2122,7 @@
"@executable_path/../../Frameworks",
);
LLVM_LTO = YES;
MARKETING_VERSION = 6.2.2;
MARKETING_VERSION = 6.2.3;
PRODUCT_BUNDLE_IDENTIFIER = "chat.simplex.app.SimpleX-NSE";
PRODUCT_NAME = "$(TARGET_NAME)";
PROVISIONING_PROFILE_SPECIFIER = "";
@@ -2144,7 +2144,7 @@
CLANG_TIDY_BUGPRONE_REDUNDANT_BRANCH_CONDITION = YES;
CLANG_TIDY_MISC_REDUNDANT_EXPRESSION = YES;
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 256;
CURRENT_PROJECT_VERSION = 257;
DEFINES_MODULE = YES;
DEVELOPMENT_TEAM = 5NN7GUYB6T;
DYLIB_COMPATIBILITY_VERSION = 1;
@@ -2170,7 +2170,7 @@
"$(PROJECT_DIR)/Libraries/sim",
);
LLVM_LTO = YES;
MARKETING_VERSION = 6.2.2;
MARKETING_VERSION = 6.2.3;
PRODUCT_BUNDLE_IDENTIFIER = chat.simplex.SimpleXChat;
PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)";
SDKROOT = iphoneos;
@@ -2195,7 +2195,7 @@
CLANG_TIDY_BUGPRONE_REDUNDANT_BRANCH_CONDITION = YES;
CLANG_TIDY_MISC_REDUNDANT_EXPRESSION = YES;
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 256;
CURRENT_PROJECT_VERSION = 257;
DEFINES_MODULE = YES;
DEVELOPMENT_TEAM = 5NN7GUYB6T;
DYLIB_COMPATIBILITY_VERSION = 1;
@@ -2221,7 +2221,7 @@
"$(PROJECT_DIR)/Libraries/sim",
);
LLVM_LTO = YES;
MARKETING_VERSION = 6.2.2;
MARKETING_VERSION = 6.2.3;
PRODUCT_BUNDLE_IDENTIFIER = chat.simplex.SimpleXChat;
PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)";
SDKROOT = iphoneos;
@@ -2246,7 +2246,7 @@
CLANG_CXX_LANGUAGE_STANDARD = "gnu++20";
CODE_SIGN_ENTITLEMENTS = "SimpleX SE/SimpleX SE.entitlements";
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 256;
CURRENT_PROJECT_VERSION = 257;
DEVELOPMENT_TEAM = 5NN7GUYB6T;
ENABLE_USER_SCRIPT_SANDBOXING = YES;
GCC_C_LANGUAGE_STANDARD = gnu17;
@@ -2261,7 +2261,7 @@
"@executable_path/../../Frameworks",
);
LOCALIZATION_PREFERS_STRING_CATALOGS = YES;
MARKETING_VERSION = 6.2.2;
MARKETING_VERSION = 6.2.3;
PRODUCT_BUNDLE_IDENTIFIER = "chat.simplex.app.SimpleX-SE";
PRODUCT_NAME = "$(TARGET_NAME)";
SDKROOT = iphoneos;
@@ -2280,7 +2280,7 @@
CLANG_CXX_LANGUAGE_STANDARD = "gnu++20";
CODE_SIGN_ENTITLEMENTS = "SimpleX SE/SimpleX SE.entitlements";
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 256;
CURRENT_PROJECT_VERSION = 257;
DEVELOPMENT_TEAM = 5NN7GUYB6T;
ENABLE_USER_SCRIPT_SANDBOXING = YES;
GCC_C_LANGUAGE_STANDARD = gnu17;
@@ -2295,7 +2295,7 @@
"@executable_path/../../Frameworks",
);
LOCALIZATION_PREFERS_STRING_CATALOGS = YES;
MARKETING_VERSION = 6.2.2;
MARKETING_VERSION = 6.2.3;
PRODUCT_BUNDLE_IDENTIFIER = "chat.simplex.app.SimpleX-SE";
PRODUCT_NAME = "$(TARGET_NAME)";
SDKROOT = iphoneos;
+3 -3
View File
@@ -1324,7 +1324,7 @@ public struct ServerOperatorConditions: Decodable {
}
public enum ConditionsAcceptance: Equatable, Codable, Hashable {
case accepted(acceptedAt: Date?)
case accepted(acceptedAt: Date?, autoAccepted: Bool)
// If deadline is present, it means there's a grace period to review and accept conditions during which user can continue to use the operator.
// No deadline indicates it's required to accept conditions for the operator to start using it.
case required(deadline: Date?)
@@ -1398,7 +1398,7 @@ public struct ServerOperator: Identifiable, Equatable, Codable {
tradeName: "SimpleX Chat",
legalName: "SimpleX Chat Ltd",
serverDomains: ["simplex.im"],
conditionsAcceptance: .accepted(acceptedAt: nil),
conditionsAcceptance: .accepted(acceptedAt: nil, autoAccepted: false),
enabled: true,
smpRoles: ServerRoles(storage: true, proxy: true),
xftpRoles: ServerRoles(storage: true, proxy: true)
@@ -1431,7 +1431,7 @@ public struct UserOperatorServers: Identifiable, Equatable, Codable {
tradeName: "",
legalName: "",
serverDomains: [],
conditionsAcceptance: .accepted(acceptedAt: nil),
conditionsAcceptance: .accepted(acceptedAt: nil, autoAccepted: false),
enabled: false,
smpRoles: ServerRoles(storage: true, proxy: true),
xftpRoles: ServerRoles(storage: true, proxy: true)
@@ -470,53 +470,65 @@ class SimplexService: Service() {
)
}
private fun showBGServiceNoticeIgnoreOptimization(mode: NotificationsMode, showOffAlert: Boolean) = AlertManager.shared.showAlert {
val ignoreOptimization = {
AlertManager.shared.hideAlert()
askAboutIgnoringBatteryOptimization()
private var showingIgnoreNotification = false
private fun showBGServiceNoticeIgnoreOptimization(mode: NotificationsMode, showOffAlert: Boolean) {
// that's workaround for situation when the app receives onPause/onResume events multiple times
// (for example, after showing system alert for enabling notifications) which triggers showing that alert multiple times
if (showingIgnoreNotification) {
return
}
val disableNotifications = {
AlertManager.shared.hideAlert()
disableNotifications(mode, showOffAlert)
}
AlertDialog(
onDismissRequest = disableNotifications,
title = {
Row {
Icon(
painterResource(MR.images.ic_bolt),
contentDescription =
if (mode == NotificationsMode.SERVICE) stringResource(MR.strings.icon_descr_instant_notifications) else stringResource(MR.strings.periodic_notifications),
)
Text(
if (mode == NotificationsMode.SERVICE) stringResource(MR.strings.service_notifications) else stringResource(MR.strings.periodic_notifications),
fontWeight = FontWeight.Bold
)
}
},
text = {
Column {
Text(
if (mode == NotificationsMode.SERVICE) annotatedStringResource(MR.strings.to_preserve_privacy_simplex_has_background_service_instead_of_push_notifications_it_uses_a_few_pc_battery) else annotatedStringResource(MR.strings.periodic_notifications_desc),
Modifier.padding(bottom = 8.dp)
)
Text(annotatedStringResource(MR.strings.turn_off_battery_optimization))
if (platform.androidIsXiaomiDevice() && (mode == NotificationsMode.PERIODIC || mode == NotificationsMode.SERVICE)) {
Text(annotatedStringResource(MR.strings.xiaomi_ignore_battery_optimization),
Modifier.padding(top = 8.dp)
showingIgnoreNotification = true
AlertManager.shared.showAlert {
val ignoreOptimization = {
AlertManager.shared.hideAlert()
showingIgnoreNotification = false
askAboutIgnoringBatteryOptimization()
}
val disableNotifications = {
AlertManager.shared.hideAlert()
showingIgnoreNotification = false
disableNotifications(mode, showOffAlert)
}
AlertDialog(
onDismissRequest = disableNotifications,
title = {
Row {
Icon(
painterResource(MR.images.ic_bolt),
contentDescription =
if (mode == NotificationsMode.SERVICE) stringResource(MR.strings.icon_descr_instant_notifications) else stringResource(MR.strings.periodic_notifications),
)
Text(
if (mode == NotificationsMode.SERVICE) stringResource(MR.strings.service_notifications) else stringResource(MR.strings.periodic_notifications),
fontWeight = FontWeight.Bold
)
}
}
},
dismissButton = {
TextButton(onClick = disableNotifications) { Text(stringResource(MR.strings.disable_notifications_button), color = MaterialTheme.colors.error) }
},
confirmButton = {
TextButton(onClick = ignoreOptimization) { Text(stringResource(MR.strings.turn_off_battery_optimization_button)) }
},
shape = RoundedCornerShape(corner = CornerSize(25.dp))
)
},
text = {
Column {
Text(
if (mode == NotificationsMode.SERVICE) annotatedStringResource(MR.strings.to_preserve_privacy_simplex_has_background_service_instead_of_push_notifications_it_uses_a_few_pc_battery) else annotatedStringResource(MR.strings.periodic_notifications_desc),
Modifier.padding(bottom = 8.dp)
)
Text(annotatedStringResource(MR.strings.turn_off_battery_optimization))
if (platform.androidIsXiaomiDevice() && (mode == NotificationsMode.PERIODIC || mode == NotificationsMode.SERVICE)) {
Text(
annotatedStringResource(MR.strings.xiaomi_ignore_battery_optimization),
Modifier.padding(top = 8.dp)
)
}
}
},
dismissButton = {
TextButton(onClick = disableNotifications) { Text(stringResource(MR.strings.disable_notifications_button), color = MaterialTheme.colors.error) }
},
confirmButton = {
TextButton(onClick = ignoreOptimization) { Text(stringResource(MR.strings.turn_off_battery_optimization_button)) }
},
shape = RoundedCornerShape(corner = CornerSize(25.dp))
)
}
}
private fun showBGServiceNoticeSystemRestricted(mode: NotificationsMode, showOffAlert: Boolean) = AlertManager.shared.showAlert {
@@ -4,19 +4,31 @@ import android.Manifest
import android.os.Build
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import chat.simplex.common.platform.ntfManager
import com.google.accompanist.permissions.PermissionStatus
import com.google.accompanist.permissions.rememberPermissionState
import chat.simplex.common.model.ChatController.appPrefs
import chat.simplex.common.platform.*
import com.google.accompanist.permissions.*
@Composable
actual fun SetNotificationsModeAdditions() {
if (Build.VERSION.SDK_INT >= 33) {
val notificationsPermissionState = rememberPermissionState(Manifest.permission.POST_NOTIFICATIONS)
LaunchedEffect(notificationsPermissionState.status == PermissionStatus.Granted) {
if (notificationsPermissionState.status == PermissionStatus.Granted) {
ntfManager.androidCreateNtfChannelsMaybeShowAlert()
val canAsk = appPrefs.canAskToEnableNotifications.get()
if (notificationsPermissionState.status is PermissionStatus.Denied) {
if (notificationsPermissionState.status.shouldShowRationale || !canAsk) {
if (canAsk) {
appPrefs.canAskToEnableNotifications.set(false)
}
Log.w(TAG, "Notifications are disabled and nobody will ask to enable them")
} else {
notificationsPermissionState.launchPermissionRequest()
}
} else {
notificationsPermissionState.launchPermissionRequest()
if (!canAsk) {
// the user allowed notifications in system alert or manually in settings, allow to ask him next time if needed
appPrefs.canAskToEnableNotifications.set(true)
}
ntfManager.androidCreateNtfChannelsMaybeShowAlert()
}
}
} else {
@@ -80,6 +80,7 @@ class AppPreferences {
if (!runServiceInBackground.get()) NotificationsMode.OFF else NotificationsMode.default
) { NotificationsMode.values().firstOrNull { it.name == this } }
val notificationPreviewMode = mkStrPreference(SHARED_PREFS_NOTIFICATION_PREVIEW_MODE, NotificationPreviewMode.default.name)
val canAskToEnableNotifications = mkBoolPreference(SHARED_PREFS_CAN_ASK_TO_ENABLE_NOTIFICATIONS, true)
val backgroundServiceNoticeShown = mkBoolPreference(SHARED_PREFS_SERVICE_NOTICE_SHOWN, false)
val backgroundServiceBatteryNoticeShown = mkBoolPreference(SHARED_PREFS_SERVICE_BATTERY_NOTICE_SHOWN, false)
val autoRestartWorkerVersion = mkIntPreference(SHARED_PREFS_AUTO_RESTART_WORKER_VERSION, 0)
@@ -358,6 +359,7 @@ class AppPreferences {
private const val SHARED_PREFS_RUN_SERVICE_IN_BACKGROUND = "RunServiceInBackground"
private const val SHARED_PREFS_NOTIFICATIONS_MODE = "NotificationsMode"
private const val SHARED_PREFS_NOTIFICATION_PREVIEW_MODE = "NotificationPreviewMode"
private const val SHARED_PREFS_CAN_ASK_TO_ENABLE_NOTIFICATIONS = "CanAskToEnableNotifications"
private const val SHARED_PREFS_SERVICE_NOTICE_SHOWN = "BackgroundServiceNoticeShown"
private const val SHARED_PREFS_SERVICE_BATTERY_NOTICE_SHOWN = "BackgroundServiceBatteryNoticeShown"
private const val SHARED_PREFS_WEBRTC_POLICY_RELAY = "WebrtcPolicyRelay"
@@ -3813,7 +3815,7 @@ data class ServerOperatorConditionsDetail(
@Serializable()
sealed class ConditionsAcceptance {
@Serializable @SerialName("accepted") data class Accepted(val acceptedAt: Instant?) : ConditionsAcceptance()
@Serializable @SerialName("accepted") data class Accepted(val acceptedAt: Instant?, val autoAccepted: Boolean) : ConditionsAcceptance()
@Serializable @SerialName("required") data class Required(val deadline: Instant?) : ConditionsAcceptance()
val conditionsAccepted: Boolean
@@ -3857,7 +3859,7 @@ data class ServerOperator(
tradeName = "SimpleX Chat",
legalName = "SimpleX Chat Ltd",
serverDomains = listOf("simplex.im"),
conditionsAcceptance = ConditionsAcceptance.Accepted(acceptedAt = null),
conditionsAcceptance = ConditionsAcceptance.Accepted(acceptedAt = null, autoAccepted = false),
enabled = true,
smpRoles = ServerRoles(storage = true, proxy = true),
xftpRoles = ServerRoles(storage = true, proxy = true)
@@ -3939,7 +3941,7 @@ data class UserOperatorServers(
tradeName = "",
legalName = null,
serverDomains = emptyList(),
conditionsAcceptance = ConditionsAcceptance.Accepted(null),
conditionsAcceptance = ConditionsAcceptance.Accepted(null, autoAccepted = false),
enabled = false,
smpRoles = ServerRoles(storage = true, proxy = true),
xftpRoles = ServerRoles(storage = true, proxy = true)
@@ -197,6 +197,12 @@ fun ChatListView(chatModel: ChatModel, userPickerState: MutableStateFlow<Animate
}
}
if (appPlatform.isAndroid) {
val wasAllowedToSetupNotifications = rememberSaveable { mutableStateOf(false) }
val canEnableNotifications = remember { derivedStateOf { chatModel.chatRunning.value == true } }
if (wasAllowedToSetupNotifications.value || canEnableNotifications.value) {
SetNotificationsModeAdditions()
LaunchedEffect(Unit) { wasAllowedToSetupNotifications.value = true }
}
tryOrShowError("UserPicker", error = {}) {
UserPicker(
chatModel = chatModel,
+4 -4
View File
@@ -24,11 +24,11 @@ android.nonTransitiveRClass=true
kotlin.mpp.androidSourceSetLayoutVersion=2
kotlin.jvm.target=11
android.version_name=6.2.2
android.version_code=263
android.version_name=6.2.3
android.version_code=265
desktop.version_name=6.2.2
desktop.version_code=84
desktop.version_name=6.2.3
desktop.version_code=85
kotlin.version=1.9.23
gradle.plugin.version=8.2.0