From 5188152f2f1d78aa573a5d907613bf8ea19e8948 Mon Sep 17 00:00:00 2001 From: Jake-B Date: Sat, 15 Mar 2025 09:47:52 -0400 Subject: [PATCH] Improvements to emoji handling for node names --- Meshtastic/Extensions/String.swift | 26 +++++++++++++++++++ Meshtastic/Views/Helpers/CircleText.swift | 2 +- .../Views/Helpers/ConnectedDevice.swift | 2 +- Meshtastic/Views/Settings/UserConfig.swift | 8 +++--- 4 files changed, 33 insertions(+), 5 deletions(-) diff --git a/Meshtastic/Extensions/String.swift b/Meshtastic/Extensions/String.swift index c7c6385b..aa28fa71 100644 --- a/Meshtastic/Extensions/String.swift +++ b/Meshtastic/Extensions/String.swift @@ -101,4 +101,30 @@ extension String { .map { String($0) } .joined() } + + // Adds variation selectors to prefer the graphical form of emoji. + // Looks ahead to make sure that the variation selector is not already applied. + var addingVariationSelectors: String { + var result = "" + var scalars = self.unicodeScalars + var index = scalars.startIndex + while index < scalars.endIndex { + let currentScalar = scalars[index] + result += String(currentScalar) + if currentScalar.properties.isEmoji && !currentScalar.properties.isEmojiPresentation { + // Check if the next scalar is U+FE0F + let nextIndex = scalars.index(after: index) + if nextIndex < scalars.endIndex && scalars[nextIndex].value == 0xFE0F { + // Already has variation selector; skip the next scalar + index = nextIndex + } else { + // Append variation selector + result += String(UnicodeScalar(0xFE0F)!) + } + } + // Move to the next scalar + index = scalars.index(after: index) + } + return result + } } diff --git a/Meshtastic/Views/Helpers/CircleText.swift b/Meshtastic/Views/Helpers/CircleText.swift index b7e4238d..b8f74842 100644 --- a/Meshtastic/Views/Helpers/CircleText.swift +++ b/Meshtastic/Views/Helpers/CircleText.swift @@ -16,7 +16,7 @@ struct CircleText: View { Circle() .fill(color) .frame(width: circleSize, height: circleSize) - Text(text) + Text(text.addingVariationSelectors) .frame(width: circleSize * 0.9, height: circleSize * 0.9, alignment: .center) .foregroundColor(color.isLight() ? .black : .white) .minimumScaleFactor(0.001) diff --git a/Meshtastic/Views/Helpers/ConnectedDevice.swift b/Meshtastic/Views/Helpers/ConnectedDevice.swift index 42b0ac70..c795b1b0 100644 --- a/Meshtastic/Views/Helpers/ConnectedDevice.swift +++ b/Meshtastic/Views/Helpers/ConnectedDevice.swift @@ -28,7 +28,7 @@ struct ConnectedDevice: View { .imageScale(.large) .foregroundColor(.green) .symbolRenderingMode(.hierarchical) - Text(name).font(name.isEmoji() ? .title : .callout).foregroundColor(.gray) + Text(name.addingVariationSelectors).font(name.isEmoji() ? .title : .callout).foregroundColor(.gray) } else { Image(systemName: "antenna.radiowaves.left.and.right.slash") .imageScale(.medium) diff --git a/Meshtastic/Views/Settings/UserConfig.swift b/Meshtastic/Views/Settings/UserConfig.swift index ea64e36e..644c0077 100644 --- a/Meshtastic/Views/Settings/UserConfig.swift +++ b/Meshtastic/Views/Settings/UserConfig.swift @@ -50,12 +50,14 @@ struct UserConfig: View { TextField("Long Name", text: $longName) .onChange(of: longName) { - var totalBytes = longName.utf8.count + var newValue = longName.withoutVariationSelectors + var totalBytes = newValue.utf8.count // Only mess with the value if it is too big while totalBytes > (isLicensed ? 6 : 36) { - longName = String(longName.dropLast()) - totalBytes = longName.utf8.count + newValue = String(newValue.dropLast()) + totalBytes = newValue.utf8.count } + longName = newValue } } .keyboardType(.default)