mirror of
https://github.com/meshtastic/Meshtastic-Apple.git
synced 2026-04-20 22:13:56 +00:00
Enter for submit on mac
This commit is contained in:
parent
464b74a118
commit
ca0b9e66d3
7 changed files with 133 additions and 126 deletions
|
|
@ -957,7 +957,6 @@ class BLEManager: NSObject, CBPeripheralDelegate, ObservableObject {
|
|||
fetchedMyInfo[0].channels = mutableChannels
|
||||
do {
|
||||
try context!.save()
|
||||
|
||||
} catch {
|
||||
print("Failed to clear existing channels from local app database")
|
||||
}
|
||||
|
|
|
|||
|
|
@ -756,6 +756,7 @@ func channelPacket (channel: Channel, fromNum: Int64, context: NSManagedObjectCo
|
|||
if fetchedMyInfo.count == 1 {
|
||||
|
||||
let newChannel = ChannelEntity(context: context)
|
||||
newChannel.id = Int32(channel.index)
|
||||
newChannel.index = Int32(channel.index)
|
||||
newChannel.uplinkEnabled = channel.settings.uplinkEnabled
|
||||
newChannel.downlinkEnabled = channel.settings.downlinkEnabled
|
||||
|
|
|
|||
|
|
@ -60,9 +60,9 @@ public func clearTelemetry(destNum: Int64, metricsType: Int32, context: NSManage
|
|||
}
|
||||
}
|
||||
|
||||
public func deleteChannelMessages(channelIndex: Int32, context: NSManagedObjectContext) {
|
||||
public func deleteChannelMessages(channel: ChannelEntity, context: NSManagedObjectContext) {
|
||||
let fetchChannelMessagesRequest = NSFetchRequest<NSFetchRequestResult>(entityName: "MessageEntity")
|
||||
fetchChannelMessagesRequest.predicate = NSPredicate(format: "channel == %i AND toUser == nil AND admin == false", Int32(channelIndex))
|
||||
fetchChannelMessagesRequest.predicate = NSPredicate(format: "channel == %i AND toUser == nil AND admin == false", Int32(channel.id))
|
||||
fetchChannelMessagesRequest.includesPropertyValues = false
|
||||
do {
|
||||
let objects = try context.fetch(fetchChannelMessagesRequest) as! [NSManagedObject]
|
||||
|
|
@ -70,7 +70,6 @@ public func deleteChannelMessages(channelIndex: Int32, context: NSManagedObjectC
|
|||
context.delete(object)
|
||||
}
|
||||
try context.save()
|
||||
context.refreshAllObjects()
|
||||
} catch let error as NSError {
|
||||
print("Error: \(error.localizedDescription)")
|
||||
}
|
||||
|
|
|
|||
|
|
@ -311,9 +311,22 @@ struct ChannelMessageList: View {
|
|||
.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(destNum: Int64(channel.index), wantAck: true) {
|
||||
print("Location Sent")
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
Text(typingMessage).opacity(0).padding(.all, 0)
|
||||
|
||||
}
|
||||
.overlay(RoundedRectangle(cornerRadius: 20).stroke(.tertiary, lineWidth: 1))
|
||||
.padding(.bottom, 15)
|
||||
|
|
|
|||
|
|
@ -33,82 +33,79 @@ struct Contacts: View {
|
|||
if node != nil && node!.myInfo != nil && node!.myInfo!.channels != nil {
|
||||
ForEach(node!.myInfo!.channels!.array as! [ChannelEntity], id: \.self) { (channel: ChannelEntity) in
|
||||
if channel.name?.lowercased() ?? "" != "admin" && channel.name?.lowercased() ?? "" != "gpio" && channel.name?.lowercased() ?? "" != "serial" {
|
||||
VStack {
|
||||
NavigationLink(destination: ChannelMessageList(channel: channel)) {
|
||||
|
||||
let mostRecent = channel.allPrivateMessages.last(where: { $0.channel == channel.index })
|
||||
let lastMessageTime = Date(timeIntervalSince1970: TimeInterval(Int64((mostRecent?.messageTimestamp ?? 0 ))))
|
||||
let lastMessageDay = Calendar.current.dateComponents([.day], from: lastMessageTime).day ?? 0
|
||||
let currentDay = Calendar.current.dateComponents([.day], from: Date()).day ?? 0
|
||||
VStack(alignment: .leading) {
|
||||
HStack {
|
||||
CircleText(text: String(channel.index), color: .accentColor, circleSize: 52, fontSize: 40, brightness: 0.1)
|
||||
.padding(.trailing, 5)
|
||||
VStack {
|
||||
HStack {
|
||||
if channel.name?.isEmpty ?? false {
|
||||
if channel.role == 1 {
|
||||
Text(String("PrimaryChannel").camelCaseToWords()).font(.headline)
|
||||
} else {
|
||||
Text(String("Channel \(channel.index)").camelCaseToWords()).font(.headline)
|
||||
}
|
||||
NavigationLink(destination: ChannelMessageList(channel: channel)) {
|
||||
|
||||
let mostRecent = channel.allPrivateMessages.last(where: { $0.channel == channel.index })
|
||||
let lastMessageTime = Date(timeIntervalSince1970: TimeInterval(Int64((mostRecent?.messageTimestamp ?? 0 ))))
|
||||
let lastMessageDay = Calendar.current.dateComponents([.day], from: lastMessageTime).day ?? 0
|
||||
let currentDay = Calendar.current.dateComponents([.day], from: Date()).day ?? 0
|
||||
VStack(alignment: .leading) {
|
||||
HStack {
|
||||
CircleText(text: String(channel.index), color: .accentColor, circleSize: 52, fontSize: 40, brightness: 0.1)
|
||||
.padding(.trailing, 5)
|
||||
VStack {
|
||||
HStack {
|
||||
if channel.name?.isEmpty ?? false {
|
||||
if channel.role == 1 {
|
||||
Text(String("PrimaryChannel").camelCaseToWords()).font(.headline)
|
||||
} else {
|
||||
Text(String(channel.name ?? "Channel \(channel.index)").camelCaseToWords()).font(.headline)
|
||||
}
|
||||
Spacer()
|
||||
if channel.allPrivateMessages.count > 0 {
|
||||
VStack (alignment: .trailing) {
|
||||
if lastMessageDay == currentDay {
|
||||
Text(lastMessageTime, style: .time )
|
||||
.font(.subheadline)
|
||||
} else if lastMessageDay == (currentDay - 1) {
|
||||
Text("Yesterday")
|
||||
.font(.subheadline)
|
||||
} else if lastMessageDay < (currentDay - 1) && lastMessageDay > (currentDay - 5) {
|
||||
Text(lastMessageTime.formattedDate(format: "MM/dd/yy"))
|
||||
.font(.subheadline)
|
||||
} else if lastMessageDay < (currentDay - 1800) {
|
||||
Text(lastMessageTime.formattedDate(format: "MM/dd/yy"))
|
||||
.font(.subheadline)
|
||||
}
|
||||
}
|
||||
.brightness(-0.20)
|
||||
Text(String("Channel \(channel.index)").camelCaseToWords()).font(.headline)
|
||||
}
|
||||
} else {
|
||||
Text(String(channel.name ?? "Channel \(channel.index)").camelCaseToWords()).font(.headline)
|
||||
}
|
||||
Spacer()
|
||||
if channel.allPrivateMessages.count > 0 {
|
||||
HStack(alignment: .top) {
|
||||
Text("\(mostRecent != nil ? mostRecent!.messagePayload! : " ")")
|
||||
.truncationMode(.tail)
|
||||
.frame(maxWidth: .infinity, alignment: .leading)
|
||||
.brightness(-0.20)
|
||||
.font(.body)
|
||||
VStack (alignment: .trailing) {
|
||||
if lastMessageDay == currentDay {
|
||||
Text(lastMessageTime, style: .time )
|
||||
.font(.subheadline)
|
||||
} else if lastMessageDay == (currentDay - 1) {
|
||||
Text("Yesterday")
|
||||
.font(.subheadline)
|
||||
} else if lastMessageDay < (currentDay - 1) && lastMessageDay > (currentDay - 5) {
|
||||
Text(lastMessageTime.formattedDate(format: "MM/dd/yy"))
|
||||
.font(.subheadline)
|
||||
} else if lastMessageDay < (currentDay - 1800) {
|
||||
Text(lastMessageTime.formattedDate(format: "MM/dd/yy"))
|
||||
.font(.subheadline)
|
||||
}
|
||||
}
|
||||
.brightness(-0.20)
|
||||
}
|
||||
}
|
||||
if channel.allPrivateMessages.count > 0 {
|
||||
HStack(alignment: .top) {
|
||||
Text("\(mostRecent != nil ? mostRecent!.messagePayload! : " ")")
|
||||
.truncationMode(.tail)
|
||||
.frame(maxWidth: .infinity, alignment: .leading)
|
||||
.brightness(-0.20)
|
||||
.font(.body)
|
||||
}
|
||||
}
|
||||
.frame(maxWidth: .infinity, alignment: .leading)
|
||||
}
|
||||
.frame(maxWidth: .infinity, alignment: .leading)
|
||||
}
|
||||
}
|
||||
}
|
||||
.frame(maxWidth: .infinity, maxHeight: 80, alignment: .leading)
|
||||
.contextMenu {
|
||||
// Hide mute channel menu item until I can check it in notifications
|
||||
// Button {
|
||||
// channel.mute = !channel.mute
|
||||
//
|
||||
// do {
|
||||
// try context.save()
|
||||
// // Would rather not do this but the merge changes on
|
||||
// // A single object is only working on mac GVH
|
||||
// context.refreshAllObjects()
|
||||
// //context.refresh(channel, mergeChanges: true)
|
||||
// } catch {
|
||||
// context.rollback()
|
||||
// print("💥 Save Channel Mute Error")
|
||||
// }
|
||||
// } label: {
|
||||
// Label(channel.mute ? "Show Alerts" : "Hide Alerts", systemImage: channel.mute ? "bell" : "bell.slash")
|
||||
// }
|
||||
Button {
|
||||
channel.mute = !channel.mute
|
||||
|
||||
do {
|
||||
try context.save()
|
||||
// Would rather not do this but the merge changes on
|
||||
// A single object is only working on mac GVH
|
||||
context.refreshAllObjects()
|
||||
//context.refresh(channel, mergeChanges: true)
|
||||
} catch {
|
||||
context.rollback()
|
||||
print("💥 Save Channel Mute Error")
|
||||
}
|
||||
} label: {
|
||||
Label(channel.mute ? "Show Alerts" : "Hide Alerts", systemImage: channel.mute ? "bell" : "bell.slash")
|
||||
}
|
||||
|
||||
if channel.allPrivateMessages.count > 0 {
|
||||
Button(role: .destructive) {
|
||||
|
|
@ -121,12 +118,13 @@ struct Contacts: View {
|
|||
.confirmationDialog(
|
||||
"This conversation will be deleted.",
|
||||
isPresented: $isPresentingDeleteChannelMessagesConfirm,
|
||||
|
||||
titleVisibility: .visible
|
||||
) {
|
||||
|
||||
Button(role: .destructive) {
|
||||
deleteChannelMessages(channelIndex: channel.index, context: context)
|
||||
context.refreshAllObjects()
|
||||
deleteChannelMessages(channel: channel, context: context)
|
||||
|
||||
} label: {
|
||||
Text("delete")
|
||||
}
|
||||
|
|
|
|||
|
|
@ -308,6 +308,21 @@ struct UserMessageList: View {
|
|||
.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(destNum: user.num, wantAck: true) {
|
||||
print("Location Sent")
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
Text(typingMessage).opacity(0).padding(.all, 0)
|
||||
}
|
||||
.overlay(RoundedRectangle(cornerRadius: 20).stroke(.tertiary, lineWidth: 1))
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@ import CoreData
|
|||
|
||||
func generateChannelKey(size: Int) -> String {
|
||||
var keyData = Data(count: size)
|
||||
let result = keyData.withUnsafeMutableBytes {
|
||||
_ = keyData.withUnsafeMutableBytes {
|
||||
SecRandomCopyBytes(kSecRandomDefault, size, $0.baseAddress!)
|
||||
}
|
||||
return keyData.base64EncodedString()
|
||||
|
|
@ -25,73 +25,55 @@ struct Channels: View {
|
|||
var node: NodeInfoEntity?
|
||||
|
||||
@State private var isPresentingEditView = false
|
||||
@State private var selectedIndex: Int32 = -1
|
||||
|
||||
var body: some View {
|
||||
|
||||
ScrollView {
|
||||
if node != nil && node?.myInfo != nil {
|
||||
Grid() {
|
||||
GridRow {
|
||||
Text("Index")
|
||||
.font(.caption2)
|
||||
Text("name")
|
||||
.font(.caption2)
|
||||
if sizeCategory <= ContentSizeCategory.extraExtraLarge {
|
||||
Text("Up/down link")
|
||||
.font(.caption2)
|
||||
}
|
||||
Text("Edit")
|
||||
.font(.caption2)
|
||||
Text("Delete")
|
||||
.font(.caption2)
|
||||
}
|
||||
NavigationStack {
|
||||
List {
|
||||
if node != nil && node?.myInfo != nil {
|
||||
ForEach(node!.myInfo!.channels?.array as! [ChannelEntity], id: \.self) { (channel: ChannelEntity) in
|
||||
GridRow {
|
||||
CircleText(text: String(channel.index), color: .accentColor, circleSize: 32)
|
||||
Text(((channel.name!.isEmpty ? "Primary" : channel.name) ?? "Primary").camelCaseToWords())
|
||||
if sizeCategory <= ContentSizeCategory.extraExtraLarge {
|
||||
Button(action: {
|
||||
selectedIndex = channel.index
|
||||
isPresentingEditView = true
|
||||
print("Tapity tap")
|
||||
}) {
|
||||
VStack(alignment: .leading) {
|
||||
HStack {
|
||||
if channel.uplinkEnabled {
|
||||
Image(systemName: "checkmark.square")
|
||||
} else {
|
||||
Image(systemName: "square")
|
||||
}
|
||||
if channel.downlinkEnabled {
|
||||
Image(systemName: "checkmark.square")
|
||||
} else {
|
||||
Image(systemName: "square")
|
||||
CircleText(text: String(channel.index), color: .accentColor, circleSize: 45, fontSize: 36, brightness: 0.1)
|
||||
.padding(.trailing, 5)
|
||||
VStack {
|
||||
HStack {
|
||||
if channel.name?.isEmpty ?? false {
|
||||
if channel.role == 1 {
|
||||
Text(String("PrimaryChannel").camelCaseToWords()).font(.headline)
|
||||
} else {
|
||||
Text(String("Channel \(channel.index)").camelCaseToWords()).font(.headline)
|
||||
}
|
||||
} else {
|
||||
Text(String(channel.name ?? "Channel \(channel.index)").camelCaseToWords()).font(.headline)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Button {
|
||||
print("Edit Channel")
|
||||
|
||||
} label: {
|
||||
Label("", systemImage: "square.and.pencil")
|
||||
}
|
||||
Button(role: .destructive) {
|
||||
print("Delete Channel")
|
||||
|
||||
} label: {
|
||||
Label("", systemImage: "trash")
|
||||
}
|
||||
.disabled(channel.role == 1)
|
||||
}
|
||||
}
|
||||
}
|
||||
if node!.myInfo!.channels?.array.count ?? 0 < 8 {
|
||||
}
|
||||
if node?.myInfo?.channels?.array.count ?? 0 < 8 {
|
||||
|
||||
Button {
|
||||
let key = generateChannelKey(size: 32)
|
||||
print("Add Channel Key \(key) ")
|
||||
|
||||
Button {
|
||||
print("Add Channel")
|
||||
|
||||
} label: {
|
||||
Label("Add Channel", systemImage: "plus.square")
|
||||
}
|
||||
.buttonStyle(.bordered)
|
||||
.buttonBorderShape(.capsule)
|
||||
.controlSize(.large)
|
||||
.padding()
|
||||
} label: {
|
||||
Label("Add Channel", systemImage: "plus.square")
|
||||
}
|
||||
.buttonStyle(.bordered)
|
||||
.buttonBorderShape(.capsule)
|
||||
.controlSize(.large)
|
||||
.padding()
|
||||
}
|
||||
}
|
||||
.navigationTitle("Channels")
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue