mirror of
https://github.com/Dimillian/IceCubesApp.git
synced 2024-11-27 18:51:01 +00:00
Swiftformat
This commit is contained in:
parent
96344e2815
commit
7f6419ebae
161 changed files with 1777 additions and 1746 deletions
1
.swiftformat
Normal file
1
.swiftformat
Normal file
|
@ -0,0 +1 @@
|
||||||
|
--indent 2
|
|
@ -644,7 +644,7 @@
|
||||||
CODE_SIGN_IDENTITY = "-";
|
CODE_SIGN_IDENTITY = "-";
|
||||||
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "Apple Development";
|
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "Apple Development";
|
||||||
CODE_SIGN_STYLE = Automatic;
|
CODE_SIGN_STYLE = Automatic;
|
||||||
CURRENT_PROJECT_VERSION = 1;
|
CURRENT_PROJECT_VERSION = 730;
|
||||||
DEVELOPMENT_TEAM = Z6P74P6T99;
|
DEVELOPMENT_TEAM = Z6P74P6T99;
|
||||||
GENERATE_INFOPLIST_FILE = YES;
|
GENERATE_INFOPLIST_FILE = YES;
|
||||||
INFOPLIST_FILE = IceCubesShareExtension/Info.plist;
|
INFOPLIST_FILE = IceCubesShareExtension/Info.plist;
|
||||||
|
@ -674,7 +674,7 @@
|
||||||
CODE_SIGN_IDENTITY = "-";
|
CODE_SIGN_IDENTITY = "-";
|
||||||
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "Apple Development";
|
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "Apple Development";
|
||||||
CODE_SIGN_STYLE = Automatic;
|
CODE_SIGN_STYLE = Automatic;
|
||||||
CURRENT_PROJECT_VERSION = 1;
|
CURRENT_PROJECT_VERSION = 730;
|
||||||
DEVELOPMENT_TEAM = Z6P74P6T99;
|
DEVELOPMENT_TEAM = Z6P74P6T99;
|
||||||
GENERATE_INFOPLIST_FILE = YES;
|
GENERATE_INFOPLIST_FILE = YES;
|
||||||
INFOPLIST_FILE = IceCubesShareExtension/Info.plist;
|
INFOPLIST_FILE = IceCubesShareExtension/Info.plist;
|
||||||
|
|
|
@ -1,16 +1,16 @@
|
||||||
|
import Account
|
||||||
|
import AppAccount
|
||||||
|
import DesignSystem
|
||||||
|
import Env
|
||||||
|
import Lists
|
||||||
|
import Status
|
||||||
import SwiftUI
|
import SwiftUI
|
||||||
import Timeline
|
import Timeline
|
||||||
import Account
|
|
||||||
import Env
|
|
||||||
import Status
|
|
||||||
import DesignSystem
|
|
||||||
import Lists
|
|
||||||
import AppAccount
|
|
||||||
|
|
||||||
@MainActor
|
@MainActor
|
||||||
extension View {
|
extension View {
|
||||||
func withAppRouteur() -> some View {
|
func withAppRouteur() -> some View {
|
||||||
self.navigationDestination(for: RouteurDestinations.self) { destination in
|
navigationDestination(for: RouteurDestinations.self) { destination in
|
||||||
switch destination {
|
switch destination {
|
||||||
case let .accountDetail(id):
|
case let .accountDetail(id):
|
||||||
AccountDetailView(accountId: id)
|
AccountDetailView(accountId: id)
|
||||||
|
@ -37,7 +37,7 @@ extension View {
|
||||||
}
|
}
|
||||||
|
|
||||||
func withSheetDestinations(sheetDestinations: Binding<SheetDestinations?>) -> some View {
|
func withSheetDestinations(sheetDestinations: Binding<SheetDestinations?>) -> some View {
|
||||||
self.sheet(item: sheetDestinations) { destination in
|
sheet(item: sheetDestinations) { destination in
|
||||||
switch destination {
|
switch destination {
|
||||||
case let .replyToStatusEditor(status):
|
case let .replyToStatusEditor(status):
|
||||||
StatusEditorView(mode: .replyTo(status: status))
|
StatusEditorView(mode: .replyTo(status: status))
|
||||||
|
@ -71,8 +71,7 @@ extension View {
|
||||||
}
|
}
|
||||||
|
|
||||||
func withEnvironments() -> some View {
|
func withEnvironments() -> some View {
|
||||||
self
|
environmentObject(CurrentAccount.shared)
|
||||||
.environmentObject(CurrentAccount.shared)
|
|
||||||
.environmentObject(UserPreferences.shared)
|
.environmentObject(UserPreferences.shared)
|
||||||
.environmentObject(CurrentInstance.shared)
|
.environmentObject(CurrentInstance.shared)
|
||||||
.environmentObject(Theme.shared)
|
.environmentObject(Theme.shared)
|
||||||
|
|
|
@ -1,13 +1,13 @@
|
||||||
import SwiftUI
|
|
||||||
import AVFoundation
|
|
||||||
import Timeline
|
|
||||||
import Network
|
|
||||||
import KeychainSwift
|
|
||||||
import Env
|
|
||||||
import DesignSystem
|
|
||||||
import RevenueCat
|
|
||||||
import AppAccount
|
|
||||||
import Account
|
import Account
|
||||||
|
import AppAccount
|
||||||
|
import AVFoundation
|
||||||
|
import DesignSystem
|
||||||
|
import Env
|
||||||
|
import KeychainSwift
|
||||||
|
import Network
|
||||||
|
import RevenueCat
|
||||||
|
import SwiftUI
|
||||||
|
import Timeline
|
||||||
|
|
||||||
@main
|
@main
|
||||||
struct IceCubesApp: App {
|
struct IceCubesApp: App {
|
||||||
|
@ -168,14 +168,16 @@ struct IceCubesApp: App {
|
||||||
}
|
}
|
||||||
|
|
||||||
class AppDelegate: NSObject, UIApplicationDelegate {
|
class AppDelegate: NSObject, UIApplicationDelegate {
|
||||||
func application(_ application: UIApplication,
|
func application(_: UIApplication,
|
||||||
didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey : Any]? = nil) -> Bool {
|
didFinishLaunchingWithOptions _: [UIApplication.LaunchOptionsKey: Any]? = nil) -> Bool
|
||||||
|
{
|
||||||
try? AVAudioSession.sharedInstance().setCategory(.ambient, options: .mixWithOthers)
|
try? AVAudioSession.sharedInstance().setCategory(.ambient, options: .mixWithOthers)
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
func application(_ application: UIApplication,
|
func application(_: UIApplication,
|
||||||
didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) {
|
didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data)
|
||||||
|
{
|
||||||
PushNotificationsService.shared.pushToken = deviceToken
|
PushNotificationsService.shared.pushToken = deviceToken
|
||||||
Task {
|
Task {
|
||||||
await PushNotificationsService.shared.fetchSubscriptions(accounts: AppAccountsManager.shared.pushAccounts)
|
await PushNotificationsService.shared.fetchSubscriptions(accounts: AppAccountsManager.shared.pushAccounts)
|
||||||
|
@ -183,6 +185,5 @@ class AppDelegate: NSObject, UIApplicationDelegate {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func application(_ application: UIApplication, didFailToRegisterForRemoteNotificationsWithError error: Error) {
|
func application(_: UIApplication, didFailToRegisterForRemoteNotificationsWithError _: Error) {}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
import UIKit
|
|
||||||
import SwiftUI
|
|
||||||
import QuickLook
|
import QuickLook
|
||||||
|
import SwiftUI
|
||||||
|
import UIKit
|
||||||
|
|
||||||
extension URL: Identifiable {
|
extension URL: Identifiable {
|
||||||
public var id: String {
|
public var id: String {
|
||||||
|
@ -21,7 +21,8 @@ struct QuickLookPreview: UIViewControllerRepresentable {
|
||||||
}
|
}
|
||||||
|
|
||||||
func updateUIViewController(
|
func updateUIViewController(
|
||||||
_ uiViewController: UINavigationController, context: Context) {}
|
_: UINavigationController, context _: Context
|
||||||
|
) {}
|
||||||
|
|
||||||
func makeCoordinator() -> Coordinator {
|
func makeCoordinator() -> Coordinator {
|
||||||
return Coordinator(parent: self)
|
return Coordinator(parent: self)
|
||||||
|
@ -34,15 +35,15 @@ struct QuickLookPreview: UIViewControllerRepresentable {
|
||||||
self.parent = parent
|
self.parent = parent
|
||||||
}
|
}
|
||||||
|
|
||||||
func numberOfPreviewItems(in controller: QLPreviewController) -> Int {
|
func numberOfPreviewItems(in _: QLPreviewController) -> Int {
|
||||||
return parent.urls.count
|
return parent.urls.count
|
||||||
}
|
}
|
||||||
|
|
||||||
func previewController(_ controller: QLPreviewController, previewItemAt index: Int) -> QLPreviewItem {
|
func previewController(_: QLPreviewController, previewItemAt index: Int) -> QLPreviewItem {
|
||||||
return parent.urls[index] as QLPreviewItem
|
return parent.urls[index] as QLPreviewItem
|
||||||
}
|
}
|
||||||
|
|
||||||
func previewController(_ controller: QLPreviewController, editingModeFor previewItem: QLPreviewItem) -> QLPreviewItemEditingMode {
|
func previewController(_: QLPreviewController, editingModeFor _: QLPreviewItem) -> QLPreviewItemEditingMode {
|
||||||
.createCopy
|
.createCopy
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import SwiftUI
|
|
||||||
import SafariServices
|
|
||||||
import Env
|
|
||||||
import DesignSystem
|
import DesignSystem
|
||||||
|
import Env
|
||||||
|
import SafariServices
|
||||||
|
import SwiftUI
|
||||||
|
|
||||||
extension View {
|
extension View {
|
||||||
func withSafariRouteur() -> some View {
|
func withSafariRouteur() -> some View {
|
||||||
|
@ -45,14 +45,14 @@ private struct SafariRouteur: ViewModifier {
|
||||||
struct SafariPresenter: UIViewRepresentable {
|
struct SafariPresenter: UIViewRepresentable {
|
||||||
var safari: SFSafariViewController?
|
var safari: SFSafariViewController?
|
||||||
|
|
||||||
func makeUIView(context: Context) -> UIView {
|
func makeUIView(context _: Context) -> UIView {
|
||||||
let view = UIView(frame: .zero)
|
let view = UIView(frame: .zero)
|
||||||
view.isHidden = true
|
view.isHidden = true
|
||||||
view.isUserInteractionEnabled = false
|
view.isUserInteractionEnabled = false
|
||||||
return view
|
return view
|
||||||
}
|
}
|
||||||
|
|
||||||
func updateUIView(_ uiView: UIView, context: Context) {
|
func updateUIView(_ uiView: UIView, context _: Context) {
|
||||||
guard let safari = safari, let viewController = uiView.findTopViewController() else { return }
|
guard let safari = safari, let viewController = uiView.findTopViewController() else { return }
|
||||||
viewController.present(safari, animated: true)
|
viewController.present(safari, animated: true)
|
||||||
}
|
}
|
||||||
|
@ -61,9 +61,9 @@ private struct SafariRouteur: ViewModifier {
|
||||||
|
|
||||||
private extension UIView {
|
private extension UIView {
|
||||||
func findTopViewController() -> UIViewController? {
|
func findTopViewController() -> UIViewController? {
|
||||||
if let nextResponder = self.next as? UIViewController {
|
if let nextResponder = next as? UIViewController {
|
||||||
return nextResponder.topViewController()
|
return nextResponder.topViewController()
|
||||||
} else if let nextResponder = self.next as? UIView {
|
} else if let nextResponder = next as? UIView {
|
||||||
return nextResponder.findTopViewController()
|
return nextResponder.findTopViewController()
|
||||||
} else {
|
} else {
|
||||||
return nil
|
return nil
|
||||||
|
@ -77,7 +77,7 @@ private extension UIViewController {
|
||||||
return nvc.visibleViewController?.topViewController()
|
return nvc.visibleViewController?.topViewController()
|
||||||
} else if let tbc = self as? UITabBarController, let selected = tbc.selectedViewController {
|
} else if let tbc = self as? UITabBarController, let selected = tbc.selectedViewController {
|
||||||
return selected.topViewController()
|
return selected.topViewController()
|
||||||
} else if let presented = self.presentedViewController {
|
} else if let presented = presentedViewController {
|
||||||
return presented.topViewController()
|
return presented.topViewController()
|
||||||
}
|
}
|
||||||
return self
|
return self
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
import SwiftUI
|
|
||||||
import Env
|
|
||||||
import Account
|
import Account
|
||||||
import DesignSystem
|
|
||||||
import AppAccount
|
import AppAccount
|
||||||
|
import DesignSystem
|
||||||
|
import Env
|
||||||
|
import SwiftUI
|
||||||
|
|
||||||
struct SideBarView<Content: View>: View {
|
struct SideBarView<Content: View>: View {
|
||||||
@EnvironmentObject private var currentAccount: CurrentAccount
|
@EnvironmentObject private var currentAccount: CurrentAccount
|
||||||
|
|
|
@ -1,11 +1,10 @@
|
||||||
import SwiftUI
|
|
||||||
import Env
|
|
||||||
import Models
|
|
||||||
import Shimmer
|
|
||||||
import Explore
|
|
||||||
import Env
|
|
||||||
import Network
|
|
||||||
import AppAccount
|
import AppAccount
|
||||||
|
import Env
|
||||||
|
import Explore
|
||||||
|
import Models
|
||||||
|
import Network
|
||||||
|
import Shimmer
|
||||||
|
import SwiftUI
|
||||||
|
|
||||||
struct ExploreTab: View {
|
struct ExploreTab: View {
|
||||||
@EnvironmentObject private var preferences: UserPreferences
|
@EnvironmentObject private var preferences: UserPreferences
|
||||||
|
|
|
@ -1,12 +1,11 @@
|
||||||
import SwiftUI
|
|
||||||
import Env
|
|
||||||
import Network
|
|
||||||
import Account
|
import Account
|
||||||
import Models
|
import AppAccount
|
||||||
import Shimmer
|
|
||||||
import Conversations
|
import Conversations
|
||||||
import Env
|
import Env
|
||||||
import AppAccount
|
import Models
|
||||||
|
import Network
|
||||||
|
import Shimmer
|
||||||
|
import SwiftUI
|
||||||
|
|
||||||
struct MessagesTab: View {
|
struct MessagesTab: View {
|
||||||
@EnvironmentObject private var watcher: StreamWatcher
|
@EnvironmentObject private var watcher: StreamWatcher
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
import SwiftUI
|
import AppAccount
|
||||||
import Timeline
|
|
||||||
import Env
|
import Env
|
||||||
import Network
|
import Network
|
||||||
import Notifications
|
import Notifications
|
||||||
import AppAccount
|
import SwiftUI
|
||||||
|
import Timeline
|
||||||
|
|
||||||
struct NotificationsTab: View {
|
struct NotificationsTab: View {
|
||||||
@EnvironmentObject private var client: Client
|
@EnvironmentObject private var client: Client
|
||||||
|
|
|
@ -1,12 +1,12 @@
|
||||||
import SwiftUI
|
|
||||||
import Network
|
|
||||||
import Models
|
|
||||||
import Env
|
|
||||||
import DesignSystem
|
|
||||||
import NukeUI
|
|
||||||
import Shimmer
|
|
||||||
import AppAccount
|
import AppAccount
|
||||||
import Combine
|
import Combine
|
||||||
|
import DesignSystem
|
||||||
|
import Env
|
||||||
|
import Models
|
||||||
|
import Network
|
||||||
|
import NukeUI
|
||||||
|
import Shimmer
|
||||||
|
import SwiftUI
|
||||||
|
|
||||||
struct AddAccountView: View {
|
struct AddAccountView: View {
|
||||||
@Environment(\.dismiss) private var dismiss
|
@Environment(\.dismiss) private var dismiss
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import SwiftUI
|
|
||||||
import Models
|
|
||||||
import DesignSystem
|
import DesignSystem
|
||||||
|
import Models
|
||||||
import Status
|
import Status
|
||||||
|
import SwiftUI
|
||||||
|
|
||||||
struct DisplaySettingsView: View {
|
struct DisplaySettingsView: View {
|
||||||
@EnvironmentObject private var theme: Theme
|
@EnvironmentObject private var theme: Theme
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import SwiftUI
|
|
||||||
import DesignSystem
|
import DesignSystem
|
||||||
|
import SwiftUI
|
||||||
|
|
||||||
struct IconSelectorView: View {
|
struct IconSelectorView: View {
|
||||||
enum Icon: Int, CaseIterable, Identifiable {
|
enum Icon: Int, CaseIterable, Identifiable {
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import SwiftUI
|
|
||||||
import Models
|
|
||||||
import DesignSystem
|
import DesignSystem
|
||||||
|
import Models
|
||||||
import NukeUI
|
import NukeUI
|
||||||
|
import SwiftUI
|
||||||
|
|
||||||
struct InstanceInfoView: View {
|
struct InstanceInfoView: View {
|
||||||
@EnvironmentObject private var theme: Theme
|
@EnvironmentObject private var theme: Theme
|
||||||
|
|
|
@ -1,11 +1,11 @@
|
||||||
import SwiftUI
|
|
||||||
import Models
|
|
||||||
import DesignSystem
|
|
||||||
import NukeUI
|
|
||||||
import Network
|
|
||||||
import UserNotifications
|
|
||||||
import Env
|
|
||||||
import AppAccount
|
import AppAccount
|
||||||
|
import DesignSystem
|
||||||
|
import Env
|
||||||
|
import Models
|
||||||
|
import Network
|
||||||
|
import NukeUI
|
||||||
|
import SwiftUI
|
||||||
|
import UserNotifications
|
||||||
|
|
||||||
struct PushNotificationsView: View {
|
struct PushNotificationsView: View {
|
||||||
@EnvironmentObject private var theme: Theme
|
@EnvironmentObject private var theme: Theme
|
||||||
|
|
|
@ -1,11 +1,11 @@
|
||||||
|
import Account
|
||||||
|
import AppAccount
|
||||||
|
import DesignSystem
|
||||||
|
import Env
|
||||||
|
import Models
|
||||||
|
import Network
|
||||||
import SwiftUI
|
import SwiftUI
|
||||||
import Timeline
|
import Timeline
|
||||||
import Env
|
|
||||||
import Network
|
|
||||||
import Account
|
|
||||||
import Models
|
|
||||||
import DesignSystem
|
|
||||||
import AppAccount
|
|
||||||
|
|
||||||
struct SettingsTabs: View {
|
struct SettingsTabs: View {
|
||||||
@EnvironmentObject private var pushNotifications: PushNotificationsService
|
@EnvironmentObject private var pushNotifications: PushNotificationsService
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
import SwiftUI
|
|
||||||
import Env
|
|
||||||
import DesignSystem
|
import DesignSystem
|
||||||
|
import Env
|
||||||
import RevenueCat
|
import RevenueCat
|
||||||
import Shimmer
|
import Shimmer
|
||||||
|
import SwiftUI
|
||||||
|
|
||||||
struct SupportAppView: View {
|
struct SupportAppView: View {
|
||||||
enum Tips: String, CaseIterable {
|
enum Tips: String, CaseIterable {
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import Foundation
|
|
||||||
import Status
|
|
||||||
import Account
|
import Account
|
||||||
import Explore
|
import Explore
|
||||||
|
import Foundation
|
||||||
|
import Status
|
||||||
import SwiftUI
|
import SwiftUI
|
||||||
|
|
||||||
enum Tab: Int, Identifiable, Hashable {
|
enum Tab: Int, Identifiable, Hashable {
|
||||||
|
@ -96,4 +96,3 @@ enum Tab: Int, Identifiable, Hashable {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,11 +1,11 @@
|
||||||
import SwiftUI
|
import Combine
|
||||||
import Network
|
|
||||||
import Models
|
|
||||||
import Env
|
|
||||||
import DesignSystem
|
import DesignSystem
|
||||||
|
import Env
|
||||||
|
import Models
|
||||||
|
import Network
|
||||||
import NukeUI
|
import NukeUI
|
||||||
import Shimmer
|
import Shimmer
|
||||||
import Combine
|
import SwiftUI
|
||||||
|
|
||||||
struct AddRemoteTimelineView: View {
|
struct AddRemoteTimelineView: View {
|
||||||
@Environment(\.dismiss) private var dismiss
|
@Environment(\.dismiss) private var dismiss
|
||||||
|
|
|
@ -1,11 +1,11 @@
|
||||||
import SwiftUI
|
import AppAccount
|
||||||
import Timeline
|
|
||||||
import Env
|
|
||||||
import Network
|
|
||||||
import Combine
|
import Combine
|
||||||
import DesignSystem
|
import DesignSystem
|
||||||
|
import Env
|
||||||
import Models
|
import Models
|
||||||
import AppAccount
|
import Network
|
||||||
|
import SwiftUI
|
||||||
|
import Timeline
|
||||||
|
|
||||||
struct TimelineTab: View {
|
struct TimelineTab: View {
|
||||||
@EnvironmentObject private var theme: Theme
|
@EnvironmentObject private var theme: Theme
|
||||||
|
@ -72,7 +72,6 @@ struct TimelineTab: View {
|
||||||
.environmentObject(routeurPath)
|
.environmentObject(routeurPath)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ViewBuilder
|
@ViewBuilder
|
||||||
private var timelineFilterButton: some View {
|
private var timelineFilterButton: some View {
|
||||||
ForEach(TimelineFilter.availableTimeline(client: client), id: \.self) { timeline in
|
ForEach(TimelineFilter.availableTimeline(client: client), id: \.self) { timeline in
|
||||||
|
|
|
@ -1,13 +1,12 @@
|
||||||
import UserNotifications
|
|
||||||
import KeychainSwift
|
|
||||||
import Env
|
|
||||||
import CryptoKit
|
import CryptoKit
|
||||||
|
import Env
|
||||||
|
import KeychainSwift
|
||||||
import Models
|
import Models
|
||||||
import UIKit
|
import UIKit
|
||||||
|
import UserNotifications
|
||||||
|
|
||||||
@MainActor
|
@MainActor
|
||||||
class NotificationService: UNNotificationServiceExtension {
|
class NotificationService: UNNotificationServiceExtension {
|
||||||
|
|
||||||
var contentHandler: ((UNNotificationContent) -> Void)?
|
var contentHandler: ((UNNotificationContent) -> Void)?
|
||||||
var bestAttemptContent: UNMutableNotificationContent?
|
var bestAttemptContent: UNMutableNotificationContent?
|
||||||
|
|
||||||
|
@ -20,20 +19,23 @@ class NotificationService: UNNotificationServiceExtension {
|
||||||
let auth = PushNotificationsService.shared.notificationsAuthKeyAsKey
|
let auth = PushNotificationsService.shared.notificationsAuthKeyAsKey
|
||||||
|
|
||||||
guard let encodedPayload = bestAttemptContent.userInfo["m"] as? String,
|
guard let encodedPayload = bestAttemptContent.userInfo["m"] as? String,
|
||||||
let payload = Data(base64Encoded: encodedPayload.URLSafeBase64ToBase64()) else {
|
let payload = Data(base64Encoded: encodedPayload.URLSafeBase64ToBase64())
|
||||||
|
else {
|
||||||
contentHandler(bestAttemptContent)
|
contentHandler(bestAttemptContent)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
guard let encodedPublicKey = bestAttemptContent.userInfo["k"] as? String,
|
guard let encodedPublicKey = bestAttemptContent.userInfo["k"] as? String,
|
||||||
let publicKeyData = Data(base64Encoded: encodedPublicKey.URLSafeBase64ToBase64()),
|
let publicKeyData = Data(base64Encoded: encodedPublicKey.URLSafeBase64ToBase64()),
|
||||||
let publicKey = try? P256.KeyAgreement.PublicKey(x963Representation: publicKeyData) else {
|
let publicKey = try? P256.KeyAgreement.PublicKey(x963Representation: publicKeyData)
|
||||||
|
else {
|
||||||
contentHandler(bestAttemptContent)
|
contentHandler(bestAttemptContent)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
guard let encodedSalt = bestAttemptContent.userInfo["s"] as? String,
|
guard let encodedSalt = bestAttemptContent.userInfo["s"] as? String,
|
||||||
let salt = Data(base64Encoded: encodedSalt.URLSafeBase64ToBase64()) else {
|
let salt = Data(base64Encoded: encodedSalt.URLSafeBase64ToBase64())
|
||||||
|
else {
|
||||||
contentHandler(bestAttemptContent)
|
contentHandler(bestAttemptContent)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -43,7 +45,8 @@ class NotificationService: UNNotificationServiceExtension {
|
||||||
auth: auth,
|
auth: auth,
|
||||||
privateKey: privateKey,
|
privateKey: privateKey,
|
||||||
publicKey: publicKey),
|
publicKey: publicKey),
|
||||||
let notification = try? JSONDecoder().decode(MastodonPushNotification.self, from: plaintextData) else {
|
let notification = try? JSONDecoder().decode(MastodonPushNotification.self, from: plaintextData)
|
||||||
|
else {
|
||||||
contentHandler(bestAttemptContent)
|
contentHandler(bestAttemptContent)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -52,7 +55,7 @@ class NotificationService: UNNotificationServiceExtension {
|
||||||
bestAttemptContent.subtitle = ""
|
bestAttemptContent.subtitle = ""
|
||||||
bestAttemptContent.body = notification.body.escape()
|
bestAttemptContent.body = notification.body.escape()
|
||||||
bestAttemptContent.userInfo["plaintext"] = plaintextData
|
bestAttemptContent.userInfo["plaintext"] = plaintextData
|
||||||
bestAttemptContent.sound = UNNotificationSound.init(named: UNNotificationSoundName(rawValue: "glass.wav"))
|
bestAttemptContent.sound = UNNotificationSound(named: UNNotificationSoundName(rawValue: "glass.wav"))
|
||||||
|
|
||||||
let preferences = UserPreferences.shared
|
let preferences = UserPreferences.shared
|
||||||
preferences.pushNotificationsCount += 1
|
preferences.pushNotificationsCount += 1
|
||||||
|
@ -60,7 +63,8 @@ class NotificationService: UNNotificationServiceExtension {
|
||||||
bestAttemptContent.badge = .init(integerLiteral: preferences.pushNotificationsCount)
|
bestAttemptContent.badge = .init(integerLiteral: preferences.pushNotificationsCount)
|
||||||
|
|
||||||
if let urlString = notification.icon,
|
if let urlString = notification.icon,
|
||||||
let url = URL(string: urlString) {
|
let url = URL(string: urlString)
|
||||||
|
{
|
||||||
let temporaryDirectoryURL = URL(fileURLWithPath: NSTemporaryDirectory()).appendingPathComponent("notification-attachments")
|
let temporaryDirectoryURL = URL(fileURLWithPath: NSTemporaryDirectory()).appendingPathComponent("notification-attachments")
|
||||||
try? FileManager.default.createDirectory(at: temporaryDirectoryURL, withIntermediateDirectories: true, attributes: nil)
|
try? FileManager.default.createDirectory(at: temporaryDirectoryURL, withIntermediateDirectories: true, attributes: nil)
|
||||||
let filename = url.lastPathComponent
|
let filename = url.lastPathComponent
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import Foundation
|
|
||||||
import CryptoKit
|
import CryptoKit
|
||||||
|
import Foundation
|
||||||
|
|
||||||
extension NotificationService {
|
extension NotificationService {
|
||||||
static func decrypt(payload: Data, salt: Data, auth: Data, privateKey: P256.KeyAgreement.PrivateKey, publicKey: P256.KeyAgreement.PublicKey) -> Data? {
|
static func decrypt(payload: Data, salt: Data, auth: Data, privateKey: P256.KeyAgreement.PrivateKey, publicKey: P256.KeyAgreement.PublicKey) -> Data? {
|
||||||
|
@ -41,7 +41,7 @@ extension NotificationService {
|
||||||
return Data(unpadded)
|
return Data(unpadded)
|
||||||
}
|
}
|
||||||
|
|
||||||
static private func info(type: String, clientPublicKey: Data, serverPublicKey: Data) -> Data {
|
private static func info(type: String, clientPublicKey: Data, serverPublicKey: Data) -> Data {
|
||||||
var info = Data()
|
var info = Data()
|
||||||
|
|
||||||
info.append("Content-Encoding: ".data(using: .utf8)!)
|
info.append("Content-Encoding: ".data(using: .utf8)!)
|
||||||
|
@ -62,14 +62,12 @@ extension NotificationService {
|
||||||
|
|
||||||
extension String {
|
extension String {
|
||||||
func escape() -> String {
|
func escape() -> String {
|
||||||
return self
|
return replacingOccurrences(of: "&", with: "&")
|
||||||
.replacingOccurrences(of: "&", with: "&")
|
|
||||||
.replacingOccurrences(of: "<", with: "<")
|
.replacingOccurrences(of: "<", with: "<")
|
||||||
.replacingOccurrences(of: ">", with: ">")
|
.replacingOccurrences(of: ">", with: ">")
|
||||||
.replacingOccurrences(of: """, with: "\"")
|
.replacingOccurrences(of: """, with: "\"")
|
||||||
.replacingOccurrences(of: "'", with: "'")
|
.replacingOccurrences(of: "'", with: "'")
|
||||||
.replacingOccurrences(of: "'", with: "’")
|
.replacingOccurrences(of: "'", with: "’")
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func URLSafeBase64ToBase64() -> String {
|
func URLSafeBase64ToBase64() -> String {
|
||||||
|
@ -83,4 +81,3 @@ extension String {
|
||||||
return base64
|
return base64
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -8,14 +8,14 @@
|
||||||
<dict>
|
<dict>
|
||||||
<key>NSExtensionActivationRule</key>
|
<key>NSExtensionActivationRule</key>
|
||||||
<dict>
|
<dict>
|
||||||
<key>NSExtensionActivationSupportsText</key>
|
|
||||||
<true/>
|
|
||||||
<key>NSExtensionActivationSupportsWebURLWithMaxCount</key>
|
|
||||||
<integer>1</integer>
|
|
||||||
<key>NSExtensionActivationSupportsWebPageWithMaxCount</key>
|
|
||||||
<integer>1</integer>
|
|
||||||
<key>NSExtensionActivationSupportsImageWithMaxCount</key>
|
<key>NSExtensionActivationSupportsImageWithMaxCount</key>
|
||||||
<integer>4</integer>
|
<integer>4</integer>
|
||||||
|
<key>NSExtensionActivationSupportsText</key>
|
||||||
|
<true/>
|
||||||
|
<key>NSExtensionActivationSupportsWebPageWithMaxCount</key>
|
||||||
|
<integer>1</integer>
|
||||||
|
<key>NSExtensionActivationSupportsWebURLWithMaxCount</key>
|
||||||
|
<integer>1</integer>
|
||||||
</dict>
|
</dict>
|
||||||
</dict>
|
</dict>
|
||||||
<key>NSExtensionMainStoryboard</key>
|
<key>NSExtensionMainStoryboard</key>
|
||||||
|
|
|
@ -1,11 +1,11 @@
|
||||||
|
import Account
|
||||||
|
import AppAccount
|
||||||
|
import DesignSystem
|
||||||
|
import Env
|
||||||
|
import Network
|
||||||
|
import Status
|
||||||
import SwiftUI
|
import SwiftUI
|
||||||
import UIKit
|
import UIKit
|
||||||
import Status
|
|
||||||
import DesignSystem
|
|
||||||
import Account
|
|
||||||
import Network
|
|
||||||
import Env
|
|
||||||
import AppAccount
|
|
||||||
|
|
||||||
class ShareViewController: UIViewController {
|
class ShareViewController: UIViewController {
|
||||||
@IBOutlet var container: UIView!
|
@IBOutlet var container: UIView!
|
||||||
|
@ -35,9 +35,9 @@ class ShareViewController: UIViewController {
|
||||||
.tint(theme.tintColor)
|
.tint(theme.tintColor)
|
||||||
.preferredColorScheme(colorScheme == .light ? .light : .dark)
|
.preferredColorScheme(colorScheme == .light ? .light : .dark)
|
||||||
let childView = UIHostingController(rootView: view)
|
let childView = UIHostingController(rootView: view)
|
||||||
self.addChild(childView)
|
addChild(childView)
|
||||||
childView.view.frame = self.container.bounds
|
childView.view.frame = container.bounds
|
||||||
self.container.addSubview(childView.view)
|
container.addSubview(childView.view)
|
||||||
childView.didMove(toParent: self)
|
childView.didMove(toParent: self)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,7 +11,8 @@ let package = Package(
|
||||||
products: [
|
products: [
|
||||||
.library(
|
.library(
|
||||||
name: "Account",
|
name: "Account",
|
||||||
targets: ["Account"]),
|
targets: ["Account"]
|
||||||
|
),
|
||||||
],
|
],
|
||||||
dependencies: [
|
dependencies: [
|
||||||
.package(name: "Network", path: "../Network"),
|
.package(name: "Network", path: "../Network"),
|
||||||
|
@ -25,9 +26,11 @@ let package = Package(
|
||||||
.product(name: "Network", package: "Network"),
|
.product(name: "Network", package: "Network"),
|
||||||
.product(name: "Models", package: "Models"),
|
.product(name: "Models", package: "Models"),
|
||||||
.product(name: "Status", package: "Status"),
|
.product(name: "Status", package: "Status"),
|
||||||
]),
|
]
|
||||||
|
),
|
||||||
.testTarget(
|
.testTarget(
|
||||||
name: "AccountTests",
|
name: "AccountTests",
|
||||||
dependencies: ["Account"]),
|
dependencies: ["Account"]
|
||||||
|
),
|
||||||
]
|
]
|
||||||
)
|
)
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
import SwiftUI
|
|
||||||
import Models
|
|
||||||
import DesignSystem
|
import DesignSystem
|
||||||
import Env
|
|
||||||
import Shimmer
|
|
||||||
import NukeUI
|
|
||||||
import EmojiText
|
import EmojiText
|
||||||
|
import Env
|
||||||
|
import Models
|
||||||
|
import NukeUI
|
||||||
|
import Shimmer
|
||||||
|
import SwiftUI
|
||||||
|
|
||||||
struct AccountDetailHeaderView: View {
|
struct AccountDetailHeaderView: View {
|
||||||
@EnvironmentObject private var theme: Theme
|
@EnvironmentObject private var theme: Theme
|
||||||
|
@ -30,7 +30,7 @@ struct AccountDetailHeaderView: View {
|
||||||
}
|
}
|
||||||
|
|
||||||
private var headerImageView: some View {
|
private var headerImageView: some View {
|
||||||
GeometryReader { proxy in
|
GeometryReader { _ in
|
||||||
ZStack(alignment: .bottomTrailing) {
|
ZStack(alignment: .bottomTrailing) {
|
||||||
if reasons.contains(.placeholder) {
|
if reasons.contains(.placeholder) {
|
||||||
Rectangle()
|
Rectangle()
|
||||||
|
|
|
@ -1,11 +1,11 @@
|
||||||
import SwiftUI
|
import DesignSystem
|
||||||
|
import EmojiText
|
||||||
|
import Env
|
||||||
import Models
|
import Models
|
||||||
import Network
|
import Network
|
||||||
import Status
|
|
||||||
import Shimmer
|
import Shimmer
|
||||||
import DesignSystem
|
import Status
|
||||||
import Env
|
import SwiftUI
|
||||||
import EmojiText
|
|
||||||
|
|
||||||
public struct AccountDetailView: View {
|
public struct AccountDetailView: View {
|
||||||
@Environment(\.redactionReasons) private var reasons
|
@Environment(\.redactionReasons) private var reasons
|
||||||
|
@ -94,9 +94,10 @@ public struct AccountDetailView: View {
|
||||||
await viewModel.fetchStatuses()
|
await viewModel.fetchStatuses()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.onChange(of: watcher.latestEvent?.id) { id in
|
.onChange(of: watcher.latestEvent?.id) { _ in
|
||||||
if let latestEvent = watcher.latestEvent,
|
if let latestEvent = watcher.latestEvent,
|
||||||
viewModel.accountId == currentAccount.account?.id {
|
viewModel.accountId == currentAccount.account?.id
|
||||||
|
{
|
||||||
viewModel.handleEvent(event: latestEvent, currentAccount: currentAccount)
|
viewModel.handleEvent(event: latestEvent, currentAccount: currentAccount)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -396,4 +397,3 @@ struct AccountDetailView_Previews: PreviewProvider {
|
||||||
AccountDetailView(account: .placeholder())
|
AccountDetailView(account: .placeholder())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
import SwiftUI
|
|
||||||
import Network
|
|
||||||
import Models
|
|
||||||
import Status
|
|
||||||
import Env
|
import Env
|
||||||
|
import Models
|
||||||
|
import Network
|
||||||
|
import Status
|
||||||
|
import SwiftUI
|
||||||
|
|
||||||
@MainActor
|
@MainActor
|
||||||
class AccountDetailViewModel: ObservableObject, StatusesFetcher {
|
class AccountDetailViewModel: ObservableObject, StatusesFetcher {
|
||||||
|
@ -57,6 +57,7 @@ class AccountDetailViewModel: ObservableObject, StatusesFetcher {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Published var statusesState: StatusesState = .loading
|
@Published var statusesState: StatusesState = .loading
|
||||||
|
|
||||||
@Published var relationship: Relationshionship?
|
@Published var relationship: Relationshionship?
|
||||||
|
@ -90,14 +91,14 @@ class AccountDetailViewModel: ObservableObject, StatusesFetcher {
|
||||||
/// When coming from a URL like a mention tap in a status.
|
/// When coming from a URL like a mention tap in a status.
|
||||||
init(accountId: String) {
|
init(accountId: String) {
|
||||||
self.accountId = accountId
|
self.accountId = accountId
|
||||||
self.isCurrentUser = false
|
isCurrentUser = false
|
||||||
}
|
}
|
||||||
|
|
||||||
/// When the account is already fetched by the parent caller.
|
/// When the account is already fetched by the parent caller.
|
||||||
init(account: Account) {
|
init(account: Account) {
|
||||||
self.accountId = account.id
|
accountId = account.id
|
||||||
self.account = account
|
self.account = account
|
||||||
self.accountState = .data(account: account)
|
accountState = .data(account: account)
|
||||||
}
|
}
|
||||||
|
|
||||||
struct AccountData {
|
struct AccountData {
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
import SwiftUI
|
import DesignSystem
|
||||||
|
import EmojiText
|
||||||
|
import Env
|
||||||
import Models
|
import Models
|
||||||
import Network
|
import Network
|
||||||
import DesignSystem
|
import SwiftUI
|
||||||
import Env
|
|
||||||
import EmojiText
|
|
||||||
|
|
||||||
@MainActor
|
@MainActor
|
||||||
public class AccountsListRowViewModel: ObservableObject {
|
public class AccountsListRowViewModel: ObservableObject {
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
import SwiftUI
|
|
||||||
import Network
|
|
||||||
import Models
|
|
||||||
import Env
|
|
||||||
import Shimmer
|
|
||||||
import DesignSystem
|
import DesignSystem
|
||||||
|
import Env
|
||||||
|
import Models
|
||||||
|
import Network
|
||||||
|
import Shimmer
|
||||||
|
import SwiftUI
|
||||||
|
|
||||||
public struct AccountsListView: View {
|
public struct AccountsListView: View {
|
||||||
@EnvironmentObject private var theme: Theme
|
@EnvironmentObject private var theme: Theme
|
||||||
|
@ -19,7 +19,7 @@ public struct AccountsListView: View {
|
||||||
List {
|
List {
|
||||||
switch viewModel.state {
|
switch viewModel.state {
|
||||||
case .loading:
|
case .loading:
|
||||||
ForEach(Account.placeholders()) { account in
|
ForEach(Account.placeholders()) { _ in
|
||||||
AccountsListRow(viewModel: .init(account: .placeholder(), relationShip: .placeholder()))
|
AccountsListRow(viewModel: .init(account: .placeholder(), relationShip: .placeholder()))
|
||||||
.redacted(reason: .placeholder)
|
.redacted(reason: .placeholder)
|
||||||
.shimmering()
|
.shimmering()
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
import SwiftUI
|
|
||||||
import Models
|
import Models
|
||||||
import Network
|
import Network
|
||||||
|
import SwiftUI
|
||||||
|
|
||||||
public enum AccountsListMode {
|
public enum AccountsListMode {
|
||||||
case following(accountId: String), followers(accountId: String)
|
case following(accountId: String), followers(accountId: String)
|
||||||
|
@ -30,6 +30,7 @@ class AccountsListViewModel: ObservableObject {
|
||||||
public enum PagingState {
|
public enum PagingState {
|
||||||
case hasNextPage, loadingNextPage, none
|
case hasNextPage, loadingNextPage, none
|
||||||
}
|
}
|
||||||
|
|
||||||
case loading
|
case loading
|
||||||
case display(accounts: [Account],
|
case display(accounts: [Account],
|
||||||
relationships: [Relationshionship],
|
relationships: [Relationshionship],
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import SwiftUI
|
import DesignSystem
|
||||||
import Models
|
import Models
|
||||||
import Network
|
import Network
|
||||||
import DesignSystem
|
import SwiftUI
|
||||||
|
|
||||||
struct EditAccountView: View {
|
struct EditAccountView: View {
|
||||||
@Environment(\.dismiss) private var dismiss
|
@Environment(\.dismiss) private var dismiss
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
import SwiftUI
|
|
||||||
import Models
|
import Models
|
||||||
import Network
|
import Network
|
||||||
|
import SwiftUI
|
||||||
|
|
||||||
@MainActor
|
@MainActor
|
||||||
class EditAccountViewModel: ObservableObject {
|
class EditAccountViewModel: ObservableObject {
|
||||||
|
@ -57,5 +57,4 @@ class EditAccountViewModel: ObservableObject {
|
||||||
saveError = true
|
saveError = true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import Foundation
|
import Foundation
|
||||||
import SwiftUI
|
|
||||||
import Models
|
import Models
|
||||||
import Network
|
import Network
|
||||||
|
import SwiftUI
|
||||||
|
|
||||||
@MainActor
|
@MainActor
|
||||||
public class FollowButtonViewModel: ObservableObject {
|
public class FollowButtonViewModel: ObservableObject {
|
||||||
|
@ -9,8 +9,8 @@ public class FollowButtonViewModel: ObservableObject {
|
||||||
|
|
||||||
public let accountId: String
|
public let accountId: String
|
||||||
public let shouldDisplayNotify: Bool
|
public let shouldDisplayNotify: Bool
|
||||||
@Published private(set) public var relationship: Relationshionship
|
@Published public private(set) var relationship: Relationshionship
|
||||||
@Published private(set) public var isUpdating: Bool = false
|
@Published public private(set) var isUpdating: Bool = false
|
||||||
|
|
||||||
public init(accountId: String, relationship: Relationshionship, shouldDisplayNotify: Bool) {
|
public init(accountId: String, relationship: Relationshionship, shouldDisplayNotify: Bool) {
|
||||||
self.accountId = accountId
|
self.accountId = accountId
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import XCTest
|
|
||||||
@testable import Account
|
@testable import Account
|
||||||
|
import XCTest
|
||||||
|
|
||||||
final class AccountTests: XCTestCase {
|
final class AccountTests: XCTestCase {
|
||||||
func testExample() throws {
|
func testExample() throws {
|
||||||
|
|
|
@ -11,7 +11,8 @@ let package = Package(
|
||||||
products: [
|
products: [
|
||||||
.library(
|
.library(
|
||||||
name: "AppAccount",
|
name: "AppAccount",
|
||||||
targets: ["AppAccount"]),
|
targets: ["AppAccount"]
|
||||||
|
),
|
||||||
],
|
],
|
||||||
dependencies: [
|
dependencies: [
|
||||||
.package(name: "Network", path: "../Network"),
|
.package(name: "Network", path: "../Network"),
|
||||||
|
@ -27,6 +28,7 @@ let package = Package(
|
||||||
.product(name: "Models", package: "Models"),
|
.product(name: "Models", package: "Models"),
|
||||||
.product(name: "Env", package: "Env"),
|
.product(name: "Env", package: "Env"),
|
||||||
.product(name: "DesignSystem", package: "DesignSystem"),
|
.product(name: "DesignSystem", package: "DesignSystem"),
|
||||||
])
|
]
|
||||||
|
),
|
||||||
]
|
]
|
||||||
)
|
)
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
import SwiftUI
|
import CryptoKit
|
||||||
import Network
|
|
||||||
import KeychainSwift
|
import KeychainSwift
|
||||||
import Models
|
import Models
|
||||||
import CryptoKit
|
import Network
|
||||||
|
import SwiftUI
|
||||||
|
|
||||||
public struct AppAccount: Codable, Identifiable {
|
public struct AppAccount: Codable, Identifiable {
|
||||||
public let server: String
|
public let server: String
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import SwiftUI
|
|
||||||
import DesignSystem
|
import DesignSystem
|
||||||
import Env
|
|
||||||
import EmojiText
|
import EmojiText
|
||||||
|
import Env
|
||||||
|
import SwiftUI
|
||||||
|
|
||||||
public struct AppAccountView: View {
|
public struct AppAccountView: View {
|
||||||
@EnvironmentObject private var routeurPath: RouterPath
|
@EnvironmentObject private var routeurPath: RouterPath
|
||||||
|
@ -43,7 +43,8 @@ public struct AppAccountView: View {
|
||||||
}
|
}
|
||||||
.onTapGesture {
|
.onTapGesture {
|
||||||
if appAccounts.currentAccount.id == viewModel.appAccount.id,
|
if appAccounts.currentAccount.id == viewModel.appAccount.id,
|
||||||
let account = viewModel.account {
|
let account = viewModel.account
|
||||||
|
{
|
||||||
routeurPath.navigate(to: .accountDetailWithAccount(account: account))
|
routeurPath.navigate(to: .accountDetailWithAccount(account: account))
|
||||||
} else {
|
} else {
|
||||||
appAccounts.currentAccount = viewModel.appAccount
|
appAccounts.currentAccount = viewModel.appAccount
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
import SwiftUI
|
|
||||||
import Models
|
import Models
|
||||||
import Network
|
import Network
|
||||||
|
import SwiftUI
|
||||||
|
|
||||||
@MainActor
|
@MainActor
|
||||||
public class AppAccountViewModel: ObservableObject {
|
public class AppAccountViewModel: ObservableObject {
|
||||||
|
@ -15,7 +15,7 @@ public class AppAccountViewModel: ObservableObject {
|
||||||
|
|
||||||
public init(appAccount: AppAccount) {
|
public init(appAccount: AppAccount) {
|
||||||
self.appAccount = appAccount
|
self.appAccount = appAccount
|
||||||
self.client = .init(server: appAccount.server, oauthToken: appAccount.oauthToken)
|
client = .init(server: appAccount.server, oauthToken: appAccount.oauthToken)
|
||||||
}
|
}
|
||||||
|
|
||||||
func fetchAccount() async {
|
func fetchAccount() async {
|
||||||
|
|
|
@ -1,12 +1,12 @@
|
||||||
import SwiftUI
|
|
||||||
import Network
|
|
||||||
import Env
|
import Env
|
||||||
import Models
|
import Models
|
||||||
|
import Network
|
||||||
|
import SwiftUI
|
||||||
|
|
||||||
@MainActor
|
@MainActor
|
||||||
public class AppAccountsManager: ObservableObject {
|
public class AppAccountsManager: ObservableObject {
|
||||||
@AppStorage("latestCurrentAccountKey", store: UserPreferences.sharedDefault)
|
@AppStorage("latestCurrentAccountKey", store: UserPreferences.sharedDefault)
|
||||||
static public var latestCurrentAccountKey: String = ""
|
public static var latestCurrentAccountKey: String = ""
|
||||||
|
|
||||||
@Published public var currentAccount: AppAccount {
|
@Published public var currentAccount: AppAccount {
|
||||||
didSet {
|
didSet {
|
||||||
|
@ -15,6 +15,7 @@ public class AppAccountsManager: ObservableObject {
|
||||||
oauthToken: currentAccount.oauthToken)
|
oauthToken: currentAccount.oauthToken)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Published public var availableAccounts: [AppAccount]
|
@Published public var availableAccounts: [AppAccount]
|
||||||
@Published public var currentClient: Client
|
@Published public var currentClient: Client
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
import SwiftUI
|
|
||||||
import Env
|
|
||||||
import DesignSystem
|
import DesignSystem
|
||||||
|
import Env
|
||||||
|
import SwiftUI
|
||||||
|
|
||||||
public struct AppAccountsSelectorView: View {
|
public struct AppAccountsSelectorView: View {
|
||||||
@EnvironmentObject private var currentAccount: CurrentAccount
|
@EnvironmentObject private var currentAccount: CurrentAccount
|
||||||
|
@ -15,7 +15,8 @@ public struct AppAccountsSelectorView: View {
|
||||||
|
|
||||||
public init(routeurPath: RouterPath,
|
public init(routeurPath: RouterPath,
|
||||||
accountCreationEnabled: Bool = true,
|
accountCreationEnabled: Bool = true,
|
||||||
avatarSize: AvatarView.Size = .badge) {
|
avatarSize: AvatarView.Size = .badge)
|
||||||
|
{
|
||||||
self.routeurPath = routeurPath
|
self.routeurPath = routeurPath
|
||||||
self.accountCreationEnabled = accountCreationEnabled
|
self.accountCreationEnabled = accountCreationEnabled
|
||||||
self.avatarSize = avatarSize
|
self.avatarSize = avatarSize
|
||||||
|
@ -59,7 +60,8 @@ public struct AppAccountsSelectorView: View {
|
||||||
Section(viewModel.acct) {
|
Section(viewModel.acct) {
|
||||||
Button {
|
Button {
|
||||||
if let account = currentAccount.account,
|
if let account = currentAccount.account,
|
||||||
viewModel.account?.id == account.id {
|
viewModel.account?.id == account.id
|
||||||
|
{
|
||||||
routeurPath.navigate(to: .accountDetailWithAccount(account: account))
|
routeurPath.navigate(to: .accountDetailWithAccount(account: account))
|
||||||
} else {
|
} else {
|
||||||
appAccounts.currentAccount = viewModel.appAccount
|
appAccounts.currentAccount = viewModel.appAccount
|
||||||
|
@ -98,5 +100,4 @@ public struct AppAccountsSelectorView: View {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,7 +11,8 @@ let package = Package(
|
||||||
products: [
|
products: [
|
||||||
.library(
|
.library(
|
||||||
name: "Conversations",
|
name: "Conversations",
|
||||||
targets: ["Conversations"]),
|
targets: ["Conversations"]
|
||||||
|
),
|
||||||
],
|
],
|
||||||
dependencies: [
|
dependencies: [
|
||||||
.package(name: "Models", path: "../Models"),
|
.package(name: "Models", path: "../Models"),
|
||||||
|
@ -27,7 +28,7 @@ let package = Package(
|
||||||
.product(name: "Network", package: "Network"),
|
.product(name: "Network", package: "Network"),
|
||||||
.product(name: "Env", package: "Env"),
|
.product(name: "Env", package: "Env"),
|
||||||
.product(name: "DesignSystem", package: "DesignSystem"),
|
.product(name: "DesignSystem", package: "DesignSystem"),
|
||||||
]),
|
]
|
||||||
|
),
|
||||||
]
|
]
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
import SwiftUI
|
|
||||||
import Models
|
|
||||||
import Accounts
|
import Accounts
|
||||||
import DesignSystem
|
import DesignSystem
|
||||||
import Env
|
import Env
|
||||||
|
import Models
|
||||||
import Network
|
import Network
|
||||||
|
import SwiftUI
|
||||||
|
|
||||||
struct ConversationsListRow: View {
|
struct ConversationsListRow: View {
|
||||||
@EnvironmentObject private var client: Client
|
@EnvironmentObject private var client: Client
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
import SwiftUI
|
|
||||||
import Network
|
|
||||||
import Models
|
|
||||||
import DesignSystem
|
import DesignSystem
|
||||||
import Shimmer
|
|
||||||
import Env
|
import Env
|
||||||
|
import Models
|
||||||
|
import Network
|
||||||
|
import Shimmer
|
||||||
|
import SwiftUI
|
||||||
|
|
||||||
public struct ConversationsListView: View {
|
public struct ConversationsListView: View {
|
||||||
@EnvironmentObject private var routeurPath: RouterPath
|
@EnvironmentObject private var routeurPath: RouterPath
|
||||||
|
@ -61,7 +61,7 @@ public struct ConversationsListView: View {
|
||||||
.toolbar {
|
.toolbar {
|
||||||
StatusEditorToolbarItem(visibility: .direct)
|
StatusEditorToolbarItem(visibility: .direct)
|
||||||
}
|
}
|
||||||
.onChange(of: watcher.latestEvent?.id) { id in
|
.onChange(of: watcher.latestEvent?.id) { _ in
|
||||||
if let latestEvent = watcher.latestEvent {
|
if let latestEvent = watcher.latestEvent {
|
||||||
viewModel.handleEvent(event: latestEvent)
|
viewModel.handleEvent(event: latestEvent)
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,14 +11,15 @@ let package = Package(
|
||||||
products: [
|
products: [
|
||||||
.library(
|
.library(
|
||||||
name: "DesignSystem",
|
name: "DesignSystem",
|
||||||
targets: ["DesignSystem"]),
|
targets: ["DesignSystem"]
|
||||||
|
),
|
||||||
],
|
],
|
||||||
dependencies: [
|
dependencies: [
|
||||||
.package(name: "Models", path: "../Models"),
|
.package(name: "Models", path: "../Models"),
|
||||||
.package(name: "Env", path: "../Env"),
|
.package(name: "Env", path: "../Env"),
|
||||||
.package(url: "https://github.com/markiv/SwiftUI-Shimmer", exact: "1.1.0"),
|
.package(url: "https://github.com/markiv/SwiftUI-Shimmer", exact: "1.1.0"),
|
||||||
.package(url: "https://github.com/kean/Nuke", from: "11.5.0"),
|
.package(url: "https://github.com/kean/Nuke", from: "11.5.0"),
|
||||||
.package(url: "https://github.com/divadretlaw/EmojiText", from: "1.1.0")
|
.package(url: "https://github.com/divadretlaw/EmojiText", from: "1.1.0"),
|
||||||
],
|
],
|
||||||
targets: [
|
targets: [
|
||||||
.target(
|
.target(
|
||||||
|
@ -29,8 +30,8 @@ let package = Package(
|
||||||
.product(name: "Shimmer", package: "SwiftUI-Shimmer"),
|
.product(name: "Shimmer", package: "SwiftUI-Shimmer"),
|
||||||
.product(name: "NukeUI", package: "Nuke"),
|
.product(name: "NukeUI", package: "Nuke"),
|
||||||
.product(name: "Nuke", package: "Nuke"),
|
.product(name: "Nuke", package: "Nuke"),
|
||||||
.product(name: "EmojiText", package: "EmojiText")
|
.product(name: "EmojiText", package: "EmojiText"),
|
||||||
]),
|
]
|
||||||
|
),
|
||||||
]
|
]
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
@ -1,22 +1,22 @@
|
||||||
import Foundation
|
import Foundation
|
||||||
import SwiftUI
|
|
||||||
import NukeUI
|
|
||||||
import Models
|
import Models
|
||||||
|
import NukeUI
|
||||||
|
import SwiftUI
|
||||||
|
|
||||||
extension Account {
|
public extension Account {
|
||||||
private struct Part: Identifiable {
|
private struct Part: Identifiable {
|
||||||
let id = UUID().uuidString
|
let id = UUID().uuidString
|
||||||
let value: Substring
|
let value: Substring
|
||||||
}
|
}
|
||||||
|
|
||||||
public var safeDisplayName: String {
|
var safeDisplayName: String {
|
||||||
if displayName.isEmpty {
|
if displayName.isEmpty {
|
||||||
return username
|
return username
|
||||||
}
|
}
|
||||||
return displayName
|
return displayName
|
||||||
}
|
}
|
||||||
|
|
||||||
public var displayNameWithoutEmojis: String {
|
var displayNameWithoutEmojis: String {
|
||||||
var name = safeDisplayName
|
var name = safeDisplayName
|
||||||
for emoji in emojis {
|
for emoji in emojis {
|
||||||
name = name.replacingOccurrences(of: ":\(emoji.shortcode):", with: "")
|
name = name.replacingOccurrences(of: ":\(emoji.shortcode):", with: "")
|
||||||
|
|
|
@ -24,9 +24,9 @@ public enum ColorSetName: String {
|
||||||
public struct IceCubeDark: ColorSet {
|
public struct IceCubeDark: ColorSet {
|
||||||
public var name: ColorSetName = .iceCubeDark
|
public var name: ColorSetName = .iceCubeDark
|
||||||
public var scheme: ColorScheme = .dark
|
public var scheme: ColorScheme = .dark
|
||||||
public var tintColor: Color = Color(red: 187/255, green: 59/255, blue: 226/255)
|
public var tintColor: Color = .init(red: 187 / 255, green: 59 / 255, blue: 226 / 255)
|
||||||
public var primaryBackgroundColor: Color = Color(red: 16/255, green: 21/255, blue: 35/255)
|
public var primaryBackgroundColor: Color = .init(red: 16 / 255, green: 21 / 255, blue: 35 / 255)
|
||||||
public var secondaryBackgroundColor: Color = Color(red: 30/255, green: 35/255, blue: 62/255)
|
public var secondaryBackgroundColor: Color = .init(red: 30 / 255, green: 35 / 255, blue: 62 / 255)
|
||||||
public var labelColor: Color = .white
|
public var labelColor: Color = .white
|
||||||
|
|
||||||
public init() {}
|
public init() {}
|
||||||
|
@ -35,9 +35,9 @@ public struct IceCubeDark: ColorSet {
|
||||||
public struct IceCubeLight: ColorSet {
|
public struct IceCubeLight: ColorSet {
|
||||||
public var name: ColorSetName = .iceCubeLight
|
public var name: ColorSetName = .iceCubeLight
|
||||||
public var scheme: ColorScheme = .light
|
public var scheme: ColorScheme = .light
|
||||||
public var tintColor: Color = Color(red: 187/255, green: 59/255, blue: 226/255)
|
public var tintColor: Color = .init(red: 187 / 255, green: 59 / 255, blue: 226 / 255)
|
||||||
public var primaryBackgroundColor: Color = .white
|
public var primaryBackgroundColor: Color = .white
|
||||||
public var secondaryBackgroundColor: Color = Color(hex:0xF0F1F2)
|
public var secondaryBackgroundColor: Color = .init(hex: 0xF0F1F2)
|
||||||
public var labelColor: Color = .black
|
public var labelColor: Color = .black
|
||||||
|
|
||||||
public init() {}
|
public init() {}
|
||||||
|
@ -46,9 +46,9 @@ public struct IceCubeLight: ColorSet {
|
||||||
public struct DesertDark: ColorSet {
|
public struct DesertDark: ColorSet {
|
||||||
public var name: ColorSetName = .desertDark
|
public var name: ColorSetName = .desertDark
|
||||||
public var scheme: ColorScheme = .dark
|
public var scheme: ColorScheme = .dark
|
||||||
public var tintColor: Color = Color(hex: 0xdf915e)
|
public var tintColor: Color = .init(hex: 0xDF915E)
|
||||||
public var primaryBackgroundColor: Color = Color(hex: 0x433744)
|
public var primaryBackgroundColor: Color = .init(hex: 0x433744)
|
||||||
public var secondaryBackgroundColor: Color = Color(hex:0x654868)
|
public var secondaryBackgroundColor: Color = .init(hex: 0x654868)
|
||||||
public var labelColor: Color = .white
|
public var labelColor: Color = .white
|
||||||
|
|
||||||
public init() {}
|
public init() {}
|
||||||
|
@ -57,9 +57,9 @@ public struct DesertDark: ColorSet {
|
||||||
public struct DesertLight: ColorSet {
|
public struct DesertLight: ColorSet {
|
||||||
public var name: ColorSetName = .desertLight
|
public var name: ColorSetName = .desertLight
|
||||||
public var scheme: ColorScheme = .light
|
public var scheme: ColorScheme = .light
|
||||||
public var tintColor: Color = Color(hex: 0xdf915e)
|
public var tintColor: Color = .init(hex: 0xDF915E)
|
||||||
public var primaryBackgroundColor: Color = Color(hex: 0xfcf2eb)
|
public var primaryBackgroundColor: Color = .init(hex: 0xFCF2EB)
|
||||||
public var secondaryBackgroundColor: Color = Color(hex:0xeeede7)
|
public var secondaryBackgroundColor: Color = .init(hex: 0xEEEDE7)
|
||||||
public var labelColor: Color = .black
|
public var labelColor: Color = .black
|
||||||
|
|
||||||
public init() {}
|
public init() {}
|
||||||
|
@ -68,9 +68,9 @@ public struct DesertLight: ColorSet {
|
||||||
public struct NemesisDark: ColorSet {
|
public struct NemesisDark: ColorSet {
|
||||||
public var name: ColorSetName = .nemesisDark
|
public var name: ColorSetName = .nemesisDark
|
||||||
public var scheme: ColorScheme = .dark
|
public var scheme: ColorScheme = .dark
|
||||||
public var tintColor: Color = Color(hex: 0x17a2f2)
|
public var tintColor: Color = .init(hex: 0x17A2F2)
|
||||||
public var primaryBackgroundColor: Color = Color(hex: 0x000000)
|
public var primaryBackgroundColor: Color = .init(hex: 0x000000)
|
||||||
public var secondaryBackgroundColor: Color = Color(hex:0x151e2b)
|
public var secondaryBackgroundColor: Color = .init(hex: 0x151E2B)
|
||||||
public var labelColor: Color = .white
|
public var labelColor: Color = .white
|
||||||
|
|
||||||
public init() {}
|
public init() {}
|
||||||
|
@ -79,13 +79,10 @@ public struct NemesisDark: ColorSet {
|
||||||
public struct NemesisLight: ColorSet {
|
public struct NemesisLight: ColorSet {
|
||||||
public var name: ColorSetName = .nemesisLight
|
public var name: ColorSetName = .nemesisLight
|
||||||
public var scheme: ColorScheme = .light
|
public var scheme: ColorScheme = .light
|
||||||
public var tintColor: Color = Color(hex: 0x17a2f2)
|
public var tintColor: Color = .init(hex: 0x17A2F2)
|
||||||
public var primaryBackgroundColor: Color = Color(hex: 0xffffff)
|
public var primaryBackgroundColor: Color = .init(hex: 0xFFFFFF)
|
||||||
public var secondaryBackgroundColor: Color = Color(hex:0xe8ecef)
|
public var secondaryBackgroundColor: Color = .init(hex: 0xE8ECEF)
|
||||||
public var labelColor: Color = .black
|
public var labelColor: Color = .black
|
||||||
|
|
||||||
public init() {}
|
public init() {}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
import Foundation
|
import Foundation
|
||||||
|
|
||||||
extension CGFloat {
|
public extension CGFloat {
|
||||||
public static let layoutPadding: CGFloat = 20
|
static let layoutPadding: CGFloat = 20
|
||||||
public static let dividerPadding: CGFloat = 2
|
static let dividerPadding: CGFloat = 2
|
||||||
public static let statusColumnsSpacing: CGFloat = 8
|
static let statusColumnsSpacing: CGFloat = 8
|
||||||
public static let maxColumnWidth: CGFloat = 650
|
static let maxColumnWidth: CGFloat = 650
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,19 +1,19 @@
|
||||||
import SwiftUI
|
import SwiftUI
|
||||||
|
|
||||||
extension Color {
|
public extension Color {
|
||||||
public static var brand: Color {
|
static var brand: Color {
|
||||||
Color(red: 187 / 255, green: 59 / 255, blue: 226 / 255)
|
Color(red: 187 / 255, green: 59 / 255, blue: 226 / 255)
|
||||||
}
|
}
|
||||||
|
|
||||||
public static var primaryBackground: Color {
|
static var primaryBackground: Color {
|
||||||
Color(red: 16 / 255, green: 21 / 255, blue: 35 / 255)
|
Color(red: 16 / 255, green: 21 / 255, blue: 35 / 255)
|
||||||
}
|
}
|
||||||
|
|
||||||
public static var secondaryBackground: Color {
|
static var secondaryBackground: Color {
|
||||||
Color(red: 30 / 255, green: 35 / 255, blue: 62 / 255)
|
Color(red: 30 / 255, green: 35 / 255, blue: 62 / 255)
|
||||||
}
|
}
|
||||||
|
|
||||||
public static var label: Color {
|
static var label: Color {
|
||||||
Color("label", bundle: .module)
|
Color("label", bundle: .module)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -43,10 +43,9 @@ extension Color: RawRepresentable {
|
||||||
|
|
||||||
extension Color {
|
extension Color {
|
||||||
init(hex: Int, opacity: Double = 1.0) {
|
init(hex: Int, opacity: Double = 1.0) {
|
||||||
let red = Double((hex & 0xff0000) >> 16) / 255.0
|
let red = Double((hex & 0xFF0000) >> 16) / 255.0
|
||||||
let green = Double((hex & 0xff00) >> 8) / 255.0
|
let green = Double((hex & 0xFF00) >> 8) / 255.0
|
||||||
let blue = Double((hex & 0xff) >> 0) / 255.0
|
let blue = Double((hex & 0xFF) >> 0) / 255.0
|
||||||
self.init(.sRGB, red: red, green: green, blue: blue, opacity: opacity)
|
self.init(.sRGB, red: red, green: green, blue: blue, opacity: opacity)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -127,17 +127,17 @@ public class Theme: ObservableObject {
|
||||||
DesertDark(),
|
DesertDark(),
|
||||||
DesertLight(),
|
DesertLight(),
|
||||||
NemesisDark(),
|
NemesisDark(),
|
||||||
NemesisLight()
|
NemesisLight(),
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
public func setColor(withName name: ColorSetName) {
|
public func setColor(withName name: ColorSetName) {
|
||||||
let colorSet = Theme.allColorSet.filter { $0.name == name }.first ?? IceCubeDark()
|
let colorSet = Theme.allColorSet.filter { $0.name == name }.first ?? IceCubeDark()
|
||||||
self.selectedScheme = colorSet.scheme
|
selectedScheme = colorSet.scheme
|
||||||
self.tintColor = colorSet.tintColor
|
tintColor = colorSet.tintColor
|
||||||
self.primaryBackgroundColor = colorSet.primaryBackgroundColor
|
primaryBackgroundColor = colorSet.primaryBackgroundColor
|
||||||
self.secondaryBackgroundColor = colorSet.secondaryBackgroundColor
|
secondaryBackgroundColor = colorSet.secondaryBackgroundColor
|
||||||
self.labelColor = colorSet.labelColor
|
labelColor = colorSet.labelColor
|
||||||
self.storedSet = name
|
storedSet = name
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
import SwiftUI
|
|
||||||
import Shimmer
|
|
||||||
import NukeUI
|
import NukeUI
|
||||||
|
import Shimmer
|
||||||
|
import SwiftUI
|
||||||
|
|
||||||
public struct AvatarView: View {
|
public struct AvatarView: View {
|
||||||
@Environment(\.redactionReasons) private var reasons
|
@Environment(\.redactionReasons) private var reasons
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import Foundation
|
|
||||||
import EmojiText
|
import EmojiText
|
||||||
import Models
|
import Foundation
|
||||||
import HTML2Markdown
|
import HTML2Markdown
|
||||||
|
import Models
|
||||||
import SwiftUI
|
import SwiftUI
|
||||||
|
|
||||||
public struct EmojiTextApp: View {
|
public struct EmojiTextApp: View {
|
||||||
|
|
|
@ -4,7 +4,7 @@ public struct ErrorView: View {
|
||||||
public let title: String
|
public let title: String
|
||||||
public let message: String
|
public let message: String
|
||||||
public let buttonTitle: String
|
public let buttonTitle: String
|
||||||
public let onButtonPress: (() -> Void)
|
public let onButtonPress: () -> Void
|
||||||
|
|
||||||
public init(title: String, message: String, buttonTitle: String, onButtonPress: @escaping (() -> Void)) {
|
public init(title: String, message: String, buttonTitle: String, onButtonPress: @escaping (() -> Void)) {
|
||||||
self.title = title
|
self.title = title
|
||||||
|
|
|
@ -40,5 +40,5 @@ public struct ScrollViewOffsetReader<Content: View>: View {
|
||||||
|
|
||||||
private struct OffsetPreferenceKey: PreferenceKey {
|
private struct OffsetPreferenceKey: PreferenceKey {
|
||||||
static var defaultValue: CGFloat = .zero
|
static var defaultValue: CGFloat = .zero
|
||||||
static func reduce(value: inout CGFloat, nextValue: () -> CGFloat) {}
|
static func reduce(value _: inout CGFloat, nextValue _: () -> CGFloat) {}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
import SwiftUI
|
|
||||||
import Env
|
import Env
|
||||||
import Models
|
import Models
|
||||||
|
import SwiftUI
|
||||||
|
|
||||||
@MainActor
|
@MainActor
|
||||||
extension View {
|
public extension View {
|
||||||
public func statusEditorToolbarItem(routeurPath: RouterPath, visibility: Models.Visibility) -> some ToolbarContent {
|
func statusEditorToolbarItem(routeurPath: RouterPath, visibility: Models.Visibility) -> some ToolbarContent {
|
||||||
ToolbarItem(placement: .navigationBarTrailing) {
|
ToolbarItem(placement: .navigationBarTrailing) {
|
||||||
Button {
|
Button {
|
||||||
routeurPath.presentedSheet = .newStatusEditor(visibility: visibility)
|
routeurPath.presentedSheet = .newStatusEditor(visibility: visibility)
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
|
import Env
|
||||||
import Models
|
import Models
|
||||||
import SwiftUI
|
import SwiftUI
|
||||||
import Env
|
|
||||||
|
|
||||||
public struct TagRowView: View {
|
public struct TagRowView: View {
|
||||||
@EnvironmentObject private var routeurPath: RouterPath
|
@EnvironmentObject private var routeurPath: RouterPath
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import SwiftUI
|
|
||||||
import Combine
|
import Combine
|
||||||
|
import SwiftUI
|
||||||
|
|
||||||
public struct ThemePreviewView: View {
|
public struct ThemePreviewView: View {
|
||||||
private let gutterSpace: Double = 8
|
private let gutterSpace: Double = 8
|
||||||
|
@ -31,7 +31,6 @@ public struct ThemePreviewView: View {
|
||||||
}
|
}
|
||||||
|
|
||||||
struct ThemeBoxView: View {
|
struct ThemeBoxView: View {
|
||||||
|
|
||||||
@EnvironmentObject var theme: Theme
|
@EnvironmentObject var theme: Theme
|
||||||
private let gutterSpace = 8.0
|
private let gutterSpace = 8.0
|
||||||
@State private var isSelected = false
|
@State private var isSelected = false
|
||||||
|
@ -95,4 +94,3 @@ struct ThemeBoxView: View {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -11,11 +11,12 @@ let package = Package(
|
||||||
products: [
|
products: [
|
||||||
.library(
|
.library(
|
||||||
name: "Env",
|
name: "Env",
|
||||||
targets: ["Env"]),
|
targets: ["Env"]
|
||||||
|
),
|
||||||
],
|
],
|
||||||
dependencies: [
|
dependencies: [
|
||||||
.package(name: "Models", path: "../Models"),
|
.package(name: "Models", path: "../Models"),
|
||||||
.package(name: "Network", path: "../Network")
|
.package(name: "Network", path: "../Network"),
|
||||||
],
|
],
|
||||||
targets: [
|
targets: [
|
||||||
.target(
|
.target(
|
||||||
|
@ -23,6 +24,7 @@ let package = Package(
|
||||||
dependencies: [
|
dependencies: [
|
||||||
.product(name: "Models", package: "Models"),
|
.product(name: "Models", package: "Models"),
|
||||||
.product(name: "Network", package: "Network"),
|
.product(name: "Network", package: "Network"),
|
||||||
]),
|
]
|
||||||
|
),
|
||||||
]
|
]
|
||||||
)
|
)
|
||||||
|
|
|
@ -10,7 +10,7 @@ public class CurrentAccount: ObservableObject {
|
||||||
|
|
||||||
private var client: Client?
|
private var client: Client?
|
||||||
|
|
||||||
static public let shared = CurrentAccount()
|
public static let shared = CurrentAccount()
|
||||||
|
|
||||||
private init() {}
|
private init() {}
|
||||||
|
|
||||||
|
|
|
@ -8,7 +8,7 @@ public class CurrentInstance: ObservableObject {
|
||||||
|
|
||||||
private var client: Client?
|
private var client: Client?
|
||||||
|
|
||||||
static public let shared = CurrentInstance()
|
public static let shared = CurrentInstance()
|
||||||
|
|
||||||
private init() {}
|
private init() {}
|
||||||
|
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
import Foundation
|
|
||||||
import UserNotifications
|
|
||||||
import SwiftUI
|
|
||||||
import KeychainSwift
|
|
||||||
import CryptoKit
|
import CryptoKit
|
||||||
|
import Foundation
|
||||||
|
import KeychainSwift
|
||||||
import Models
|
import Models
|
||||||
import Network
|
import Network
|
||||||
|
import SwiftUI
|
||||||
|
import UserNotifications
|
||||||
|
|
||||||
@MainActor
|
@MainActor
|
||||||
public class PushNotificationsService: ObservableObject {
|
public class PushNotificationsService: ObservableObject {
|
||||||
|
@ -36,6 +36,7 @@ public class PushNotificationsService: ObservableObject {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Published public var isFollowNotificationEnabled: Bool = true
|
@Published public var isFollowNotificationEnabled: Bool = true
|
||||||
@Published public var isFavoriteNotificationEnabled: Bool = true
|
@Published public var isFavoriteNotificationEnabled: Bool = true
|
||||||
@Published public var isReblogNotificationEnabled: Bool = true
|
@Published public var isReblogNotificationEnabled: Bool = true
|
||||||
|
@ -54,7 +55,7 @@ public class PushNotificationsService: ObservableObject {
|
||||||
}
|
}
|
||||||
|
|
||||||
public func requestPushNotifications() {
|
public func requestPushNotifications() {
|
||||||
UNUserNotificationCenter.current().requestAuthorization(options: [.alert, .sound, .badge]) { (_, _) in
|
UNUserNotificationCenter.current().requestAuthorization(options: [.alert, .sound, .badge]) { _, _ in
|
||||||
DispatchQueue.main.async {
|
DispatchQueue.main.async {
|
||||||
UIApplication.shared.registerForRemoteNotifications()
|
UIApplication.shared.registerForRemoteNotifications()
|
||||||
}
|
}
|
||||||
|
@ -133,7 +134,8 @@ public class PushNotificationsService: ObservableObject {
|
||||||
|
|
||||||
public var notificationsPrivateKeyAsKey: P256.KeyAgreement.PrivateKey {
|
public var notificationsPrivateKeyAsKey: P256.KeyAgreement.PrivateKey {
|
||||||
if let key = keychain.get(Constants.keychainPrivateKey),
|
if let key = keychain.get(Constants.keychainPrivateKey),
|
||||||
let data = Data(base64Encoded: key) {
|
let data = Data(base64Encoded: key)
|
||||||
|
{
|
||||||
do {
|
do {
|
||||||
return try P256.KeyAgreement.PrivateKey(rawRepresentation: data)
|
return try P256.KeyAgreement.PrivateKey(rawRepresentation: data)
|
||||||
} catch {
|
} catch {
|
||||||
|
@ -154,7 +156,8 @@ public class PushNotificationsService: ObservableObject {
|
||||||
|
|
||||||
public var notificationsAuthKeyAsKey: Data {
|
public var notificationsAuthKeyAsKey: Data {
|
||||||
if let key = keychain.get(Constants.keychainAuthKey),
|
if let key = keychain.get(Constants.keychainAuthKey),
|
||||||
let data = Data(base64Encoded: key) {
|
let data = Data(base64Encoded: key)
|
||||||
|
{
|
||||||
return data
|
return data
|
||||||
} else {
|
} else {
|
||||||
let key = Self.makeRandomeNotificationsAuthKey()
|
let key = Self.makeRandomeNotificationsAuthKey()
|
||||||
|
@ -165,7 +168,7 @@ public class PushNotificationsService: ObservableObject {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static private func makeRandomeNotificationsAuthKey() -> Data {
|
private static func makeRandomeNotificationsAuthKey() -> Data {
|
||||||
let byteCount = 16
|
let byteCount = 16
|
||||||
var bytes = Data(count: byteCount)
|
var bytes = Data(count: byteCount)
|
||||||
_ = bytes.withUnsafeMutableBytes { SecRandomCopyBytes(kSecRandomDefault, byteCount, $0.baseAddress!) }
|
_ = bytes.withUnsafeMutableBytes { SecRandomCopyBytes(kSecRandomDefault, byteCount, $0.baseAddress!) }
|
||||||
|
@ -178,4 +181,3 @@ extension Data {
|
||||||
return map { String(format: "%02.2hhx", arguments: [$0]) }.joined()
|
return map { String(format: "%02.2hhx", arguments: [$0]) }.joined()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -8,9 +8,7 @@ public class QuickLook: ObservableObject {
|
||||||
@Published public private(set) var isPreparing: Bool = false
|
@Published public private(set) var isPreparing: Bool = false
|
||||||
@Published public private(set) var latestError: Error?
|
@Published public private(set) var latestError: Error?
|
||||||
|
|
||||||
public init() {
|
public init() {}
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
public func prepareFor(urls: [URL], selectedURL: URL) async {
|
public func prepareFor(urls: [URL], selectedURL: URL) async {
|
||||||
withAnimation {
|
withAnimation {
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import Foundation
|
import Foundation
|
||||||
import SwiftUI
|
|
||||||
import Models
|
import Models
|
||||||
import Network
|
import Network
|
||||||
|
import SwiftUI
|
||||||
|
|
||||||
public enum RouteurDestinations: Hashable {
|
public enum RouteurDestinations: Hashable {
|
||||||
case accountDetail(id: String)
|
case accountDetail(id: String)
|
||||||
|
@ -59,7 +59,8 @@ public class RouterPath: ObservableObject {
|
||||||
|
|
||||||
public func handleStatus(status: AnyStatus, url: URL) -> OpenURLAction.Result {
|
public func handleStatus(status: AnyStatus, url: URL) -> OpenURLAction.Result {
|
||||||
if url.pathComponents.contains(where: { $0 == "tags" }),
|
if url.pathComponents.contains(where: { $0 == "tags" }),
|
||||||
let tag = url.pathComponents.last {
|
let tag = url.pathComponents.last
|
||||||
|
{
|
||||||
navigate(to: .hashTag(tag: tag, account: nil))
|
navigate(to: .hashTag(tag: tag, account: nil))
|
||||||
return .handled
|
return .handled
|
||||||
} else if let mention = status.mentions.first(where: { $0.url == url }) {
|
} else if let mention = status.mentions.first(where: { $0.url == url }) {
|
||||||
|
@ -68,7 +69,8 @@ public class RouterPath: ObservableObject {
|
||||||
} else if let client = client,
|
} else if let client = client,
|
||||||
client.isAuth,
|
client.isAuth,
|
||||||
client.hasConnection(with: url),
|
client.hasConnection(with: url),
|
||||||
let id = Int(url.lastPathComponent) {
|
let id = Int(url.lastPathComponent)
|
||||||
|
{
|
||||||
if url.absoluteString.contains(client.server) {
|
if url.absoluteString.contains(client.server) {
|
||||||
navigate(to: .statusDetail(id: String(id)))
|
navigate(to: .statusDetail(id: String(id)))
|
||||||
} else {
|
} else {
|
||||||
|
@ -81,7 +83,8 @@ public class RouterPath: ObservableObject {
|
||||||
|
|
||||||
public func handle(url: URL) -> OpenURLAction.Result {
|
public func handle(url: URL) -> OpenURLAction.Result {
|
||||||
if url.pathComponents.contains(where: { $0 == "tags" }),
|
if url.pathComponents.contains(where: { $0 == "tags" }),
|
||||||
let tag = url.pathComponents.last {
|
let tag = url.pathComponents.last
|
||||||
|
{
|
||||||
navigate(to: .hashTag(tag: tag, account: nil))
|
navigate(to: .hashTag(tag: tag, account: nil))
|
||||||
return .handled
|
return .handled
|
||||||
} else if url.lastPathComponent.first == "@", let host = url.host {
|
} else if url.lastPathComponent.first == "@", let host = url.host {
|
||||||
|
|
|
@ -1,11 +1,11 @@
|
||||||
import SwiftUI
|
|
||||||
import Foundation
|
import Foundation
|
||||||
import Models
|
import Models
|
||||||
import Network
|
import Network
|
||||||
|
import SwiftUI
|
||||||
|
|
||||||
@MainActor
|
@MainActor
|
||||||
public class UserPreferences: ObservableObject {
|
public class UserPreferences: ObservableObject {
|
||||||
public static let sharedDefault = UserDefaults.init(suiteName: "group.icecubesapps")
|
public static let sharedDefault = UserDefaults(suiteName: "group.icecubesapps")
|
||||||
public static let shared = UserPreferences()
|
public static let shared = UserPreferences()
|
||||||
|
|
||||||
private var client: Client?
|
private var client: Client?
|
||||||
|
|
|
@ -11,7 +11,8 @@ let package = Package(
|
||||||
products: [
|
products: [
|
||||||
.library(
|
.library(
|
||||||
name: "Explore",
|
name: "Explore",
|
||||||
targets: ["Explore"]),
|
targets: ["Explore"]
|
||||||
|
),
|
||||||
],
|
],
|
||||||
dependencies: [
|
dependencies: [
|
||||||
.package(name: "Account", path: "../Account"),
|
.package(name: "Account", path: "../Account"),
|
||||||
|
@ -30,8 +31,8 @@ let package = Package(
|
||||||
.product(name: "Models", package: "Models"),
|
.product(name: "Models", package: "Models"),
|
||||||
.product(name: "Env", package: "Env"),
|
.product(name: "Env", package: "Env"),
|
||||||
.product(name: "Status", package: "Status"),
|
.product(name: "Status", package: "Status"),
|
||||||
.product(name: "DesignSystem", package: "DesignSystem")
|
.product(name: "DesignSystem", package: "DesignSystem"),
|
||||||
])
|
]
|
||||||
|
),
|
||||||
]
|
]
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
@ -1,11 +1,11 @@
|
||||||
import SwiftUI
|
|
||||||
import Env
|
|
||||||
import Network
|
|
||||||
import DesignSystem
|
|
||||||
import Models
|
|
||||||
import Status
|
|
||||||
import Shimmer
|
|
||||||
import Account
|
import Account
|
||||||
|
import DesignSystem
|
||||||
|
import Env
|
||||||
|
import Models
|
||||||
|
import Network
|
||||||
|
import Shimmer
|
||||||
|
import Status
|
||||||
|
import SwiftUI
|
||||||
|
|
||||||
public struct ExploreView: View {
|
public struct ExploreView: View {
|
||||||
@EnvironmentObject private var theme: Theme
|
@EnvironmentObject private var theme: Theme
|
||||||
|
@ -228,5 +228,4 @@ public struct ExploreView: View {
|
||||||
.listRowBackground(theme.primaryBackgroundColor)
|
.listRowBackground(theme.primaryBackgroundColor)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import SwiftUI
|
import Combine
|
||||||
import Models
|
import Models
|
||||||
import Network
|
import Network
|
||||||
import Combine
|
import SwiftUI
|
||||||
|
|
||||||
@MainActor
|
@MainActor
|
||||||
class ExploreViewModel: ObservableObject {
|
class ExploreViewModel: ObservableObject {
|
||||||
|
@ -61,7 +61,7 @@ class ExploreViewModel: ObservableObject {
|
||||||
$searchQuery
|
$searchQuery
|
||||||
.removeDuplicates()
|
.removeDuplicates()
|
||||||
.debounce(for: .milliseconds(500), scheduler: DispatchQueue.main)
|
.debounce(for: .milliseconds(500), scheduler: DispatchQueue.main)
|
||||||
.sink(receiveValue: { [weak self] newValue in
|
.sink(receiveValue: { [weak self] _ in
|
||||||
guard let self else { return }
|
guard let self else { return }
|
||||||
|
|
||||||
if self.searchQuery.starts(with: "@") {
|
if self.searchQuery.starts(with: "@") {
|
||||||
|
@ -81,12 +81,12 @@ class ExploreViewModel: ObservableObject {
|
||||||
guard let client else { return }
|
guard let client else { return }
|
||||||
do {
|
do {
|
||||||
let data = try await fetchTrendingsData(client: client)
|
let data = try await fetchTrendingsData(client: client)
|
||||||
self.suggestedAccounts = data.suggestedAccounts
|
suggestedAccounts = data.suggestedAccounts
|
||||||
self.trendingTags = data.trendingTags
|
trendingTags = data.trendingTags
|
||||||
self.trendingStatuses = data.trendingStatuses
|
trendingStatuses = data.trendingStatuses
|
||||||
self.trendingLinks = data.trendingLinks
|
trendingLinks = data.trendingLinks
|
||||||
|
|
||||||
self.suggestedAccountsRelationShips = try await client.get(endpoint: Accounts.relationships(ids: self.suggestedAccounts.map{ $0.id }))
|
suggestedAccountsRelationShips = try await client.get(endpoint: Accounts.relationships(ids: suggestedAccounts.map { $0.id }))
|
||||||
withAnimation {
|
withAnimation {
|
||||||
isLoaded = true
|
isLoaded = true
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,7 +11,8 @@ let package = Package(
|
||||||
products: [
|
products: [
|
||||||
.library(
|
.library(
|
||||||
name: "Lists",
|
name: "Lists",
|
||||||
targets: ["Lists"]),
|
targets: ["Lists"]
|
||||||
|
),
|
||||||
],
|
],
|
||||||
dependencies: [
|
dependencies: [
|
||||||
.package(name: "Network", path: "../Network"),
|
.package(name: "Network", path: "../Network"),
|
||||||
|
@ -26,8 +27,8 @@ let package = Package(
|
||||||
.product(name: "Network", package: "Network"),
|
.product(name: "Network", package: "Network"),
|
||||||
.product(name: "Models", package: "Models"),
|
.product(name: "Models", package: "Models"),
|
||||||
.product(name: "Env", package: "Env"),
|
.product(name: "Env", package: "Env"),
|
||||||
.product(name: "DesignSystem", package: "DesignSystem")
|
.product(name: "DesignSystem", package: "DesignSystem"),
|
||||||
]),
|
]
|
||||||
|
),
|
||||||
]
|
]
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
import SwiftUI
|
|
||||||
import Network
|
|
||||||
import DesignSystem
|
import DesignSystem
|
||||||
import Env
|
import Env
|
||||||
import Models
|
import Models
|
||||||
|
import Network
|
||||||
|
import SwiftUI
|
||||||
|
|
||||||
public struct ListAddAccountView: View {
|
public struct ListAddAccountView: View {
|
||||||
@Environment(\.dismiss) private var dismiss
|
@Environment(\.dismiss) private var dismiss
|
||||||
|
@ -14,7 +14,6 @@ public struct ListAddAccountView: View {
|
||||||
@State private var isCreateListAlertPresented: Bool = false
|
@State private var isCreateListAlertPresented: Bool = false
|
||||||
@State private var createListTitle: String = ""
|
@State private var createListTitle: String = ""
|
||||||
|
|
||||||
|
|
||||||
public init(account: Account) {
|
public init(account: Account) {
|
||||||
_viewModel = StateObject(wrappedValue: .init(account: account))
|
_viewModel = StateObject(wrappedValue: .init(account: account))
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
import SwiftUI
|
|
||||||
import Models
|
import Models
|
||||||
import Network
|
import Network
|
||||||
|
import SwiftUI
|
||||||
|
|
||||||
@MainActor
|
@MainActor
|
||||||
class ListAddAccountViewModel: ObservableObject {
|
class ListAddAccountViewModel: ObservableObject {
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
import SwiftUI
|
|
||||||
import Models
|
|
||||||
import DesignSystem
|
import DesignSystem
|
||||||
import Network
|
|
||||||
import EmojiText
|
import EmojiText
|
||||||
|
import Models
|
||||||
|
import Network
|
||||||
|
import SwiftUI
|
||||||
|
|
||||||
public struct ListEditView: View {
|
public struct ListEditView: View {
|
||||||
@Environment(\.dismiss) private var dismiss
|
@Environment(\.dismiss) private var dismiss
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
import SwiftUI
|
|
||||||
import Models
|
import Models
|
||||||
import Network
|
import Network
|
||||||
|
import SwiftUI
|
||||||
|
|
||||||
@MainActor
|
@MainActor
|
||||||
public class ListEditViewModel: ObservableObject {
|
public class ListEditViewModel: ObservableObject {
|
||||||
|
|
|
@ -11,7 +11,8 @@ let package = Package(
|
||||||
products: [
|
products: [
|
||||||
.library(
|
.library(
|
||||||
name: "Models",
|
name: "Models",
|
||||||
targets: ["Models"]),
|
targets: ["Models"]
|
||||||
|
),
|
||||||
],
|
],
|
||||||
dependencies: [
|
dependencies: [
|
||||||
.package(url: "https://gitlab.com/mflint/HTML2Markdown", exact: "1.0.0"),
|
.package(url: "https://gitlab.com/mflint/HTML2Markdown", exact: "1.0.0"),
|
||||||
|
@ -21,9 +22,11 @@ let package = Package(
|
||||||
.target(
|
.target(
|
||||||
name: "Models",
|
name: "Models",
|
||||||
dependencies: ["HTML2Markdown",
|
dependencies: ["HTML2Markdown",
|
||||||
"SwiftSoup"]),
|
"SwiftSoup"]
|
||||||
|
),
|
||||||
.testTarget(
|
.testTarget(
|
||||||
name: "ModelsTests",
|
name: "ModelsTests",
|
||||||
dependencies: ["Models"]),
|
dependencies: ["Models"]
|
||||||
|
),
|
||||||
]
|
]
|
||||||
)
|
)
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
import Foundation
|
import Foundation
|
||||||
|
|
||||||
public struct Account: Codable, Identifiable, Equatable, Hashable {
|
public struct Account: Codable, Identifiable, Equatable, Hashable {
|
||||||
|
|
||||||
public func hash(into hasher: inout Hasher) {
|
public func hash(into hasher: inout Hasher) {
|
||||||
hasher.combine(id)
|
hasher.combine(id)
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,8 +5,8 @@ import SwiftUI
|
||||||
|
|
||||||
public typealias HTMLString = String
|
public typealias HTMLString = String
|
||||||
|
|
||||||
extension HTMLString {
|
public extension HTMLString {
|
||||||
public var asMarkdown: String {
|
var asMarkdown: String {
|
||||||
do {
|
do {
|
||||||
let dom = try HTMLParser().parse(html: self)
|
let dom = try HTMLParser().parse(html: self)
|
||||||
return dom.toMarkdown()
|
return dom.toMarkdown()
|
||||||
|
@ -17,7 +17,7 @@ extension HTMLString {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public var asRawText: String {
|
var asRawText: String {
|
||||||
do {
|
do {
|
||||||
let document: Document = try SwiftSoup.parse(self)
|
let document: Document = try SwiftSoup.parse(self)
|
||||||
return try document.text()
|
return try document.text()
|
||||||
|
@ -26,7 +26,7 @@ extension HTMLString {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public func findStatusesURLs() -> [URL]? {
|
func findStatusesURLs() -> [URL]? {
|
||||||
do {
|
do {
|
||||||
let document: Document = try SwiftSoup.parse(self)
|
let document: Document = try SwiftSoup.parse(self)
|
||||||
let links: Elements = try document.select("a")
|
let links: Elements = try document.select("a")
|
||||||
|
@ -34,7 +34,8 @@ extension HTMLString {
|
||||||
for link in links {
|
for link in links {
|
||||||
let href = try link.attr("href")
|
let href = try link.attr("href")
|
||||||
if let url = URL(string: href),
|
if let url = URL(string: href),
|
||||||
let _ = Int(url.lastPathComponent) {
|
let _ = Int(url.lastPathComponent)
|
||||||
|
{
|
||||||
URLs.append(url)
|
URLs.append(url)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -44,7 +45,7 @@ extension HTMLString {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public var asSafeAttributedString: AttributedString {
|
var asSafeAttributedString: AttributedString {
|
||||||
do {
|
do {
|
||||||
let options = AttributedString.MarkdownParsingOptions(allowsExtendedAttributes: true,
|
let options = AttributedString.MarkdownParsingOptions(allowsExtendedAttributes: true,
|
||||||
interpretedSyntax: .inlineOnlyPreservingWhitespace)
|
interpretedSyntax: .inlineOnlyPreservingWhitespace)
|
||||||
|
@ -54,4 +55,3 @@ extension HTMLString {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -37,7 +37,6 @@ extension ServerDate {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
extension Calendar {
|
extension Calendar {
|
||||||
func numberOfDaysBetween(_ from: Date, and to: Date) -> Int {
|
func numberOfDaysBetween(_ from: Date, and to: Date) -> Int {
|
||||||
let fromDate = startOfDay(for: from)
|
let fromDate = startOfDay(for: from)
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
import Foundation
|
import Foundation
|
||||||
|
|
||||||
public struct AppInfo {
|
public enum AppInfo {
|
||||||
public static let clientName = "IceCubesApp"
|
public static let clientName = "IceCubesApp"
|
||||||
public static let scheme = "icecubesapp://"
|
public static let scheme = "icecubesapp://"
|
||||||
public static let scopes = "read write follow push"
|
public static let scopes = "read write follow push"
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
import Foundation
|
import Foundation
|
||||||
|
|
||||||
public struct Emoji: Codable, Hashable, Identifiable {
|
public struct Emoji: Codable, Hashable, Identifiable {
|
||||||
|
|
||||||
public func hash(into hasher: inout Hasher) {
|
public func hash(into hasher: inout Hasher) {
|
||||||
hasher.combine(shortcode)
|
hasher.combine(shortcode)
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,6 +4,7 @@ public struct InstanceSocial: Decodable, Identifiable {
|
||||||
public struct Info: Decodable {
|
public struct Info: Decodable {
|
||||||
public let shortDescription: String
|
public let shortDescription: String
|
||||||
}
|
}
|
||||||
|
|
||||||
public let id: String
|
public let id: String
|
||||||
public let name: String
|
public let name: String
|
||||||
public let dead: Bool
|
public let dead: Bool
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
import Foundation
|
import Foundation
|
||||||
|
|
||||||
public struct MastodonPushNotification: Codable {
|
public struct MastodonPushNotification: Codable {
|
||||||
|
|
||||||
public let accessToken: String
|
public let accessToken: String
|
||||||
|
|
||||||
public let notificationID: Int
|
public let notificationID: Int
|
||||||
|
|
|
@ -1,12 +1,12 @@
|
||||||
import Foundation
|
import Foundation
|
||||||
|
|
||||||
public struct MediaAttachement: Codable, Identifiable, Hashable {
|
public struct MediaAttachement: Codable, Identifiable, Hashable {
|
||||||
|
|
||||||
public struct MetaContainer: Codable, Equatable {
|
public struct MetaContainer: Codable, Equatable {
|
||||||
public struct Meta: Codable, Equatable {
|
public struct Meta: Codable, Equatable {
|
||||||
public let width: Int?
|
public let width: Int?
|
||||||
public let height: Int?
|
public let height: Int?
|
||||||
}
|
}
|
||||||
|
|
||||||
public let original: Meta?
|
public let original: Meta?
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -23,9 +23,9 @@ public struct MediaAttachement: Codable, Identifiable, Hashable {
|
||||||
public var supportedType: SupportedType? {
|
public var supportedType: SupportedType? {
|
||||||
SupportedType(rawValue: type)
|
SupportedType(rawValue: type)
|
||||||
}
|
}
|
||||||
|
|
||||||
public let url: URL?
|
public let url: URL?
|
||||||
public let previewUrl: URL?
|
public let previewUrl: URL?
|
||||||
public let description: String?
|
public let description: String?
|
||||||
public let meta: MetaContainer?
|
public let meta: MetaContainer?
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -27,4 +27,3 @@ public struct Notification: Codable, Identifiable {
|
||||||
[.placeholder(), .placeholder(), .placeholder(), .placeholder(), .placeholder(), .placeholder(), .placeholder(), .placeholder()]
|
[.placeholder(), .placeholder(), .placeholder(), .placeholder(), .placeholder(), .placeholder(), .placeholder(), .placeholder()]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -15,7 +15,7 @@ public struct Relationshionship: Codable {
|
||||||
public let note: String
|
public let note: String
|
||||||
public let notifying: Bool
|
public let notifying: Bool
|
||||||
|
|
||||||
static public func placeholder() -> Relationshionship {
|
public static func placeholder() -> Relationshionship {
|
||||||
.init(id: UUID().uuidString,
|
.init(id: UUID().uuidString,
|
||||||
following: false,
|
following: false,
|
||||||
showingReblogs: false,
|
showingReblogs: false,
|
||||||
|
|
|
@ -4,12 +4,13 @@ public struct Application: Codable, Identifiable {
|
||||||
public var id: String {
|
public var id: String {
|
||||||
name
|
name
|
||||||
}
|
}
|
||||||
|
|
||||||
public let name: String
|
public let name: String
|
||||||
public let website: URL?
|
public let website: URL?
|
||||||
}
|
}
|
||||||
|
|
||||||
extension Application {
|
public extension Application {
|
||||||
public init(from decoder: Decoder) throws {
|
init(from decoder: Decoder) throws {
|
||||||
let values = try decoder.container(keyedBy: CodingKeys.self)
|
let values = try decoder.container(keyedBy: CodingKeys.self)
|
||||||
|
|
||||||
name = try values.decodeIfPresent(String.self, forKey: .name) ?? ""
|
name = try values.decodeIfPresent(String.self, forKey: .name) ?? ""
|
||||||
|
@ -53,7 +54,6 @@ public protocol AnyStatus {
|
||||||
var language: String? { get }
|
var language: String? { get }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public struct Status: AnyStatus, Codable, Identifiable {
|
public struct Status: AnyStatus, Codable, Identifiable {
|
||||||
public var viewId: String {
|
public var viewId: String {
|
||||||
id + createdAt + (editedAt ?? "")
|
id + createdAt + (editedAt ?? "")
|
||||||
|
|
|
@ -8,5 +8,4 @@ public struct StreamMessage: Encodable {
|
||||||
self.type = type
|
self.type = type
|
||||||
self.stream = stream
|
self.stream = stream
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import XCTest
|
|
||||||
@testable import Models
|
@testable import Models
|
||||||
|
import XCTest
|
||||||
|
|
||||||
final class ModelsTests: XCTestCase {
|
final class ModelsTests: XCTestCase {
|
||||||
func testExample() throws {
|
func testExample() throws {
|
||||||
|
|
|
@ -11,7 +11,8 @@ let package = Package(
|
||||||
products: [
|
products: [
|
||||||
.library(
|
.library(
|
||||||
name: "Network",
|
name: "Network",
|
||||||
targets: ["Network"]),
|
targets: ["Network"]
|
||||||
|
),
|
||||||
],
|
],
|
||||||
dependencies: [
|
dependencies: [
|
||||||
.package(name: "Models", path: "../Models"),
|
.package(name: "Models", path: "../Models"),
|
||||||
|
@ -20,10 +21,12 @@ let package = Package(
|
||||||
.target(
|
.target(
|
||||||
name: "Network",
|
name: "Network",
|
||||||
dependencies: [
|
dependencies: [
|
||||||
.product(name: "Models", package: "Models")
|
.product(name: "Models", package: "Models"),
|
||||||
]),
|
]
|
||||||
|
),
|
||||||
.testTarget(
|
.testTarget(
|
||||||
name: "NetworkTests",
|
name: "NetworkTests",
|
||||||
dependencies: ["Network"]),
|
dependencies: ["Network"]
|
||||||
|
),
|
||||||
]
|
]
|
||||||
)
|
)
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
import Foundation
|
import Foundation
|
||||||
import SwiftUI
|
|
||||||
import Models
|
import Models
|
||||||
|
import SwiftUI
|
||||||
|
|
||||||
public class Client: ObservableObject, Equatable {
|
public class Client: ObservableObject, Equatable {
|
||||||
public static func == (lhs: Client, rhs: Client) -> Bool {
|
public static func == (lhs: Client, rhs: Client) -> Bool {
|
||||||
|
@ -36,10 +36,10 @@ public class Client: ObservableObject, Equatable {
|
||||||
public init(server: String, version: Version = .v1, oauthToken: OauthToken? = nil) {
|
public init(server: String, version: Version = .v1, oauthToken: OauthToken? = nil) {
|
||||||
self.server = server
|
self.server = server
|
||||||
self.version = version
|
self.version = version
|
||||||
self.urlSession = URLSession.shared
|
urlSession = URLSession.shared
|
||||||
self.decoder.keyDecodingStrategy = .convertFromSnakeCase
|
decoder.keyDecodingStrategy = .convertFromSnakeCase
|
||||||
self.oauthToken = oauthToken
|
self.oauthToken = oauthToken
|
||||||
self.connections = Set([server])
|
connections = Set([server])
|
||||||
}
|
}
|
||||||
|
|
||||||
public func addConnections(_ connections: [String]) {
|
public func addConnections(_ connections: [String]) {
|
||||||
|
@ -99,7 +99,8 @@ public class Client: ObservableObject, Equatable {
|
||||||
let (data, httpResponse) = try await urlSession.data(for: makeGet(endpoint: endpoint))
|
let (data, httpResponse) = try await urlSession.data(for: makeGet(endpoint: endpoint))
|
||||||
var linkHandler: LinkHandler?
|
var linkHandler: LinkHandler?
|
||||||
if let response = httpResponse as? HTTPURLResponse,
|
if let response = httpResponse as? HTTPURLResponse,
|
||||||
let link = response.allHeaderFields["Link"] as? String{
|
let link = response.allHeaderFields["Link"] as? String
|
||||||
|
{
|
||||||
linkHandler = .init(rawLink: link)
|
linkHandler = .init(rawLink: link)
|
||||||
}
|
}
|
||||||
logResponseOnError(httpResponse: httpResponse, data: data)
|
logResponseOnError(httpResponse: httpResponse, data: data)
|
||||||
|
@ -137,7 +138,8 @@ public class Client: ObservableObject, Equatable {
|
||||||
|
|
||||||
private func makeEntityRequest<Entity: Decodable>(endpoint: Endpoint,
|
private func makeEntityRequest<Entity: Decodable>(endpoint: Endpoint,
|
||||||
method: String,
|
method: String,
|
||||||
forceVersion: Version? = nil) async throws -> Entity {
|
forceVersion: Version? = nil) async throws -> Entity
|
||||||
|
{
|
||||||
let url = makeURL(endpoint: endpoint, forceVersion: forceVersion)
|
let url = makeURL(endpoint: endpoint, forceVersion: forceVersion)
|
||||||
let request = makeURLRequest(url: url, endpoint: endpoint, httpMethod: method)
|
let request = makeURLRequest(url: url, endpoint: endpoint, httpMethod: method)
|
||||||
let (data, httpResponse) = try await urlSession.data(for: request)
|
let (data, httpResponse) = try await urlSession.data(for: request)
|
||||||
|
@ -147,7 +149,7 @@ public class Client: ObservableObject, Equatable {
|
||||||
|
|
||||||
public func oauthURL() async throws -> URL {
|
public func oauthURL() async throws -> URL {
|
||||||
let app: InstanceApp = try await post(endpoint: Apps.registerApp)
|
let app: InstanceApp = try await post(endpoint: Apps.registerApp)
|
||||||
self.oauthApp = app
|
oauthApp = app
|
||||||
return makeURL(endpoint: Oauth.authorize(clientId: app.clientId))
|
return makeURL(endpoint: Oauth.authorize(clientId: app.clientId))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -156,13 +158,14 @@ public class Client: ObservableObject, Equatable {
|
||||||
throw OauthError.missingApp
|
throw OauthError.missingApp
|
||||||
}
|
}
|
||||||
guard let components = URLComponents(url: url, resolvingAgainstBaseURL: false),
|
guard let components = URLComponents(url: url, resolvingAgainstBaseURL: false),
|
||||||
let code = components.queryItems?.first(where: { $0.name == "code"})?.value else {
|
let code = components.queryItems?.first(where: { $0.name == "code" })?.value
|
||||||
|
else {
|
||||||
throw OauthError.invalidRedirectURL
|
throw OauthError.invalidRedirectURL
|
||||||
}
|
}
|
||||||
let token: OauthToken = try await post(endpoint: Oauth.token(code: code,
|
let token: OauthToken = try await post(endpoint: Oauth.token(code: code,
|
||||||
clientId: app.clientId,
|
clientId: app.clientId,
|
||||||
clientSecret: app.clientSecret))
|
clientSecret: app.clientSecret))
|
||||||
self.oauthToken = token
|
oauthToken = token
|
||||||
return token
|
return token
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -177,7 +180,8 @@ public class Client: ObservableObject, Equatable {
|
||||||
method: String,
|
method: String,
|
||||||
mimeType: String,
|
mimeType: String,
|
||||||
filename: String,
|
filename: String,
|
||||||
data: Data) async throws -> Entity {
|
data: Data) async throws -> Entity
|
||||||
|
{
|
||||||
let url = makeURL(endpoint: endpoint, forceVersion: version)
|
let url = makeURL(endpoint: endpoint, forceVersion: version)
|
||||||
var request = makeURLRequest(url: url, endpoint: endpoint, httpMethod: method)
|
var request = makeURLRequest(url: url, endpoint: endpoint, httpMethod: method)
|
||||||
let boundary = UUID().uuidString
|
let boundary = UUID().uuidString
|
||||||
|
|
|
@ -33,7 +33,7 @@ public enum Accounts: Endpoint {
|
||||||
|
|
||||||
public func path() -> String {
|
public func path() -> String {
|
||||||
switch self {
|
switch self {
|
||||||
case .accounts(let id):
|
case let .accounts(id):
|
||||||
return "accounts/\(id)"
|
return "accounts/\(id)"
|
||||||
case .favourites:
|
case .favourites:
|
||||||
return "favourites"
|
return "favourites"
|
||||||
|
@ -41,29 +41,29 @@ public enum Accounts: Endpoint {
|
||||||
return "bookmarks"
|
return "bookmarks"
|
||||||
case .followedTags:
|
case .followedTags:
|
||||||
return "followed_tags"
|
return "followed_tags"
|
||||||
case .featuredTags(let id):
|
case let .featuredTags(id):
|
||||||
return "accounts/\(id)/featured_tags"
|
return "accounts/\(id)/featured_tags"
|
||||||
case .verifyCredentials:
|
case .verifyCredentials:
|
||||||
return "accounts/verify_credentials"
|
return "accounts/verify_credentials"
|
||||||
case .updateCredentials:
|
case .updateCredentials:
|
||||||
return "accounts/update_credentials"
|
return "accounts/update_credentials"
|
||||||
case .statuses(let id, _, _, _, _, _):
|
case let .statuses(id, _, _, _, _, _):
|
||||||
return "accounts/\(id)/statuses"
|
return "accounts/\(id)/statuses"
|
||||||
case .relationships:
|
case .relationships:
|
||||||
return "accounts/relationships"
|
return "accounts/relationships"
|
||||||
case .follow(let id, _):
|
case let .follow(id, _):
|
||||||
return "accounts/\(id)/follow"
|
return "accounts/\(id)/follow"
|
||||||
case .unfollow(let id):
|
case let .unfollow(id):
|
||||||
return "accounts/\(id)/unfollow"
|
return "accounts/\(id)/unfollow"
|
||||||
case .familiarFollowers:
|
case .familiarFollowers:
|
||||||
return "accounts/familiar_followers"
|
return "accounts/familiar_followers"
|
||||||
case .suggestions:
|
case .suggestions:
|
||||||
return "suggestions"
|
return "suggestions"
|
||||||
case .following(let id, _):
|
case let .following(id, _):
|
||||||
return "accounts/\(id)/following"
|
return "accounts/\(id)/following"
|
||||||
case .followers(let id, _):
|
case let .followers(id, _):
|
||||||
return "accounts/\(id)/followers"
|
return "accounts/\(id)/followers"
|
||||||
case .lists(let id):
|
case let .lists(id):
|
||||||
return "accounts/\(id)/lists"
|
return "accounts/\(id)/lists"
|
||||||
case .preferences:
|
case .preferences:
|
||||||
return "preferences"
|
return "preferences"
|
||||||
|
@ -72,7 +72,7 @@ public enum Accounts: Endpoint {
|
||||||
|
|
||||||
public func queryItems() -> [URLQueryItem]? {
|
public func queryItems() -> [URLQueryItem]? {
|
||||||
switch self {
|
switch self {
|
||||||
case .statuses(_, let sinceId, let tag, let onlyMedia, let excludeReplies, let pinned):
|
case let .statuses(_, sinceId, tag, onlyMedia, excludeReplies, pinned):
|
||||||
var params: [URLQueryItem] = []
|
var params: [URLQueryItem] = []
|
||||||
if let tag {
|
if let tag {
|
||||||
params.append(.init(name: "tagged", value: tag))
|
params.append(.init(name: "tagged", value: tag))
|
||||||
|
|
|
@ -18,7 +18,7 @@ public enum Apps: Endpoint {
|
||||||
.init(name: "client_name", value: AppInfo.clientName),
|
.init(name: "client_name", value: AppInfo.clientName),
|
||||||
.init(name: "redirect_uris", value: AppInfo.scheme),
|
.init(name: "redirect_uris", value: AppInfo.scheme),
|
||||||
.init(name: "scopes", value: AppInfo.scopes),
|
.init(name: "scopes", value: AppInfo.scopes),
|
||||||
.init(name: "website", value: AppInfo.weblink)
|
.init(name: "website", value: AppInfo.weblink),
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,8 +6,8 @@ public protocol Endpoint {
|
||||||
var jsonValue: Encodable? { get }
|
var jsonValue: Encodable? { get }
|
||||||
}
|
}
|
||||||
|
|
||||||
extension Endpoint {
|
public extension Endpoint {
|
||||||
public var jsonValue: Encodable? {
|
var jsonValue: Encodable? {
|
||||||
nil
|
nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -22,7 +22,7 @@ public enum Lists: Endpoint {
|
||||||
|
|
||||||
public func queryItems() -> [URLQueryItem]? {
|
public func queryItems() -> [URLQueryItem]? {
|
||||||
switch self {
|
switch self {
|
||||||
case .accounts(_):
|
case .accounts:
|
||||||
return [.init(name: "limit", value: String(0))]
|
return [.init(name: "limit", value: String(0))]
|
||||||
case let .createList(title):
|
case let .createList(title):
|
||||||
return [.init(name: "title", value: title)]
|
return [.init(name: "title", value: title)]
|
||||||
|
|
|
@ -17,7 +17,7 @@ public enum Notifications: Endpoint {
|
||||||
|
|
||||||
public func queryItems() -> [URLQueryItem]? {
|
public func queryItems() -> [URLQueryItem]? {
|
||||||
switch self {
|
switch self {
|
||||||
case .notifications(let sinceId, let maxId, let types):
|
case let .notifications(sinceId, maxId, types):
|
||||||
var params = makePaginationParam(sinceId: sinceId, maxId: maxId, mindId: nil) ?? []
|
var params = makePaginationParam(sinceId: sinceId, maxId: maxId, mindId: nil) ?? []
|
||||||
if let types {
|
if let types {
|
||||||
for type in types {
|
for type in types {
|
||||||
|
|
|
@ -21,7 +21,7 @@ public enum Oauth: Endpoint {
|
||||||
.init(name: "response_type", value: "code"),
|
.init(name: "response_type", value: "code"),
|
||||||
.init(name: "client_id", value: clientId),
|
.init(name: "client_id", value: clientId),
|
||||||
.init(name: "redirect_uri", value: AppInfo.scheme),
|
.init(name: "redirect_uri", value: AppInfo.scheme),
|
||||||
.init(name: "scope", value: AppInfo.scopes)
|
.init(name: "scope", value: AppInfo.scopes),
|
||||||
]
|
]
|
||||||
case let .token(code, clientId, clientSecret):
|
case let .token(code, clientId, clientSecret):
|
||||||
return [
|
return [
|
||||||
|
@ -30,7 +30,7 @@ public enum Oauth: Endpoint {
|
||||||
.init(name: "client_secret", value: clientSecret),
|
.init(name: "client_secret", value: clientSecret),
|
||||||
.init(name: "redirect_uri", value: AppInfo.scheme),
|
.init(name: "redirect_uri", value: AppInfo.scheme),
|
||||||
.init(name: "code", value: code),
|
.init(name: "code", value: code),
|
||||||
.init(name: "scope", value: AppInfo.scopes)
|
.init(name: "scope", value: AppInfo.scopes),
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,9 +6,9 @@ public enum Polls: Endpoint {
|
||||||
|
|
||||||
public func path() -> String {
|
public func path() -> String {
|
||||||
switch self {
|
switch self {
|
||||||
case .poll(let id):
|
case let .poll(id):
|
||||||
return "polls/\(id)/"
|
return "polls/\(id)/"
|
||||||
case .vote(let id, _):
|
case let .vote(id, _):
|
||||||
return "polls/\(id)/votes"
|
return "polls/\(id)/votes"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -21,23 +21,23 @@ public enum Statuses: Endpoint {
|
||||||
switch self {
|
switch self {
|
||||||
case .postStatus:
|
case .postStatus:
|
||||||
return "statuses"
|
return "statuses"
|
||||||
case .status(let id):
|
case let .status(id):
|
||||||
return "statuses/\(id)"
|
return "statuses/\(id)"
|
||||||
case .editStatus(let id, _):
|
case let .editStatus(id, _):
|
||||||
return "statuses/\(id)"
|
return "statuses/\(id)"
|
||||||
case .context(let id):
|
case let .context(id):
|
||||||
return "statuses/\(id)/context"
|
return "statuses/\(id)/context"
|
||||||
case .favourite(let id):
|
case let .favourite(id):
|
||||||
return "statuses/\(id)/favourite"
|
return "statuses/\(id)/favourite"
|
||||||
case .unfavourite(let id):
|
case let .unfavourite(id):
|
||||||
return "statuses/\(id)/unfavourite"
|
return "statuses/\(id)/unfavourite"
|
||||||
case .reblog(let id):
|
case let .reblog(id):
|
||||||
return "statuses/\(id)/reblog"
|
return "statuses/\(id)/reblog"
|
||||||
case .unreblog(let id):
|
case let .unreblog(id):
|
||||||
return "statuses/\(id)/unreblog"
|
return "statuses/\(id)/unreblog"
|
||||||
case .rebloggedBy(let id, _):
|
case let .rebloggedBy(id, _):
|
||||||
return "statuses/\(id)/reblogged_by"
|
return "statuses/\(id)/reblogged_by"
|
||||||
case .favouritedBy(let id, _):
|
case let .favouritedBy(id, _):
|
||||||
return "statuses/\(id)/favourited_by"
|
return "statuses/\(id)/favourited_by"
|
||||||
case let .pin(id):
|
case let .pin(id):
|
||||||
return "statuses/\(id)/pin"
|
return "statuses/\(id)/pin"
|
||||||
|
@ -100,7 +100,8 @@ public struct StatusData: Encodable {
|
||||||
spoilerText: String? = nil,
|
spoilerText: String? = nil,
|
||||||
mediaIds: [String]? = nil,
|
mediaIds: [String]? = nil,
|
||||||
poll: PollData? = nil,
|
poll: PollData? = nil,
|
||||||
language: String? = nil) {
|
language: String? = nil)
|
||||||
|
{
|
||||||
self.status = status
|
self.status = status
|
||||||
self.visibility = visibility
|
self.visibility = visibility
|
||||||
self.inReplyToId = inReplyToId
|
self.inReplyToId = inReplyToId
|
||||||
|
|
|
@ -7,11 +7,11 @@ public enum Tags: Endpoint {
|
||||||
|
|
||||||
public func path() -> String {
|
public func path() -> String {
|
||||||
switch self {
|
switch self {
|
||||||
case .tag(let id):
|
case let .tag(id):
|
||||||
return "tags/\(id)/"
|
return "tags/\(id)/"
|
||||||
case .follow(let id):
|
case let .follow(id):
|
||||||
return "tags/\(id)/follow"
|
return "tags/\(id)/follow"
|
||||||
case .unfollow(let id):
|
case let .unfollow(id):
|
||||||
return "tags/\(id)/unfollow"
|
return "tags/\(id)/unfollow"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -21,13 +21,13 @@ public enum Timelines: Endpoint {
|
||||||
|
|
||||||
public func queryItems() -> [URLQueryItem]? {
|
public func queryItems() -> [URLQueryItem]? {
|
||||||
switch self {
|
switch self {
|
||||||
case .pub(let sinceId, let maxId, let minId, let local):
|
case let .pub(sinceId, maxId, minId, local):
|
||||||
var params = makePaginationParam(sinceId: sinceId, maxId: maxId, mindId: minId) ?? []
|
var params = makePaginationParam(sinceId: sinceId, maxId: maxId, mindId: minId) ?? []
|
||||||
params.append(.init(name: "local", value: local ? "true" : "false"))
|
params.append(.init(name: "local", value: local ? "true" : "false"))
|
||||||
return params
|
return params
|
||||||
case .home(let sinceId, let maxId, let mindId):
|
case let .home(sinceId, maxId, mindId):
|
||||||
return makePaginationParam(sinceId: sinceId, maxId: maxId, mindId: mindId)
|
return makePaginationParam(sinceId: sinceId, maxId: maxId, mindId: mindId)
|
||||||
case .list(_, let sinceId, let maxId, let mindId):
|
case let .list(_, sinceId, maxId, mindId):
|
||||||
return makePaginationParam(sinceId: sinceId, maxId: maxId, mindId: mindId)
|
return makePaginationParam(sinceId: sinceId, maxId: maxId, mindId: mindId)
|
||||||
case let .hashtag(_, maxId):
|
case let .hashtag(_, maxId):
|
||||||
return makePaginationParam(sinceId: nil, maxId: maxId, mindId: nil)
|
return makePaginationParam(sinceId: nil, maxId: maxId, mindId: nil)
|
||||||
|
|
|
@ -9,9 +9,7 @@ public struct InstanceSocialClient {
|
||||||
let instances: [InstanceSocial]
|
let instances: [InstanceSocial]
|
||||||
}
|
}
|
||||||
|
|
||||||
public init() {
|
public init() {}
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
public func fetchInstances() async -> [InstanceSocial] {
|
public func fetchInstances() async -> [InstanceSocial] {
|
||||||
do {
|
do {
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import Foundation
|
import Foundation
|
||||||
|
|
||||||
public struct OpenAIClient {
|
public struct OpenAIClient {
|
||||||
private let endpoint: URL = URL(string: "https://api.openai.com/v1/completions")!
|
private let endpoint: URL = .init(string: "https://api.openai.com/v1/completions")!
|
||||||
|
|
||||||
private var APIKey: String {
|
private var APIKey: String {
|
||||||
if let path = Bundle.main.path(forResource: "Secret", ofType: "plist") {
|
if let path = Bundle.main.path(forResource: "Secret", ofType: "plist") {
|
||||||
|
@ -90,7 +90,7 @@ public struct OpenAIClient {
|
||||||
let (result, _) = try await URLSession.shared.data(for: request)
|
let (result, _) = try await URLSession.shared.data(for: request)
|
||||||
let response = try decoder.decode(Response.self, from: result)
|
let response = try decoder.decode(Response.self, from: result)
|
||||||
return response
|
return response
|
||||||
} catch let error {
|
} catch {
|
||||||
throw error
|
throw error
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue