2022-07-26 12:33:10 +04:00
//
// G r o u p M e m b e r I n f o V i e w . s w i f t
// S i m p l e X ( i O S )
//
// C r e a t e d b y J R o b e r t s o n 2 5 . 0 7 . 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
import SimpleXChat
struct GroupMemberInfoView : View {
@ EnvironmentObject var chatModel : ChatModel
2022-07-27 11:16:07 +04:00
@ Environment ( \ . dismiss ) var dismiss : DismissAction
2023-10-31 09:44:57 +00:00
@ State var groupInfo : GroupInfo
@ ObservedObject var groupMember : GMember
2022-12-12 08:59:35 +00:00
var navigation : Bool = false
@ State private var connectionStats : ConnectionStats ? = nil
@ State private var connectionCode : String ? = nil
2022-10-04 09:53:43 +01:00
@ State private var newRole : GroupMemberRole = . member
2022-07-27 11:16:07 +04:00
@ State private var alert : GroupMemberInfoViewAlert ?
2023-10-13 19:19:00 +04:00
@ State private var sheet : PlanAndConnectActionSheet ?
2022-08-02 17:00:12 +04:00
@ AppStorage ( DEFAULT_DEVELOPER_TOOLS ) private var developerTools = false
2023-05-24 15:29:27 +02:00
@ State private var justOpened = true
2023-09-20 12:26:16 +04:00
@ State private var progressIndicator = false
2022-07-26 12:33:10 +04:00
enum GroupMemberInfoViewAlert : Identifiable {
2023-10-31 09:44:57 +00:00
case blockMemberAlert ( mem : GroupMember )
case unblockMemberAlert ( mem : GroupMember )
2022-11-07 20:44:04 +04:00
case removeMemberAlert ( mem : GroupMember )
case changeMemberRoleAlert ( mem : GroupMember , role : GroupMemberRole )
2022-11-02 09:48:20 +00:00
case switchAddressAlert
2023-06-19 14:46:08 +04:00
case abortSwitchAddressAlert
2023-07-10 19:01:22 +04:00
case syncConnectionForceAlert
2023-10-13 19:19:00 +04:00
case planAndConnectAlert ( alert : PlanAndConnectAlert )
2022-10-06 15:02:58 +01:00
case error ( title : LocalizedStringKey , error : LocalizedStringKey )
2022-07-26 12:33:10 +04:00
2022-10-04 09:53:43 +01:00
var id : String {
switch self {
2023-10-31 09:44:57 +00:00
case let . blockMemberAlert ( mem ) : return " blockMemberAlert \( mem . groupMemberId ) "
case let . unblockMemberAlert ( mem ) : return " unblockMemberAlert \( mem . groupMemberId ) "
case let . removeMemberAlert ( mem ) : return " removeMemberAlert \( mem . groupMemberId ) "
case let . changeMemberRoleAlert ( mem , role ) : return " changeMemberRoleAlert \( mem . groupMemberId ) \( role . rawValue ) "
2022-11-02 09:48:20 +00:00
case . switchAddressAlert : return " switchAddressAlert "
2023-06-19 14:46:08 +04:00
case . abortSwitchAddressAlert : return " abortSwitchAddressAlert "
2023-07-10 19:01:22 +04:00
case . syncConnectionForceAlert : return " syncConnectionForceAlert "
2023-10-13 19:19:00 +04:00
case let . planAndConnectAlert ( alert ) : return " planAndConnectAlert \( alert . id ) "
2022-10-04 09:53:43 +01:00
case let . error ( title , _ ) : return " error \( title ) "
}
}
2022-07-26 12:33:10 +04:00
}
var body : some View {
2022-12-12 08:59:35 +00:00
if navigation {
NavigationView { groupMemberInfoView ( ) }
} else {
groupMemberInfoView ( )
}
}
2023-05-16 15:03:41 +04:00
private func knownDirectChat ( _ contactId : Int64 ) -> Chat ? {
if let chat = chatModel . getContactChat ( contactId ) ,
chat . chatInfo . contact ? . directOrUsed = = true {
return chat
} else {
return nil
}
}
2022-12-12 08:59:35 +00:00
private func groupMemberInfoView ( ) -> some View {
2023-09-20 12:26:16 +04:00
ZStack {
VStack {
2023-10-31 09:44:57 +00:00
let member = groupMember . wrapped
2023-09-20 12:26:16 +04:00
List {
groupMemberInfoHeader ( member )
. listRowBackground ( Color . clear )
2022-11-07 20:44:04 +04:00
2023-09-20 12:26:16 +04:00
if member . memberActive {
Section {
if let contactId = member . memberContactId , let chat = knownDirectChat ( contactId ) {
2022-12-12 15:27:52 +04:00
knownDirectChatButton ( chat )
} else if groupInfo . fullGroupPreferences . directMessages . on {
2023-09-20 12:26:16 +04:00
if let contactId = member . memberContactId {
newDirectChatButton ( contactId )
} else if member . activeConn ? . peerChatVRange . isCompatibleRange ( CREATE_MEMBER_CONTACT_VRANGE ) ? ? false {
createMemberContactButton ( )
}
2022-12-12 15:27:52 +04:00
}
2023-09-20 12:26:16 +04:00
if let code = connectionCode { verifyCodeButton ( code ) }
if let connStats = connectionStats ,
connStats . ratchetSyncAllowed {
synchronizeConnectionButton ( )
}
// } e l s e i f d e v e l o p e r T o o l s {
// s y n c h r o n i z e C o n n e c t i o n B u t t o n F o r c e ( )
// }
2022-11-07 20:44:04 +04:00
}
2022-08-29 14:08:46 +01:00
}
2022-08-26 17:27:38 +04:00
2023-09-20 12:26:16 +04:00
if let contactLink = member . contactLink {
Section {
2023-10-17 12:56:12 +04:00
SimpleXLinkQRCode ( uri : contactLink )
2023-09-20 12:26:16 +04:00
Button {
2023-10-17 12:56:12 +04:00
showShareSheet ( items : [ simplexChatLink ( contactLink ) ] )
2023-09-20 12:26:16 +04:00
} label : {
Label ( " Share address " , systemImage : " square.and.arrow.up " )
}
if let contactId = member . memberContactId {
if knownDirectChat ( contactId ) = = nil && ! groupInfo . fullGroupPreferences . directMessages . on {
connectViaAddressButton ( contactLink )
}
} else {
2023-05-16 15:03:41 +04:00
connectViaAddressButton ( contactLink )
}
2023-09-20 12:26:16 +04:00
} header : {
Text ( " Address " )
} footer : {
Text ( " You can share this address with your contacts to let them connect with ** \( member . displayName ) **. " )
2023-05-16 15:03:41 +04:00
}
2023-04-27 17:19:21 +04:00
}
2023-09-20 12:26:16 +04:00
Section ( " Member " ) {
infoRow ( " Group " , groupInfo . displayName )
2022-10-04 09:53:43 +01:00
2023-09-20 12:26:16 +04:00
if let roles = member . canChangeRoleTo ( groupInfo : groupInfo ) {
Picker ( " Change role " , selection : $ newRole ) {
ForEach ( roles ) { role in
Text ( role . text )
}
2022-10-22 18:40:21 +04:00
}
2023-09-20 12:26:16 +04:00
. frame ( height : 36 )
} else {
infoRow ( " Role " , member . memberRole . text )
2022-10-22 18:40:21 +04:00
}
2022-11-07 20:44:04 +04:00
2023-09-20 12:26:16 +04:00
// T O D O i n v i t e d b y - n e e d t o g e t c o n t a c t b y c o n t a c t i d
if let conn = member . activeConn {
let connLevelDesc = conn . connLevel = = 0 ? NSLocalizedString ( " direct " , comment : " connection level description " ) : String . localizedStringWithFormat ( NSLocalizedString ( " indirect (%d) " , comment : " connection level description " ) , conn . connLevel )
infoRow ( " Connection " , connLevelDesc )
}
2022-10-22 18:40:21 +04:00
}
2022-10-04 09:53:43 +01:00
2023-09-20 12:26:16 +04:00
if let connStats = connectionStats {
Section ( " Servers " ) {
// T O D O n e t w o r k c o n n e c t i o n s t a t u s
Button ( " Change receiving address " ) {
alert = . switchAddressAlert
2023-06-19 14:46:08 +04:00
}
2023-07-10 19:01:22 +04:00
. disabled (
2023-09-20 12:26:16 +04:00
connStats . rcvQueuesInfo . contains { $0 . rcvSwitchStatus != nil }
2023-07-10 19:01:22 +04:00
|| connStats . ratchetSyncSendProhibited
)
2023-09-20 12:26:16 +04:00
if connStats . rcvQueuesInfo . contains ( where : { $0 . rcvSwitchStatus != nil } ) {
Button ( " Abort changing address " ) {
alert = . abortSwitchAddressAlert
}
. disabled (
connStats . rcvQueuesInfo . contains { $0 . rcvSwitchStatus != nil && ! $0 . canAbortSwitch }
|| connStats . ratchetSyncSendProhibited
)
}
smpServers ( " Receiving via " , connStats . rcvQueuesInfo . map { $0 . rcvServer } )
smpServers ( " Sending via " , connStats . sndQueuesInfo . map { $0 . sndServer } )
2023-06-19 14:46:08 +04:00
}
2022-07-27 11:16:07 +04:00
}
2023-10-31 09:44:57 +00:00
Section {
if member . memberSettings . showMessages {
blockMemberButton ( member )
} else {
unblockMemberButton ( member )
}
if member . canBeRemoved ( groupInfo : groupInfo ) {
removeMemberButton ( member )
2023-09-20 12:26:16 +04:00
}
2022-11-01 20:30:53 +00:00
}
2022-07-26 12:33:10 +04:00
2023-09-20 12:26:16 +04:00
if developerTools {
Section ( " For console " ) {
infoRow ( " Local name " , member . localDisplayName )
infoRow ( " Database ID " , " \( member . groupMemberId ) " )
}
2022-07-27 11:16:07 +04:00
}
}
2023-09-20 12:26:16 +04:00
. navigationBarHidden ( true )
. onAppear {
if # unavailable ( iOS 16 ) {
// t h i s c o n d i t i o n p r e v e n t s r e - s e t t i n g p i c k e r
if ! justOpened { return }
}
justOpened = false
2023-12-13 11:27:28 +00:00
DispatchQueue . main . async {
newRole = member . memberRole
do {
let ( _ , stats ) = try apiGroupMemberInfo ( groupInfo . apiId , member . groupMemberId )
let ( mem , code ) = member . memberActive ? try apiGetGroupMemberCode ( groupInfo . apiId , member . groupMemberId ) : ( member , nil )
_ = chatModel . upsertGroupMember ( groupInfo , mem )
connectionStats = stats
connectionCode = code
} catch let error {
logger . error ( " apiGroupMemberInfo or apiGetGroupMemberCode error: \( responseError ( error ) ) " )
}
}
2023-05-24 15:29:27 +02:00
}
2023-10-31 09:44:57 +00:00
. onChange ( of : newRole ) { newRole in
2023-09-20 12:26:16 +04:00
if newRole != member . memberRole {
alert = . changeMemberRoleAlert ( mem : member , role : newRole )
}
2022-12-12 08:59:35 +00:00
}
2023-10-31 09:44:57 +00:00
. onChange ( of : member . memberRole ) { role in
newRole = role
}
2022-12-12 08:59:35 +00:00
}
2023-09-20 12:26:16 +04:00
. frame ( maxWidth : . infinity , maxHeight : . infinity , alignment : . top )
. alert ( item : $ alert ) { alertItem in
switch ( alertItem ) {
2023-10-31 09:44:57 +00:00
case let . blockMemberAlert ( mem ) : return blockMemberAlert ( groupInfo , mem )
case let . unblockMemberAlert ( mem ) : return unblockMemberAlert ( groupInfo , mem )
2023-09-20 12:26:16 +04:00
case let . removeMemberAlert ( mem ) : return removeMemberAlert ( mem )
case let . changeMemberRoleAlert ( mem , _ ) : return changeMemberRoleAlert ( mem )
case . switchAddressAlert : return switchAddressAlert ( switchMemberAddress )
case . abortSwitchAddressAlert : return abortSwitchAddressAlert ( abortSwitchMemberAddress )
case . syncConnectionForceAlert : return syncConnectionForceAlert ( { syncMemberConnection ( force : true ) } )
2023-10-13 19:19:00 +04:00
case let . planAndConnectAlert ( alert ) : return planAndConnectAlert ( alert , dismiss : true )
2023-09-20 12:26:16 +04:00
case let . error ( title , error ) : return Alert ( title : Text ( title ) , message : Text ( error ) )
2022-07-26 12:33:10 +04:00
}
}
2023-10-13 19:19:00 +04:00
. actionSheet ( item : $ sheet ) { s in planAndConnectActionSheet ( s , dismiss : true ) }
2023-09-20 12:26:16 +04:00
if progressIndicator {
ProgressView ( ) . scaleEffect ( 2 )
2023-05-16 15:03:41 +04:00
}
}
}
func connectViaAddressButton ( _ contactLink : String ) -> some View {
Button {
2023-10-13 19:19:00 +04:00
planAndConnect (
contactLink ,
showAlert : { alert = . planAndConnectAlert ( alert : $0 ) } ,
showActionSheet : { sheet = $0 } ,
dismiss : true ,
incognito : nil
)
2023-05-16 15:03:41 +04:00
} label : {
Label ( " Connect " , systemImage : " link " )
}
2022-07-26 12:33:10 +04:00
}
2022-12-07 17:30:15 +04:00
func knownDirectChatButton ( _ chat : Chat ) -> some View {
2022-08-26 17:27:38 +04:00
Button {
2022-12-07 17:30:15 +04:00
dismissAllSheets ( animated : true )
DispatchQueue . main . async {
chatModel . chatId = chat . id
2022-08-29 14:08:46 +01:00
}
2022-12-07 17:30:15 +04:00
} label : {
Label ( " Send direct message " , systemImage : " message " )
}
}
func newDirectChatButton ( _ contactId : Int64 ) -> some View {
Button {
do {
let chat = try apiGetChat ( type : . direct , id : contactId )
chatModel . addChat ( chat )
2022-08-26 17:27:38 +04:00
dismissAllSheets ( animated : true )
2022-11-21 08:37:13 +00:00
DispatchQueue . main . async {
chatModel . chatId = chat . id
}
2022-12-07 17:30:15 +04:00
} catch let error {
logger . error ( " openDirectChatButton apiGetChat error: \( responseError ( error ) ) " )
2022-08-26 17:27:38 +04:00
}
} label : {
Label ( " Send direct message " , systemImage : " message " )
}
}
2023-09-20 12:26:16 +04:00
func createMemberContactButton ( ) -> some View {
Button {
progressIndicator = true
Task {
do {
2023-10-31 09:44:57 +00:00
let memberContact = try await apiCreateMemberContact ( groupInfo . apiId , groupMember . groupMemberId )
2023-09-20 12:26:16 +04:00
await MainActor . run {
progressIndicator = false
chatModel . addChat ( Chat ( chatInfo : . direct ( contact : memberContact ) ) )
dismissAllSheets ( animated : true )
chatModel . chatId = memberContact . id
chatModel . setContactNetworkStatus ( memberContact , . connected )
}
} catch let error {
logger . error ( " createMemberContactButton apiCreateMemberContact error: \( responseError ( error ) ) " )
let a = getErrorAlert ( error , " Error creating member contact " )
await MainActor . run {
progressIndicator = false
alert = . error ( title : a . title , error : a . message )
}
}
}
} label : {
Label ( " Send direct message " , systemImage : " message " )
}
}
2022-11-07 20:44:04 +04:00
private func groupMemberInfoHeader ( _ mem : GroupMember ) -> some View {
2022-07-26 12:33:10 +04:00
VStack {
2022-11-07 20:44:04 +04:00
ProfileImage ( imageStr : mem . image , color : Color ( uiColor : . tertiarySystemFill ) )
2022-07-26 12:33:10 +04:00
. frame ( width : 192 , height : 192 )
. padding ( . top , 12 )
. padding ( )
2023-07-19 15:16:50 +04:00
if mem . verified {
(
Text ( Image ( systemName : " checkmark.shield " ) )
. foregroundColor ( . secondary )
. font ( . title2 )
+ Text ( " " )
+ Text ( mem . displayName )
. font ( . largeTitle )
)
. multilineTextAlignment ( . center )
. lineLimit ( 2 )
. padding ( . bottom , 2 )
} else {
2022-12-12 08:59:35 +00:00
Text ( mem . displayName )
. font ( . largeTitle )
2023-07-19 15:16:50 +04:00
. multilineTextAlignment ( . center )
. lineLimit ( 2 )
. padding ( . bottom , 2 )
2022-12-12 08:59:35 +00:00
}
2022-11-07 20:44:04 +04:00
if mem . fullName != " " && mem . fullName != mem . displayName {
Text ( mem . fullName )
2022-07-27 11:16:07 +04:00
. font ( . title2 )
2023-07-19 15:16:50 +04:00
. multilineTextAlignment ( . center )
. lineLimit ( 4 )
2022-07-27 11:16:07 +04:00
}
2022-07-26 12:33:10 +04:00
}
. frame ( maxWidth : . infinity , alignment : . center )
}
2022-12-12 08:59:35 +00:00
private func verifyCodeButton ( _ code : String ) -> some View {
2023-10-31 09:44:57 +00:00
let member = groupMember . wrapped
return NavigationLink {
2022-12-12 08:59:35 +00:00
VerifyCodeView (
displayName : member . displayName ,
connectionCode : code ,
connectionVerified : member . verified ,
verify : { code in
2023-10-31 09:44:57 +00:00
var member = groupMember . wrapped
2022-12-12 08:59:35 +00:00
if let r = apiVerifyGroupMember ( member . groupId , member . groupMemberId , connectionCode : code ) {
let ( verified , existingCode ) = r
let connCode = verified ? SecurityCode ( securityCode : existingCode , verifiedAt : . now ) : nil
connectionCode = existingCode
member . activeConn ? . connectionCode = connCode
2023-10-31 09:44:57 +00:00
_ = chatModel . upsertGroupMember ( groupInfo , member )
2022-12-12 08:59:35 +00:00
return r
}
return nil
}
)
. navigationBarTitleDisplayMode ( . inline )
. navigationTitle ( " Security code " )
} label : {
Label (
member . verified ? " View security code " : " Verify security code " ,
systemImage : member . verified ? " checkmark.shield " : " shield "
)
}
2023-07-10 19:01:22 +04:00
}
private func synchronizeConnectionButton ( ) -> some View {
Button {
syncMemberConnection ( force : false )
} label : {
Label ( " Fix connection " , systemImage : " exclamationmark.arrow.triangle.2.circlepath " )
. foregroundColor ( . orange )
}
}
2022-12-12 08:59:35 +00:00
2023-07-10 19:01:22 +04:00
private func synchronizeConnectionButtonForce ( ) -> some View {
Button {
alert = . syncConnectionForceAlert
} label : {
Label ( " Renegotiate encryption " , systemImage : " exclamationmark.triangle " )
. foregroundColor ( . red )
}
2022-12-12 08:59:35 +00:00
}
2023-10-31 09:44:57 +00:00
private func blockMemberButton ( _ mem : GroupMember ) -> some View {
Button ( role : . destructive ) {
alert = . blockMemberAlert ( mem : mem )
} label : {
Label ( " Block member " , systemImage : " hand.raised " )
. foregroundColor ( . red )
}
}
private func unblockMemberButton ( _ mem : GroupMember ) -> some View {
Button {
alert = . unblockMemberAlert ( mem : mem )
} label : {
Label ( " Unblock member " , systemImage : " hand.raised.slash " )
}
}
2022-12-12 08:59:35 +00:00
private func removeMemberButton ( _ mem : GroupMember ) -> some View {
2022-07-26 12:33:10 +04:00
Button ( role : . destructive ) {
2022-11-07 20:44:04 +04:00
alert = . removeMemberAlert ( mem : mem )
2022-07-26 12:33:10 +04:00
} label : {
Label ( " Remove member " , systemImage : " trash " )
2023-10-31 09:44:57 +00:00
. foregroundColor ( . red )
2022-07-26 12:33:10 +04:00
}
}
2022-11-07 20:44:04 +04:00
private func removeMemberAlert ( _ mem : GroupMember ) -> Alert {
2022-07-26 12:33:10 +04:00
Alert (
title : Text ( " Remove member? " ) ,
message : Text ( " Member will be removed from group - this cannot be undone! " ) ,
primaryButton : . destructive ( Text ( " Remove " ) ) {
Task {
do {
2022-11-07 20:44:04 +04:00
let updatedMember = try await apiRemoveMember ( groupInfo . groupId , mem . groupMemberId )
2022-08-09 13:43:19 +04:00
await MainActor . run {
2022-11-07 20:44:04 +04:00
_ = chatModel . upsertGroupMember ( groupInfo , updatedMember )
2022-08-09 13:43:19 +04:00
dismiss ( )
}
2022-07-26 12:33:10 +04:00
} catch let error {
2022-08-09 13:43:19 +04:00
logger . error ( " apiRemoveMember error: \( responseError ( error ) ) " )
2022-10-06 15:02:58 +01:00
let a = getErrorAlert ( error , " Error removing member " )
alert = . error ( title : a . title , error : a . message )
2022-07-26 12:33:10 +04:00
}
}
} ,
secondaryButton : . cancel ( )
)
}
2022-10-04 09:53:43 +01:00
2022-11-07 20:44:04 +04:00
private func changeMemberRoleAlert ( _ mem : GroupMember ) -> Alert {
2022-10-04 09:53:43 +01:00
Alert (
title : Text ( " Change member role? " ) ,
2022-11-07 20:44:04 +04:00
message : mem . memberCurrent ? Text ( " Member role will be changed to \" \( newRole . text ) \" . All group members will be notified. " ) : Text ( " Member role will be changed to \" \( newRole . text ) \" . The member will receive a new invitation. " ) ,
2022-10-04 09:53:43 +01:00
primaryButton : . default ( Text ( " Change " ) ) {
Task {
do {
2022-11-07 20:44:04 +04:00
let updatedMember = try await apiMemberRole ( groupInfo . groupId , mem . groupMemberId , newRole )
2022-10-04 09:53:43 +01:00
await MainActor . run {
2022-11-07 20:44:04 +04:00
_ = chatModel . upsertGroupMember ( groupInfo , updatedMember )
2022-10-04 09:53:43 +01:00
}
2022-11-07 20:44:04 +04:00
2022-10-04 09:53:43 +01:00
} catch let error {
2022-11-07 20:44:04 +04:00
newRole = mem . memberRole
2022-10-04 09:53:43 +01:00
logger . error ( " apiMemberRole error: \( responseError ( error ) ) " )
2022-10-06 15:02:58 +01:00
let a = getErrorAlert ( error , " Error changing role " )
alert = . error ( title : a . title , error : a . message )
2022-10-04 09:53:43 +01:00
}
}
} ,
secondaryButton : . cancel {
2022-11-07 20:44:04 +04:00
newRole = mem . memberRole
2022-10-04 09:53:43 +01:00
}
)
}
2022-11-02 09:48:20 +00:00
private func switchMemberAddress ( ) {
Task {
do {
2023-10-31 09:44:57 +00:00
let stats = try apiSwitchGroupMember ( groupInfo . apiId , groupMember . groupMemberId )
2023-07-10 19:01:22 +04:00
connectionStats = stats
await MainActor . run {
2023-10-31 09:44:57 +00:00
chatModel . updateGroupMemberConnectionStats ( groupInfo , groupMember . wrapped , stats )
2023-07-10 19:01:22 +04:00
dismiss ( )
}
2022-11-02 09:48:20 +00:00
} catch let error {
logger . error ( " switchMemberAddress apiSwitchGroupMember error: \( responseError ( error ) ) " )
let a = getErrorAlert ( error , " Error changing address " )
await MainActor . run {
alert = . error ( title : a . title , error : a . message )
}
}
}
}
2023-06-19 14:46:08 +04:00
private func abortSwitchMemberAddress ( ) {
Task {
do {
2023-10-31 09:44:57 +00:00
let stats = try apiAbortSwitchGroupMember ( groupInfo . apiId , groupMember . groupMemberId )
2023-06-19 14:46:08 +04:00
connectionStats = stats
2023-07-10 19:01:22 +04:00
await MainActor . run {
2023-10-31 09:44:57 +00:00
chatModel . updateGroupMemberConnectionStats ( groupInfo , groupMember . wrapped , stats )
2023-07-10 19:01:22 +04:00
}
2023-06-19 14:46:08 +04:00
} catch let error {
logger . error ( " abortSwitchMemberAddress apiAbortSwitchGroupMember error: \( responseError ( error ) ) " )
let a = getErrorAlert ( error , " Error aborting address change " )
await MainActor . run {
alert = . error ( title : a . title , error : a . message )
}
}
}
}
2023-07-10 19:01:22 +04:00
private func syncMemberConnection ( force : Bool ) {
Task {
do {
2023-10-31 09:44:57 +00:00
let ( mem , stats ) = try apiSyncGroupMemberRatchet ( groupInfo . apiId , groupMember . groupMemberId , force )
2023-07-10 19:01:22 +04:00
connectionStats = stats
await MainActor . run {
chatModel . updateGroupMemberConnectionStats ( groupInfo , mem , stats )
dismiss ( )
}
} catch let error {
logger . error ( " syncMemberConnection apiSyncGroupMemberRatchet error: \( responseError ( error ) ) " )
let a = getErrorAlert ( error , " Error synchronizing connection " )
await MainActor . run {
alert = . error ( title : a . title , error : a . message )
}
}
}
}
2022-07-26 12:33:10 +04:00
}
2023-10-31 09:44:57 +00:00
func blockMemberAlert ( _ gInfo : GroupInfo , _ mem : GroupMember ) -> Alert {
Alert (
title : Text ( " Block member? " ) ,
message : Text ( " All new messages from \( mem . chatViewName ) will be hidden! " ) ,
primaryButton : . destructive ( Text ( " Block " ) ) {
toggleShowMemberMessages ( gInfo , mem , false )
} ,
secondaryButton : . cancel ( )
)
}
func unblockMemberAlert ( _ gInfo : GroupInfo , _ mem : GroupMember ) -> Alert {
Alert (
title : Text ( " Unblock member? " ) ,
message : Text ( " Messages from \( mem . chatViewName ) will be shown! " ) ,
primaryButton : . default ( Text ( " Unblock " ) ) {
toggleShowMemberMessages ( gInfo , mem , true )
} ,
secondaryButton : . cancel ( )
)
}
func toggleShowMemberMessages ( _ gInfo : GroupInfo , _ member : GroupMember , _ showMessages : Bool ) {
var memberSettings = member . memberSettings
memberSettings . showMessages = showMessages
updateMemberSettings ( gInfo , member , memberSettings )
}
func updateMemberSettings ( _ gInfo : GroupInfo , _ member : GroupMember , _ memberSettings : GroupMemberSettings ) {
Task {
do {
try await apiSetMemberSettings ( gInfo . groupId , member . groupMemberId , memberSettings )
await MainActor . run {
var mem = member
mem . memberSettings = memberSettings
_ = ChatModel . shared . upsertGroupMember ( gInfo , mem )
}
} catch let error {
logger . error ( " apiSetMemberSettings error \( responseError ( error ) ) " )
}
}
}
2022-07-26 12:33:10 +04:00
struct GroupMemberInfoView_Previews : PreviewProvider {
static var previews : some View {
2022-11-01 20:30:53 +00:00
GroupMemberInfoView (
groupInfo : GroupInfo . sampleData ,
2023-10-31 09:44:57 +00:00
groupMember : GMember . sampleData
2022-11-01 20:30:53 +00:00
)
2022-07-26 12:33:10 +04:00
}
}