mirror of
https://github.com/meshtastic/Meshtastic-Apple.git
synced 2026-04-20 22:13:56 +00:00
Merge pull request #484 from Austinpayne/fix/slow-typing
fix: slow typing speed when lots of messages
This commit is contained in:
commit
8f50e7f447
8 changed files with 275 additions and 250 deletions
|
|
@ -10,8 +10,12 @@
|
|||
6DA39D8E2A92DC52007E311C /* MeshtasticAppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6DA39D8D2A92DC52007E311C /* MeshtasticAppDelegate.swift */; };
|
||||
6DEDA55A2A957B8E00321D2E /* DetectionSensorLog.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6DEDA5592A957B8E00321D2E /* DetectionSensorLog.swift */; };
|
||||
6DEDA55C2A9592F900321D2E /* MessageEntityExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6DEDA55B2A9592F900321D2E /* MessageEntityExtension.swift */; };
|
||||
B3E905B12B71F7F300654D07 /* TextMessageField.swift in Sources */ = {isa = PBXBuildFile; fileRef = B3E905B02B71F7F300654D07 /* TextMessageField.swift */; };
|
||||
C9697F9D279336B700250207 /* LocalMBTileOverlay.swift in Sources */ = {isa = PBXBuildFile; fileRef = C9697F9C279336B700250207 /* LocalMBTileOverlay.swift */; };
|
||||
C9697FA527933B8C00250207 /* SQLite in Frameworks */ = {isa = PBXBuildFile; productRef = C9697FA427933B8C00250207 /* SQLite */; };
|
||||
D9C9839D2B79CFD700BDBE6A /* TextMessageSize.swift in Sources */ = {isa = PBXBuildFile; fileRef = D9C9839C2B79CFD700BDBE6A /* TextMessageSize.swift */; };
|
||||
D9C983A02B79D0E800BDBE6A /* AlertButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = D9C9839F2B79D0E800BDBE6A /* AlertButton.swift */; };
|
||||
D9C983A22B79D1A600BDBE6A /* RequestPositionButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = D9C983A12B79D1A600BDBE6A /* RequestPositionButton.swift */; };
|
||||
DD007BAE2AA4E91200F5FA12 /* MyInfoEntityExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD007BAD2AA4E91200F5FA12 /* MyInfoEntityExtension.swift */; };
|
||||
DD007BB02AA5981000F5FA12 /* NodeInfoEntityExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD007BAF2AA5981000F5FA12 /* NodeInfoEntityExtension.swift */; };
|
||||
DD0D3D222A55CEB10066DB71 /* CocoaMQTT in Frameworks */ = {isa = PBXBuildFile; productRef = DD0D3D212A55CEB10066DB71 /* CocoaMQTT */; };
|
||||
|
|
@ -226,7 +230,11 @@
|
|||
6DEDA5592A957B8E00321D2E /* DetectionSensorLog.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DetectionSensorLog.swift; sourceTree = "<group>"; };
|
||||
6DEDA55B2A9592F900321D2E /* MessageEntityExtension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MessageEntityExtension.swift; sourceTree = "<group>"; };
|
||||
A65FA974296876BF00A97686 /* zh-Hans */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "zh-Hans"; path = "zh-Hans.lproj/Localizable.strings"; sourceTree = "<group>"; };
|
||||
B3E905B02B71F7F300654D07 /* TextMessageField.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TextMessageField.swift; sourceTree = "<group>"; };
|
||||
C9697F9C279336B700250207 /* LocalMBTileOverlay.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LocalMBTileOverlay.swift; sourceTree = "<group>"; };
|
||||
D9C9839C2B79CFD700BDBE6A /* TextMessageSize.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TextMessageSize.swift; sourceTree = "<group>"; };
|
||||
D9C9839F2B79D0E800BDBE6A /* AlertButton.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AlertButton.swift; sourceTree = "<group>"; };
|
||||
D9C983A12B79D1A600BDBE6A /* RequestPositionButton.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RequestPositionButton.swift; sourceTree = "<group>"; };
|
||||
DD007BAD2AA4E91200F5FA12 /* MyInfoEntityExtension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MyInfoEntityExtension.swift; sourceTree = "<group>"; };
|
||||
DD007BAF2AA5981000F5FA12 /* NodeInfoEntityExtension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NodeInfoEntityExtension.swift; sourceTree = "<group>"; };
|
||||
DD05296F2B77F454008E44CD /* MeshtasticDataModelV 26.xcdatamodel */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcdatamodel; path = "MeshtasticDataModelV 26.xcdatamodel"; sourceTree = "<group>"; };
|
||||
|
|
@ -487,6 +495,17 @@
|
|||
path = Custom;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
D9C9839E2B79D0C600BDBE6A /* TextMessageField */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
B3E905B02B71F7F300654D07 /* TextMessageField.swift */,
|
||||
D9C9839F2B79D0E800BDBE6A /* AlertButton.swift */,
|
||||
D9C983A12B79D1A600BDBE6A /* RequestPositionButton.swift */,
|
||||
D9C9839C2B79CFD700BDBE6A /* TextMessageSize.swift */,
|
||||
);
|
||||
path = TextMessageField;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
DD007BB12AA59B9A00F5FA12 /* CoreData */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
|
|
@ -818,6 +837,7 @@
|
|||
DDC2E18B26CE25A70042C5E4 /* Messages */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
D9C9839E2B79D0C600BDBE6A /* TextMessageField */,
|
||||
DDB8F4132A9EE5F000230ECE /* ChannelList.swift */,
|
||||
DD798B062915928D005217CD /* ChannelMessageList.swift */,
|
||||
DDB8F40F2A9EE5B400230ECE /* Messages.swift */,
|
||||
|
|
@ -1162,6 +1182,7 @@
|
|||
DDD6EEAF29BC024700383354 /* Firmware.swift in Sources */,
|
||||
DD77093B2AA1ABB8007A8BF0 /* BluetoothTips.swift in Sources */,
|
||||
DD90860E26F69BAE00DC5189 /* NodeMap.swift in Sources */,
|
||||
D9C9839D2B79CFD700BDBE6A /* TextMessageSize.swift in Sources */,
|
||||
DDC94FCE29CF55310082EA6E /* RtttlConfig.swift in Sources */,
|
||||
DD964FBD296E6B01007C176F /* EmojiOnlyTextField.swift in Sources */,
|
||||
DD8169FF272476C700F4AB02 /* LogDocument.swift in Sources */,
|
||||
|
|
@ -1238,6 +1259,7 @@
|
|||
DDC3B274283F411B00AC321C /* LastHeardText.swift in Sources */,
|
||||
DDDE5A1029AFE69700490C6C /* MeshActivityAttributes.swift in Sources */,
|
||||
DD1925B928CDA93900720036 /* SerialConfigEnums.swift in Sources */,
|
||||
D9C983A02B79D0E800BDBE6A /* AlertButton.swift in Sources */,
|
||||
DD86D4112881D16900BAEB7A /* WriteCsvFile.swift in Sources */,
|
||||
DDDB445029F8AC9C00EE2349 /* UIImage.swift in Sources */,
|
||||
DD86D40F2881BE4C00BAEB7A /* CsvDocument.swift in Sources */,
|
||||
|
|
@ -1271,6 +1293,7 @@
|
|||
DD0F791B28713C8A00A6FDAD /* AdminMessageList.swift in Sources */,
|
||||
DD3CC6BC28E366DF00FA9159 /* Meshtastic.xcdatamodeld in Sources */,
|
||||
DDC4C9FF2A8D982900CE201C /* DetectionSensorConfig.swift in Sources */,
|
||||
D9C983A22B79D1A600BDBE6A /* RequestPositionButton.swift in Sources */,
|
||||
DDDB26442AAC0206003AFCB7 /* NodeDetail.swift in Sources */,
|
||||
DD5E5210298EE33B00D21B61 /* telemetry.pb.swift in Sources */,
|
||||
DD77093F2AA1B146007A8BF0 /* UIColor.swift in Sources */,
|
||||
|
|
@ -1281,6 +1304,7 @@
|
|||
DD1925B728CDA5A400720036 /* CannedMessagesConfigEnums.swift in Sources */,
|
||||
DDDB444429F8A8DD00EE2349 /* Float.swift in Sources */,
|
||||
DDAB580F2B0DAFBC00147258 /* LocationEntityExtension.swift in Sources */,
|
||||
B3E905B12B71F7F300654D07 /* TextMessageField.swift in Sources */,
|
||||
DD5E5211298EE33B00D21B61 /* remote_hardware.pb.swift in Sources */,
|
||||
DD5E5204298EE33B00D21B61 /* xmodem.pb.swift in Sources */,
|
||||
DDE5B4062B227E3200FCDD05 /* TraceRouteEntityExtension.swift in Sources */,
|
||||
|
|
|
|||
|
|
@ -38,7 +38,7 @@ class BLEManager: NSObject, CBPeripheralDelegate, MqttClientProxyManagerDelegate
|
|||
var timeoutTimerCount = 0
|
||||
var positionTimer: Timer?
|
||||
var lastPosition: CLLocationCoordinate2D?
|
||||
let emptyNodeNum: UInt32 = 4294967295
|
||||
static let emptyNodeNum: UInt32 = 4294967295
|
||||
let mqttManager = MqttClientProxyManager.shared
|
||||
var wantRangeTestPackets = false
|
||||
var wantStoreAndForwardPackets = false
|
||||
|
|
@ -865,7 +865,7 @@ class BLEManager: NSObject, CBPeripheralDelegate, MqttClientProxyManagerDelegate
|
|||
if toUserNum > 0 {
|
||||
meshPacket.to = UInt32(toUserNum)
|
||||
} else {
|
||||
meshPacket.to = emptyNodeNum
|
||||
meshPacket.to = Self.emptyNodeNum
|
||||
}
|
||||
meshPacket.channel = UInt32(channel)
|
||||
meshPacket.from = UInt32(fromUserNum)
|
||||
|
|
@ -912,7 +912,7 @@ class BLEManager: NSObject, CBPeripheralDelegate, MqttClientProxyManagerDelegate
|
|||
var success = false
|
||||
let fromNodeNum = UInt32(connectedPeripheral.num)
|
||||
var meshPacket = MeshPacket()
|
||||
meshPacket.to = emptyNodeNum
|
||||
meshPacket.to = Self.emptyNodeNum
|
||||
meshPacket.from = fromNodeNum
|
||||
meshPacket.wantAck = true
|
||||
var dataMessage = DataMessage()
|
||||
|
|
|
|||
|
|
@ -9,27 +9,18 @@ import SwiftUI
|
|||
import CoreData
|
||||
|
||||
struct ChannelMessageList: View {
|
||||
|
||||
@StateObject var appState = AppState.shared
|
||||
@Environment(\.managedObjectContext) var context
|
||||
@EnvironmentObject var bleManager: BLEManager
|
||||
|
||||
enum Field: Hashable {
|
||||
case messageText
|
||||
}
|
||||
|
||||
// Keyboard State
|
||||
@State var typingMessage: String = ""
|
||||
@State private var totalBytes = 0
|
||||
var maxbytes = 228
|
||||
@FocusState var focusedField: Field?
|
||||
@FocusState var messageFieldFocused: Bool
|
||||
|
||||
@ObservedObject var myInfo: MyInfoEntity
|
||||
@ObservedObject var channel: ChannelEntity
|
||||
@State var showDeleteMessageAlert = false
|
||||
@State private var deleteMessageId: Int64 = 0
|
||||
@State private var replyMessageId: Int64 = 0
|
||||
@State private var sendPositionWithMessage: Bool = false
|
||||
@AppStorage("preferredPeripheralNum") private var preferredPeripheralNum = -1
|
||||
|
||||
var body: some View {
|
||||
|
|
@ -115,7 +106,7 @@ struct ChannelMessageList: View {
|
|||
}
|
||||
Button(action: {
|
||||
self.replyMessageId = message.messageId
|
||||
self.focusedField = .messageText
|
||||
self.messageFieldFocused = true
|
||||
print("I want to reply to \(message.messageId)")
|
||||
}) {
|
||||
Text("reply")
|
||||
|
|
@ -288,134 +279,14 @@ struct ChannelMessageList: View {
|
|||
}
|
||||
})
|
||||
}
|
||||
#if targetEnvironment(macCatalyst)
|
||||
HStack {
|
||||
Spacer()
|
||||
Button {
|
||||
let bell = "🔔 Alert Bell Character! \u{7}"
|
||||
print(bell)
|
||||
typingMessage += bell
|
||||
|
||||
} label: {
|
||||
Text("Alert Bell")
|
||||
Image(systemName: "bell.fill")
|
||||
.symbolRenderingMode(.hierarchical)
|
||||
.imageScale(.large).foregroundColor(.accentColor)
|
||||
}
|
||||
Spacer()
|
||||
Button {
|
||||
let userLongName = bleManager.connectedPeripheral != nil ? bleManager.connectedPeripheral.longName : "Unknown"
|
||||
sendPositionWithMessage = true
|
||||
typingMessage += "📍 " + userLongName + " has shared their position with you."
|
||||
} label: {
|
||||
Text("share.position")
|
||||
Image(systemName: "mappin.and.ellipse")
|
||||
.symbolRenderingMode(.hierarchical)
|
||||
.imageScale(.large).foregroundColor(.accentColor)
|
||||
}
|
||||
ProgressView("\("bytes".localized): \(totalBytes) / \(maxbytes)", value: Double(totalBytes), total: Double(maxbytes))
|
||||
.frame(width: 130)
|
||||
.padding(5)
|
||||
.font(.subheadline)
|
||||
.accentColor(.accentColor)
|
||||
.padding(.trailing)
|
||||
|
||||
TextMessageField(
|
||||
destination: .channel(channel.index),
|
||||
replyMessageId: $replyMessageId,
|
||||
isFocused: $messageFieldFocused
|
||||
) {
|
||||
context.refresh(channel, mergeChanges: true)
|
||||
}
|
||||
#endif
|
||||
HStack(alignment: .top) {
|
||||
|
||||
ZStack {
|
||||
TextField("message", text: $typingMessage, axis: .vertical)
|
||||
.onChange(of: typingMessage, perform: { value in
|
||||
totalBytes = value.utf8.count
|
||||
// Only mess with the value if it is too big
|
||||
if totalBytes > maxbytes {
|
||||
let firstNBytes = Data(typingMessage.utf8.prefix(maxbytes))
|
||||
if let maxBytesString = String(data: firstNBytes, encoding: String.Encoding.utf8) {
|
||||
// Set the message back to the last place where it was the right size
|
||||
typingMessage = maxBytesString
|
||||
} else {
|
||||
print("not a valid UTF-8 sequence")
|
||||
}
|
||||
}
|
||||
})
|
||||
.keyboardType(.default)
|
||||
.toolbar {
|
||||
ToolbarItemGroup(placement: .keyboard) {
|
||||
Button("dismiss.keyboard") {
|
||||
focusedField = nil
|
||||
}
|
||||
.font(.subheadline)
|
||||
Spacer()
|
||||
Button {
|
||||
let bell = "🔔 Alert Bell Character! \u{7}"
|
||||
print(bell)
|
||||
typingMessage += bell
|
||||
|
||||
} label: {
|
||||
Text("Alert")
|
||||
Image(systemName: "bell.fill")
|
||||
.symbolRenderingMode(.hierarchical)
|
||||
.imageScale(.large).foregroundColor(.accentColor)
|
||||
}
|
||||
Spacer()
|
||||
Button {
|
||||
let userLongName = bleManager.connectedPeripheral != nil ? bleManager.connectedPeripheral.longName : "Unknown"
|
||||
sendPositionWithMessage = true
|
||||
typingMessage = "📍 " + userLongName + " has shared their position with you."
|
||||
|
||||
} label: {
|
||||
Image(systemName: "mappin.and.ellipse")
|
||||
.symbolRenderingMode(.hierarchical)
|
||||
.imageScale(.large).foregroundColor(.accentColor)
|
||||
}
|
||||
|
||||
ProgressView("\("bytes".localized): \(totalBytes) / \(maxbytes)", value: Double(totalBytes), total: Double(maxbytes))
|
||||
.frame(width: 130)
|
||||
.padding(5)
|
||||
.font(.subheadline)
|
||||
.accentColor(.accentColor)
|
||||
}
|
||||
}
|
||||
.padding(.horizontal, 8)
|
||||
.focused($focusedField, equals: .messageText)
|
||||
.multilineTextAlignment(.leading)
|
||||
.frame(minHeight: 50)
|
||||
.keyboardShortcut(.defaultAction)
|
||||
.onSubmit {
|
||||
#if targetEnvironment(macCatalyst)
|
||||
if bleManager.sendMessage(message: typingMessage, toUserNum: 0, channel: channel.index, isEmoji: false, replyID: replyMessageId) {
|
||||
typingMessage = ""
|
||||
focusedField = nil
|
||||
replyMessageId = 0
|
||||
if sendPositionWithMessage {
|
||||
if bleManager.sendPosition(channel: Int32(channel.index), destNum: Int64(bleManager.emptyNodeNum), wantResponse: false) {
|
||||
print("Location Sent")
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
Text(typingMessage).opacity(0).padding(.all, 0)
|
||||
}
|
||||
.overlay(RoundedRectangle(cornerRadius: 20).stroke(.tertiary, lineWidth: 1))
|
||||
.padding(.bottom, 15)
|
||||
Button(action: {
|
||||
if bleManager.sendMessage(message: typingMessage, toUserNum: 0, channel: channel.index, isEmoji: false, replyID: replyMessageId) {
|
||||
typingMessage = ""
|
||||
focusedField = nil
|
||||
replyMessageId = 0
|
||||
if sendPositionWithMessage {
|
||||
if bleManager.sendPosition(channel: Int32(channel.index), destNum: Int64(bleManager.emptyNodeNum), wantResponse: false) {
|
||||
print("Location Sent")
|
||||
}
|
||||
}
|
||||
}
|
||||
}) {
|
||||
Image(systemName: "arrow.up.circle.fill").font(.largeTitle).foregroundColor(.accentColor)
|
||||
}
|
||||
|
||||
}
|
||||
.padding(.all, 15)
|
||||
}
|
||||
.navigationBarTitleDisplayMode(.inline)
|
||||
.toolbar {
|
||||
|
|
|
|||
21
Meshtastic/Views/Messages/TextMessageField/AlertButton.swift
Normal file
21
Meshtastic/Views/Messages/TextMessageField/AlertButton.swift
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
import SwiftUI
|
||||
|
||||
struct AlertButton: View {
|
||||
let action: () -> Void
|
||||
|
||||
var body: some View {
|
||||
Button(action: action) {
|
||||
Text("Alert")
|
||||
Image(systemName: "bell.fill")
|
||||
.symbolRenderingMode(.hierarchical)
|
||||
.imageScale(.large)
|
||||
.foregroundColor(.accentColor)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct AlertButtonPreview: PreviewProvider {
|
||||
static var previews: some View {
|
||||
AlertButton {}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,20 @@
|
|||
import SwiftUI
|
||||
|
||||
struct RequestPositionButton: View {
|
||||
let action: () -> Void
|
||||
|
||||
var body: some View {
|
||||
Button(action: action) {
|
||||
Image(systemName: "mappin.and.ellipse")
|
||||
.symbolRenderingMode(.hierarchical)
|
||||
.imageScale(.large)
|
||||
.foregroundColor(.accentColor)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct RequestPositionButtonPreview: PreviewProvider {
|
||||
static var previews: some View {
|
||||
RequestPositionButton {}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,170 @@
|
|||
import SwiftUI
|
||||
|
||||
struct TextMessageField: View {
|
||||
static let maxbytes = 228
|
||||
@EnvironmentObject var bleManager: BLEManager
|
||||
|
||||
let destination: Destination
|
||||
@Binding var replyMessageId: Int64
|
||||
@FocusState.Binding var isFocused: Bool
|
||||
let onSubmit: () -> Void
|
||||
|
||||
enum Destination {
|
||||
case user(Int64)
|
||||
case channel(Int32)
|
||||
}
|
||||
|
||||
@State private var typingMessage: String = ""
|
||||
@State private var totalBytes = 0
|
||||
@State private var sendPositionWithMessage = false
|
||||
|
||||
var body: some View {
|
||||
#if targetEnvironment(macCatalyst)
|
||||
HStack {
|
||||
if destination.showAlertButton {
|
||||
Spacer()
|
||||
AlertButton { typingMessage += "🔔 Alert Bell Character! \u{7}" }
|
||||
}
|
||||
Spacer()
|
||||
RequestPositionButton(action: requestPosition)
|
||||
TextMessageSize(maxbytes: Self.maxbytes, totalBytes: totalBytes).padding(.trailing)
|
||||
}
|
||||
#endif
|
||||
|
||||
HStack(alignment: .top) {
|
||||
ZStack {
|
||||
TextField("message", text: $typingMessage, axis: .vertical)
|
||||
.onChange(of: typingMessage, perform: { value in
|
||||
totalBytes = value.utf8.count
|
||||
// Only mess with the value if it is too big
|
||||
if totalBytes > Self.maxbytes {
|
||||
let firstNBytes = Data(typingMessage.utf8.prefix(Self.maxbytes))
|
||||
if let maxBytesString = String(data: firstNBytes, encoding: String.Encoding.utf8) {
|
||||
// Set the message back to the last place where it was the right size
|
||||
typingMessage = maxBytesString
|
||||
} else {
|
||||
print("not a valid UTF-8 sequence")
|
||||
}
|
||||
}
|
||||
})
|
||||
.keyboardType(.default)
|
||||
.toolbar {
|
||||
ToolbarItemGroup(placement: .keyboard) {
|
||||
Button("dismiss.keyboard") {
|
||||
isFocused = false
|
||||
}
|
||||
.font(.subheadline)
|
||||
|
||||
if destination.showAlertButton {
|
||||
Spacer()
|
||||
AlertButton { typingMessage += "🔔 Alert Bell Character! \u{7}" }
|
||||
}
|
||||
|
||||
Spacer()
|
||||
RequestPositionButton(action: requestPosition)
|
||||
TextMessageSize(maxbytes: Self.maxbytes, totalBytes: totalBytes)
|
||||
}
|
||||
}
|
||||
.padding(.horizontal, 8)
|
||||
.focused($isFocused)
|
||||
.multilineTextAlignment(.leading)
|
||||
.frame(minHeight: 50)
|
||||
.keyboardShortcut(.defaultAction)
|
||||
.onSubmit {
|
||||
#if targetEnvironment(macCatalyst)
|
||||
sendMessage()
|
||||
#endif
|
||||
}
|
||||
|
||||
Text(typingMessage)
|
||||
.opacity(0)
|
||||
.padding(.all, 0)
|
||||
}
|
||||
.overlay(RoundedRectangle(cornerRadius: 20).stroke(.tertiary, lineWidth: 1))
|
||||
.padding(.bottom, 15)
|
||||
|
||||
Button(action: sendMessage) {
|
||||
Image(systemName: "arrow.up.circle.fill")
|
||||
.font(.largeTitle)
|
||||
.foregroundColor(.accentColor)
|
||||
}
|
||||
}
|
||||
.padding(.all, 15)
|
||||
}
|
||||
|
||||
private func requestPosition() {
|
||||
let userLongName = bleManager.connectedPeripheral != nil ? bleManager.connectedPeripheral.longName : "Unknown"
|
||||
sendPositionWithMessage = true
|
||||
typingMessage = "📍 " + userLongName + " \(destination.positionShareMessage)."
|
||||
}
|
||||
|
||||
private func sendMessage() {
|
||||
let messageSent = bleManager.sendMessage(
|
||||
message: typingMessage,
|
||||
toUserNum: destination.userNum,
|
||||
channel: destination.channelNum,
|
||||
isEmoji: false,
|
||||
replyID: replyMessageId
|
||||
)
|
||||
if messageSent {
|
||||
typingMessage = ""
|
||||
isFocused = false
|
||||
replyMessageId = 0
|
||||
onSubmit()
|
||||
if sendPositionWithMessage {
|
||||
let positionSent = bleManager.sendPosition(
|
||||
channel: destination.channelNum,
|
||||
destNum: destination.positionDestNum,
|
||||
wantResponse: destination.wantPositionResponse
|
||||
)
|
||||
if positionSent {
|
||||
print("Location Sent")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private extension TextMessageField.Destination {
|
||||
var positionShareMessage: String {
|
||||
switch self {
|
||||
case .user: return "has shared their position and requested a response with your position"
|
||||
case .channel: return "has shared their position with you"
|
||||
}
|
||||
}
|
||||
|
||||
var userNum: Int64 {
|
||||
switch self {
|
||||
case let .user(num): return num
|
||||
case .channel: return 0
|
||||
}
|
||||
}
|
||||
|
||||
var channelNum: Int32 {
|
||||
switch self {
|
||||
case .user: return 0
|
||||
case let .channel(num): return num
|
||||
}
|
||||
}
|
||||
|
||||
var positionDestNum: Int64 {
|
||||
switch self {
|
||||
case let .user(num): return num
|
||||
case .channel: return Int64(BLEManager.emptyNodeNum)
|
||||
}
|
||||
}
|
||||
|
||||
var showAlertButton: Bool {
|
||||
switch self {
|
||||
case .user: return false
|
||||
case .channel: return true
|
||||
}
|
||||
}
|
||||
|
||||
var wantPositionResponse: Bool {
|
||||
switch self {
|
||||
case .user: return true
|
||||
case .channel: return false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,20 @@
|
|||
import SwiftUI
|
||||
|
||||
struct TextMessageSize: View {
|
||||
let maxbytes: Int
|
||||
let totalBytes: Int
|
||||
|
||||
var body: some View {
|
||||
ProgressView("\("bytes".localized): \(totalBytes) / \(maxbytes)", value: Double(totalBytes), total: Double(maxbytes))
|
||||
.frame(width: 130)
|
||||
.padding(5)
|
||||
.font(.subheadline)
|
||||
.accentColor(.accentColor)
|
||||
}
|
||||
}
|
||||
|
||||
struct TextMessageSizePreview: PreviewProvider {
|
||||
static var previews: some View {
|
||||
TextMessageSize(maxbytes: 228, totalBytes: 100)
|
||||
}
|
||||
}
|
||||
|
|
@ -9,25 +9,17 @@ import SwiftUI
|
|||
import CoreData
|
||||
|
||||
struct UserMessageList: View {
|
||||
|
||||
@StateObject var appState = AppState.shared
|
||||
@Environment(\.managedObjectContext) var context
|
||||
@EnvironmentObject var bleManager: BLEManager
|
||||
|
||||
enum Field: Hashable {
|
||||
case messageText
|
||||
}
|
||||
// Keyboard State
|
||||
@State var typingMessage: String = ""
|
||||
@State private var totalBytes = 0
|
||||
var maxbytes = 228
|
||||
@FocusState var focusedField: Field?
|
||||
@FocusState var messageFieldFocused: Bool
|
||||
// View State Items
|
||||
@ObservedObject var user: UserEntity
|
||||
@State var showDeleteMessageAlert = false
|
||||
@State private var deleteMessageId: Int64 = 0
|
||||
@State private var replyMessageId: Int64 = 0
|
||||
@State private var sendPositionWithMessage: Bool = false
|
||||
|
||||
var body: some View {
|
||||
VStack {
|
||||
|
|
@ -88,7 +80,7 @@ struct UserMessageList: View {
|
|||
}
|
||||
Button(action: {
|
||||
self.replyMessageId = message.messageId
|
||||
self.focusedField = .messageText
|
||||
self.messageFieldFocused = true
|
||||
print("I want to reply to \(message.messageId)")
|
||||
}) {
|
||||
Text("reply")
|
||||
|
|
@ -265,107 +257,14 @@ struct UserMessageList: View {
|
|||
}
|
||||
})
|
||||
}
|
||||
#if targetEnvironment(macCatalyst)
|
||||
HStack {
|
||||
Spacer()
|
||||
Button {
|
||||
let userLongName = bleManager.connectedPeripheral != nil ? bleManager.connectedPeripheral.longName : "Unknown"
|
||||
sendPositionWithMessage = true
|
||||
typingMessage = "📍 " + userLongName + " has shared their position and requested a response with your position."
|
||||
} label: {
|
||||
Text("share.position")
|
||||
Image(systemName: "mappin.and.ellipse")
|
||||
.symbolRenderingMode(.hierarchical)
|
||||
.imageScale(.large).foregroundColor(.accentColor)
|
||||
}
|
||||
ProgressView("\("bytes".localized): \(totalBytes) / \(maxbytes)", value: Double(totalBytes), total: Double(maxbytes))
|
||||
.frame(width: 130)
|
||||
.padding(5)
|
||||
.font(.subheadline)
|
||||
.accentColor(.accentColor)
|
||||
.padding(.trailing)
|
||||
}
|
||||
#endif
|
||||
|
||||
HStack(alignment: .top) {
|
||||
ZStack {
|
||||
TextField("message", text: $typingMessage, axis: .vertical)
|
||||
.onChange(of: typingMessage, perform: { value in
|
||||
totalBytes = value.utf8.count
|
||||
// Only mess with the value if it is too big
|
||||
if totalBytes > maxbytes {
|
||||
let firstNBytes = Data(typingMessage.utf8.prefix(maxbytes))
|
||||
if let maxBytesString = String(data: firstNBytes, encoding: String.Encoding.utf8) {
|
||||
// Set the message back to the last place where it was the right size
|
||||
typingMessage = maxBytesString
|
||||
} else {
|
||||
print("not a valid UTF-8 sequence")
|
||||
}
|
||||
}
|
||||
})
|
||||
.keyboardType(.default)
|
||||
.toolbar {
|
||||
ToolbarItemGroup(placement: .keyboard) {
|
||||
Button("dismiss.keyboard") {
|
||||
focusedField = nil
|
||||
}
|
||||
.font(.subheadline)
|
||||
Spacer()
|
||||
Button {
|
||||
let userLongName = bleManager.connectedPeripheral != nil ? bleManager.connectedPeripheral.longName : "Unknown"
|
||||
sendPositionWithMessage = true
|
||||
typingMessage = "📍 " + userLongName + " has shared their position and requested a response with your position."
|
||||
} label: {
|
||||
Image(systemName: "mappin.and.ellipse")
|
||||
.symbolRenderingMode(.hierarchical)
|
||||
.imageScale(.large).foregroundColor(.accentColor)
|
||||
}
|
||||
ProgressView("\("bytes".localized): \(totalBytes) / \(maxbytes)", value: Double(totalBytes), total: Double(maxbytes))
|
||||
.frame(width: 130)
|
||||
.padding(5)
|
||||
.font(.subheadline)
|
||||
.accentColor(.accentColor)
|
||||
}
|
||||
}
|
||||
.padding(.horizontal, 8)
|
||||
.focused($focusedField, equals: .messageText)
|
||||
.multilineTextAlignment(.leading)
|
||||
.frame(minHeight: 50)
|
||||
.keyboardShortcut(.defaultAction)
|
||||
.onSubmit {
|
||||
#if targetEnvironment(macCatalyst)
|
||||
if bleManager.sendMessage(message: typingMessage, toUserNum: user.num, channel: 0, isEmoji: false, replyID: replyMessageId) {
|
||||
typingMessage = ""
|
||||
focusedField = nil
|
||||
replyMessageId = 0
|
||||
if sendPositionWithMessage {
|
||||
if bleManager.sendPosition(channel: 0, destNum: user.num, wantResponse: true) {
|
||||
print("Location Sent")
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
Text(typingMessage).opacity(0).padding(.all, 0)
|
||||
}
|
||||
.overlay(RoundedRectangle(cornerRadius: 20).stroke(.tertiary, lineWidth: 1))
|
||||
.padding(.bottom, 15)
|
||||
Button(action: {
|
||||
if bleManager.sendMessage(message: typingMessage, toUserNum: user.num, channel: 0, isEmoji: false, replyID: replyMessageId) {
|
||||
typingMessage = ""
|
||||
focusedField = nil
|
||||
replyMessageId = 0
|
||||
if sendPositionWithMessage {
|
||||
if bleManager.sendPosition(channel: 0, destNum: user.num, wantResponse: true) {
|
||||
print("Location Sent")
|
||||
}
|
||||
}
|
||||
}
|
||||
}) {
|
||||
Image(systemName: "arrow.up.circle.fill").font(.largeTitle).foregroundColor(.accentColor)
|
||||
}
|
||||
TextMessageField(
|
||||
destination: .user(user.num),
|
||||
replyMessageId: $replyMessageId,
|
||||
isFocused: $messageFieldFocused
|
||||
) {
|
||||
context.refresh(user, mergeChanges: true)
|
||||
}
|
||||
.padding(.all, 15)
|
||||
}
|
||||
.navigationBarTitleDisplayMode(.inline)
|
||||
.toolbar {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue