mirror of
https://github.com/meshtastic/Meshtastic-Apple.git
synced 2026-04-20 22:13:56 +00:00
array of restricted channels for messages
This commit is contained in:
parent
3409de0da4
commit
bfd71ca263
7 changed files with 97 additions and 67 deletions
|
|
@ -25,3 +25,20 @@
|
|||
Image(systemName: "qrcode")
|
||||
}
|
||||
}
|
||||
|
||||
@available(iOS 17.0, macOS 14.0, *)
|
||||
struct CreateChannelsTip: Tip {
|
||||
|
||||
var id: String {
|
||||
return "tip.channels.create"
|
||||
}
|
||||
var title: Text {
|
||||
Text("tip.channels.create.title")
|
||||
}
|
||||
var message: Text? {
|
||||
Text("tip.channels.create.message")
|
||||
}
|
||||
var image: Image? {
|
||||
Image(systemName: "fibrechannel")
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -21,6 +21,8 @@ struct ChannelList: View {
|
|||
|
||||
@State private var isPresentingTraceRouteSentAlert = false
|
||||
|
||||
var restrictedChannels = ["admin", "gpio", "mqtt", "serial"]
|
||||
|
||||
var body: some View {
|
||||
let localeDateFormat = DateFormatter.dateFormat(fromTemplate: "yyMMdd", options: 0, locale: Locale.current)
|
||||
let dateFormatString = (localeDateFormat ?? "MM/dd/YY")
|
||||
|
|
@ -29,7 +31,7 @@ struct ChannelList: View {
|
|||
// Display Contacts for the rest of the non admin channels
|
||||
if node != nil && node!.myInfo != nil && node!.myInfo!.channels != nil {
|
||||
List(node!.myInfo!.channels!.array as! [ChannelEntity], id: \.self, selection: $channelSelection) { (channel: ChannelEntity) in
|
||||
if channel.name?.lowercased() ?? "" != "admin" && channel.name?.lowercased() ?? "" != "gpio" && channel.name?.lowercased() ?? "" != "serial" {
|
||||
if !restrictedChannels.contains(channel.name?.lowercased() ?? "") {
|
||||
|
||||
NavigationLink(destination: ChannelMessageList(myInfo: node!.myInfo!, channel: channel)) {
|
||||
|
||||
|
|
@ -85,9 +87,6 @@ struct ChannelList: View {
|
|||
.foregroundColor(.secondary)
|
||||
}
|
||||
}
|
||||
// Image(systemName: "chevron.forward")
|
||||
// .font(.caption)
|
||||
// .foregroundColor(.secondary)
|
||||
}
|
||||
|
||||
if channel.allPrivateMessages.count > 0 {
|
||||
|
|
|
|||
|
|
@ -19,7 +19,28 @@ struct AppSettings: View {
|
|||
var body: some View {
|
||||
VStack {
|
||||
Form {
|
||||
Section(header: Text("options")) {
|
||||
Section(header: Text("Location Settings")) {
|
||||
Toggle(isOn: $provideLocation) {
|
||||
Label("appsettings.provide.location", systemImage: "location.circle.fill")
|
||||
}
|
||||
.toggleStyle(SwitchToggleStyle(tint: .accentColor))
|
||||
if provideLocation {
|
||||
Toggle(isOn: $enableSmartPosition) {
|
||||
Label("appsettings.smartposition", systemImage: "brain.fill")
|
||||
}
|
||||
.toggleStyle(SwitchToggleStyle(tint: .accentColor))
|
||||
VStack {
|
||||
Picker("update.interval", selection: $provideLocationInterval) {
|
||||
ForEach(LocationUpdateInterval.allCases) { lu in
|
||||
Text(lu.description)
|
||||
}
|
||||
}
|
||||
.pickerStyle(DefaultPickerStyle())
|
||||
Text("phone.gps.interval.description")
|
||||
.font(.caption2)
|
||||
.foregroundColor(.gray)
|
||||
}
|
||||
}
|
||||
Toggle(isOn: $useLegacyMap) {
|
||||
Label("map.use.legacy", systemImage: "map")
|
||||
}
|
||||
|
|
@ -63,35 +84,6 @@ struct AppSettings: View {
|
|||
}
|
||||
}
|
||||
}
|
||||
Section(header: Text("Location Settings")) {
|
||||
Toggle(isOn: $provideLocation) {
|
||||
Label("appsettings.provide.location", systemImage: "location.circle.fill")
|
||||
}
|
||||
.toggleStyle(SwitchToggleStyle(tint: .accentColor))
|
||||
if provideLocation {
|
||||
Toggle(isOn: $enableSmartPosition) {
|
||||
Label("appsettings.smartposition", systemImage: "brain.fill")
|
||||
}
|
||||
.toggleStyle(SwitchToggleStyle(tint: .accentColor))
|
||||
.onChange(of: (enableSmartPosition)) { newEnableSmartPosition in
|
||||
UserDefaults.enableSmartPosition = newEnableSmartPosition
|
||||
}
|
||||
VStack {
|
||||
Picker("update.interval", selection: $provideLocationInterval) {
|
||||
ForEach(LocationUpdateInterval.allCases) { lu in
|
||||
Text(lu.description)
|
||||
}
|
||||
}
|
||||
.pickerStyle(DefaultPickerStyle())
|
||||
.onChange(of: (provideLocationInterval)) { newProvideLocationInterval in
|
||||
UserDefaults.provideLocationInterval = newProvideLocationInterval
|
||||
}
|
||||
Text("phone.gps.interval.description")
|
||||
.font(.caption2)
|
||||
.foregroundColor(.gray)
|
||||
}
|
||||
}
|
||||
}
|
||||
Section(header: Text("App Data")) {
|
||||
Button {
|
||||
isPresentingCoreDataResetConfirm = true
|
||||
|
|
@ -158,6 +150,12 @@ struct AppSettings: View {
|
|||
self.bleManager.sendWantConfig()
|
||||
}
|
||||
}
|
||||
.onChange(of: enableSmartPosition) { newEnableSmartPosition in
|
||||
UserDefaults.enableSmartPosition = newEnableSmartPosition
|
||||
}
|
||||
.onChange(of: (provideLocationInterval)) { newProvideLocationInterval in
|
||||
UserDefaults.provideLocationInterval = newProvideLocationInterval
|
||||
}
|
||||
.onChange(of: useLegacyMap) { newMapUseLegacy in
|
||||
UserDefaults.mapUseLegacy = newMapUseLegacy
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,6 +7,9 @@
|
|||
|
||||
import SwiftUI
|
||||
import CoreData
|
||||
#if canImport(TipKit)
|
||||
import TipKit
|
||||
#endif
|
||||
|
||||
func generateChannelKey(size: Int) -> String {
|
||||
var keyData = Data(count: size)
|
||||
|
|
@ -40,7 +43,11 @@ struct Channels: View {
|
|||
var body: some View {
|
||||
|
||||
VStack {
|
||||
|
||||
List {
|
||||
if #available(iOS 17.0, macOS 14.0, *) {
|
||||
TipView(CreateChannelsTip(), arrowEdge: .bottom)
|
||||
}
|
||||
if node != nil && node?.myInfo != nil {
|
||||
ForEach(node?.myInfo?.channels?.array as? [ChannelEntity] ?? [], id: \.self) { (channel: ChannelEntity) in
|
||||
Button(action: {
|
||||
|
|
@ -91,7 +98,9 @@ struct Channels: View {
|
|||
if node?.myInfo?.channels?.array.count ?? 0 < 8 && node != nil {
|
||||
|
||||
Button {
|
||||
let key = generateChannelKey(size: 32)
|
||||
channelKeySize = 16
|
||||
let key = generateChannelKey(size: channelKeySize)
|
||||
|
||||
channelName = ""
|
||||
channelIndex = Int32(node!.myInfo!.channels!.array.count)
|
||||
channelRole = 2
|
||||
|
|
@ -201,18 +210,21 @@ struct Channels: View {
|
|||
.disabled(channelKeySize <= 0)
|
||||
}
|
||||
HStack {
|
||||
Text("Role")
|
||||
Spacer()
|
||||
Picker("Channel Role", selection: $channelRole) {
|
||||
if channelRole == 1 {
|
||||
if channelRole == 1 {
|
||||
Picker("Channel Role", selection: $channelRole) {
|
||||
Text("Primary").tag(1)
|
||||
} else {
|
||||
Text("Disabled").tag(0)
|
||||
Text("Secondary").tag(2)
|
||||
}
|
||||
.pickerStyle(.automatic)
|
||||
.disabled(true)
|
||||
} else {
|
||||
Text("Channel Role")
|
||||
Spacer()
|
||||
Picker("Channel Role", selection: $channelRole) {
|
||||
Text("Disabled").tag(0)
|
||||
Text("Secondary").tag(2)
|
||||
}
|
||||
.pickerStyle(.segmented)
|
||||
}
|
||||
.pickerStyle(.segmented)
|
||||
.disabled(channelRole == 1)
|
||||
}
|
||||
Toggle("Uplink Enabled", isOn: $uplink)
|
||||
.toggleStyle(SwitchToggleStyle(tint: .accentColor))
|
||||
|
|
|
|||
|
|
@ -91,7 +91,7 @@ struct StoreForwardConfig: View {
|
|||
}
|
||||
|
||||
if isRouter {
|
||||
Section(header: Text("options")) {
|
||||
Section(header: Text("Router Options")) {
|
||||
Toggle(isOn: $heartbeat) {
|
||||
Label("storeforward.heartbeat", systemImage: "waveform.path.ecg")
|
||||
}
|
||||
|
|
|
|||
|
|
@ -117,27 +117,10 @@ struct Settings: View {
|
|||
}
|
||||
}
|
||||
} else {
|
||||
Text("Configuring Node \(node?.user?.longName ?? "unknown".localized)")
|
||||
Text("Connected Node \(node?.user?.longName ?? "unknown".localized)")
|
||||
}
|
||||
}
|
||||
Section("radio.configuration") {
|
||||
NavigationLink {
|
||||
ShareChannels(node: nodes.first(where: { $0.num == preferredNodeNum }))
|
||||
} label: {
|
||||
Image(systemName: "qrcode")
|
||||
.symbolRenderingMode(.hierarchical)
|
||||
Text("share.channels")
|
||||
}
|
||||
.tag(SettingsSidebar.shareChannels)
|
||||
.disabled(selectedNode > 0 && selectedNode != preferredNodeNum)
|
||||
NavigationLink {
|
||||
UserConfig(node: nodes.first(where: { $0.num == selectedNode }))
|
||||
} label: {
|
||||
Image(systemName: "person.crop.rectangle.fill")
|
||||
.symbolRenderingMode(.hierarchical)
|
||||
Text("user")
|
||||
}
|
||||
.tag(SettingsSidebar.userConfig)
|
||||
NavigationLink {
|
||||
LoRaConfig(node: nodes.first(where: { $0.num == selectedNode }))
|
||||
} label: {
|
||||
|
|
@ -155,6 +138,25 @@ struct Settings: View {
|
|||
}
|
||||
.tag(SettingsSidebar.channelConfig)
|
||||
.disabled(selectedNode > 0 && selectedNode != preferredNodeNum)
|
||||
NavigationLink {
|
||||
ShareChannels(node: nodes.first(where: { $0.num == preferredNodeNum }))
|
||||
} label: {
|
||||
Image(systemName: "qrcode")
|
||||
.symbolRenderingMode(.hierarchical)
|
||||
Text("share.channels")
|
||||
}
|
||||
.tag(SettingsSidebar.shareChannels)
|
||||
.disabled(selectedNode > 0 && selectedNode != preferredNodeNum)
|
||||
}
|
||||
Section("device.configuration") {
|
||||
NavigationLink {
|
||||
UserConfig(node: nodes.first(where: { $0.num == selectedNode }))
|
||||
} label: {
|
||||
Image(systemName: "person.crop.rectangle.fill")
|
||||
.symbolRenderingMode(.hierarchical)
|
||||
Text("user")
|
||||
}
|
||||
.tag(SettingsSidebar.userConfig)
|
||||
NavigationLink {
|
||||
BluetoothConfig(node: nodes.first(where: { $0.num == selectedNode }))
|
||||
} label: {
|
||||
|
|
|
|||
|
|
@ -81,7 +81,7 @@
|
|||
"device.role.routerclient"="Combination of both ROUTER and CLIENT. Not for mobile devices.";
|
||||
"direct.messages"="Direct Messages";
|
||||
"dismiss.keyboard"="Dismiss";
|
||||
"display"="Display (Device Screen)";
|
||||
"display"="Display";
|
||||
"display.config"="Display Config";
|
||||
"distance"="Distance";
|
||||
"disconnect"="Disconnect";
|
||||
|
|
@ -270,7 +270,7 @@
|
|||
"serial.mode.txtmsg"="Text Message";
|
||||
"serial.mode.nmea"="NMEA Positions";
|
||||
"settings"="Settings";
|
||||
"share.channels"="Share Channels QR Code";
|
||||
"share.channels"="Share QR Code";
|
||||
"share.position"="Share Position";
|
||||
"subscribed"="Subscribed to mesh";
|
||||
"select.contact"="Select a Contact";
|
||||
|
|
@ -297,9 +297,11 @@
|
|||
"timeout"="Timeout";
|
||||
"timestamp"="Timestamp";
|
||||
"tip.bluetooth.connect.title"="Connected Radio";
|
||||
"tip.bluetooth.connect.message"="Shows information for the Lora radio currently connected via bluetooth. You can swipe left to disconnect the radio and long press to view stats or start the live activity.";
|
||||
"tip.bluetooth.connect.message"="Shows information for the Lora radio connected via bluetooth. You can swipe left to disconnect the radio and long press to view stats or start the live activity.";
|
||||
"tip.channels.create.title"="Manage Channels";
|
||||
"tip.channels.create.message"="Most data on your mesh is sent over the primary channel. You can set up secondary channels to create additional messaging groups secured by their own key. [Channel config tips](https://meshtastic.org/docs/configuration/radio/channels/)";
|
||||
"tip.channels.share.title"="Sharing Meshtastic Channels";
|
||||
"tip.channels.share.message"="In a Meshtastic LoRa Mesh there are up to 8 channels. The first one is the Primary channel where most activity happens and is required. If you don't share your primary channel your first shared channel becomes the primary channel on the other network. It talks on its primary and your secondary channel. A channel with the name 'admin' controls nodes remotely. Other channels are for private groups, each with its own key.";
|
||||
"tip.channels.share.message"="A Meshtastic QR code contains the LoRa config and channel values needed to communicate. Most mesh activity takes place on the required Primary channel. If you don't share your primary channel your first shared channel becomes the primary channel on the other network. Other channels are for private groups, each with its own key.";
|
||||
"tip.messages.title"="Messages";
|
||||
"tip.messages.message"="You can send and receive channel (group chats) and direct messages. From any message you can long press to see available actions like copy, reply, tapback and delete as well as delivery details.";
|
||||
"twitter"="Twitter";
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue