Fix regressions from merged pull request updates in 2.7.10

This commit is contained in:
Garth Vander Houwen 2026-04-20 11:05:01 -07:00
parent 4839a978ab
commit 92b0cadd3d
12 changed files with 56 additions and 135 deletions

View file

@ -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]()
}

View file

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

View file

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

View file

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

View file

@ -130,6 +130,7 @@ struct ChannelMessageList: View {
replyMessageId: $replyMessageId,
isFocused: $messageFieldFocused
)
.fixedSize(horizontal: false, vertical: true)
}
.navigationBarTitleDisplayMode(.inline)
.toolbar {

View file

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

View file

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

View file

@ -36,6 +36,7 @@ struct TextMessageField: View {
}
}
TextField("Message", text: $typingMessage, axis: .vertical)
.frame(minHeight: 36)
.padding(10)
.background(
RoundedRectangle(cornerRadius: 20)

View file

@ -130,6 +130,7 @@ struct UserMessageList: View {
replyMessageId: $replyMessageId,
isFocused: $messageFieldFocused
)
.fixedSize(horizontal: false, vertical: true)
}
.navigationBarTitleDisplayMode(.inline)
.toolbar {

View file

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

View file

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

View file

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