Automatically remove spaces in server names (#1600)

* Automatically remove spaces in server names

If a server name includes a space (which can happen if the string is pasted /
autocompleted), this space is removed, which results in the app not crashing.
Fixes #1599

Signed-off-by: Paul Schuetz <pa.schuetz@web.de>

* Format

---------

Signed-off-by: Paul Schuetz <pa.schuetz@web.de>
Co-authored-by: Thomas Ricouard <ricouard77@gmail.com>
This commit is contained in:
Paul Schuetz 2023-10-01 09:37:09 +02:00 committed by GitHub
parent d32c5c004c
commit 0b5e764556
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
21 changed files with 135 additions and 99 deletions

View file

@ -136,7 +136,7 @@ extension View {
modelContainer(for: [ modelContainer(for: [
Draft.self, Draft.self,
LocalTimeline.self, LocalTimeline.self,
TagGroup.self TagGroup.self,
]) ])
} }
} }

View file

@ -6,9 +6,9 @@ import Env
import KeychainSwift import KeychainSwift
import Network import Network
import RevenueCat import RevenueCat
import Status
import SwiftUI import SwiftUI
import Timeline import Timeline
import Status
@main @main
struct IceCubesApp: App { struct IceCubesApp: App {
@ -217,7 +217,7 @@ struct IceCubesApp: App {
case .active: case .active:
watcher.watch(streams: [.user, .direct]) watcher.watch(streams: [.user, .direct])
UNUserNotificationCenter.current().setBadgeCount(0) UNUserNotificationCenter.current().setBadgeCount(0)
userPreferences.reloadNotificationsCount(tokens: appAccountsManager.availableAccounts.compactMap{ $0.oauthToken }) userPreferences.reloadNotificationsCount(tokens: appAccountsManager.availableAccounts.compactMap(\.oauthToken))
Task { Task {
await userPreferences.refreshServerPreferences() await userPreferences.refreshServerPreferences()
} }
@ -287,9 +287,8 @@ class AppDelegate: NSObject, UIApplicationDelegate {
func application(_: UIApplication, didFailToRegisterForRemoteNotificationsWithError _: Error) {} func application(_: UIApplication, didFailToRegisterForRemoteNotificationsWithError _: Error) {}
func application(_ application: UIApplication, didReceiveRemoteNotification userInfo: [AnyHashable : Any]) async -> UIBackgroundFetchResult { func application(_: UIApplication, didReceiveRemoteNotification _: [AnyHashable: Any]) async -> UIBackgroundFetchResult {
UserPreferences.shared.reloadNotificationsCount(tokens: AppAccountsManager.shared.availableAccounts.compactMap(\.oauthToken))
UserPreferences.shared.reloadNotificationsCount(tokens: AppAccountsManager.shared.availableAccounts.compactMap{ $0.oauthToken })
return .noData return .noData
} }

View file

@ -44,6 +44,10 @@ struct AddAccountView: View {
@FocusState private var isInstanceURLFieldFocused: Bool @FocusState private var isInstanceURLFieldFocused: Bool
private func cleanServerStr(_ server: String) -> String {
server.replacingOccurrences(of: " ", with: "")
}
var body: some View { var body: some View {
NavigationStack { NavigationStack {
Form { Form {
@ -54,6 +58,9 @@ struct AddAccountView: View {
.textInputAutocapitalization(.never) .textInputAutocapitalization(.never)
.autocorrectionDisabled() .autocorrectionDisabled()
.focused($isInstanceURLFieldFocused) .focused($isInstanceURLFieldFocused)
.onChange(of: instanceName) { _, _ in
instanceName = cleanServerStr(instanceName)
}
if let instanceFetchError { if let instanceFetchError {
Text(instanceFetchError) Text(instanceFetchError)
} }

View file

@ -6,9 +6,9 @@ import Foundation
import Models import Models
import Network import Network
import Nuke import Nuke
import SwiftData
import SwiftUI import SwiftUI
import Timeline import Timeline
import SwiftData
@MainActor @MainActor
struct SettingsTabs: View { struct SettingsTabs: View {

View file

@ -4,9 +4,9 @@ import DesignSystem
import Env import Env
import Models import Models
import Network import Network
import SwiftData
import SwiftUI import SwiftUI
import Timeline import Timeline
import SwiftData
@MainActor @MainActor
struct TimelineTab: View { struct TimelineTab: View {

View file

@ -105,11 +105,10 @@ struct ConversationMessageView: View {
Button { Button {
Task { Task {
do { do {
let status: Status let status: Status = if isLiked {
if isLiked { try await client.post(endpoint: Statuses.unfavorite(id: message.id))
status = try await client.post(endpoint: Statuses.unfavorite(id: message.id))
} else { } else {
status = try await client.post(endpoint: Statuses.favorite(id: message.id)) try await client.post(endpoint: Statuses.favorite(id: message.id))
} }
withAnimation { withAnimation {
isLiked = status.favourited == true isLiked = status.favourited == true
@ -122,11 +121,10 @@ struct ConversationMessageView: View {
} }
Button { Task { Button { Task {
do { do {
let status: Status let status: Status = if isBookmarked {
if isBookmarked { try await client.post(endpoint: Statuses.unbookmark(id: message.id))
status = try await client.post(endpoint: Statuses.unbookmark(id: message.id))
} else { } else {
status = try await client.post(endpoint: Statuses.bookmark(id: message.id)) try await client.post(endpoint: Statuses.bookmark(id: message.id))
} }
withAnimation { withAnimation {
isBookmarked = status.bookmarked == true isBookmarked = status.bookmarked == true

View file

@ -18,8 +18,8 @@ import SwiftUI
@AppStorage(ThemeKey.primaryBackground.rawValue) public var primaryBackgroundColor: Color = .white @AppStorage(ThemeKey.primaryBackground.rawValue) public var primaryBackgroundColor: Color = .white
@AppStorage(ThemeKey.secondaryBackground.rawValue) public var secondaryBackgroundColor: Color = .gray @AppStorage(ThemeKey.secondaryBackground.rawValue) public var secondaryBackgroundColor: Color = .gray
@AppStorage(ThemeKey.label.rawValue) public var labelColor: Color = .black @AppStorage(ThemeKey.label.rawValue) public var labelColor: Color = .black
@AppStorage(ThemeKey.avatarPosition2.rawValue) var avatarPosition: AvatarPosition = AvatarPosition.top @AppStorage(ThemeKey.avatarPosition2.rawValue) var avatarPosition: AvatarPosition = .top
@AppStorage(ThemeKey.avatarShape2.rawValue) var avatarShape: AvatarShape = AvatarShape.rounded @AppStorage(ThemeKey.avatarShape2.rawValue) var avatarShape: AvatarShape = .rounded
@AppStorage(ThemeKey.selectedSet.rawValue) var storedSet: ColorSetName = .iceCubeDark @AppStorage(ThemeKey.selectedSet.rawValue) var storedSet: ColorSetName = .iceCubeDark
@AppStorage(ThemeKey.statusActionsDisplay.rawValue) public var statusActionsDisplay: StatusActionsDisplay = .full @AppStorage(ThemeKey.statusActionsDisplay.rawValue) public var statusActionsDisplay: StatusActionsDisplay = .full
@AppStorage(ThemeKey.statusDisplayStyle.rawValue) public var statusDisplayStyle: StatusDisplayStyle = .large @AppStorage(ThemeKey.statusDisplayStyle.rawValue) public var statusDisplayStyle: StatusDisplayStyle = .large

View file

@ -53,7 +53,7 @@ import SwiftUI
@AppStorage("share-button-behavior") public var shareButtonBehavior: PreferredShareButtonBehavior = .linkAndText @AppStorage("share-button-behavior") public var shareButtonBehavior: PreferredShareButtonBehavior = .linkAndText
init() { } init() {}
} }
public static let sharedDefault = UserDefaults(suiteName: "group.com.thomasricouard.IceCubesApp") public static let sharedDefault = UserDefaults(suiteName: "group.com.thomasricouard.IceCubesApp")
@ -73,168 +73,199 @@ import SwiftUI
storage.showTranslateButton = showTranslateButton storage.showTranslateButton = showTranslateButton
} }
} }
public var pendingShownAtBottom : Bool { public var pendingShownAtBottom : Bool {
didSet { didSet {
storage.pendingShownAtBottom = pendingShownAtBottom storage.pendingShownAtBottom = pendingShownAtBottom
} }
} }
public var isOpenAIEnabled: Bool { public var isOpenAIEnabled: Bool {
didSet { didSet {
storage.isOpenAIEnabled = isOpenAIEnabled storage.isOpenAIEnabled = isOpenAIEnabled
} }
} }
public var recentlyUsedLanguages: [String] { public var recentlyUsedLanguages: [String] {
didSet { didSet {
storage.recentlyUsedLanguages = recentlyUsedLanguages storage.recentlyUsedLanguages = recentlyUsedLanguages
} }
} }
public var isSocialKeyboardEnabled: Bool { public var isSocialKeyboardEnabled: Bool {
didSet { didSet {
storage.isSocialKeyboardEnabled = isSocialKeyboardEnabled storage.isSocialKeyboardEnabled = isSocialKeyboardEnabled
} }
} }
public var useInstanceContentSettings: Bool { public var useInstanceContentSettings: Bool {
didSet { didSet {
storage.useInstanceContentSettings = useInstanceContentSettings storage.useInstanceContentSettings = useInstanceContentSettings
} }
} }
public var appAutoExpandSpoilers: Bool { public var appAutoExpandSpoilers: Bool {
didSet { didSet {
storage.appAutoExpandSpoilers = appAutoExpandSpoilers storage.appAutoExpandSpoilers = appAutoExpandSpoilers
} }
} }
public var appAutoExpandMedia: ServerPreferences.AutoExpandMedia { public var appAutoExpandMedia: ServerPreferences.AutoExpandMedia {
didSet { didSet {
storage.appAutoExpandMedia = appAutoExpandMedia storage.appAutoExpandMedia = appAutoExpandMedia
} }
} }
public var appDefaultPostVisibility: Models.Visibility { public var appDefaultPostVisibility: Models.Visibility {
didSet { didSet {
storage.appDefaultPostVisibility = appDefaultPostVisibility storage.appDefaultPostVisibility = appDefaultPostVisibility
} }
} }
public var appDefaultReplyVisibility: Models.Visibility { public var appDefaultReplyVisibility: Models.Visibility {
didSet { didSet {
storage.appDefaultReplyVisibility = appDefaultReplyVisibility storage.appDefaultReplyVisibility = appDefaultReplyVisibility
} }
} }
public var appDefaultPostsSensitive: Bool { public var appDefaultPostsSensitive: Bool {
didSet { didSet {
storage.appDefaultPostsSensitive = appDefaultPostsSensitive storage.appDefaultPostsSensitive = appDefaultPostsSensitive
} }
} }
public var autoPlayVideo: Bool { public var autoPlayVideo: Bool {
didSet { didSet {
storage.autoPlayVideo = autoPlayVideo storage.autoPlayVideo = autoPlayVideo
} }
} }
public var alwaysUseDeepl: Bool { public var alwaysUseDeepl: Bool {
didSet { didSet {
storage.alwaysUseDeepl = alwaysUseDeepl storage.alwaysUseDeepl = alwaysUseDeepl
} }
} }
public var userDeeplAPIFree: Bool { public var userDeeplAPIFree: Bool {
didSet { didSet {
storage.userDeeplAPIFree = userDeeplAPIFree storage.userDeeplAPIFree = userDeeplAPIFree
} }
} }
public var autoDetectPostLanguage: Bool { public var autoDetectPostLanguage: Bool {
didSet { didSet {
storage.autoDetectPostLanguage = autoDetectPostLanguage storage.autoDetectPostLanguage = autoDetectPostLanguage
} }
} }
public var suppressDupeReblogs: Bool { public var suppressDupeReblogs: Bool {
didSet { didSet {
storage.suppressDupeReblogs = suppressDupeReblogs storage.suppressDupeReblogs = suppressDupeReblogs
} }
} }
public var inAppBrowserReaderView: Bool { public var inAppBrowserReaderView: Bool {
didSet { didSet {
storage.inAppBrowserReaderView = inAppBrowserReaderView storage.inAppBrowserReaderView = inAppBrowserReaderView
} }
} }
public var hapticTabSelectionEnabled: Bool { public var hapticTabSelectionEnabled: Bool {
didSet { didSet {
storage.hapticTabSelectionEnabled = hapticTabSelectionEnabled storage.hapticTabSelectionEnabled = hapticTabSelectionEnabled
} }
} }
public var hapticTimelineEnabled: Bool { public var hapticTimelineEnabled: Bool {
didSet { didSet {
storage.hapticTimelineEnabled = hapticTimelineEnabled storage.hapticTimelineEnabled = hapticTimelineEnabled
} }
} }
public var hapticButtonPressEnabled: Bool { public var hapticButtonPressEnabled: Bool {
didSet { didSet {
storage.hapticButtonPressEnabled = hapticButtonPressEnabled storage.hapticButtonPressEnabled = hapticButtonPressEnabled
} }
} }
public var soundEffectEnabled: Bool { public var soundEffectEnabled: Bool {
didSet { didSet {
storage.soundEffectEnabled = soundEffectEnabled storage.soundEffectEnabled = soundEffectEnabled
} }
} }
public var showiPhoneTabLabel: Bool { public var showiPhoneTabLabel: Bool {
didSet { didSet {
storage.showiPhoneTabLabel = showiPhoneTabLabel storage.showiPhoneTabLabel = showiPhoneTabLabel
} }
} }
public var showAltTextForMedia: Bool { public var showAltTextForMedia: Bool {
didSet { didSet {
storage.showAltTextForMedia = showAltTextForMedia storage.showAltTextForMedia = showAltTextForMedia
} }
} }
public var showiPadSecondaryColumn: Bool { public var showiPadSecondaryColumn: Bool {
didSet { didSet {
storage.showiPadSecondaryColumn = showiPadSecondaryColumn storage.showiPadSecondaryColumn = showiPadSecondaryColumn
} }
} }
public var swipeActionsStatusTrailingRight: StatusAction { public var swipeActionsStatusTrailingRight: StatusAction {
didSet { didSet {
storage.swipeActionsStatusTrailingRight = swipeActionsStatusTrailingRight storage.swipeActionsStatusTrailingRight = swipeActionsStatusTrailingRight
} }
} }
public var swipeActionsStatusTrailingLeft: StatusAction { public var swipeActionsStatusTrailingLeft: StatusAction {
didSet { didSet {
storage.swipeActionsStatusTrailingLeft = swipeActionsStatusTrailingLeft storage.swipeActionsStatusTrailingLeft = swipeActionsStatusTrailingLeft
} }
} }
public var swipeActionsStatusLeadingLeft: StatusAction { public var swipeActionsStatusLeadingLeft: StatusAction {
didSet { didSet {
storage.swipeActionsStatusLeadingLeft = swipeActionsStatusLeadingLeft storage.swipeActionsStatusLeadingLeft = swipeActionsStatusLeadingLeft
} }
} }
public var swipeActionsStatusLeadingRight: StatusAction { public var swipeActionsStatusLeadingRight: StatusAction {
didSet { didSet {
storage.swipeActionsStatusLeadingRight = swipeActionsStatusLeadingRight storage.swipeActionsStatusLeadingRight = swipeActionsStatusLeadingRight
} }
} }
public var swipeActionsUseThemeColor: Bool { public var swipeActionsUseThemeColor: Bool {
didSet { didSet {
storage.swipeActionsUseThemeColor = swipeActionsUseThemeColor storage.swipeActionsUseThemeColor = swipeActionsUseThemeColor
} }
} }
public var swipeActionsIconStyle: SwipeActionsIconStyle { public var swipeActionsIconStyle: SwipeActionsIconStyle {
didSet { didSet {
storage.swipeActionsIconStyle = swipeActionsIconStyle storage.swipeActionsIconStyle = swipeActionsIconStyle
} }
} }
public var requestedReview: Bool { public var requestedReview: Bool {
didSet { didSet {
storage.requestedReview = requestedReview storage.requestedReview = requestedReview
} }
} }
public var collapseLongPosts: Bool { public var collapseLongPosts: Bool {
didSet { didSet {
storage.collapseLongPosts = collapseLongPosts storage.collapseLongPosts = collapseLongPosts
} }
} }
public var shareButtonBehavior: PreferredShareButtonBehavior { public var shareButtonBehavior: PreferredShareButtonBehavior {
didSet { didSet {
storage.shareButtonBehavior = shareButtonBehavior storage.shareButtonBehavior = shareButtonBehavior
} }
} }
public enum SwipeActionsIconStyle: String, CaseIterable { public enum SwipeActionsIconStyle: String, CaseIterable {
case iconWithText, iconOnly case iconWithText, iconOnly
@ -318,7 +349,7 @@ import SwiftUI
} }
public var totalNotificationsCount: Int { public var totalNotificationsCount: Int {
notificationsCount.compactMap{ $0.value }.reduce(0, +) notificationsCount.compactMap(\.value).reduce(0, +)
} }
public func reloadNotificationsCount(tokens: [OauthToken]) { public func reloadNotificationsCount(tokens: [OauthToken]) {

View file

@ -1,6 +1,6 @@
import Foundation
import SwiftData import SwiftData
import SwiftUI import SwiftUI
import Foundation
@Model public class Draft { @Model public class Draft {
@Attribute(.unique) public var id: UUID @Attribute(.unique) public var id: UUID
@ -8,8 +8,8 @@ import Foundation
public var creationDate: Date public var creationDate: Date
public init(content: String) { public init(content: String) {
self.id = UUID() id = UUID()
self.content = content self.content = content
self.creationDate = Date() creationDate = Date()
} }
} }

View file

@ -1,6 +1,6 @@
import Foundation
import SwiftData import SwiftData
import SwiftUI import SwiftUI
import Foundation
@Model public class LocalTimeline { @Model public class LocalTimeline {
public var instance: String public var instance: String
@ -8,6 +8,6 @@ import Foundation
public init(instance: String) { public init(instance: String) {
self.instance = instance self.instance = instance
self.creationDate = Date() creationDate = Date()
} }
} }

View file

@ -1,6 +1,6 @@
import Foundation
import SwiftData import SwiftData
import SwiftUI import SwiftUI
import Foundation
@Model public class TagGroup: Equatable { @Model public class TagGroup: Equatable {
public var title: String public var title: String
@ -12,7 +12,7 @@ import Foundation
self.title = title self.title = title
self.symbolName = symbolName self.symbolName = symbolName
self.tags = tags self.tags = tags
self.creationDate = Date() creationDate = Date()
} }
} }

View file

@ -62,4 +62,3 @@ public struct FeaturedTag: Codable, Identifiable {
extension Tag: Sendable {} extension Tag: Sendable {}
extension Tag.History: Sendable {} extension Tag.History: Sendable {}
extension FeaturedTag: Sendable {} extension FeaturedTag: Sendable {}

View file

@ -1,7 +1,7 @@
import SwiftUI
import SwiftData
import DesignSystem import DesignSystem
import Models import Models
import SwiftData
import SwiftUI
struct DraftsListView: View { struct DraftsListView: View {
@AppStorage("draft_posts") public var legacyDraftPosts: [String] = [] @AppStorage("draft_posts") public var legacyDraftPosts: [String] = []

View file

@ -161,7 +161,8 @@ public struct StatusEditorView: View {
object: nil) object: nil)
} }
Button("action.cancel", role: .cancel) {} Button("action.cancel", role: .cancel) {}
}) }
)
} }
} }
} }

View file

@ -33,7 +33,8 @@ public struct TimelineView: View {
public init(timeline: Binding<TimelineFilter>, public init(timeline: Binding<TimelineFilter>,
selectedTagGroup: Binding<TagGroup?>, selectedTagGroup: Binding<TagGroup?>,
scrollToTopSignal: Binding<Int>, canFilterTimeline: Bool) { scrollToTopSignal: Binding<Int>, canFilterTimeline: Bool)
{
_timeline = timeline _timeline = timeline
_selectedTagGroup = selectedTagGroup _selectedTagGroup = selectedTagGroup
_scrollToTopSignal = scrollToTopSignal _scrollToTopSignal = scrollToTopSignal