array of restricted channels for messages

This commit is contained in:
Garth Vander Houwen 2024-02-17 14:46:09 -08:00
parent 3409de0da4
commit bfd71ca263
7 changed files with 97 additions and 67 deletions

View file

@ -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")
}
}

View file

@ -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 {

View file

@ -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
}

View file

@ -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))

View file

@ -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")
}

View file

@ -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: {

View file

@ -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";