2022-06-22 09:05:56 -07:00
//
// C a n n e d M e s s a g e s C o n f i g . s w i f t
2022-07-01 10:57:54 -07:00
// M e s h t a s t i c A p p l e
2022-06-22 09:05:56 -07:00
//
2022-07-01 10:57:54 -07:00
// C o p y r i g h t ( c ) G a r t h V a n d e r H o u w e n 6 / 2 2 / 2 2 .
2022-06-22 09:05:56 -07:00
//
2022-07-01 10:57:54 -07:00
import SwiftUI
2022-06-22 09:05:56 -07:00
2022-07-01 10:57:54 -07:00
struct CannedMessagesConfig : View {
@ Environment ( \ . managedObjectContext ) var context
@ EnvironmentObject var bleManager : BLEManager
2022-12-09 18:19:00 -08:00
@ Environment ( \ . dismiss ) private var goBack
2022-07-07 00:29:52 -07:00
var node : NodeInfoEntity ?
2022-07-01 10:57:54 -07:00
@ State private var isPresentingSaveConfirm : Bool = false
@ State var hasChanges = false
2022-07-09 06:42:30 -07:00
@ State var hasMessagesChanges = false
2022-07-01 10:57:54 -07:00
@ State var configPreset = 0
@ State var enabled = false
// / C a n n e d M e s s a g e M o d u l e w i l l s e n d s a b e l l c h a r a c t e r w i t h t h e m e s s a g e s .
@ State var sendBell : Bool = false
// / E n a b l e t h e r o t a r y e n c o d e r # 1 . T h i s i s a ' d u m b ' e n c o d e r s e n d i n g p u l s e s o n b o t h A a n d B p i n s w h i l e r o t a t i n g .
@ State var rotary1Enabled = false
// / E n a b l e t h e U p / D o w n / S e l e c t i n p u t d e v i c e . C a n b e R A K r o t a r y e n c o d e r o r 3 b u t t o n s . U s e s t h e a / b / p r e s s d e f i n i t i o n s f r o m i n p u t b r o k e r .
@ State var updown1Enabled : Bool = false
// / G P I O p i n f o r r o t a r y e n c o d e r A p o r t .
@ State var inputbrokerPinA = 0
// / G P I O p i n f o r r o t a r y e n c o d e r B p o r t .
@ State var inputbrokerPinB = 0
// / G P I O p i n f o r r o t a r y e n c o d e r P r e s s p o r t .
@ State var inputbrokerPinPress = 0
// / G e n e r a t e i n p u t e v e n t o n C W o f t h i s k i n d .
@ State var inputbrokerEventCw = 0
// / G e n e r a t e i n p u t e v e n t o n C C W o f t h i s k i n d .
@ State var inputbrokerEventCcw = 0
// / G e n e r a t e i n p u t e v e n t o n P r e s s o f t h i s k i n d .
@ State var inputbrokerEventPress = 0
2022-09-04 21:45:03 -07:00
@ State var messages = " "
2022-07-01 10:57:54 -07:00
var body : some View {
VStack {
Form {
2023-03-13 19:17:43 -07:00
if node != nil && node ? . metadata = = nil && node ? . num ? ? 0 != bleManager . connectedPeripheral ? . num ? ? 0 {
Text ( " There has been no response to a request for device metadata over the admin channel for this node. " )
. font ( . callout )
. foregroundColor ( . orange )
2023-03-14 12:44:10 -07:00
2023-03-13 19:17:43 -07:00
} else if node != nil && node ? . num ? ? 0 != bleManager . connectedPeripheral ? . num ? ? 0 {
// L e t u s e r s k n o w w h a t i s g o i n g o n i f t h e y a r e u s i n g r e m o t e a d m i n a n d d o n ' t h a v e t h e c o n f i g y e t
2023-03-14 12:44:10 -07:00
if node ? . cannedMessageConfig = = nil {
2023-03-13 19:17:43 -07:00
Text ( " Canned messages config data was requested over the admin channel but no response has been returned from the remote node. You can check the status of admin message requests in the admin message log. " )
. font ( . callout )
. foregroundColor ( . orange )
} else {
Text ( " Remote administration for: \( node ? . user ? . longName ? ? " Unknown " ) " )
. font ( . title3 )
2023-03-19 18:37:23 -07:00
. onAppear {
setCannedMessagesValues ( )
}
2023-03-13 19:17:43 -07:00
}
2023-03-14 12:44:10 -07:00
} else if node != nil && node ? . num ? ? 0 = = bleManager . connectedPeripheral ? . num ? ? 0 {
2023-03-13 19:17:43 -07:00
Text ( " Configuration for: \( node ? . user ? . longName ? ? " Unknown " ) " )
. font ( . title3 )
} else {
Text ( " Please connect to a radio to configure settings. " )
. font ( . callout )
. foregroundColor ( . orange )
}
2022-12-13 08:47:14 -08:00
Section ( header : Text ( " options " ) ) {
2022-07-01 10:57:54 -07:00
Toggle ( isOn : $ enabled ) {
2022-12-13 08:47:14 -08:00
Label ( " enabled " , systemImage : " list.bullet.rectangle.fill " )
2022-07-01 10:57:54 -07:00
}
. toggleStyle ( SwitchToggleStyle ( tint : . accentColor ) )
Toggle ( isOn : $ sendBell ) {
Label ( " Send Bell " , systemImage : " bell " )
}
. toggleStyle ( SwitchToggleStyle ( tint : . accentColor ) )
Picker ( " Configuration Presets " , selection : $ configPreset ) {
ForEach ( ConfigPresets . allCases ) { cp in
Text ( cp . description )
}
}
. pickerStyle ( DefaultPickerStyle ( ) )
. padding ( . top , 10 )
. padding ( . bottom , 10 )
}
2022-09-04 21:45:03 -07:00
HStack {
Label ( " Messages " , systemImage : " message.fill " )
2023-01-15 22:17:21 -07:00
TextField ( " Messages separate with | " , text : $ messages , axis : . vertical )
2022-09-04 21:45:03 -07:00
. foregroundColor ( . gray )
. autocapitalization ( . none )
. disableAutocorrection ( true )
2023-03-06 10:33:18 -08:00
. onChange ( of : messages , perform : { _ in
2022-09-04 21:45:03 -07:00
let totalBytes = messages . utf8 . count
// O n l y m e s s w i t h t h e v a l u e i f i t i s t o o b i g
if totalBytes > 198 {
let firstNBytes = Data ( messages . utf8 . prefix ( 198 ) )
if let maxBytesString = String ( data : firstNBytes , encoding : String . Encoding . utf8 ) {
// S e t t h e s h o r t N a m e b a c k t o t h e l a s t p l a c e w h e r e i t w a s t h e r i g h t s i z e
messages = maxBytesString
}
}
hasMessagesChanges = true
} )
. foregroundColor ( . gray )
2022-07-08 06:31:47 -07:00
}
2022-09-04 21:45:03 -07:00
. keyboardType ( . default )
2022-07-01 10:57:54 -07:00
Section ( header : Text ( " Control Type " ) ) {
Toggle ( isOn : $ rotary1Enabled ) {
Label ( " Rotary 1 " , systemImage : " dial.min " )
}
. toggleStyle ( SwitchToggleStyle ( tint : . accentColor ) )
. disabled ( updown1Enabled )
Toggle ( isOn : $ updown1Enabled ) {
Label ( " Up Down 1 " , systemImage : " arrow.up.arrow.down " )
}
. toggleStyle ( SwitchToggleStyle ( tint : . accentColor ) )
. disabled ( rotary1Enabled )
}
. disabled ( configPreset > 0 )
Section ( header : Text ( " Inputs " ) ) {
Picker ( " Pin A " , selection : $ inputbrokerPinA ) {
2023-04-03 17:48:58 -07:00
ForEach ( 0. . < 46 ) {
2022-07-01 10:57:54 -07:00
if $0 = = 0 {
2022-12-30 17:44:39 -08:00
Text ( " unset " )
2022-07-01 10:57:54 -07:00
} else {
Text ( " Pin \( $0 ) " )
}
}
}
. pickerStyle ( DefaultPickerStyle ( ) )
Text ( " GPIO pin for rotary encoder A port. " )
. font ( . caption )
Picker ( " Pin B " , selection : $ inputbrokerPinB ) {
2023-04-03 17:48:58 -07:00
ForEach ( 0. . < 46 ) {
2022-07-01 10:57:54 -07:00
if $0 = = 0 {
2022-12-30 17:44:39 -08:00
Text ( " unset " )
2022-07-01 10:57:54 -07:00
} else {
Text ( " Pin \( $0 ) " )
}
}
}
. pickerStyle ( DefaultPickerStyle ( ) )
Text ( " GPIO pin for rotary encoder B port. " )
. font ( . caption )
Picker ( " Press Pin " , selection : $ inputbrokerPinPress ) {
2023-04-03 17:48:58 -07:00
ForEach ( 0. . < 46 ) {
2022-07-01 10:57:54 -07:00
if $0 = = 0 {
2022-12-30 17:44:39 -08:00
Text ( " unset " )
2022-07-01 10:57:54 -07:00
} else {
Text ( " Pin \( $0 ) " )
}
}
}
. pickerStyle ( DefaultPickerStyle ( ) )
Text ( " GPIO pin for rotary encoder Press port. " )
. font ( . caption )
}
. disabled ( configPreset > 0 )
Section ( header : Text ( " Key Mapping " ) ) {
2022-08-07 08:31:39 -07:00
Picker ( " Clockwise Rotary Event " , selection : $ inputbrokerEventCw ) {
2022-07-01 10:57:54 -07:00
ForEach ( InputEventChars . allCases ) { iec in
Text ( iec . description )
}
}
. pickerStyle ( DefaultPickerStyle ( ) )
. padding ( . top , 10 )
. padding ( . bottom , 10 )
2022-08-07 08:31:39 -07:00
Picker ( " Counter Clockwise Rotary Event " , selection : $ inputbrokerEventCcw ) {
2022-07-01 10:57:54 -07:00
ForEach ( InputEventChars . allCases ) { iec in
Text ( iec . description )
}
}
. pickerStyle ( DefaultPickerStyle ( ) )
. padding ( . top , 10 )
. padding ( . bottom , 10 )
2022-08-07 08:31:39 -07:00
Picker ( " Encoder Press Event " , selection : $ inputbrokerEventPress ) {
2022-07-01 10:57:54 -07:00
ForEach ( InputEventChars . allCases ) { iec in
Text ( iec . description )
}
}
. pickerStyle ( DefaultPickerStyle ( ) )
. padding ( . top , 10 )
. padding ( . bottom , 10 )
}
. disabled ( configPreset > 0 )
}
2022-09-15 12:34:10 -07:00
. scrollDismissesKeyboard ( . immediately )
2023-02-01 09:19:45 -08:00
. disabled ( self . bleManager . connectedPeripheral = = nil || node ? . cannedMessageConfig = = nil )
2022-07-01 10:57:54 -07:00
Button {
isPresentingSaveConfirm = true
} label : {
2022-12-12 20:35:38 -08:00
Label ( " save " , systemImage : " square.and.arrow.down " )
2022-07-01 10:57:54 -07:00
}
2022-07-09 06:42:30 -07:00
. disabled ( bleManager . connectedPeripheral = = nil || ( ! hasChanges && ! hasMessagesChanges ) )
2022-07-01 10:57:54 -07:00
. buttonStyle ( . bordered )
. buttonBorderShape ( . capsule )
. controlSize ( . large )
. padding ( )
. confirmationDialog (
2022-12-13 08:47:14 -08:00
" are.you.sure " ,
2022-10-04 18:19:02 -07:00
isPresented : $ isPresentingSaveConfirm ,
titleVisibility : . visible
2022-07-01 10:57:54 -07:00
) {
2023-05-05 09:27:24 -07:00
let nodeName = bleManager . connectedPeripheral != nil ? bleManager . connectedPeripheral . longName : " unknown " . localized
let buttonText = String . localizedStringWithFormat ( " save.config %@ " . localized , nodeName )
2023-01-09 18:34:43 -08:00
Button ( buttonText ) {
2023-03-15 09:30:00 -07:00
let connectedNode = getNodeInfo ( id : bleManager . connectedPeripheral ? . num ? ? - 1 , context : context )
2022-07-09 06:42:30 -07:00
if hasChanges {
2023-03-15 09:30:00 -07:00
if connectedNode != nil {
var cmc = ModuleConfig . CannedMessageConfig ( )
cmc . enabled = enabled
cmc . sendBell = sendBell
cmc . rotary1Enabled = rotary1Enabled
cmc . updown1Enabled = updown1Enabled
if rotary1Enabled {
// / I n p u t e v e n t o r i g i n a c c e p t e d b y t h e c a n n e d m e s s a g e s
// / C a n b e e . g . " r o t E n c 1 " , " u p D o w n E n c 1 " , " c a r d k b " , o r k e y w o r d " _ a n y "
cmc . allowInputSource = " rotEnc1 "
} else if updown1Enabled {
cmc . allowInputSource = " upDown1 "
} else {
cmc . allowInputSource = " _any "
}
cmc . inputbrokerPinA = UInt32 ( inputbrokerPinA )
cmc . inputbrokerPinB = UInt32 ( inputbrokerPinB )
cmc . inputbrokerPinPress = UInt32 ( inputbrokerPinPress )
cmc . inputbrokerEventCw = InputEventChars ( rawValue : inputbrokerEventCw ) ! . protoEnumValue ( )
cmc . inputbrokerEventCcw = InputEventChars ( rawValue : inputbrokerEventCcw ) ! . protoEnumValue ( )
cmc . inputbrokerEventPress = InputEventChars ( rawValue : inputbrokerEventPress ) ! . protoEnumValue ( )
let adminMessageId = bleManager . saveCannedMessageModuleConfig ( config : cmc , fromUser : node ! . user ! , toUser : node ! . user ! , adminIndex : connectedNode ? . myInfo ? . adminIndex ? ? 0 )
if adminMessageId > 0 {
// S h o u l d s h o w a s a v e d s u c c e s s f u l l y a l e r t o n c e I k n o w t h a t t o b e t r u e
// f o r n o w j u s t d i s a b l e t h e b u t t o n a f t e r a s u c c e s s f u l s a v e
hasChanges = false
goBack ( )
}
2022-07-09 06:42:30 -07:00
}
2022-07-01 10:57:54 -07:00
}
2022-07-09 06:42:30 -07:00
if hasMessagesChanges {
2023-03-15 09:30:00 -07:00
let adminMessageId = bleManager . saveCannedMessageModuleMessages ( messages : messages , fromUser : node ! . user ! , toUser : node ! . user ! , adminIndex : connectedNode ? . myInfo ? . adminIndex ? ? 0 )
2022-07-09 06:42:30 -07:00
if adminMessageId > 0 {
// S h o u l d s h o w a s a v e d s u c c e s s f u l l y a l e r t o n c e I k n o w t h a t t o b e t r u e
// f o r n o w j u s t d i s a b l e t h e b u t t o n a f t e r a s u c c e s s f u l s a v e
hasMessagesChanges = false
2022-12-29 16:26:00 -08:00
if ! hasChanges {
2023-01-03 21:45:10 -08:00
bleManager . sendWantConfig ( )
2022-12-29 16:26:00 -08:00
goBack ( )
}
2022-07-09 06:42:30 -07:00
}
2022-07-02 12:18:20 -07:00
}
2022-07-01 10:57:54 -07:00
}
}
2022-12-30 11:08:59 -08:00
message : {
Text ( " config.save.confirm " )
}
2022-12-13 07:49:46 -08:00
. navigationTitle ( " canned.messages.config " )
2022-07-01 10:57:54 -07:00
. navigationBarItems ( trailing :
ZStack {
2022-07-01 19:44:25 -07:00
ConnectedDevice ( bluetoothOn : bleManager . isSwitchedOn , deviceConnected : bleManager . connectedPeripheral != nil , name : ( bleManager . connectedPeripheral != nil ) ? bleManager . connectedPeripheral . shortName : " ???? " )
2022-07-01 10:57:54 -07:00
} )
. onAppear {
2022-11-12 08:48:01 -08:00
self . bleManager . context = context
2023-03-19 18:37:23 -07:00
setCannedMessagesValues ( )
2023-03-06 10:33:18 -08:00
2023-02-01 09:19:45 -08:00
// N e e d t o r e q u e s t a C a n n e d M e s s a g e s M o d u l e C o n f i g f r o m t h e r e m o t e n o d e b e f o r e a l l o w i n g c h a n g e s
if bleManager . connectedPeripheral != nil && node ? . cannedMessageConfig = = nil {
print ( " empty canned messages module config " )
let connectedNode = getNodeInfo ( id : bleManager . connectedPeripheral . num , context : context )
2023-03-05 14:40:07 -08:00
if node != nil && connectedNode != nil {
2023-02-06 18:45:03 -08:00
_ = bleManager . requestCannedMessagesModuleConfig ( fromUser : connectedNode ! . user ! , toUser : node ! . user ! , adminIndex : connectedNode ? . myInfo ? . adminIndex ? ? 0 )
2023-02-01 09:19:45 -08:00
}
}
2022-07-01 10:57:54 -07:00
}
. onChange ( of : configPreset ) { newPreset in
2023-03-06 10:33:18 -08:00
2022-07-01 10:57:54 -07:00
if newPreset = = 1 {
2023-03-06 10:33:18 -08:00
2022-07-01 10:57:54 -07:00
// R A K R o t a r y E n c o d e r
2022-12-03 09:32:20 -08:00
updown1Enabled = true
2022-07-01 10:57:54 -07:00
rotary1Enabled = false
2022-10-13 07:45:23 -07:00
inputbrokerPinA = 4
inputbrokerPinB = 10
inputbrokerPinPress = 9
inputbrokerEventCw = InputEventChars . down . rawValue
inputbrokerEventCcw = InputEventChars . up . rawValue
inputbrokerEventPress = InputEventChars . select . rawValue
2023-03-06 10:33:18 -08:00
2022-07-01 10:57:54 -07:00
} else if newPreset = = 2 {
2023-03-06 10:33:18 -08:00
2022-10-30 17:48:26 -07:00
// C a r d K B / R A K K e y p a d
updown1Enabled = false
2022-07-01 10:57:54 -07:00
rotary1Enabled = false
2022-10-30 17:48:26 -07:00
inputbrokerPinA = 0
inputbrokerPinB = 0
inputbrokerPinPress = 0
inputbrokerEventCw = InputEventChars . none . rawValue
inputbrokerEventCcw = InputEventChars . none . rawValue
inputbrokerEventPress = InputEventChars . none . rawValue
2022-07-01 10:57:54 -07:00
}
2023-03-06 10:33:18 -08:00
2022-07-01 10:57:54 -07:00
hasChanges = true
}
. onChange ( of : enabled ) { newEnabled in
2022-07-11 16:18:16 -07:00
if node != nil && node ! . cannedMessageConfig != nil {
2022-07-08 06:31:47 -07:00
if newEnabled != node ! . cannedMessageConfig ! . enabled { hasChanges = true }
}
2022-07-01 10:57:54 -07:00
}
. onChange ( of : sendBell ) { newBell in
2022-07-11 16:18:16 -07:00
if node != nil && node ! . cannedMessageConfig != nil {
if newBell != node ! . cannedMessageConfig ! . sendBell { hasChanges = true }
}
2022-07-02 12:18:20 -07:00
}
2022-07-08 06:31:47 -07:00
. onChange ( of : rotary1Enabled ) { newRot1 in
2022-07-11 16:18:16 -07:00
if node != nil && node ! . cannedMessageConfig != nil {
if newRot1 != node ! . cannedMessageConfig ! . rotary1Enabled { hasChanges = true }
}
2022-07-08 06:31:47 -07:00
}
. onChange ( of : updown1Enabled ) { newUpDown in
2022-07-11 16:18:16 -07:00
if node != nil && node ! . cannedMessageConfig != nil {
if newUpDown != node ! . cannedMessageConfig ! . updown1Enabled { hasChanges = true }
}
2022-07-08 06:31:47 -07:00
}
2022-07-02 12:18:20 -07:00
. onChange ( of : inputbrokerPinA ) { newPinA in
2022-07-11 16:18:16 -07:00
if node != nil && node ! . cannedMessageConfig != nil {
if newPinA != node ! . cannedMessageConfig ! . inputbrokerPinA { hasChanges = true }
}
2022-07-02 12:18:20 -07:00
}
. onChange ( of : inputbrokerPinB ) { newPinB in
2022-07-11 16:18:16 -07:00
if node != nil && node ! . cannedMessageConfig != nil {
if newPinB != node ! . cannedMessageConfig ! . inputbrokerPinB { hasChanges = true }
}
2022-07-02 12:18:20 -07:00
}
. onChange ( of : inputbrokerPinPress ) { newPinPress in
2022-07-11 16:18:16 -07:00
if node != nil && node ! . cannedMessageConfig != nil {
if newPinPress != node ! . cannedMessageConfig ! . inputbrokerPinPress { hasChanges = true }
}
2022-07-02 12:18:20 -07:00
}
. onChange ( of : inputbrokerEventCw ) { newKeyA in
2022-07-11 16:18:16 -07:00
if node != nil && node ! . cannedMessageConfig != nil {
if newKeyA != node ! . cannedMessageConfig ! . inputbrokerEventCw { hasChanges = true }
}
2022-07-02 12:18:20 -07:00
}
. onChange ( of : inputbrokerEventCcw ) { newKeyB in
2022-07-11 16:18:16 -07:00
if node != nil && node ! . cannedMessageConfig != nil {
if newKeyB != node ! . cannedMessageConfig ! . inputbrokerEventCcw { hasChanges = true }
}
2022-07-02 12:18:20 -07:00
}
. onChange ( of : inputbrokerEventPress ) { newKeyPress in
2022-07-11 16:18:16 -07:00
if node != nil && node ! . cannedMessageConfig != nil {
if newKeyPress != node ! . cannedMessageConfig ! . inputbrokerEventPress { hasChanges = true }
}
2022-07-01 10:57:54 -07:00
}
}
}
2023-03-19 18:37:23 -07:00
func setCannedMessagesValues ( ) {
self . enabled = node ? . cannedMessageConfig ? . enabled ? ? false
self . sendBell = node ? . cannedMessageConfig ? . sendBell ? ? false
self . rotary1Enabled = node ? . cannedMessageConfig ? . rotary1Enabled ? ? false
self . updown1Enabled = node ? . cannedMessageConfig ? . updown1Enabled ? ? false
self . inputbrokerPinA = Int ( node ? . cannedMessageConfig ? . inputbrokerPinA ? ? 0 )
self . inputbrokerPinB = Int ( node ? . cannedMessageConfig ? . inputbrokerPinB ? ? 0 )
self . inputbrokerPinPress = Int ( node ? . cannedMessageConfig ? . inputbrokerPinPress ? ? 0 )
self . inputbrokerEventCw = Int ( node ? . cannedMessageConfig ? . inputbrokerEventCw ? ? 0 )
self . inputbrokerEventCcw = Int ( node ? . cannedMessageConfig ? . inputbrokerEventCcw ? ? 0 )
self . inputbrokerEventPress = Int ( node ? . cannedMessageConfig ? . inputbrokerEventPress ? ? 0 )
self . messages = node ? . cannedMessageConfig ? . messages ? ? " "
self . hasChanges = false
self . hasMessagesChanges = false
}
2022-07-01 10:57:54 -07:00
}