mirror of
https://github.com/meshtastic/Meshtastic-Apple.git
synced 2026-04-20 22:13:56 +00:00
2.7.1 Working Changes (#1392)
* Bump version * Offset for map controls on the mesh map * Only mark messages as read if they are unread (#1388) * Only mark messages as read if they are unread * More cheap optimizations * Fix map control positions on the route recorder * Add seperate state variable for delete all channel messges button since the channelSelection is being used for navigation * Use a seperate state variable to track what user messages are being deleted for as userSelection is being used for navigation * Get the ringtone if external notifications is enabled * Fix RTTTL typo * Dont show modem lights popover if we are on macOS 26 cause it crashes * Fix annoying connect bottom background bug * Update mesh map detents * Move divider inside of the hstack keyboard toolbar * Update Meshtastic/Helpers/MeshPackets.swift Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> * Remove extra environment variable that is not getting used --------- Co-authored-by: Benjamin Faershtein <119711889+RCGV1@users.noreply.github.com> Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
This commit is contained in:
parent
e5bc161444
commit
88ed168725
13 changed files with 87 additions and 28 deletions
|
|
@ -2043,7 +2043,7 @@
|
|||
"$(inherited)",
|
||||
"@executable_path/Frameworks",
|
||||
);
|
||||
MARKETING_VERSION = 2.7.0;
|
||||
MARKETING_VERSION = 2.7.1;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = gvh.MeshtasticClient;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SUPPORTS_MACCATALYST = YES;
|
||||
|
|
@ -2076,7 +2076,7 @@
|
|||
"$(inherited)",
|
||||
"@executable_path/Frameworks",
|
||||
);
|
||||
MARKETING_VERSION = 2.7.0;
|
||||
MARKETING_VERSION = 2.7.1;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = gvh.MeshtasticClient;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SUPPORTS_MACCATALYST = YES;
|
||||
|
|
@ -2107,7 +2107,7 @@
|
|||
"@executable_path/Frameworks",
|
||||
"@executable_path/../../Frameworks",
|
||||
);
|
||||
MARKETING_VERSION = 2.7.0;
|
||||
MARKETING_VERSION = 2.7.1;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = gvh.MeshtasticClient.Widgets;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
PROVISIONING_PROFILE_SPECIFIER = "";
|
||||
|
|
@ -2139,7 +2139,7 @@
|
|||
"@executable_path/Frameworks",
|
||||
"@executable_path/../../Frameworks",
|
||||
);
|
||||
MARKETING_VERSION = 2.7.0;
|
||||
MARKETING_VERSION = 2.7.1;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = gvh.MeshtasticClient.Widgets;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
PROVISIONING_PROFILE_SPECIFIER = "";
|
||||
|
|
|
|||
|
|
@ -164,6 +164,10 @@ extension AccessoryManager {
|
|||
if moduleConfigPacket.payloadVariant == ModuleConfig.OneOf_PayloadVariant.cannedMessage(moduleConfigPacket.cannedMessage) {
|
||||
try? getCannedMessageModuleMessages(destNum: deviceNum, wantResponse: true)
|
||||
}
|
||||
// Get the Ringtone if the Module is External Notifications
|
||||
if moduleConfigPacket.payloadVariant == ModuleConfig.OneOf_PayloadVariant.externalNotification(moduleConfigPacket.externalNotification) {
|
||||
try? getRingtone(destNum: deviceNum, wantResponse: true)
|
||||
}
|
||||
}
|
||||
|
||||
func handleDeviceMetadata(_ metadata: DeviceMetadata) {
|
||||
|
|
|
|||
|
|
@ -47,6 +47,43 @@ extension AccessoryManager {
|
|||
try await send(toRadio, debugDescription: logString)
|
||||
}
|
||||
}
|
||||
|
||||
public func getRingtone(destNum: Int64, wantResponse: Bool) throws {
|
||||
guard let deviceNum = self.activeConnection?.device.num else {
|
||||
Logger.services.error("Error while sending RtttlConfig request. No active device.")
|
||||
throw AccessoryError.ioFailed("No active device")
|
||||
}
|
||||
|
||||
var adminPacket = AdminMessage()
|
||||
adminPacket.getRingtoneRequest = true
|
||||
|
||||
var meshPacket: MeshPacket = MeshPacket()
|
||||
meshPacket.to = UInt32(destNum)
|
||||
meshPacket.from = UInt32(deviceNum)
|
||||
meshPacket.id = UInt32.random(in: UInt32(UInt8.max)..<UInt32.max)
|
||||
meshPacket.priority = MeshPacket.Priority.reliable
|
||||
meshPacket.wantAck = true
|
||||
meshPacket.decoded.wantResponse = wantResponse
|
||||
|
||||
var dataMessage = DataMessage()
|
||||
guard let adminData: Data = try? adminPacket.serializedData() else {
|
||||
throw AccessoryError.ioFailed("Error serializing admin packet")
|
||||
}
|
||||
dataMessage.payload = adminData
|
||||
dataMessage.portnum = PortNum.adminApp
|
||||
dataMessage.wantResponse = wantResponse
|
||||
|
||||
meshPacket.decoded = dataMessage
|
||||
|
||||
var toRadio: ToRadio!
|
||||
toRadio = ToRadio()
|
||||
toRadio.packet = meshPacket
|
||||
|
||||
let logString = String.localizedStringWithFormat("Requested RTTTL Config Module ringtone for node: %@".localized, String(deviceNum))
|
||||
Task {
|
||||
try await send(toRadio, debugDescription: logString)
|
||||
}
|
||||
}
|
||||
|
||||
public func saveTimeZone(config: Config.DeviceConfig, user: Int64) async throws -> Int64 {
|
||||
var adminPacket = AdminMessage()
|
||||
|
|
|
|||
|
|
@ -585,8 +585,9 @@ func adminAppPacket (packet: MeshPacket, context: NSManagedObjectContext) {
|
|||
upsertTelemetryModuleConfigPacket(config: moduleConfig.telemetry, nodeNum: Int64(packet.from), context: context)
|
||||
}
|
||||
} else if adminMessage.payloadVariant == AdminMessage.OneOf_PayloadVariant.getRingtoneResponse(adminMessage.getRingtoneResponse) {
|
||||
let ringtone = adminMessage.getRingtoneResponse
|
||||
upsertRtttlConfigPacket(ringtone: ringtone, nodeNum: Int64(packet.from), context: context)
|
||||
if let rt = try? RTTTLConfig(serializedBytes: packet.decoded.payload) {
|
||||
upsertRtttlConfigPacket(ringtone: rt.ringtone, nodeNum: Int64(packet.from), context: context)
|
||||
}
|
||||
} else {
|
||||
Logger.mesh.error("🕸️ MESH PACKET received Admin App UNHANDLED \((try? packet.decoded.jsonString()) ?? "JSON Decode Failure", privacy: .public)")
|
||||
}
|
||||
|
|
|
|||
|
|
@ -314,7 +314,7 @@ struct Connect: View {
|
|||
.textCase(nil)
|
||||
}
|
||||
}
|
||||
|
||||
.scrollContentBackground(.hidden)
|
||||
HStack(alignment: .center) {
|
||||
Spacer()
|
||||
#if targetEnvironment(macCatalyst)
|
||||
|
|
@ -338,8 +338,9 @@ struct Connect: View {
|
|||
Spacer()
|
||||
}
|
||||
.padding(.bottom, 10)
|
||||
.background(Color(.tertiarySystemGroupedBackground))
|
||||
|
||||
}
|
||||
.background(Color(.systemGroupedBackground))
|
||||
.navigationTitle("Connect")
|
||||
.navigationBarItems(
|
||||
leading: MeshtasticLogo(),
|
||||
|
|
|
|||
|
|
@ -29,7 +29,16 @@ struct RXTXIndicatorWidget: View {
|
|||
}
|
||||
}
|
||||
}
|
||||
self.isPopoverOpen.toggle()
|
||||
#if targetEnvironment(macCatalyst)
|
||||
if #available(macOS 26.0, *) {
|
||||
// Dont show popover that crashes on mac 26
|
||||
} else {
|
||||
self.isPopoverOpen.toggle()
|
||||
}
|
||||
#else
|
||||
self.isPopoverOpen.toggle()
|
||||
#endif
|
||||
|
||||
}) {
|
||||
VStack(spacing: 3.0) {
|
||||
HStack(spacing: 2.0) {
|
||||
|
|
|
|||
|
|
@ -13,13 +13,9 @@ struct ChannelList: View {
|
|||
|
||||
@Environment(\.managedObjectContext) var context
|
||||
@EnvironmentObject var accessoryManager: AccessoryManager
|
||||
|
||||
@Binding
|
||||
var node: NodeInfoEntity?
|
||||
|
||||
@Binding
|
||||
var channelSelection: ChannelEntity?
|
||||
|
||||
@Binding var node: NodeInfoEntity?
|
||||
@Binding var channelSelection: ChannelEntity?
|
||||
@State private var channelToDeleteMessages: ChannelEntity?
|
||||
@State private var isPresentingDeleteChannelMessagesConfirm: Bool = false
|
||||
@State private var isPresentingTraceRouteSentAlert = false
|
||||
@State private var showingHelp = false
|
||||
|
|
@ -123,7 +119,7 @@ struct ChannelList: View {
|
|||
if channel.allPrivateMessages.count > 0 {
|
||||
Button(role: .destructive) {
|
||||
isPresentingDeleteChannelMessagesConfirm = true
|
||||
channelSelection = channel
|
||||
channelToDeleteMessages = channel
|
||||
} label: {
|
||||
Label("Delete Messages", systemImage: "trash")
|
||||
}
|
||||
|
|
@ -158,9 +154,9 @@ struct ChannelList: View {
|
|||
titleVisibility: .visible
|
||||
) {
|
||||
Button(role: .destructive) {
|
||||
deleteChannelMessages(channel: channelSelection!, context: context)
|
||||
deleteChannelMessages(channel: channelToDeleteMessages!, context: context)
|
||||
context.refresh(myInfo, mergeChanges: true)
|
||||
channelSelection = nil
|
||||
channelToDeleteMessages = nil
|
||||
} label: {
|
||||
Text("Delete")
|
||||
}
|
||||
|
|
|
|||
|
|
@ -130,7 +130,6 @@ struct ChannelMessageList: View {
|
|||
|
||||
TapbackResponses(message: message) {
|
||||
appState.unreadChannelMessages = myInfo.unreadMessages
|
||||
context.refresh(myInfo, mergeChanges: true)
|
||||
}
|
||||
|
||||
HStack {
|
||||
|
|
@ -159,7 +158,9 @@ struct ChannelMessageList: View {
|
|||
.frame(maxWidth: .infinity)
|
||||
.id(message.messageId)
|
||||
.onAppear {
|
||||
markMessagesAsRead()
|
||||
if !message.read {
|
||||
markMessagesAsRead()
|
||||
}
|
||||
}
|
||||
}
|
||||
Color.clear
|
||||
|
|
|
|||
|
|
@ -68,8 +68,8 @@ struct TextMessageField: View {
|
|||
}
|
||||
}
|
||||
.padding(15)
|
||||
Divider()
|
||||
if isFocused {
|
||||
Divider()
|
||||
HStack {
|
||||
Spacer()
|
||||
AlertButton { typingMessage += "🔔 Alert Bell Character! \u{7}" }
|
||||
|
|
|
|||
|
|
@ -18,10 +18,9 @@ struct UserList: View {
|
|||
@State private var showingHelp = false
|
||||
@State private var showingTrustConfirm: Bool = false
|
||||
@StateObject private var filters: NodeFilterParameters = NodeFilterParameters()
|
||||
|
||||
@Binding var node: NodeInfoEntity?
|
||||
@Binding var userSelection: UserEntity?
|
||||
|
||||
@State private var userToDeleteMessages: UserEntity?
|
||||
@State private var isPresentingDeleteUserMessagesConfirm: Bool = false
|
||||
|
||||
private func fetchUsers(withFilters: NodeFilterParameters) -> [UserEntity] {
|
||||
|
|
@ -152,7 +151,7 @@ struct UserList: View {
|
|||
if user.messageList.count > 0 {
|
||||
Button(role: .destructive) {
|
||||
isPresentingDeleteUserMessagesConfirm = true
|
||||
userSelection = user
|
||||
userToDeleteMessages = user
|
||||
} label: {
|
||||
Label("Delete Messages", systemImage: "trash")
|
||||
}
|
||||
|
|
@ -164,7 +163,7 @@ struct UserList: View {
|
|||
titleVisibility: .visible
|
||||
) {
|
||||
Button(role: .destructive) {
|
||||
deleteUserMessages(user: userSelection!, context: context)
|
||||
deleteUserMessages(user: userToDeleteMessages!, context: context)
|
||||
context.refresh(node!.user!, mergeChanges: true)
|
||||
} label: {
|
||||
Text("Delete")
|
||||
|
|
|
|||
|
|
@ -74,6 +74,7 @@ struct MeshMap: View {
|
|||
.mapControlVisibility(.automatic)
|
||||
}
|
||||
.controlSize(.regular)
|
||||
.offset(y: 100)
|
||||
.onMapCameraChange(frequency: MapCameraUpdateFrequency.continuous, { context in
|
||||
distance = context.camera.distance
|
||||
})
|
||||
|
|
@ -126,7 +127,7 @@ struct MeshMap: View {
|
|||
}
|
||||
.sheet(isPresented: $editingSettings) {
|
||||
MapSettingsForm(traffic: $showTraffic, pointsOfInterest: $showPointsOfInterest, mapLayer: $selectedMapLayer, meshMap: $isMeshMap, enabledOverlayConfigs: $enabledOverlayConfigs)
|
||||
.presentationDetents([.fraction(0.85), .large])
|
||||
.presentationDetents([.large])
|
||||
|
||||
}
|
||||
.onChange(of: router.navigationState) {
|
||||
|
|
|
|||
|
|
@ -49,6 +49,16 @@ struct RouteRecorder: View {
|
|||
}
|
||||
.mapStyle(mapStyle)
|
||||
}
|
||||
.mapControls {
|
||||
MapScaleView(scope: routerecorderscope)
|
||||
.mapControlVisibility(.automatic)
|
||||
MapPitchToggle(scope: routerecorderscope)
|
||||
.mapControlVisibility(.automatic)
|
||||
MapCompass(scope: routerecorderscope)
|
||||
.mapControlVisibility(.automatic)
|
||||
}
|
||||
.controlSize(.regular)
|
||||
.offset(y: 100)
|
||||
.mapScope(routerecorderscope)
|
||||
.safeAreaInset(edge: .bottom) {
|
||||
ZStack {
|
||||
|
|
|
|||
|
|
@ -236,7 +236,7 @@ struct Settings: View {
|
|||
}
|
||||
}
|
||||
|
||||
if isModuleSupported(.audioConfig) {
|
||||
if isModuleSupported(.extnotifConfig) {
|
||||
NavigationLink(value: SettingsNavigationState.ringtone) {
|
||||
Label {
|
||||
Text("Ringtone")
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue