2022-01-31 21:28:07 +00:00
//
// S e t t i n g s V i e w . s w i f t
// S i m p l e X
//
// C r e a t e d b y E v g e n y P o b e r e z k i n o n 3 1 / 0 1 / 2 0 2 2 .
// C o p y r i g h t © 2 0 2 2 S i m p l e X C h a t . A l l r i g h t s r e s e r v e d .
//
import SwiftUI
2022-02-11 07:42:00 +00:00
let simplexTeamURL = URL ( string : " simplex:/contact#/?v=1&smp=smp%3A%2F%2FPQUV2eL0t7OStZOoAsPEV2QYWt4-xilbakvGUGOItUo%3D%40smp6.simplex.im%2FK1rslx-m5bpXVIdMZg9NLUZ_8JBm8xTt%23MCowBQYDK2VuAyEALDeVe-sG8mRY22LsXlPgiwTNs9dbiLrNuA7f3ZMAJ2w%3D " ) !
2022-03-18 09:23:01 +00:00
let appVersion = Bundle . main . object ( forInfoDictionaryKey : " CFBundleShortVersionString " ) as ? String
let appBuild = Bundle . main . object ( forInfoDictionaryKey : " CFBundleVersion " ) as ? String
2022-05-28 22:09:46 +04:00
let DEFAULT_SHOW_LA_NOTICE = " showLocalAuthenticationNotice "
let DEFAULT_LA_NOTICE_SHOWN = " localAuthenticationNoticeShown "
2022-05-28 14:58:52 +04:00
let DEFAULT_PERFORM_LA = " performLocalAuthentication "
2022-05-07 16:10:57 +01:00
let DEFAULT_USE_NOTIFICATIONS = " useNotifications "
let DEFAULT_PENDING_CONNECTIONS = " pendingConnections "
2022-05-27 16:36:33 +01:00
let DEFAULT_WEBRTC_POLICY_RELAY = " webrtcPolicyRelay "
let appDefaults : [ String : Any ] = [
2022-05-28 22:09:46 +04:00
DEFAULT_SHOW_LA_NOTICE : false ,
DEFAULT_LA_NOTICE_SHOWN : false ,
2022-05-28 14:58:52 +04:00
DEFAULT_PERFORM_LA : false ,
2022-05-27 16:36:33 +01:00
DEFAULT_USE_NOTIFICATIONS : false ,
DEFAULT_PENDING_CONNECTIONS : true ,
DEFAULT_WEBRTC_POLICY_RELAY : true
]
2022-05-07 16:10:57 +01:00
2022-05-09 09:52:09 +01:00
private var indent : CGFloat = 36
2022-01-31 21:28:07 +00:00
struct SettingsView : View {
2022-02-12 15:59:43 +00:00
@ Environment ( \ . colorScheme ) var colorScheme
2022-01-31 21:28:07 +00:00
@ EnvironmentObject var chatModel : ChatModel
2022-02-11 07:42:00 +00:00
@ Binding var showSettings : Bool
2022-05-28 22:09:46 +04:00
@ State var performLA : Bool = false
@ AppStorage ( DEFAULT_LA_NOTICE_SHOWN ) private var prefLANoticeShown = false
2022-05-28 14:58:52 +04:00
@ AppStorage ( DEFAULT_PERFORM_LA ) private var prefPerformLA = false
2022-05-07 16:10:57 +01:00
@ AppStorage ( DEFAULT_USE_NOTIFICATIONS ) private var useNotifications = false
@ AppStorage ( DEFAULT_PENDING_CONNECTIONS ) private var pendingConnections = true
2022-05-28 22:09:46 +04:00
@ State private var performLAToggleReset = false
2022-04-22 13:46:05 +01:00
@ State var showNotificationsAlert : Bool = false
@ State var whichNotificationsAlert = NotificationAlert . enable
2022-05-28 14:58:52 +04:00
@ State var alert : SettingsViewAlert ? = nil
enum SettingsViewAlert : Identifiable {
case laTurnedOnAlert
case laFailedAlert
case laUnavailableInstructionAlert
case laUnavailableTurningOffAlert
var id : SettingsViewAlert { get { self } }
}
2022-01-31 21:28:07 +00:00
var body : some View {
2022-02-03 07:16:29 +00:00
let user : User = chatModel . currentUser !
return NavigationView {
List {
Section ( " You " ) {
NavigationLink {
UserProfile ( )
. navigationTitle ( " Your chat profile " )
} label : {
2022-05-24 19:34:27 +01:00
ProfilePreview ( profileOf : user )
2022-03-25 22:13:01 +04:00
. padding ( . leading , - 8 )
2022-02-03 07:16:29 +00:00
}
NavigationLink {
UserAddress ( )
. navigationTitle ( " Your chat address " )
} label : {
2022-05-09 09:52:09 +01:00
settingsRow ( " qrcode " ) { Text ( " Your SimpleX contact address " ) }
2022-02-03 07:16:29 +00:00
}
}
2022-03-10 15:45:40 +04:00
Section ( " Settings " ) {
2022-05-28 14:58:52 +04:00
settingsRow ( " lock " ) {
2022-05-28 22:09:46 +04:00
Toggle ( " SimpleX Lock " , isOn : $ performLA )
2022-05-28 14:58:52 +04:00
}
2022-05-09 09:52:09 +01:00
settingsRow ( " link " ) {
2022-04-25 10:39:28 +01:00
Toggle ( " Show pending connections " , isOn : $ pendingConnections )
}
2022-03-10 15:45:40 +04:00
NavigationLink {
SMPServers ( )
. navigationTitle ( " Your SMP servers " )
} label : {
2022-05-09 09:52:09 +01:00
settingsRow ( " server.rack " ) { Text ( " SMP servers " ) }
2022-03-10 15:45:40 +04:00
}
2022-05-27 16:36:33 +01:00
NavigationLink {
CallSettings ( )
. navigationTitle ( " Call settings " )
} label : {
settingsRow ( " video " ) { Text ( " Call settings " ) }
}
2022-03-10 15:45:40 +04:00
}
2022-02-03 07:16:29 +00:00
2022-02-11 07:42:00 +00:00
Section ( " Help " ) {
NavigationLink {
2022-02-25 07:16:19 +00:00
ChatHelp ( showSettings : $ showSettings )
. navigationTitle ( " Welcome \( user . displayName ) ! " )
. frame ( maxHeight : . infinity , alignment : . top )
2022-02-11 07:42:00 +00:00
} label : {
2022-05-09 09:52:09 +01:00
settingsRow ( " questionmark " ) { Text ( " How to use it " ) }
}
NavigationLink {
SimpleXInfo ( onboarding : false )
. navigationBarTitle ( " " , displayMode : . inline )
. frame ( maxHeight : . infinity , alignment : . top )
} label : {
settingsRow ( " info " ) { Text ( " About SimpleX Chat " ) }
2022-02-11 07:42:00 +00:00
}
2022-02-25 07:16:19 +00:00
NavigationLink {
MarkdownHelp ( )
. navigationTitle ( " How to use markdown " )
. frame ( maxHeight : . infinity , alignment : . top )
} label : {
2022-05-09 09:52:09 +01:00
settingsRow ( " textformat " ) { Text ( " Markdown in messages " ) }
2022-02-25 07:16:19 +00:00
}
2022-05-09 09:52:09 +01:00
settingsRow ( " number " ) {
2022-02-11 07:42:00 +00:00
Button {
showSettings = false
DispatchQueue . main . async {
UIApplication . shared . open ( simplexTeamURL )
}
} label : {
2022-04-16 09:37:01 +01:00
Text ( " Chat with the developers " )
2022-02-11 07:42:00 +00:00
}
}
2022-05-09 09:52:09 +01:00
settingsRow ( " envelope " ) { Text ( " [Send us email](mailto:chat@simplex.chat) " ) }
2022-02-11 07:42:00 +00:00
}
2022-02-04 16:31:08 +00:00
Section ( " Develop " ) {
NavigationLink {
TerminalView ( )
} label : {
2022-05-09 09:52:09 +01:00
settingsRow ( " terminal " ) { Text ( " Chat console " ) }
2022-02-11 07:42:00 +00:00
}
2022-05-09 09:52:09 +01:00
ZStack ( alignment : . leading ) {
2022-02-12 15:59:43 +00:00
Image ( colorScheme = = . dark ? " github_light " : " github " )
2022-02-11 07:42:00 +00:00
. resizable ( )
. frame ( width : 24 , height : 24 )
2022-05-28 09:06:38 +01:00
. opacity ( 0.5 )
2022-02-11 07:42:00 +00:00
Text ( " Install [SimpleX Chat for terminal](https://github.com/simplex-chat/simplex-chat) " )
2022-05-09 09:52:09 +01:00
. padding ( . leading , indent )
2022-02-04 16:31:08 +00:00
}
2022-05-07 16:10:57 +01:00
// i f l e t t o k e n = c h a t M o d e l . d e v i c e T o k e n {
// H S t a c k {
// n o t i f i c a t i o n s I c o n ( )
// n o t i f i c a t i o n s T o g g l e ( t o k e n )
// }
// }
2022-05-28 09:06:38 +01:00
Text ( " v \( appVersion ? ? " ? " ) ( \( appBuild ? ? " ? " ) ) " )
2022-02-04 16:31:08 +00:00
}
2022-02-03 07:16:29 +00:00
}
2022-02-04 16:31:08 +00:00
. navigationTitle ( " Your settings " )
2022-05-28 22:09:46 +04:00
. onChange ( of : performLA ) { performLAToggle in
prefLANoticeShown = true
2022-05-28 14:58:52 +04:00
if performLAToggleReset {
performLAToggleReset = false
} else {
if performLAToggle {
enableLA ( )
} else {
disableLA ( )
}
}
}
. alert ( item : $ alert ) { alertItem in
switch alertItem {
case . laTurnedOnAlert : return laTurnedOnAlert ( )
case . laFailedAlert : return laFailedAlert ( )
case . laUnavailableInstructionAlert : return laUnavailableInstructionAlert ( )
case . laUnavailableTurningOffAlert : return laUnavailableTurningOffAlert ( )
}
}
}
}
private func enableLA ( ) {
authenticate ( reason : " Enable SimpleX Lock " ) { laResult in
switch laResult {
case . success :
prefPerformLA = true
alert = . laTurnedOnAlert
case . failed :
prefPerformLA = false
withAnimation ( ) {
2022-05-28 22:09:46 +04:00
performLA = false
2022-05-28 14:58:52 +04:00
}
performLAToggleReset = true
alert = . laFailedAlert
case . unavailable :
prefPerformLA = false
withAnimation ( ) {
2022-05-28 22:09:46 +04:00
performLA = false
2022-05-28 14:58:52 +04:00
}
performLAToggleReset = true
alert = . laUnavailableInstructionAlert
}
}
}
private func disableLA ( ) {
authenticate ( reason : " Disable SimpleX Lock " ) { laResult in
switch ( laResult ) {
case . success :
prefPerformLA = false
case . failed :
prefPerformLA = true
withAnimation ( ) {
2022-05-28 22:09:46 +04:00
performLA = true
2022-05-28 14:58:52 +04:00
}
performLAToggleReset = true
alert = . laFailedAlert
case . unavailable :
prefPerformLA = false
alert = . laUnavailableTurningOffAlert
}
2022-02-03 07:16:29 +00:00
}
2022-01-31 21:28:07 +00:00
}
2022-04-22 13:46:05 +01:00
2022-05-09 09:52:09 +01:00
private func settingsRow < Content : View > ( _ icon : String , content : @ escaping ( ) -> Content ) -> some View {
ZStack ( alignment : . leading ) {
2022-05-28 09:06:38 +01:00
Image ( systemName : icon ) . frame ( maxWidth : 24 , maxHeight : 24 , alignment : . center ) . foregroundColor ( . secondary )
2022-05-09 09:52:09 +01:00
content ( ) . padding ( . leading , indent )
}
}
2022-04-22 13:46:05 +01:00
enum NotificationAlert {
case enable
case error ( LocalizedStringKey , String )
}
2022-04-23 06:32:16 +01:00
private func notificationsIcon ( ) -> some View {
let icon : String
let color : Color
switch ( chatModel . tokenStatus ) {
case . new :
icon = " bolt "
color = . primary
case . registered :
icon = " bolt.fill "
color = . primary
case . invalid :
icon = " bolt.slash "
color = . primary
case . confirmed :
icon = " bolt.fill "
color = . yellow
case . active :
icon = " bolt.fill "
color = . green
case . expired :
icon = " bolt.slash.fill "
color = . primary
}
return Image ( systemName : icon )
. padding ( . trailing , 9 )
. foregroundColor ( color )
}
private func notificationsToggle ( _ token : String ) -> some View {
2022-04-22 13:46:05 +01:00
Toggle ( " Check messages " , isOn : $ useNotifications )
. onChange ( of : useNotifications ) { enable in
if enable {
showNotificationsAlert = true
whichNotificationsAlert = . enable
} else {
Task {
do {
try await apiDeleteToken ( token : token )
2022-04-23 06:32:16 +01:00
chatModel . tokenStatus = . new
2022-04-22 13:46:05 +01:00
}
catch {
DispatchQueue . main . async {
if let cr = error as ? ChatResponse {
let err = String ( describing : cr )
logger . error ( " apiDeleteToken error: \( err ) " )
showNotificationsAlert = true
whichNotificationsAlert = . error ( " Error deleting token " , err )
} else {
logger . error ( " apiDeleteToken unknown error: \( error . localizedDescription ) " )
}
}
}
}
}
}
. alert ( isPresented : $ showNotificationsAlert ) {
switch ( whichNotificationsAlert ) {
case . enable : return enableNotificationsAlert ( token )
case let . error ( title , err ) : return Alert ( title : Text ( title ) , message : Text ( err ) )
}
}
}
private func enableNotificationsAlert ( _ token : String ) -> Alert {
Alert (
title : Text ( " Enable notifications? (BETA) " ) ,
message : Text ( " The app can receive background notifications every 20 minutes to check the new messages. \n *Please note*: if you confirm, your device token will be sent to SimpleX Chat notifications server. " ) ,
primaryButton : . destructive ( Text ( " Confirm " ) ) {
Task {
do {
2022-04-23 06:32:16 +01:00
chatModel . tokenStatus = try await apiRegisterToken ( token : token )
2022-04-22 13:46:05 +01:00
} catch {
DispatchQueue . main . async {
useNotifications = false
if let cr = error as ? ChatResponse {
let err = String ( describing : cr )
logger . error ( " apiRegisterToken error: \( err ) " )
showNotificationsAlert = true
whichNotificationsAlert = . error ( " Error registering token " , err )
} else {
logger . error ( " apiRegisterToken unknown error: \( error . localizedDescription ) " )
}
}
}
}
} , secondaryButton : . cancel ( ) {
withAnimation ( ) { useNotifications = false }
}
)
}
2022-01-31 21:28:07 +00:00
}
2022-05-24 19:34:27 +01:00
struct ProfilePreview : View {
var profileOf : NamedChat
var color = Color ( uiColor : . tertiarySystemGroupedBackground )
var body : some View {
HStack {
ProfileImage ( imageStr : profileOf . image , color : color )
. frame ( width : 44 , height : 44 )
. padding ( . trailing , 6 )
. padding ( . vertical , 6 )
VStack ( alignment : . leading ) {
Text ( profileOf . displayName )
. fontWeight ( . bold )
. font ( . title2 )
Text ( profileOf . fullName )
}
}
}
}
2022-01-31 21:28:07 +00:00
struct SettingsView_Previews : PreviewProvider {
static var previews : some View {
let chatModel = ChatModel ( )
2022-02-08 09:19:25 +00:00
chatModel . currentUser = User . sampleData
2022-02-11 07:42:00 +00:00
@ State var showSettings = false
return SettingsView ( showSettings : $ showSettings )
2022-01-31 21:28:07 +00:00
. environmentObject ( chatModel )
}
}