Swiftformat

This commit is contained in:
Thomas Ricouard 2023-09-16 14:15:03 +02:00
parent 584a0d0432
commit 8a3c971402
120 changed files with 573 additions and 579 deletions

View file

@ -155,8 +155,8 @@ struct ActivityView: UIViewControllerRepresentable {
}
func makeUIViewController(context _: UIViewControllerRepresentableContext<ActivityView>) -> UIActivityViewController {
return UIActivityViewController(activityItems: [image, LinkDelegate(image: image, status: status)],
applicationActivities: nil)
UIActivityViewController(activityItems: [image, LinkDelegate(image: image, status: status)],
applicationActivities: nil)
}
func updateUIViewController(_: UIActivityViewController, context _: UIViewControllerRepresentableContext<ActivityView>) {}

View file

@ -100,7 +100,7 @@ struct IceCubesApp: App {
}
private func badgeFor(tab: Tab) -> Int {
if tab == .notifications && selectedTab != tab,
if tab == .notifications, selectedTab != tab,
let token = appAccountsManager.currentAccount.oauthToken
{
return watcher.unreadNotificationsCount + userPreferences.getNotificationsCount(for: token)

View file

@ -13,7 +13,7 @@ struct QuickLookPreview: UIViewControllerRepresentable {
let urls: [URL]
func makeUIViewController(context _: Context) -> UIViewController {
return AppQLPreviewController(selectedURL: selectedURL, urls: urls)
AppQLPreviewController(selectedURL: selectedURL, urls: urls)
}
func updateUIViewController(
@ -53,11 +53,11 @@ class AppQLPreviewController: UIViewController {
extension AppQLPreviewController: QLPreviewControllerDataSource {
nonisolated func numberOfPreviewItems(in _: QLPreviewController) -> Int {
return urls.count
urls.count
}
nonisolated func previewController(_: QLPreviewController, previewItemAt index: Int) -> QLPreviewItem {
return urls[index] as QLPreviewItem
urls[index] as QLPreviewItem
}
}
@ -81,7 +81,7 @@ extension AppQLPreviewController: QLPreviewControllerDelegate {
struct TransparentBackground: UIViewControllerRepresentable {
public func makeUIViewController(context _: Context) -> UIViewController {
return TransparentController()
TransparentController()
}
public func updateUIViewController(_: UIViewController, context _: Context) {}

View file

@ -51,7 +51,7 @@ private struct SafariRouter: ViewModifier {
}
.background {
WindowReader { window in
self.safariManager.windowScene = window.windowScene
safariManager.windowScene = window.windowScene
}
}
}
@ -65,7 +65,7 @@ private class InAppSafariManager: NSObject, ObservableObject, SFSafariViewContro
@MainActor
func open(_ url: URL) -> OpenURLAction.Result {
guard let windowScene = windowScene else { return .systemAction }
guard let windowScene else { return .systemAction }
window = setupWindow(windowScene: windowScene)
@ -85,7 +85,7 @@ private class InAppSafariManager: NSObject, ObservableObject, SFSafariViewContro
}
func setupWindow(windowScene: UIWindowScene) -> UIWindow {
let window = self.window ?? UIWindow(windowScene: windowScene)
let window = window ?? UIWindow(windowScene: windowScene)
window.rootViewController = viewController
window.makeKeyAndVisible()

View file

@ -19,7 +19,7 @@ struct SideBarView<Content: View>: View {
@ViewBuilder var content: () -> Content
private func badgeFor(tab: Tab) -> Int {
if tab == .notifications && selectedTab != tab,
if tab == .notifications, selectedTab != tab,
let token = appAccounts.currentAccount.oauthToken
{
return watcher.unreadNotificationsCount + userPreferences.getNotificationsCount(for: token)

View file

@ -29,7 +29,7 @@ struct ExploreTab: View {
AppAccountsSelectorView(routerPath: routerPath)
}
}
if UIDevice.current.userInterfaceIdiom == .pad && !preferences.showiPadSecondaryColumn {
if UIDevice.current.userInterfaceIdiom == .pad, !preferences.showiPadSecondaryColumn {
SecondaryColumnToolbarItem()
}
}

View file

@ -75,7 +75,7 @@ struct AboutView: View {
[SwiftUI-Introspect](https://github.com/siteline/SwiftUI-Introspect)
[RevenueCat](https://github.com/RevenueCat/purchases-ios)
[SFSafeSymbols](https://github.com/SFSafeSymbols/SFSafeSymbols)
""")
.multilineTextAlignment(.leading)

View file

@ -100,11 +100,11 @@ struct AddAccountView: View {
Task {
do {
// bare bones preflight for domain validity
if client.server.contains(".") && client.server.last != "." {
if client.server.contains("."), client.server.last != "." {
let instance: Instance = try await client.get(endpoint: Instances.instance)
withAnimation {
self.instance = instance
self.instanceName = sanitizedName // clean up the text box, principally to chop off the username if present so it's clear that you might not wind up siging in as the thing in the box
instanceName = sanitizedName // clean up the text box, principally to chop off the username if present so it's clear that you might not wind up siging in as the thing in the box
}
instanceFetchError = nil
} else {
@ -178,7 +178,7 @@ struct AddAccountView: View {
} else {
ForEach(sanitizedName.isEmpty ? instances : instances.filter { $0.name.contains(sanitizedName.lowercased()) }) { instance in
Button {
self.instanceName = instance.name
instanceName = instance.name
} label: {
VStack(alignment: .leading, spacing: 4) {
Text(instance.name)

View file

@ -83,19 +83,20 @@ struct ContentSettingsView: View {
}
}
.disabled(userPreferences.useInstanceContentSettings)
Picker("settings.content.default-reply-visibility", selection: $userPreferences.appDefaultReplyVisibility) {
ForEach(Visibility.allCases, id: \.rawValue) { vis in
if UserPreferences.getIntOfVisibility(vis) <=
UserPreferences.getIntOfVisibility(userPreferences.postVisibility) {
UserPreferences.getIntOfVisibility(userPreferences.postVisibility)
{
Text(vis.title).tag(vis)
}
}
}
.onChange(of: userPreferences.postVisibility) { newValue in
.onChange(of: userPreferences.postVisibility) { _ in
userPreferences.conformReplyVisibilityConstraints()
}
Toggle(isOn: $userPreferences.appDefaultPostsSensitive) {
Text("settings.content.default-sensitive")
}

View file

@ -32,9 +32,9 @@ struct IconSelectorView: View {
var appIconName: String {
switch self {
case .primary:
return "AppIcon"
"AppIcon"
default:
return "AppIconAlternate\(rawValue)"
"AppIconAlternate\(rawValue)"
}
}
@ -120,6 +120,6 @@ struct IconSelectorView: View {
extension String {
var localized: String {
return NSLocalizedString(self, comment: "")
NSLocalizedString(self, comment: "")
}
}

View file

@ -51,7 +51,7 @@ struct SettingsTabs: View {
}
}
}
if UIDevice.current.userInterfaceIdiom == .pad && !preferences.showiPadSecondaryColumn {
if UIDevice.current.userInterfaceIdiom == .pad, !preferences.showiPadSecondaryColumn {
SecondaryColumnToolbarItem()
}
}
@ -326,7 +326,6 @@ struct SettingsTabs: View {
}
}
private func moveTimelineItems(from source: IndexSet, to destination: Int) {
preferences.remoteLocalTimelines.move(fromOffsets: source, toOffset: destination)
}

View file

@ -19,30 +19,30 @@ struct SupportAppView: View {
var title: LocalizedStringKey {
switch self {
case .one:
return "settings.support.one.title"
"settings.support.one.title"
case .two:
return "settings.support.two.title"
"settings.support.two.title"
case .three:
return "settings.support.three.title"
"settings.support.three.title"
case .four:
return "settings.support.four.title"
"settings.support.four.title"
case .supporter:
return "settings.support.supporter.title"
"settings.support.supporter.title"
}
}
var subtitle: LocalizedStringKey {
switch self {
case .one:
return "settings.support.one.subtitle"
"settings.support.one.subtitle"
case .two:
return "settings.support.two.subtitle"
"settings.support.two.subtitle"
case .three:
return "settings.support.three.subtitle"
"settings.support.three.subtitle"
case .four:
return "settings.support.four.subtitle"
"settings.support.four.subtitle"
case .supporter:
return "settings.support.supporter.subtitle"
"settings.support.supporter.subtitle"
}
}
}
@ -103,8 +103,8 @@ struct SupportAppView: View {
}
private func fetchStoreProducts() {
Purchases.shared.getProducts(Tip.allCases.map { $0.productId }) { products in
self.subscription = products.first(where: { $0.productIdentifier == Tip.supporter.productId })
Purchases.shared.getProducts(Tip.allCases.map(\.productId)) { products in
subscription = products.first(where: { $0.productIdentifier == Tip.supporter.productId })
self.products = products.filter { $0.productIdentifier != Tip.supporter.productId }.sorted(by: { $0.price < $1.price })
withAnimation {
loadingProducts = false
@ -114,7 +114,7 @@ struct SupportAppView: View {
private func refreshUserInfo() {
Purchases.shared.getCustomerInfo { info, _ in
self.customerInfo = info
customerInfo = info
}
}
@ -221,7 +221,7 @@ struct SupportAppView: View {
Spacer()
Button {
Purchases.shared.restorePurchases { info, _ in
self.customerInfo = info
customerInfo = info
}
} label: {
Text("settings.support.restore-purchase.button")

View file

@ -68,7 +68,7 @@ struct SwipeActionsSettingsView: View {
}
private func createStatusActionPicker(selection: Binding<StatusAction>, label: LocalizedStringKey) -> some View {
return Picker(selection: selection, label: Text(label)) {
Picker(selection: selection, label: Text(label)) {
Section {
Text(StatusAction.none.displayName()).tag(StatusAction.none)
}

View file

@ -86,27 +86,27 @@ enum Tab: Int, Identifiable, Hashable {
var iconName: String {
switch self {
case .timeline:
return "rectangle.stack"
"rectangle.stack"
case .trending:
return "chart.line.uptrend.xyaxis"
"chart.line.uptrend.xyaxis"
case .local:
return "person.2"
"person.2"
case .federated:
return "globe.americas"
"globe.americas"
case .notifications:
return "bell"
"bell"
case .mentions:
return "at"
"at"
case .explore:
return "magnifyingglass"
"magnifyingglass"
case .messages:
return "tray"
"tray"
case .settings:
return "gear"
"gear"
case .profile:
return "person.crop.circle"
"person.crop.circle"
case .other:
return ""
""
}
}
}

View file

@ -71,7 +71,7 @@ struct AddRemoteTimelineView: View {
isInstanceURLFieldFocused = true
let client = InstanceSocialClient()
Task {
self.instances = await client.fetchInstances()
instances = await client.fetchInstances()
}
}
}
@ -85,7 +85,7 @@ struct AddRemoteTimelineView: View {
} else {
ForEach(instanceName.isEmpty ? instances : instances.filter { $0.name.contains(instanceName.lowercased()) }) { instance in
Button {
self.instanceName = instance.name
instanceName = instance.name
} label: {
VStack(alignment: .leading, spacing: 4) {
Text(instance.name)

View file

@ -35,7 +35,7 @@ struct EditTagGroupView: View {
case symbol
case new
}
init(editingTagGroup: TagGroup? = nil, onSaved: ((TagGroup) -> Void)? = nil) {
self.editingTagGroup = editingTagGroup
self.onSaved = onSaved
@ -163,7 +163,7 @@ struct EditTagGroupView: View {
private func save() {
var toSave = tags
let main = toSave.removeFirst()
let tagGroup: TagGroup = .init(
title: title.trimmingCharacters(in: .whitespaces),
sfSymbolName: sfSymbolName,
@ -171,7 +171,8 @@ struct EditTagGroupView: View {
additional: toSave
)
if let editingTagGroup,
let index = preferences.tagGroups.firstIndex(of: editingTagGroup) {
let index = preferences.tagGroups.firstIndex(of: editingTagGroup)
{
preferences.tagGroups[index] = tagGroup
} else {
preferences.tagGroups.append(tagGroup)
@ -183,7 +184,7 @@ struct EditTagGroupView: View {
@ViewBuilder
private var symbolsSuggestionView: some View {
if focusedField == .symbol && !sfSymbolName.isEmpty {
if focusedField == .symbol, !sfSymbolName.isEmpty {
let filteredMatches = allSymbols
.filter { $0.contains(sfSymbolName) }
if !filteredMatches.isEmpty {

View file

@ -9,5 +9,5 @@ import Foundation
import SFSafeSymbols
let allSymbols: [String] = SFSymbol.allSymbols.map { symbol in
symbol.rawValue
symbol.rawValue
}

View file

@ -43,7 +43,7 @@ struct TimelineTab: View {
}
.onAppear {
routerPath.client = client
if !didAppear && canFilterTimeline {
if !didAppear, canFilterTimeline {
didAppear = true
if client.isAuth {
timeline = lastTimelineFilter
@ -97,7 +97,7 @@ struct TimelineTab: View {
private var timelineFilterButton: some View {
if timeline.supportNewestPagination {
Button {
self.timeline = .latest
timeline = .latest
} label: {
Label(TimelineFilter.latest.localizedTitle(), systemImage: TimelineFilter.latest.iconName() ?? "")
}
@ -197,7 +197,7 @@ struct TimelineTab: View {
}
statusEditorToolbarItem(routerPath: routerPath,
visibility: preferences.postVisibility)
if UIDevice.current.userInterfaceIdiom == .pad && !preferences.showiPadSecondaryColumn {
if UIDevice.current.userInterfaceIdiom == .pad, !preferences.showiPadSecondaryColumn {
SecondaryColumnToolbarItem()
}
} else {

View file

@ -70,7 +70,7 @@ class NotificationService: UNNotificationServiceExtension {
preferences.setNotification(count: currentCount, token: token)
}
let tokens = AppAccountsManager.shared.pushAccounts.map { $0.token }
let tokens = AppAccountsManager.shared.pushAccounts.map(\.token)
bestAttemptContent.badge = .init(integerLiteral: preferences.getNotificationsTotalCount(for: tokens))
if let urlString = notification.icon,

View file

@ -29,7 +29,7 @@ let package = Package(
.product(name: "Status", package: "Status"),
],
swiftSettings: [
.enableExperimentalFeature("StrictConcurrency")
.enableExperimentalFeature("StrictConcurrency"),
]
),
.testTarget(

View file

@ -89,7 +89,7 @@ public struct AccountDetailView: View {
viewModel.client = client
// Avoid capturing non-Sendable `self` just to access the view model.
let viewModel = self.viewModel
let viewModel = viewModel
Task {
await withTaskGroup(of: Void.self) { group in
group.addTask { await viewModel.fetchAccount() }
@ -334,7 +334,7 @@ public struct AccountDetailView: View {
} label: {
Label("account.action.edit-info", systemImage: "pencil")
}
Button {
if let url = URL(string: "https://\(client.server)/settings/privacy") {
openURL(url)

View file

@ -27,25 +27,25 @@ class AccountDetailViewModel: ObservableObject, StatusesFetcher {
var iconName: String {
switch self {
case .statuses: return "bubble.right"
case .favorites: return "star"
case .bookmarks: return "bookmark"
case .followedTags: return "tag"
case .postsAndReplies: return "bubble.left.and.bubble.right"
case .media: return "photo.on.rectangle.angled"
case .lists: return "list.bullet"
case .statuses: "bubble.right"
case .favorites: "star"
case .bookmarks: "bookmark"
case .followedTags: "tag"
case .postsAndReplies: "bubble.left.and.bubble.right"
case .media: "photo.on.rectangle.angled"
case .lists: "list.bullet"
}
}
var accessibilityLabel: LocalizedStringKey {
switch self {
case .statuses: return "accessibility.tabs.profile.picker.statuses"
case .favorites: return "accessibility.tabs.profile.picker.favorites"
case .bookmarks: return "accessibility.tabs.profile.picker.bookmarks"
case .followedTags: return "accessibility.tabs.profile.picker.followed-tags"
case .postsAndReplies: return "accessibility.tabs.profile.picker.posts-and-replies"
case .media: return "accessibility.tabs.profile.picker.media"
case .lists: return "accessibility.tabs.profile.picker.lists"
case .statuses: "accessibility.tabs.profile.picker.statuses"
case .favorites: "accessibility.tabs.profile.picker.favorites"
case .bookmarks: "accessibility.tabs.profile.picker.bookmarks"
case .followedTags: "accessibility.tabs.profile.picker.followed-tags"
case .postsAndReplies: "accessibility.tabs.profile.picker.posts-and-replies"
case .media: "accessibility.tabs.profile.picker.media"
case .lists: "accessibility.tabs.profile.picker.lists"
}
}
}
@ -145,7 +145,7 @@ class AccountDetailViewModel: ObservableObject, StatusesFetcher {
private func fetchAccountData(accountId: String, client: Client) async throws -> AccountData {
async let account: Account = client.get(endpoint: Accounts.accounts(id: accountId))
async let featuredTags: [FeaturedTag] = client.get(endpoint: Accounts.featuredTags(id: accountId))
if client.isAuth && !isCurrentUser {
if client.isAuth, !isCurrentUser {
async let relationships: [Relationship] = client.get(endpoint: Accounts.relationships(ids: [accountId]))
do {
return try await .init(account: account,

View file

@ -10,15 +10,15 @@ public enum AccountsListMode {
var title: LocalizedStringKey {
switch self {
case .following:
return "account.following"
"account.following"
case .followers:
return "account.followers"
"account.followers"
case .favoritedBy:
return "account.favorited-by"
"account.favorited-by"
case .rebloggedBy:
return "account.boosted-by"
"account.boosted-by"
case .accountsList:
return ""
""
}
}
}
@ -76,7 +76,7 @@ class AccountsListViewModel: ObservableObject {
}
nextPageId = link?.maxId
relationships = try await client.get(endpoint:
Accounts.relationships(ids: accounts.map { $0.id }))
Accounts.relationships(ids: accounts.map(\.id)))
state = .display(accounts: accounts,
relationships: relationships,
nextPageState: link?.maxId != nil ? .hasNextPage : .none)
@ -108,7 +108,7 @@ class AccountsListViewModel: ObservableObject {
}
accounts.append(contentsOf: newAccounts)
let newRelationships: [Relationship] =
try await client.get(endpoint: Accounts.relationships(ids: newAccounts.map { $0.id }))
try await client.get(endpoint: Accounts.relationships(ids: newAccounts.map(\.id)))
relationships.append(contentsOf: newRelationships)
self.nextPageId = link?.maxId

View file

@ -20,23 +20,21 @@ struct EditFilterView: View {
@State private var filterAction: ServerFilter.Action
@State private var expiresAt: Date?
@State private var expirySelection: Duration
enum Fields {
case title, newKeyword
}
@FocusState private var focusedField: Fields?
private var data: ServerFilterData {
var expiresIn: String?
// we add 50 seconds, otherwise we immediately show 6d for a 7d filter (6d, 23h, 59s)
switch expirySelection {
let expiresIn: String? = switch expirySelection {
case .infinite:
expiresIn = "" // need to send an empty value in order for the server to clear this field in the filter
"" // need to send an empty value in order for the server to clear this field in the filter
case .custom:
expiresIn = String(Int(expiresAt?.timeIntervalSince(Date()) ?? 0) + 50)
String(Int(expiresAt?.timeIntervalSince(Date()) ?? 0) + 50)
default:
expiresIn = String(expirySelection.rawValue + 50)
String(expirySelection.rawValue + 50)
}
return ServerFilterData(title: title,
@ -100,7 +98,7 @@ struct EditFilterView: View {
}
if expirySelection != .infinite {
DatePicker("filter.edit.expiry.date-time",
selection: Binding<Date>(get: { self.expiresAt ?? Date() }, set: { self.expiresAt = $0 }),
selection: Binding<Date>(get: { expiresAt ?? Date() }, set: { expiresAt = $0 }),
displayedComponents: [.date, .hourAndMinute])
.disabled(expirySelection != .custom)
}

View file

@ -19,11 +19,11 @@ public struct FiltersListView: View {
public var body: some View {
NavigationStack {
Form {
if !isLoading && filters.isEmpty {
if !isLoading, filters.isEmpty {
EmptyView()
} else {
Section {
if isLoading && filters.isEmpty {
if isLoading, filters.isEmpty {
ProgressView()
} else {
ForEach(filters) { filter in
@ -31,7 +31,7 @@ public struct FiltersListView: View {
VStack(alignment: .leading) {
Text(filter.title)
.font(.scaledSubheadline)
Text("\(filter.context.map { $0.name }.joined(separator: ", "))")
Text("\(filter.context.map(\.name).joined(separator: ", "))")
.font(.scaledBody)
.foregroundColor(.gray)
if filter.hasExpiry() {

View file

@ -31,7 +31,7 @@ let package = Package(
.product(name: "DesignSystem", package: "DesignSystem"),
],
swiftSettings: [
.enableExperimentalFeature("StrictConcurrency")
.enableExperimentalFeature("StrictConcurrency"),
]
),
]

View file

@ -25,9 +25,9 @@ public class AppAccountViewModel: ObservableObject {
var acct: String {
if let acct = appAccount.accountName {
return acct
acct
} else {
return "@\(account?.acct ?? "...")@\(appAccount.server)"
"@\(account?.acct ?? "...")@\(appAccount.server)"
}
}

View file

@ -27,7 +27,7 @@ public class AppAccountsManager: ObservableObject {
public static var shared = AppAccountsManager()
internal init() {
init() {
var defaultAccount = AppAccount(server: AppInfo.defaultServer, accountName: nil, oauthToken: nil)
let keychainAccounts = AppAccount.retrieveAll()
availableAccounts = keychainAccounts

View file

@ -19,7 +19,7 @@ public struct AppAccountsSelectorView: View {
private var showNotificationBadge: Bool {
accountsViewModel
.filter { $0.account?.id != currentAccount.account?.id }
.compactMap { $0.appAccount.oauthToken }
.compactMap(\.appAccount.oauthToken)
.map { preferences.getNotificationsCount(for: $0) }
.reduce(0, +) > 0
}
@ -84,7 +84,7 @@ public struct AppAccountsSelectorView: View {
.redacted(reason: .placeholder)
}
}.overlay(alignment: .topTrailing) {
if (!currentAccount.followRequests.isEmpty || showNotificationBadge) && accountCreationEnabled {
if !currentAccount.followRequests.isEmpty || showNotificationBadge, accountCreationEnabled {
Circle()
.fill(Color.red)
.frame(width: 9, height: 9)

View file

@ -31,7 +31,7 @@ let package = Package(
.product(name: "DesignSystem", package: "DesignSystem"),
],
swiftSettings: [
.enableExperimentalFeature("StrictConcurrency")
.enableExperimentalFeature("StrictConcurrency"),
]
),
]

View file

@ -27,8 +27,8 @@ struct ConversationsListRow: View {
.accessibilityHidden(true)
VStack(alignment: .leading, spacing: 4) {
HStack {
EmojiTextApp(.init(stringValue: conversation.accounts.map { $0.safeDisplayName }.joined(separator: ", ")),
emojis: conversation.accounts.flatMap { $0.emojis })
EmojiTextApp(.init(stringValue: conversation.accounts.map(\.safeDisplayName).joined(separator: ", ")),
emojis: conversation.accounts.flatMap(\.emojis))
.font(.scaledSubheadline)
.foregroundColor(theme.labelColor)
.emojiSize(Font.scaledSubheadlineFont.emojiSize)

View file

@ -18,9 +18,9 @@ public struct ConversationsListView: View {
private var conversations: Binding<[Conversation]> {
if viewModel.isLoadingFirstPage {
return Binding.constant(Conversation.placeholders())
Binding.constant(Conversation.placeholders())
} else {
return $viewModel.conversations
$viewModel.conversations
}
}
@ -40,7 +40,7 @@ public struct ConversationsListView: View {
}
Divider()
}
} else if conversations.isEmpty && !viewModel.isLoadingFirstPage && !viewModel.isError {
} else if conversations.isEmpty, !viewModel.isLoadingFirstPage, !viewModel.isError {
EmptyView(iconName: "tray",
title: "conversations.empty.title",
message: "conversations.empty.message")
@ -79,7 +79,7 @@ public struct ConversationsListView: View {
.navigationBarTitleDisplayMode(.inline)
.toolbar {
StatusEditorToolbarItem(visibility: .direct)
if UIDevice.current.userInterfaceIdiom == .pad && !preferences.showiPadSecondaryColumn {
if UIDevice.current.userInterfaceIdiom == .pad, !preferences.showiPadSecondaryColumn {
SecondaryColumnToolbarItem()
}
}

View file

@ -60,11 +60,10 @@ class ConversationsListViewModel: ObservableObject {
func favorite(conversation: Conversation) async {
guard let client, let message = conversation.lastStatus else { return }
let endpoint: Endpoint
if message.favourited ?? false {
endpoint = Statuses.unfavorite(id: message.id)
let endpoint: Endpoint = if message.favourited ?? false {
Statuses.unfavorite(id: message.id)
} else {
endpoint = Statuses.favorite(id: message.id)
Statuses.favorite(id: message.id)
}
do {
let status: Status = try await client.post(endpoint: endpoint)
@ -74,11 +73,10 @@ class ConversationsListViewModel: ObservableObject {
func bookmark(conversation: Conversation) async {
guard let client, let message = conversation.lastStatus else { return }
let endpoint: Endpoint
if message.bookmarked ?? false {
endpoint = Statuses.unbookmark(id: message.id)
let endpoint: Endpoint = if message.bookmarked ?? false {
Statuses.unbookmark(id: message.id)
} else {
endpoint = Statuses.bookmark(id: message.id)
Statuses.bookmark(id: message.id)
}
do {
let status: Status = try await client.post(endpoint: endpoint)

View file

@ -34,7 +34,7 @@ let package = Package(
.product(name: "EmojiText", package: "EmojiText"),
],
swiftSettings: [
.enableExperimentalFeature("StrictConcurrency")
.enableExperimentalFeature("StrictConcurrency"),
]
),
]

View file

@ -160,19 +160,18 @@ public struct ConstellationDark: ColorSet {
public var scheme: ColorScheme = .dark
public var tintColor: Color = .init(hex: 0xFFD966)
public var primaryBackgroundColor: Color = .init(hex: 0x09192C)
public var secondaryBackgroundColor: Color = .init(hex: 0x304c7a)
public var secondaryBackgroundColor: Color = .init(hex: 0x304C7A)
public var labelColor: Color = .init(hex: 0xE2E4E2)
public init() {}
}
public struct ConstellationLight: ColorSet {
public var name: ColorSetName = .constellationLight
public var scheme: ColorScheme = .light
public var tintColor: Color = .init(hex: 0xc82238)
public var primaryBackgroundColor: Color = .init(hex: 0xf4f5f7)
public var secondaryBackgroundColor: Color = .init(hex: 0xacc7e5)
public var tintColor: Color = .init(hex: 0xC82238)
public var primaryBackgroundColor: Color = .init(hex: 0xF4F5F7)
public var secondaryBackgroundColor: Color = .init(hex: 0xACC7E5)
public var labelColor: Color = .black
public init() {}

View file

@ -27,7 +27,7 @@ extension Color: RawRepresentable {
}
public var rawValue: Int {
guard let coreImageColor = coreImageColor else {
guard let coreImageColor else {
return 0
}
let red = Int(coreImageColor.red * 255 + 0.5)
@ -37,7 +37,7 @@ extension Color: RawRepresentable {
}
private var coreImageColor: CIColor? {
return CIColor(color: .init(self))
CIColor(color: .init(self))
}
}

View file

@ -22,15 +22,15 @@ public class Theme: ObservableObject {
public var title: LocalizedStringKey {
switch self {
case .system:
return "settings.display.font.system"
"settings.display.font.system"
case .openDyslexic:
return "Open Dyslexic"
"Open Dyslexic"
case .hyperLegible:
return "Hyper Legible"
"Hyper Legible"
case .SFRounded:
return "SF Rounded"
"SF Rounded"
case .custom:
return "settings.display.font.custom"
"settings.display.font.custom"
}
}
}
@ -41,9 +41,9 @@ public class Theme: ObservableObject {
public var description: LocalizedStringKey {
switch self {
case .leading:
return "enum.avatar-position.leading"
"enum.avatar-position.leading"
case .top:
return "enum.avatar-position.top"
"enum.avatar-position.top"
}
}
}
@ -54,9 +54,9 @@ public class Theme: ObservableObject {
public var description: LocalizedStringKey {
switch self {
case .circle:
return "enum.avatar-shape.circle"
"enum.avatar-shape.circle"
case .rounded:
return "enum.avatar-shape.rounded"
"enum.avatar-shape.rounded"
}
}
}
@ -67,11 +67,11 @@ public class Theme: ObservableObject {
public var description: LocalizedStringKey {
switch self {
case .full:
return "enum.status-actions-display.all"
"enum.status-actions-display.all"
case .discret:
return "enum.status-actions-display.only-buttons"
"enum.status-actions-display.only-buttons"
case .none:
return "enum.status-actions-display.no-buttons"
"enum.status-actions-display.no-buttons"
}
}
}
@ -82,11 +82,11 @@ public class Theme: ObservableObject {
public var description: LocalizedStringKey {
switch self {
case .large:
return "enum.status-display-style.large"
"enum.status-display-style.large"
case .medium:
return "enum.status-display-style.medium"
"enum.status-display-style.medium"
case .compact:
return "enum.status-display-style.compact"
"enum.status-display-style.compact"
}
}
}

View file

@ -97,7 +97,7 @@ struct ThemeApplier: ViewModifier {
private func allWindows() -> [UIWindow] {
UIApplication.shared.connectedScenes
.compactMap { $0 as? UIWindowScene }
.flatMap { $0.windows }
.flatMap(\.windows)
}
#endif
}

View file

@ -33,9 +33,9 @@ public struct AvatarView: View {
var cornerRadius: CGFloat {
switch self {
case .badge, .boost, .list:
return size.width / 2
size.width / 2
default:
return 4
4
}
}
}
@ -55,7 +55,7 @@ public struct AvatarView: View {
.fill(.gray)
.frame(width: size.size.width, height: size.size.height)
} else {
LazyImage(request: url.map{ makeImageRequest(for: $0) }) { state in
LazyImage(request: url.map { makeImageRequest(for: $0) }) { state in
if let image = state.image {
image
.resizable()
@ -80,9 +80,9 @@ public struct AvatarView: View {
private var clipShape: some Shape {
switch theme.avatarShape {
case .circle:
return AnyShape(Circle())
AnyShape(Circle())
case .rounded:
return AnyShape(RoundedRectangle(cornerRadius: size.cornerRadius))
AnyShape(RoundedRectangle(cornerRadius: size.cornerRadius))
}
}
}

View file

@ -38,6 +38,6 @@ public struct EmojiTextApp: View {
private func isRTL() -> Bool {
// Arabic, Hebrew, Persian, Urdu, Kurdish, Azeri, Dhivehi
return ["ar", "he", "fa", "ur", "ku", "az", "dv"].contains(language)
["ar", "he", "fa", "ur", "ku", "az", "dv"].contains(language)
}
}

View file

@ -59,7 +59,7 @@ public struct SecondaryColumnToolbarItem: ToolbarContent {
public init() {}
public var body: some ToolbarContent {
public var body: some ToolbarContent {
ToolbarItem(placement: isSecondaryColumn ? .navigationBarLeading : .navigationBarTrailing) {
Button {
withAnimation {

View file

@ -29,7 +29,7 @@ let package = Package(
.product(name: "KeychainSwift", package: "keychain-swift"),
],
swiftSettings: [
.enableExperimentalFeature("StrictConcurrency")
.enableExperimentalFeature("StrictConcurrency"),
]
),
]

View file

@ -48,7 +48,7 @@ public class CurrentAccount: ObservableObject {
}
public func fetchConnections() async {
guard let client = client else { return }
guard let client else { return }
do {
let connections: [String] = try await client.get(endpoint: Instances.peers)
client.addConnections(connections)
@ -56,7 +56,7 @@ public class CurrentAccount: ObservableObject {
}
public func fetchCurrentAccount() async {
guard let client = client, client.isAuth else {
guard let client, client.isAuth else {
account = nil
return
}

View file

@ -41,7 +41,7 @@ public class CurrentInstance: ObservableObject {
}
public func fetchCurrentInstance() async {
guard let client = client else { return }
guard let client else { return }
instance = try? await client.get(endpoint: Instances.instance)
}
}

View file

@ -15,37 +15,37 @@ public enum Duration: Int, CaseIterable {
public var description: LocalizedStringKey {
switch self {
case .infinite:
return "enum.durations.infinite"
"enum.durations.infinite"
case .fiveMinutes:
return "enum.durations.fiveMinutes"
"enum.durations.fiveMinutes"
case .thirtyMinutes:
return "enum.durations.thirtyMinutes"
"enum.durations.thirtyMinutes"
case .oneHour:
return "enum.durations.oneHour"
"enum.durations.oneHour"
case .sixHours:
return "enum.durations.sixHours"
"enum.durations.sixHours"
case .twelveHours:
return "enum.durations.twelveHours"
"enum.durations.twelveHours"
case .oneDay:
return "enum.durations.oneDay"
"enum.durations.oneDay"
case .threeDays:
return "enum.durations.threeDays"
"enum.durations.threeDays"
case .sevenDays:
return "enum.durations.sevenDays"
"enum.durations.sevenDays"
case .custom:
return "enum.durations.custom"
"enum.durations.custom"
}
}
public static func mutingDurations() -> [Duration] {
return Self.allCases.filter { $0 != .custom }
allCases.filter { $0 != .custom }
}
public static func filterDurations() -> [Duration] {
return [.infinite, .thirtyMinutes, .oneHour, .sixHours, .twelveHours, .oneDay, .sevenDays, .custom]
[.infinite, .thirtyMinutes, .oneHour, .sixHours, .twelveHours, .oneDay, .sevenDays, .custom]
}
public static func pollDurations() -> [Duration] {
return [.fiveMinutes, .thirtyMinutes, .oneHour, .sixHours, .twelveHours, .oneDay, .threeDays, .sevenDays]
[.fiveMinutes, .thirtyMinutes, .oneHour, .sixHours, .twelveHours, .oneDay, .threeDays, .sevenDays]
}
}

View file

@ -7,15 +7,15 @@ public enum PollVotingFrequency: String, CaseIterable {
public var canVoteMultipleTimes: Bool {
switch self {
case .multipleVotes: return true
case .oneVote: return false
case .multipleVotes: true
case .oneVote: false
}
}
public var displayString: LocalizedStringKey {
switch self {
case .oneVote: return "env.poll-vote-frequency.one"
case .multipleVotes: return "env.poll-vote-frequency.multiple"
case .oneVote: "env.poll-vote-frequency.one"
case .multipleVotes: "env.poll-vote-frequency.multiple"
}
}
}

View file

@ -7,8 +7,8 @@ public enum PreferredShareButtonBehavior: Int, CaseIterable, Codable {
public var title: LocalizedStringKey {
switch self {
case .linkOnly: return "settings.content.sharing.share-behavior.link-only"
case .linkAndText: return "settings.content.sharing.share-behavior.link-and-text"
case .linkOnly: "settings.content.sharing.share-behavior.link-only"
case .linkAndText: "settings.content.sharing.share-behavior.link-and-text"
}
}
}

View file

@ -7,8 +7,8 @@ import Network
import SwiftUI
import UserNotifications
extension UNNotificationResponse: @unchecked Sendable { }
extension UNUserNotificationCenter: @unchecked Sendable { }
extension UNNotificationResponse: @unchecked Sendable {}
extension UNUserNotificationCenter: @unchecked Sendable {}
public struct PushAccount: Equatable {
public let server: String
@ -157,7 +157,7 @@ extension PushNotificationsService: UNUserNotificationCenterDelegate {
extension Data {
var hexString: String {
return map { String(format: "%02.2hhx", arguments: [$0]) }.joined()
map { String(format: "%02.2hhx", arguments: [$0]) }.joined()
}
}
@ -199,7 +199,7 @@ public class PushNotificationSubscriptionSettings: ObservableObject {
}
public func updateSubscription() async {
guard let pushToken = pushToken else { return }
guard let pushToken else { return }
let client = Client(server: account.server, oauthToken: account.token)
do {
var listenerURL = PushNotificationsService.Constants.endpoint

View file

@ -45,25 +45,25 @@ public enum SheetDestination: Identifiable {
switch self {
case .editStatusEditor, .newStatusEditor, .replyToStatusEditor, .quoteStatusEditor,
.mentionStatusEditor, .settings, .accountPushNotficationsSettings:
return "statusEditor"
"statusEditor"
case .listEdit:
return "listEdit"
"listEdit"
case .listAddAccount:
return "listAddAccount"
"listAddAccount"
case .addAccount:
return "addAccount"
"addAccount"
case .addTagGroup:
return "addTagGroup"
"addTagGroup"
case .addRemoteLocalTimeline:
return "addRemoteLocalTimeline"
"addRemoteLocalTimeline"
case .statusEditHistory:
return "statusEditHistory"
"statusEditHistory"
case .report:
return "report"
"report"
case .shareImage:
return "shareImage"
"shareImage"
case .editTagGroup:
return "editTagGroup"
"editTagGroup"
}
}
}
@ -83,9 +83,9 @@ public class RouterPath: ObservableObject {
}
public func handleStatus(status: AnyStatus, url: URL) -> OpenURLAction.Result {
if url.pathComponents.count == 3 && url.pathComponents[1] == "tags" &&
url.host() == status.account.url?.host(),
let tag = url.pathComponents.last
if url.pathComponents.count == 3, url.pathComponents[1] == "tags",
url.host() == status.account.url?.host(),
let tag = url.pathComponents.last
{
// OK this test looks weird but it's
// A 3 component path i.e. ["/", "tags", "tagname"]
@ -97,7 +97,7 @@ public class RouterPath: ObservableObject {
} else if let mention = status.mentions.first(where: { $0.url == url }) {
navigate(to: .accountDetail(id: mention.id))
return .handled
} else if let client = client,
} else if let client,
client.isAuth,
client.hasConnection(with: url),
let id = Int(url.lastPathComponent)
@ -126,7 +126,7 @@ public class RouterPath: ObservableObject {
await navigateToAccountFrom(acct: acct, url: url)
}
return .handled
} else if let client = client,
} else if let client,
client.isAuth,
client.hasConnection(with: url),
let id = Int(url.lastPathComponent)

View file

@ -1,16 +1,16 @@
import AudioToolbox
import AVKit
import CoreHaptics
import UIKit
import AudioToolbox
@MainActor
public class SoundEffectManager {
public static let shared: SoundEffectManager = .init()
public enum SoundEffect: String, CaseIterable {
case pull, refresh, tootSent, tabSelection, bookmark, boost, favorite, share
}
var pullId: SystemSoundID = 0
var refreshId: SystemSoundID = 1
var tootSentId: SystemSoundID = 2
@ -19,9 +19,9 @@ public class SoundEffectManager {
var boostId: SystemSoundID = 5
var favoriteId: SystemSoundID = 6
var shareId: SystemSoundID = 7
private let userPreferences = UserPreferences.shared
private init() {
registerSounds()
}
@ -50,7 +50,7 @@ public class SoundEffectManager {
}
}
}
public func playSound(of type: SoundEffect) {
guard userPreferences.soundEffectEnabled else { return }
switch type {

View file

@ -73,7 +73,7 @@ public class StreamWatcher: ObservableObject {
private func receiveMessage() {
task?.receive(completionHandler: { [weak self] result in
guard let self = self else { return }
guard let self else { return }
switch result {
case let .success(message):
switch message {
@ -83,8 +83,8 @@ public class StreamWatcher: ObservableObject {
print("Error decoding streaming event string")
return
}
let rawEvent = try self.decoder.decode(RawStreamEvent.self, from: data)
if let event = self.rawEventToEvent(rawEvent: rawEvent) {
let rawEvent = try decoder.decode(RawStreamEvent.self, from: data)
if let event = rawEventToEvent(rawEvent: rawEvent) {
Task { @MainActor in
self.events.append(event)
self.latestEvent = event
@ -101,10 +101,10 @@ public class StreamWatcher: ObservableObject {
break
}
self.receiveMessage()
receiveMessage()
case .failure:
DispatchQueue.main.asyncAfter(deadline: .now() + .seconds(self.retryDelay)) {
DispatchQueue.main.asyncAfter(deadline: .now() + .seconds(retryDelay)) {
self.retryDelay += 30
self.stopWatching()
self.connect()

View file

@ -65,9 +65,9 @@ public class UserPreferences: ObservableObject {
public var description: LocalizedStringKey {
switch self {
case .iconWithText:
return "enum.swipeactions.icon-with-text"
"enum.swipeactions.icon-with-text"
case .iconOnly:
return "enum.swipeactions.icon-only"
"enum.swipeactions.icon-only"
}
}
@ -84,52 +84,52 @@ public class UserPreferences: ObservableObject {
public var postVisibility: Models.Visibility {
if useInstanceContentSettings {
return serverPreferences?.postVisibility ?? .pub
serverPreferences?.postVisibility ?? .pub
} else {
return appDefaultPostVisibility
appDefaultPostVisibility
}
}
public func conformReplyVisibilityConstraints() {
appDefaultReplyVisibility = getReplyVisibility()
}
private func getReplyVisibility() -> Models.Visibility {
getMinVisibility(postVisibility, appDefaultReplyVisibility)
}
public func getReplyVisibility(of status: Status) -> Models.Visibility {
getMinVisibility(getReplyVisibility(), status.visibility)
}
private func getMinVisibility(_ vis1: Models.Visibility, _ vis2: Models.Visibility) -> Models.Visibility {
let no1 = Self.getIntOfVisibility(vis1)
let no2 = Self.getIntOfVisibility(vis2)
return no1 < no2 ? vis1 : vis2
}
public var postIsSensitive: Bool {
if useInstanceContentSettings {
return serverPreferences?.postIsSensitive ?? false
serverPreferences?.postIsSensitive ?? false
} else {
return appDefaultPostsSensitive
appDefaultPostsSensitive
}
}
public var autoExpandSpoilers: Bool {
if useInstanceContentSettings {
return serverPreferences?.autoExpandSpoilers ?? true
serverPreferences?.autoExpandSpoilers ?? true
} else {
return appAutoExpandSpoilers
appAutoExpandSpoilers
}
}
public var autoExpandMedia: ServerPreferences.AutoExpandMedia {
if useInstanceContentSettings {
return serverPreferences?.autoExpandMedia ?? .hideSensitive
serverPreferences?.autoExpandMedia ?? .hideSensitive
} else {
return appAutoExpandMedia
appAutoExpandMedia
}
}
@ -174,17 +174,17 @@ public class UserPreferences: ObservableObject {
copy.insert(isoCode, at: 0)
recentlyUsedLanguages = Array(copy.prefix(3))
}
public static func getIntOfVisibility(_ vis: Models.Visibility) -> Int {
switch vis {
case .direct:
return 0
case .priv:
return 1
case .unlisted:
return 2
case .pub:
return 3
case .direct:
0
case .priv:
1
case .unlisted:
2
case .pub:
3
}
}
}

View file

@ -35,7 +35,7 @@ let package = Package(
.product(name: "DesignSystem", package: "DesignSystem"),
],
swiftSettings: [
.enableExperimentalFeature("StrictConcurrency")
.enableExperimentalFeature("StrictConcurrency"),
]
),
]

View file

@ -126,7 +126,7 @@ public struct ExploreView: View {
@ViewBuilder
private func makeSearchResultsView(results: SearchResults) -> some View {
if !results.accounts.isEmpty && (viewModel.searchScope == .all || viewModel.searchScope == .people) {
if !results.accounts.isEmpty, viewModel.searchScope == .all || viewModel.searchScope == .people {
Section("explore.section.users") {
ForEach(results.accounts) { account in
if let relationship = results.relationships.first(where: { $0.id == account.id }) {
@ -136,7 +136,7 @@ public struct ExploreView: View {
}
}
}
if !results.hashtags.isEmpty && (viewModel.searchScope == .all || viewModel.searchScope == .hashtags) {
if !results.hashtags.isEmpty, viewModel.searchScope == .all || viewModel.searchScope == .hashtags {
Section("explore.section.tags") {
ForEach(results.hashtags) { tag in
TagRowView(tag: tag)
@ -145,7 +145,7 @@ public struct ExploreView: View {
}
}
}
if !results.statuses.isEmpty && (viewModel.searchScope == .all || viewModel.searchScope == .posts) {
if !results.statuses.isEmpty, viewModel.searchScope == .all || viewModel.searchScope == .posts {
Section("explore.section.posts") {
ForEach(results.statuses) { status in
StatusRowView(viewModel: { .init(status: status, client: client, routerPath: routerPath) })

View file

@ -11,13 +11,13 @@ class ExploreViewModel: ObservableObject {
var localizedString: LocalizedStringKey {
switch self {
case .all:
return .init("explore.scope.all")
.init("explore.scope.all")
case .people:
return .init("explore.scope.people")
.init("explore.scope.people")
case .hashtags:
return .init("explore.scope.hashtags")
.init("explore.scope.hashtags")
case .posts:
return .init("explore.scope.posts")
.init("explore.scope.posts")
}
}
}
@ -77,7 +77,7 @@ class ExploreViewModel: ObservableObject {
trendingStatuses = data.trendingStatuses
trendingLinks = data.trendingLinks
suggestedAccountsRelationShips = try await client.get(endpoint: Accounts.relationships(ids: suggestedAccounts.map { $0.id }))
suggestedAccountsRelationShips = try await client.get(endpoint: Accounts.relationships(ids: suggestedAccounts.map(\.id)))
withAnimation {
isLoaded = true
}
@ -118,7 +118,7 @@ class ExploreViewModel: ObservableObject {
following: nil),
forceVersion: .v2)
let relationships: [Relationship] =
try await client.get(endpoint: Accounts.relationships(ids: results.accounts.map { $0.id }))
try await client.get(endpoint: Accounts.relationships(ids: results.accounts.map(\.id)))
results.relationships = relationships
withAnimation {
self.results[searchQuery] = results

View file

@ -31,7 +31,7 @@ let package = Package(
.product(name: "DesignSystem", package: "DesignSystem"),
],
swiftSettings: [
.enableExperimentalFeature("StrictConcurrency")
.enableExperimentalFeature("StrictConcurrency"),
]
),
]

View file

@ -25,7 +25,7 @@ let package = Package(
"SwiftSoup",
],
swiftSettings: [
.enableExperimentalFeature("StrictConcurrency")
.enableExperimentalFeature("StrictConcurrency"),
]
),
.testTarget(

View file

@ -60,11 +60,11 @@ public final class Account: Codable, Identifiable, Hashable, Sendable, Equatable
public let discoverable: Bool?
public var haveAvatar: Bool {
return avatar.lastPathComponent != "missing.png"
avatar.lastPathComponent != "missing.png"
}
public var haveHeader: Bool {
return header.lastPathComponent != "missing.png"
header.lastPathComponent != "missing.png"
}
public init(id: String, username: String, displayName: String?, avatar: URL, header: URL, acct: String, note: HTMLString, createdAt: ServerDate, followersCount: Int, followingCount: Int, statusesCount: Int, lastStatusAt: String? = nil, fields: [Account.Field], locked: Bool, emojis: [Emoji], url: URL? = nil, source: Account.Source? = nil, bot: Bool, discoverable: Bool? = nil) {

View file

@ -6,17 +6,17 @@ class DateFormatterCache: @unchecked Sendable {
let createdAtRelativeFormatter: RelativeDateTimeFormatter
let createdAtShortDateFormatted: DateFormatter
let createdAtDateFormatter: DateFormatter
init() {
let createdAtRelativeFormatter = RelativeDateTimeFormatter()
createdAtRelativeFormatter.unitsStyle = .short
self.createdAtRelativeFormatter = createdAtRelativeFormatter
let createdAtShortDateFormatted = DateFormatter()
createdAtShortDateFormatted.dateStyle = .short
createdAtShortDateFormatted.timeStyle = .none
self.createdAtShortDateFormatted = createdAtShortDateFormatted
let createdAtDateFormatter = DateFormatter()
createdAtDateFormatter.calendar = .init(identifier: .iso8601)
createdAtDateFormatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ss.SSSXXXXX"

View file

@ -11,7 +11,7 @@ public struct HTMLString: Codable, Equatable, Hashable, @unchecked Sendable {
public var asMarkdown: String = ""
public var asRawText: String = ""
public var statusesURLs = [URL]()
private(set) public var links = [Link]()
public private(set) var links = [Link]()
public var asSafeMarkdownAttributedString: AttributedString = .init()
private var main_regex: NSRegularExpression?
@ -155,16 +155,16 @@ public struct HTMLString: Codable, Equatable, Hashable, @unchecked Sendable {
let finish = asMarkdown.endIndex
var linkRef = href
// Try creating a URL from the string. If it fails, try URL encoding
// the string first.
var url = URL(string: href)
if url == nil {
url = URL(string: href, encodePath: true)
}
if let linkUrl = url {
if let linkUrl = url {
linkRef = linkUrl.absoluteString
let displayString = asMarkdown[start..<finish]
let displayString = asMarkdown[start ..< finish]
links.append(Link(linkUrl, displayString: String(displayString)))
}
@ -203,19 +203,19 @@ public struct HTMLString: Codable, Equatable, Hashable, @unchecked Sendable {
self.displayString = displayString
switch displayString.first {
case "@":
self.type = .mention
self.title = displayString
case "#":
self.type = .hashtag
self.title = String(displayString.dropFirst())
default:
self.type = .url
var hostNameUrl = url.host ?? url.absoluteString
if hostNameUrl.hasPrefix("www.") {
hostNameUrl = String(hostNameUrl.dropFirst(4))
}
self.title = hostNameUrl
case "@":
type = .mention
title = displayString
case "#":
type = .hashtag
title = String(displayString.dropFirst())
default:
type = .url
var hostNameUrl = url.host ?? url.absoluteString
if hostNameUrl.hasPrefix("www.") {
hostNameUrl = String(hostNameUrl.dropFirst(4))
}
title = hostNameUrl
}
}
@ -227,35 +227,34 @@ public struct HTMLString: Codable, Equatable, Hashable, @unchecked Sendable {
}
}
extension URL {
public extension URL {
// It's common to use non-ASCII characters in URLs even though they're technically
// invalid characters. Every modern browser handles this by silently encoding
// the invalid characters on the user's behalf. However, trying to create a URL
// object with un-encoded characters will result in nil so we need to encode the
// invalid characters before creating the URL object. The unencoded version
// should still be shown in the displayed status.
public init?(string: String, encodePath: Bool) {
init?(string: String, encodePath: Bool) {
var encodedUrlString = ""
if encodePath,
string.starts(with: "http://") || string.starts(with: "https://"),
var startIndex = string.firstIndex(of: "/")
{
startIndex = string.index(startIndex, offsetBy: 1)
// We don't want to encode the host portion of the URL
if var startIndex = string[startIndex...].firstIndex(of: "/") {
encodedUrlString = String(string[...startIndex])
while let endIndex = string[string.index(after: startIndex)...].firstIndex(of: "/") {
let componentStartIndex = string.index(after: startIndex)
encodedUrlString = encodedUrlString + (string[componentStartIndex...endIndex].addingPercentEncoding(withAllowedCharacters: .urlPathAllowed) ?? "")
encodedUrlString = encodedUrlString + (string[componentStartIndex ... endIndex].addingPercentEncoding(withAllowedCharacters: .urlPathAllowed) ?? "")
startIndex = endIndex
}
// The last part of the path may have a query string appended to it
let componentStartIndex = string.index(after: startIndex)
if let queryStartIndex = string[componentStartIndex...].firstIndex(of: "?") {
encodedUrlString = encodedUrlString + (string[componentStartIndex..<queryStartIndex].addingPercentEncoding(withAllowedCharacters: .urlPathAllowed) ?? "")
encodedUrlString = encodedUrlString + (string[componentStartIndex ..< queryStartIndex].addingPercentEncoding(withAllowedCharacters: .urlPathAllowed) ?? "")
encodedUrlString = encodedUrlString + (string[queryStartIndex...].addingPercentEncoding(withAllowedCharacters: .urlQueryAllowed) ?? "")
} else {
encodedUrlString = encodedUrlString + (string[componentStartIndex...].addingPercentEncoding(withAllowedCharacters: .urlPathAllowed) ?? "")

View file

@ -8,9 +8,9 @@ public struct AppAccount: Codable, Identifiable, Hashable {
public var key: String {
if let oauthToken {
return "\(server):\(oauthToken.createdAt)"
"\(server):\(oauthToken.createdAt)"
} else {
return "\(server):anonymous"
"\(server):anonymous"
}
}

View file

@ -2,7 +2,7 @@ import Foundation
@MainActor
public struct Language: Identifiable, Equatable, Hashable {
nonisolated public var id: String { isoCode }
public nonisolated var id: String { isoCode }
public let isoCode: String
public let nativeName: String?

View file

@ -32,7 +32,7 @@ public struct Poll: Codable, Equatable, Hashable {
// the votersCount can be null according to the docs when multiple is false.
// Didn't find that to be true, but we make sure
public var safeVotersCount: Int {
return votersCount ?? votesCount
votersCount ?? votesCount
}
}

View file

@ -24,14 +24,14 @@ public struct ServerFilter: Codable, Identifiable, Hashable, Sendable {
public let expiresAt: ServerDate?
public func hasExpiry() -> Bool {
return expiresAt != nil
expiresAt != nil
}
public func isExpired() -> Bool {
if let expiresAtDate = expiresAt?.asDate {
return expiresAtDate < Date()
expiresAtDate < Date()
} else {
return false
false
}
}
}
@ -40,30 +40,30 @@ public extension ServerFilter.Context {
var iconName: String {
switch self {
case .home:
return "rectangle.stack"
"rectangle.stack"
case .notifications:
return "bell"
"bell"
case .public:
return "globe.americas"
"globe.americas"
case .thread:
return "bubble.left.and.bubble.right"
"bubble.left.and.bubble.right"
case .account:
return "person.crop.circle"
"person.crop.circle"
}
}
var name: String {
switch self {
case .home:
return NSLocalizedString("filter.contexts.home", comment: "")
NSLocalizedString("filter.contexts.home", comment: "")
case .notifications:
return NSLocalizedString("filter.contexts.notifications", comment: "")
NSLocalizedString("filter.contexts.notifications", comment: "")
case .public:
return NSLocalizedString("filter.contexts.public", comment: "")
NSLocalizedString("filter.contexts.public", comment: "")
case .thread:
return NSLocalizedString("filter.contexts.conversations", comment: "")
NSLocalizedString("filter.contexts.conversations", comment: "")
case .account:
return NSLocalizedString("filter.contexts.profiles", comment: "")
NSLocalizedString("filter.contexts.profiles", comment: "")
}
}
}
@ -72,9 +72,9 @@ public extension ServerFilter.Action {
var label: String {
switch self {
case .warn:
return NSLocalizedString("filter.action.warning", comment: "")
NSLocalizedString("filter.action.warning", comment: "")
case .hide:
return NSLocalizedString("filter.action.hide", comment: "")
NSLocalizedString("filter.action.hide", comment: "")
}
}
}

View file

@ -16,11 +16,11 @@ public struct ServerPreferences: Decodable {
public var description: LocalizedStringKey {
switch self {
case .showAll:
return "enum.expand-media.show"
"enum.expand-media.show"
case .hideAll:
return "enum.expand-media.hide"
"enum.expand-media.hide"
case .hideSensitive:
return "enum.expand-media.hide-sensitive"
"enum.expand-media.hide-sensitive"
}
}
}

View file

@ -6,28 +6,28 @@ final class HTMLStringTests: XCTestCase {
XCTAssertNil(URL(string: "go to www.google.com", encodePath: true))
XCTAssertNil(URL(string: "go to www.google.com", encodePath: false))
XCTAssertNil(URL(string: "", encodePath: true))
let simpleUrl = URL(string: "https://www.google.com", encodePath: true)
XCTAssertEqual("https://www.google.com", simpleUrl?.absoluteString)
let urlWithTrailingSlash = URL(string: "https://www.google.com/", encodePath: true)
XCTAssertEqual("https://www.google.com/", urlWithTrailingSlash?.absoluteString)
let extendedCharPath = URL(string: "https://en.wikipedia.org/wiki/Elbbrücken_station", encodePath: true)
XCTAssertEqual("https://en.wikipedia.org/wiki/Elbbr%C3%BCcken_station", extendedCharPath?.absoluteString)
XCTAssertNil(URL(string: "https://en.wikipedia.org/wiki/Elbbrücken_station", encodePath: false))
let extendedCharQuery = URL(string: "http://test.com/blah/city?name=京都市", encodePath: true)
XCTAssertEqual("http://test.com/blah/city?name=%E4%BA%AC%E9%83%BD%E5%B8%82", extendedCharQuery?.absoluteString)
// Double encoding will happen if you ask to encodePath on an already encoded string
let alreadyEncodedPath = URL(string: "https://en.wikipedia.org/wiki/Elbbr%C3%BCcken_station", encodePath: true)
XCTAssertEqual("https://en.wikipedia.org/wiki/Elbbr%25C3%25BCcken_station", alreadyEncodedPath?.absoluteString)
}
func testHTMLStringInit() throws {
let decoder = JSONDecoder()
let basicContent = "\"<p>This is a test</p>\""
var htmlString = try decoder.decode(HTMLString.self, from: Data(basicContent.utf8))
XCTAssertEqual("This is a test", htmlString.asRawText)
@ -35,7 +35,7 @@ final class HTMLStringTests: XCTestCase {
XCTAssertEqual("This is a test", htmlString.asMarkdown)
XCTAssertEqual(0, htmlString.statusesURLs.count)
XCTAssertEqual(0, htmlString.links.count)
let basicLink = "\"<p>This is a <a href=\\\"https://test.com\\\">test</a></p>\""
htmlString = try decoder.decode(HTMLString.self, from: Data(basicLink.utf8))
XCTAssertEqual("This is a test", htmlString.asRawText)
@ -45,7 +45,7 @@ final class HTMLStringTests: XCTestCase {
XCTAssertEqual(1, htmlString.links.count)
XCTAssertEqual("https://test.com", htmlString.links[0].url.absoluteString)
XCTAssertEqual("test", htmlString.links[0].displayString)
let extendedCharLink = "\"<p>This is a <a href=\\\"https://test.com/goßëña\\\">test</a></p>\""
htmlString = try decoder.decode(HTMLString.self, from: Data(extendedCharLink.utf8))
XCTAssertEqual("This is a test", htmlString.asRawText)
@ -55,7 +55,7 @@ final class HTMLStringTests: XCTestCase {
XCTAssertEqual(1, htmlString.links.count)
XCTAssertEqual("https://test.com/go%C3%9F%C3%AB%C3%B1a", htmlString.links[0].url.absoluteString)
XCTAssertEqual("test", htmlString.links[0].displayString)
let alreadyEncodedLink = "\"<p>This is a <a href=\\\"https://test.com/go%C3%9F%C3%AB%C3%B1a\\\">test</a></p>\""
htmlString = try decoder.decode(HTMLString.self, from: Data(alreadyEncodedLink.utf8))
XCTAssertEqual("This is a test", htmlString.asRawText)
@ -66,16 +66,16 @@ final class HTMLStringTests: XCTestCase {
XCTAssertEqual("https://test.com/go%C3%9F%C3%AB%C3%B1a", htmlString.links[0].url.absoluteString)
XCTAssertEqual("test", htmlString.links[0].displayString)
}
func testHTMLStringInit_markdownEscaping() throws {
let decoder = JSONDecoder()
let stdMarkdownContent = "\"<p>This [*is*] `a`\\n**test**</p>\""
var htmlString = try decoder.decode(HTMLString.self, from: Data(stdMarkdownContent.utf8))
XCTAssertEqual("This [*is*] `a`\n**test**", htmlString.asRawText)
XCTAssertEqual("<p>This [*is*] `a`\n**test**</p>", htmlString.htmlValue)
XCTAssertEqual("This \\[\\*is\\*] \\`a\\` \\*\\*test\\*\\*", htmlString.asMarkdown)
let underscoreContent = "\"<p>This _is_ an :emoji_maybe:</p>\""
htmlString = try decoder.decode(HTMLString.self, from: Data(underscoreContent.utf8))
XCTAssertEqual("This _is_ an :emoji_maybe:", htmlString.asRawText)

View file

@ -25,7 +25,7 @@ let package = Package(
.product(name: "Models", package: "Models"),
],
swiftSettings: [
.enableExperimentalFeature("StrictConcurrency")
.enableExperimentalFeature("StrictConcurrency"),
]
),
.testTarget(

View file

@ -33,49 +33,49 @@ public enum Accounts: Endpoint {
public func path() -> String {
switch self {
case let .accounts(id):
return "accounts/\(id)"
"accounts/\(id)"
case .favorites:
return "favourites"
"favourites"
case .bookmarks:
return "bookmarks"
"bookmarks"
case .followedTags:
return "followed_tags"
"followed_tags"
case let .featuredTags(id):
return "accounts/\(id)/featured_tags"
"accounts/\(id)/featured_tags"
case .verifyCredentials:
return "accounts/verify_credentials"
"accounts/verify_credentials"
case .updateCredentials:
return "accounts/update_credentials"
"accounts/update_credentials"
case let .statuses(id, _, _, _, _, _):
return "accounts/\(id)/statuses"
"accounts/\(id)/statuses"
case .relationships:
return "accounts/relationships"
"accounts/relationships"
case let .follow(id, _, _):
return "accounts/\(id)/follow"
"accounts/\(id)/follow"
case let .unfollow(id):
return "accounts/\(id)/unfollow"
"accounts/\(id)/unfollow"
case .familiarFollowers:
return "accounts/familiar_followers"
"accounts/familiar_followers"
case .suggestions:
return "suggestions"
"suggestions"
case let .following(id, _):
return "accounts/\(id)/following"
"accounts/\(id)/following"
case let .followers(id, _):
return "accounts/\(id)/followers"
"accounts/\(id)/followers"
case let .lists(id):
return "accounts/\(id)/lists"
"accounts/\(id)/lists"
case .preferences:
return "preferences"
"preferences"
case let .block(id):
return "accounts/\(id)/block"
"accounts/\(id)/block"
case let .unblock(id):
return "accounts/\(id)/unblock"
"accounts/\(id)/unblock"
case let .mute(id, _):
return "accounts/\(id)/mute"
"accounts/\(id)/mute"
case let .unmute(id):
return "accounts/\(id)/unmute"
"accounts/\(id)/unmute"
case let .relationshipNote(id, _):
return "accounts/\(id)/note"
"accounts/\(id)/note"
}
}
@ -128,13 +128,13 @@ public enum Accounts: Endpoint {
public var jsonValue: Encodable? {
switch self {
case let .mute(_, json):
return json
json
case let .relationshipNote(_, json):
return json
json
case let .updateCredentials(json):
return json
json
default:
return nil
nil
}
}
}

View file

@ -7,7 +7,7 @@ public enum Apps: Endpoint {
public func path() -> String {
switch self {
case .registerApp:
return "apps"
"apps"
}
}

View file

@ -8,20 +8,20 @@ public enum Conversations: Endpoint {
public func path() -> String {
switch self {
case .conversations:
return "conversations"
"conversations"
case let .delete(id):
return "conversations/\(id)"
"conversations/\(id)"
case let .read(id):
return "conversations/\(id)/read"
"conversations/\(id)/read"
}
}
public func queryItems() -> [URLQueryItem]? {
switch self {
case let .conversations(maxId):
return makePaginationParam(sinceId: nil, maxId: maxId, mindId: nil)
makePaginationParam(sinceId: nil, maxId: maxId, mindId: nil)
default:
return nil
nil
}
}
}

View file

@ -6,7 +6,7 @@ public enum CustomEmojis: Endpoint {
public func path() -> String {
switch self {
case .customEmojis:
return "custom_emojis"
"custom_emojis"
}
}

View file

@ -8,11 +8,11 @@ public enum FollowRequests: Endpoint {
public func path() -> String {
switch self {
case .list:
return "follow_requests"
"follow_requests"
case let .accept(id):
return "follow_requests/\(id)/authorize"
"follow_requests/\(id)/authorize"
case let .reject(id):
return "follow_requests/\(id)/reject"
"follow_requests/\(id)/reject"
}
}

View file

@ -7,9 +7,9 @@ public enum Instances: Endpoint {
public func path() -> String {
switch self {
case .instance:
return "instance"
"instance"
case .peers:
return "instance/peers"
"instance/peers"
}
}

View file

@ -10,13 +10,13 @@ public enum Lists: Endpoint {
public func path() -> String {
switch self {
case .lists, .createList:
return "lists"
"lists"
case let .list(id):
return "lists/\(id)"
"lists/\(id)"
case let .accounts(listId):
return "lists/\(listId)/accounts"
"lists/\(listId)/accounts"
case let .updateAccounts(listId, _):
return "lists/\(listId)/accounts"
"lists/\(listId)/accounts"
}
}

View file

@ -7,22 +7,22 @@ public enum Media: Endpoint {
public func path() -> String {
switch self {
case .medias:
return "media"
"media"
case let .media(id, _):
return "media/\(id)"
"media/\(id)"
}
}
public func queryItems() -> [URLQueryItem]? {
return nil
nil
}
public var jsonValue: Encodable? {
switch self {
case let .media(_, json):
return json
json
default:
return nil
nil
}
}
}

View file

@ -11,11 +11,11 @@ public enum Notifications: Endpoint {
public func path() -> String {
switch self {
case .notifications:
return "notifications"
"notifications"
case let .notification(id):
return "notifications/\(id)"
"notifications/\(id)"
case .clear:
return "notifications/clear"
"notifications/clear"
}
}

View file

@ -8,18 +8,18 @@ public enum Oauth: Endpoint {
public func path() -> String {
switch self {
case .authorize:
return "oauth/authorize"
"oauth/authorize"
case .token:
return "oauth/token"
"oauth/token"
}
}
public var jsonValue: Encodable? {
switch self {
case let .token(code, clientId, clientSecret):
return TokenData(clientId: clientId, clientSecret: clientSecret, code: code)
TokenData(clientId: clientId, clientSecret: clientSecret, code: code)
default:
return nil
nil
}
}

View file

@ -7,9 +7,9 @@ public enum Polls: Endpoint {
public func path() -> String {
switch self {
case let .poll(id):
return "polls/\(id)"
"polls/\(id)"
case let .vote(id, _):
return "polls/\(id)/votes"
"polls/\(id)/votes"
}
}

View file

@ -15,7 +15,7 @@ public enum Push: Endpoint {
public func path() -> String {
switch self {
case .subscription, .createSub:
return "push/subscription"
"push/subscription"
}
}

View file

@ -6,7 +6,7 @@ public enum Search: Endpoint {
public func path() -> String {
switch self {
case .search:
return "search"
"search"
}
}

View file

@ -12,17 +12,17 @@ public enum ServerFilters: Endpoint {
public func path() -> String {
switch self {
case .filters:
return "filters"
"filters"
case .createFilter:
return "filters"
"filters"
case let .filter(id):
return "filters/\(id)"
"filters/\(id)"
case let .editFilter(id, _):
return "filters/\(id)"
"filters/\(id)"
case let .addKeyword(id, _, _):
return "filters/\(id)/keywords"
"filters/\(id)/keywords"
case let .removeKeyword(id):
return "filters/keywords/\(id)"
"filters/keywords/\(id)"
}
}
@ -39,11 +39,11 @@ public enum ServerFilters: Endpoint {
public var jsonValue: Encodable? {
switch self {
case let .createFilter(json):
return json
json
case let .editFilter(_, json):
return json
json
default:
return nil
nil
}
}
}

View file

@ -23,39 +23,39 @@ public enum Statuses: Endpoint {
public func path() -> String {
switch self {
case .postStatus:
return "statuses"
"statuses"
case let .status(id):
return "statuses/\(id)"
"statuses/\(id)"
case let .editStatus(id, _):
return "statuses/\(id)"
"statuses/\(id)"
case let .context(id):
return "statuses/\(id)/context"
"statuses/\(id)/context"
case let .favorite(id):
return "statuses/\(id)/favourite"
"statuses/\(id)/favourite"
case let .unfavorite(id):
return "statuses/\(id)/unfavourite"
"statuses/\(id)/unfavourite"
case let .reblog(id):
return "statuses/\(id)/reblog"
"statuses/\(id)/reblog"
case let .unreblog(id):
return "statuses/\(id)/unreblog"
"statuses/\(id)/unreblog"
case let .rebloggedBy(id, _):
return "statuses/\(id)/reblogged_by"
"statuses/\(id)/reblogged_by"
case let .favoritedBy(id, _):
return "statuses/\(id)/favourited_by"
"statuses/\(id)/favourited_by"
case let .pin(id):
return "statuses/\(id)/pin"
"statuses/\(id)/pin"
case let .unpin(id):
return "statuses/\(id)/unpin"
"statuses/\(id)/unpin"
case let .bookmark(id):
return "statuses/\(id)/bookmark"
"statuses/\(id)/bookmark"
case let .unbookmark(id):
return "statuses/\(id)/unbookmark"
"statuses/\(id)/unbookmark"
case let .history(id):
return "statuses/\(id)/history"
"statuses/\(id)/history"
case let .translate(id, _):
return "statuses/\(id)/translate"
"statuses/\(id)/translate"
case .report:
return "reports"
"reports"
}
}
@ -82,11 +82,11 @@ public enum Statuses: Endpoint {
public var jsonValue: Encodable? {
switch self {
case let .postStatus(json):
return json
json
case let .editStatus(_, json):
return json
json
default:
return nil
nil
}
}
}

View file

@ -6,14 +6,14 @@ public enum Streaming: Endpoint {
public func path() -> String {
switch self {
case .streaming:
return "streaming"
"streaming"
}
}
public func queryItems() -> [URLQueryItem]? {
switch self {
default:
return nil
nil
}
}
}

View file

@ -8,18 +8,18 @@ public enum Tags: Endpoint {
public func path() -> String {
switch self {
case let .tag(id):
return "tags/\(id)/"
"tags/\(id)/"
case let .follow(id):
return "tags/\(id)/follow"
"tags/\(id)/follow"
case let .unfollow(id):
return "tags/\(id)/unfollow"
"tags/\(id)/unfollow"
}
}
public func queryItems() -> [URLQueryItem]? {
switch self {
default:
return nil
nil
}
}
}

View file

@ -9,13 +9,13 @@ public enum Timelines: Endpoint {
public func path() -> String {
switch self {
case .pub:
return "timelines/public"
"timelines/public"
case .home:
return "timelines/home"
"timelines/home"
case let .list(listId, _, _, _):
return "timelines/list/\(listId)"
"timelines/list/\(listId)"
case let .hashtag(tag, _, _):
return "timelines/tag/\(tag)"
"timelines/tag/\(tag)"
}
}

View file

@ -8,11 +8,11 @@ public enum Trends: Endpoint {
public func path() -> String {
switch self {
case .tags:
return "trends/tags"
"trends/tags"
case .statuses:
return "trends/statuses"
"trends/statuses"
case .links:
return "trends/links"
"trends/links"
}
}

View file

@ -62,15 +62,15 @@ public struct OpenAIClient {
var request: OpenAIRequest {
switch self {
case let .correct(input):
return ChatRequest(content: "Fix the spelling and grammar mistakes in the following text: \(input)", temperature: 0.2)
ChatRequest(content: "Fix the spelling and grammar mistakes in the following text: \(input)", temperature: 0.2)
case let .addTags(input):
return ChatRequest(content: "Replace relevant words with camel-cased hashtags in the following text. Don't try to search for context or add hashtags if there is not enough context: \(input)", temperature: 0.1)
ChatRequest(content: "Replace relevant words with camel-cased hashtags in the following text. Don't try to search for context or add hashtags if there is not enough context: \(input)", temperature: 0.1)
case let .insertTags(input):
return ChatRequest(content: "Return the input with added camel-cased hashtags at the end of the input. Don't try to search for context or add hashtags if there is not enough context: \(input)", temperature: 0.2)
ChatRequest(content: "Return the input with added camel-cased hashtags at the end of the input. Don't try to search for context or add hashtags if there is not enough context: \(input)", temperature: 0.2)
case let .shorten(input):
return ChatRequest(content: "Make a shorter version of this text: \(input)", temperature: 0.5)
ChatRequest(content: "Make a shorter version of this text: \(input)", temperature: 0.5)
case let .emphasize(input):
return ChatRequest(content: "Make this text catchy, more fun: \(input)", temperature: 1)
ChatRequest(content: "Make this text catchy, more fun: \(input)", temperature: 1)
}
}
}

View file

@ -2,7 +2,7 @@ import Foundation
public extension String {
func escape() -> String {
return replacingOccurrences(of: "&amp;", with: "&")
replacingOccurrences(of: "&amp;", with: "&")
.replacingOccurrences(of: "&lt;", with: "<")
.replacingOccurrences(of: "&gt;", with: ">")
.replacingOccurrences(of: "&quot;", with: "\"")

View file

@ -2,7 +2,7 @@ import Foundation
extension Data {
func base64UrlEncodedString() -> String {
return base64EncodedString()
base64EncodedString()
.replacingOccurrences(of: "+", with: "-")
.replacingOccurrences(of: "/", with: "_")
.replacingOccurrences(of: "=", with: "")

View file

@ -33,7 +33,7 @@ let package = Package(
.product(name: "DesignSystem", package: "DesignSystem"),
],
swiftSettings: [
.enableExperimentalFeature("StrictConcurrency")
.enableExperimentalFeature("StrictConcurrency"),
]
),
]

View file

@ -11,7 +11,7 @@ extension ConsolidatedNotification {
var notificationIds: [String] { notifications.map(\.id) }
}
extension Array where Element == ConsolidatedNotification {
extension [ConsolidatedNotification] {
var notificationCount: Int {
reduce(0) { $0 + ($1.accounts.isEmpty ? 1 : $1.accounts.count) }
}

View file

@ -8,7 +8,7 @@
import Foundation
import Models
extension Array where Element == Models.Notification {
extension [Models.Notification] {
func consolidated(selectedType: Models.Notification.NotificationType?) async -> [ConsolidatedNotification] {
await withCheckedContinuation { result in
DispatchQueue.global().async {

View file

@ -6,42 +6,42 @@ extension Models.Notification.NotificationType {
public func label(count: Int) -> LocalizedStringKey {
switch self {
case .status:
return "notifications.label.status"
"notifications.label.status"
case .mention:
return ""
""
case .reblog:
return "notifications.label.reblog \(count)"
"notifications.label.reblog \(count)"
case .follow:
return "notifications.label.follow \(count)"
"notifications.label.follow \(count)"
case .follow_request:
return "notifications.label.follow-request"
"notifications.label.follow-request"
case .favourite:
return "notifications.label.favorite \(count)"
"notifications.label.favorite \(count)"
case .poll:
return "notifications.label.poll"
"notifications.label.poll"
case .update:
return "notifications.label.update"
"notifications.label.update"
}
}
public func notificationKey() -> String {
switch self {
case .status:
return "notifications.label.status.push"
"notifications.label.status.push"
case .mention:
return ""
""
case .reblog:
return "notifications.label.reblog.push"
"notifications.label.reblog.push"
case .follow:
return "notifications.label.follow.push"
"notifications.label.follow.push"
case .follow_request:
return "notifications.label.follow-request.push"
"notifications.label.follow-request.push"
case .favourite:
return "notifications.label.favorite.push"
"notifications.label.favorite.push"
case .poll:
return "notifications.label.poll.push"
"notifications.label.poll.push"
case .update:
return "notifications.label.update.push"
"notifications.label.update.push"
}
}
@ -86,21 +86,21 @@ extension Models.Notification.NotificationType {
func menuTitle() -> LocalizedStringKey {
switch self {
case .status:
return "notifications.menu-title.status"
"notifications.menu-title.status"
case .mention:
return "notifications.menu-title.mention"
"notifications.menu-title.mention"
case .reblog:
return "notifications.menu-title.reblog"
"notifications.menu-title.reblog"
case .follow:
return "notifications.menu-title.follow"
"notifications.menu-title.follow"
case .follow_request:
return "notifications.menu-title.follow-request"
"notifications.menu-title.follow-request"
case .favourite:
return "notifications.menu-title.favorite"
"notifications.menu-title.favorite"
case .poll:
return "notifications.menu-title.poll"
"notifications.menu-title.poll"
case .update:
return "notifications.menu-title.update"
"notifications.menu-title.update"
}
}
}

View file

@ -51,7 +51,7 @@ class NotificationsViewModel: ObservableObject {
if let selectedType {
var excludedTypes = Models.Notification.NotificationType.allCases
excludedTypes.removeAll(where: { $0 == selectedType })
return excludedTypes.map { $0.rawValue }
return excludedTypes.map(\.rawValue)
}
return nil
}

View file

@ -33,7 +33,7 @@ let package = Package(
.product(name: "DesignSystem", package: "DesignSystem"),
],
swiftSettings: [
.enableExperimentalFeature("StrictConcurrency")
.enableExperimentalFeature("StrictConcurrency"),
]
),
]

View file

@ -161,7 +161,7 @@ public struct StatusDetailView: View {
.id(status.id)
// VoiceOver / Switch Control focus workaround
.onAppear {
self.initialFocusBugWorkaround = true
initialFocusBugWorkaround = true
}
}

View file

@ -24,15 +24,15 @@ enum StatusEditorAIPrompt: CaseIterable {
func toRequestPrompt(text: String) -> OpenAIClient.Prompt {
switch self {
case .correct:
return .correct(input: text)
.correct(input: text)
case .addTags:
return .addTags(input: text)
.addTags(input: text)
case .insertTags:
return .insertTags(input: text)
.insertTags(input: text)
case .fit:
return .shorten(input: text)
.shorten(input: text)
case .emphasize:
return .emphasize(input: text)
.emphasize(input: text)
}
}
}

View file

@ -162,7 +162,7 @@ struct StatusEditorAccessoryView: View {
@ViewBuilder
private func languageTextView(isoCode: String, nativeName: String?, name: String?) -> some View {
if let nativeName = nativeName, let name = name {
if let nativeName, let name {
Text("\(nativeName) (\(name))")
} else {
Text(isoCode.uppercased())

View file

@ -8,7 +8,7 @@ actor StatusEditorCompressor {
}
func compressImageFrom(url: URL) async -> Data? {
return await withCheckedContinuation { continuation in
await withCheckedContinuation { continuation in
let sourceOptions = [kCGImageSourceShouldCache: false] as CFDictionary
guard let source = CGImageSourceCreateWithURL(url as CFURL, sourceOptions) else {
continuation.resume(returning: nil)

View file

@ -66,7 +66,7 @@ struct StatusEditorMediaEditView: View {
Button {
if !imageDescription.isEmpty {
isUpdating = true
if currentInstance.isEditAltTextSupported && viewModel.mode.isEditing {
if currentInstance.isEditAltTextSupported, viewModel.mode.isEditing {
Task {
await viewModel.editDescription(container: container, description: imageDescription)
dismiss()

Some files were not shown because too many files have changed in this diff Show more