mirror of
https://github.com/meshtastic/Meshtastic-Apple.git
synced 2026-04-20 22:13:56 +00:00
Fix regressions from merged pull request updates in 2.7.10
This commit is contained in:
parent
4839a978ab
commit
92b0cadd3d
12 changed files with 56 additions and 135 deletions
|
|
@ -50,6 +50,8 @@ extension MessageEntity {
|
|||
format: "replyID == %lld AND isEmoji == true",
|
||||
self.messageId
|
||||
)
|
||||
fetchRequest.fetchLimit = 20
|
||||
fetchRequest.returnsObjectsAsFaults = false
|
||||
|
||||
return (try? context.fetch(fetchRequest)) ?? [MessageEntity]()
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,105 +0,0 @@
|
|||
//
|
||||
// EmojiKeyboard.swift
|
||||
// Meshtastic
|
||||
//
|
||||
// Copyright(c) Garth Vander Houwen 1/10/23.
|
||||
//
|
||||
import SwiftUI
|
||||
|
||||
class SwiftUIEmojiTextField: UITextField {
|
||||
var shouldBecomeFirstResponderOnAppear = false
|
||||
|
||||
func setEmoji() {
|
||||
_ = self.textInputMode
|
||||
}
|
||||
|
||||
override var textInputContextIdentifier: String? {
|
||||
return ""
|
||||
}
|
||||
|
||||
override var textInputMode: UITextInputMode? {
|
||||
for mode in UITextInputMode.activeInputModes where mode.primaryLanguage == "emoji" {
|
||||
self.keyboardType = .default // do not remove this
|
||||
return mode
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
override func didMoveToWindow() {
|
||||
super.didMoveToWindow()
|
||||
if shouldBecomeFirstResponderOnAppear && window != nil {
|
||||
DispatchQueue.main.async { [weak self] in
|
||||
self?.becomeFirstResponder()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct EmojiOnlyTextField: UIViewRepresentable {
|
||||
@Binding var text: String
|
||||
var placeholder: String = ""
|
||||
var onBecomeFirstResponder: (() -> Void)?
|
||||
var onKeyboardTypeChanged: ((Bool) -> Void)? // true if NOT emoji (should dismiss), false if emoji
|
||||
var onKeyboardDismissed: (() -> Void)? // Called when keyboard is dismissed
|
||||
|
||||
func makeUIView(context: Context) -> SwiftUIEmojiTextField {
|
||||
let emojiTextField = SwiftUIEmojiTextField()
|
||||
emojiTextField.placeholder = placeholder
|
||||
emojiTextField.text = text
|
||||
emojiTextField.delegate = context.coordinator
|
||||
emojiTextField.shouldBecomeFirstResponderOnAppear = true
|
||||
context.coordinator.textField = emojiTextField
|
||||
return emojiTextField
|
||||
}
|
||||
|
||||
func updateUIView(_ uiView: SwiftUIEmojiTextField, context: Context) {
|
||||
uiView.text = text
|
||||
context.coordinator.onBecomeFirstResponder = onBecomeFirstResponder
|
||||
context.coordinator.onKeyboardTypeChanged = onKeyboardTypeChanged
|
||||
context.coordinator.onKeyboardDismissed = onKeyboardDismissed
|
||||
}
|
||||
|
||||
func makeCoordinator() -> Coordinator {
|
||||
Coordinator(parent: self)
|
||||
}
|
||||
|
||||
class Coordinator: NSObject, UITextFieldDelegate {
|
||||
var parent: EmojiOnlyTextField
|
||||
var textField: SwiftUIEmojiTextField?
|
||||
var onBecomeFirstResponder: (() -> Void)?
|
||||
var onKeyboardTypeChanged: ((Bool) -> Void)?
|
||||
var onKeyboardDismissed: (() -> Void)?
|
||||
var previousInputMode: String?
|
||||
|
||||
init(parent: EmojiOnlyTextField) {
|
||||
self.parent = parent
|
||||
}
|
||||
|
||||
func textFieldDidBeginEditing(_ textField: UITextField) {
|
||||
onBecomeFirstResponder?()
|
||||
checkInputMode(textField)
|
||||
}
|
||||
|
||||
func textFieldDidEndEditing(_ textField: UITextField) {
|
||||
// Keyboard was dismissed
|
||||
onKeyboardDismissed?()
|
||||
}
|
||||
|
||||
func textFieldDidChangeSelection(_ textField: UITextField) {
|
||||
DispatchQueue.main.async { [weak self] in
|
||||
self?.parent.text = textField.text ?? ""
|
||||
}
|
||||
checkInputMode(textField)
|
||||
}
|
||||
|
||||
private func checkInputMode(_ textField: UITextField) {
|
||||
if let inputMode = textField.textInputMode {
|
||||
let isEmoji = inputMode.primaryLanguage == "emoji"
|
||||
if previousInputMode != inputMode.primaryLanguage {
|
||||
previousInputMode = inputMode.primaryLanguage
|
||||
onKeyboardTypeChanged?(!isEmoji) // true if NOT emoji (should dismiss)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -189,7 +189,7 @@ extension MeshPackets {
|
|||
// crash when this method is called with a background context.
|
||||
let fetchRequest = MessageEntity.fetchRequest()
|
||||
fetchRequest.predicate = user.messageFetchRequest.predicate
|
||||
let objects = (try? context.fetch(fetchRequest)) ?? []
|
||||
let objects = try context.fetch(fetchRequest)
|
||||
for object in objects {
|
||||
context.delete(object)
|
||||
}
|
||||
|
|
@ -435,13 +435,19 @@ extension MeshPackets {
|
|||
}
|
||||
}
|
||||
|
||||
let myInfoEntity = MyInfoEntity(context: context)
|
||||
myInfoEntity.myNodeNum = Int64(packet.from)
|
||||
myInfoEntity.rebootCount = 0
|
||||
newNode.myInfo = myInfoEntity
|
||||
|
||||
do {
|
||||
try context.save()
|
||||
Logger.data.info("💾 [NodeInfo] Saved a NodeInfo for node number: \(packet.from.toHex(), privacy: .public)")
|
||||
Logger.data.info("💾 [MyInfoEntity] Saved a new myInfo for node number: \(packet.from.toHex(), privacy: .public)")
|
||||
} catch {
|
||||
context.rollback()
|
||||
let nsError = error as NSError
|
||||
Logger.data.error("💥 [NodeInfoEntity] Error Inserting New Core Data: \(nsError, privacy: .public)")
|
||||
Logger.data.error("💥 [MyInfoEntity] Error Inserting New Core Data: \(nsError, privacy: .public)")
|
||||
}
|
||||
|
||||
} else {
|
||||
|
|
|
|||
|
|
@ -23,23 +23,15 @@ class Router: ObservableObject {
|
|||
|
||||
/// Computed property that assembles the individual per-tab properties into a `NavigationState`.
|
||||
/// Provided for backward compatibility (e.g. tests) and convenience.
|
||||
/// Use the individual `@Published` properties to mutate navigation state.
|
||||
var navigationState: NavigationState {
|
||||
get {
|
||||
NavigationState(
|
||||
selectedTab: selectedTab,
|
||||
messages: messagesState,
|
||||
nodeListSelectedNodeNum: nodeListSelectedNodeNum,
|
||||
map: mapState,
|
||||
settings: settingsState
|
||||
)
|
||||
}
|
||||
set {
|
||||
selectedTab = newValue.selectedTab
|
||||
messagesState = newValue.messages
|
||||
nodeListSelectedNodeNum = newValue.nodeListSelectedNodeNum
|
||||
mapState = newValue.map
|
||||
settingsState = newValue.settings
|
||||
}
|
||||
NavigationState(
|
||||
selectedTab: selectedTab,
|
||||
messages: messagesState,
|
||||
nodeListSelectedNodeNum: nodeListSelectedNodeNum,
|
||||
map: mapState,
|
||||
settings: settingsState
|
||||
)
|
||||
}
|
||||
|
||||
// MARK: Node Object ID Cache
|
||||
|
|
|
|||
|
|
@ -130,6 +130,7 @@ struct ChannelMessageList: View {
|
|||
replyMessageId: $replyMessageId,
|
||||
isFocused: $messageFieldFocused
|
||||
)
|
||||
.fixedSize(horizontal: false, vertical: true)
|
||||
}
|
||||
.navigationBarTitleDisplayMode(.inline)
|
||||
.toolbar {
|
||||
|
|
|
|||
|
|
@ -121,7 +121,7 @@ struct MessageText: View {
|
|||
.keyboardType(.emoji)
|
||||
.scrollDismissesKeyboard(.immediately)
|
||||
.focused($isTapbackInputFocused)
|
||||
.frame(width: 0, height: 0)
|
||||
.frame(width: 1, height: 1)
|
||||
.opacity(0)
|
||||
.onChange(of: tapbackText) {
|
||||
processTapback()
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@ struct TapbackResponses: View {
|
|||
if !tapbacks.isEmpty {
|
||||
VStack(alignment: .trailing) {
|
||||
HStack {
|
||||
ForEach( tapbacks ) { (tapback: MessageEntity) in
|
||||
ForEach(tapbacks) { (tapback: MessageEntity) in
|
||||
VStack {
|
||||
let image = tapback.messagePayload!.image(fontSize: 20)
|
||||
Image(uiImage: image!).font(.caption)
|
||||
|
|
|
|||
|
|
@ -36,6 +36,7 @@ struct TextMessageField: View {
|
|||
}
|
||||
}
|
||||
TextField("Message", text: $typingMessage, axis: .vertical)
|
||||
.frame(minHeight: 36)
|
||||
.padding(10)
|
||||
.background(
|
||||
RoundedRectangle(cornerRadius: 20)
|
||||
|
|
|
|||
|
|
@ -130,6 +130,7 @@ struct UserMessageList: View {
|
|||
replyMessageId: $replyMessageId,
|
||||
isFocused: $messageFieldFocused
|
||||
)
|
||||
.fixedSize(horizontal: false, vertical: true)
|
||||
}
|
||||
.navigationBarTitleDisplayMode(.inline)
|
||||
.toolbar {
|
||||
|
|
|
|||
|
|
@ -236,17 +236,23 @@ struct MapLegend: View {
|
|||
}
|
||||
|
||||
private var routeStartSymbol: some View {
|
||||
Circle()
|
||||
.fill(Color.green)
|
||||
.strokeBorder(Color.white, lineWidth: 2)
|
||||
.frame(width: 15, height: 15)
|
||||
ZStack {
|
||||
Circle()
|
||||
.fill(Color.green)
|
||||
Circle()
|
||||
.strokeBorder(Color.white, lineWidth: 2)
|
||||
}
|
||||
.frame(width: 15, height: 15)
|
||||
}
|
||||
|
||||
private var routeEndSymbol: some View {
|
||||
Circle()
|
||||
.fill(Color.black)
|
||||
.strokeBorder(Color.white, lineWidth: 2)
|
||||
.frame(width: 15, height: 15)
|
||||
ZStack {
|
||||
Circle()
|
||||
.fill(Color.black)
|
||||
Circle()
|
||||
.strokeBorder(Color.white, lineWidth: 2)
|
||||
}
|
||||
.frame(width: 15, height: 15)
|
||||
}
|
||||
|
||||
private var routeLineSymbol: some View {
|
||||
|
|
|
|||
|
|
@ -239,8 +239,8 @@ struct WaypointForm: View {
|
|||
newWaypoint.longitudeI = waypoint.longitudeI
|
||||
// Unicode scalar value for the icon emoji string
|
||||
let unicodeScalers = icon.unicodeScalars
|
||||
// First element as an UInt32
|
||||
let unicode = unicodeScalers[unicodeScalers.startIndex].value
|
||||
// First element as an UInt32 (fall back to 📍 if empty)
|
||||
let unicode = unicodeScalers.first?.value ?? 128205
|
||||
newWaypoint.icon = unicode
|
||||
if locked {
|
||||
if lockedTo == 0 {
|
||||
|
|
|
|||
|
|
@ -35,6 +35,23 @@ struct MeshActivityAttributes: ActivityAttributes {
|
|||
var nodeNum: Int
|
||||
var name: String
|
||||
var shortName: String
|
||||
|
||||
enum CodingKeys: String, CodingKey {
|
||||
case nodeNum, name, shortName
|
||||
}
|
||||
|
||||
init(nodeNum: Int, name: String, shortName: String) {
|
||||
self.nodeNum = nodeNum
|
||||
self.name = name
|
||||
self.shortName = shortName
|
||||
}
|
||||
|
||||
init(from decoder: Decoder) throws {
|
||||
let container = try decoder.container(keyedBy: CodingKeys.self)
|
||||
nodeNum = try container.decode(Int.self, forKey: .nodeNum)
|
||||
name = try container.decode(String.self, forKey: .name)
|
||||
shortName = try container.decodeIfPresent(String.self, forKey: .shortName) ?? "?"
|
||||
}
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue