mirror of
https://github.com/lumaa-dev/BubbleApp.git
synced 2025-01-29 17:59:19 +01:00
Revamped Navigation system and more
This commit is contained in:
commit
f2da07ab52
@ -43,6 +43,9 @@
|
||||
B98BC7492B46CEDA00595441 /* AppearenceView.swift in Sources */ = {isa = PBXBuildFile; fileRef = B98BC7482B46CEDA00595441 /* AppearenceView.swift */; };
|
||||
B98BC74B2B46CF0400595441 /* ThreadedStyle.swift in Sources */ = {isa = PBXBuildFile; fileRef = B98BC74A2B46CF0400595441 /* ThreadedStyle.swift */; };
|
||||
B98BC74D2B46CFCE00595441 /* UserPreferences.swift in Sources */ = {isa = PBXBuildFile; fileRef = B98BC74C2B46CFCE00595441 /* UserPreferences.swift */; };
|
||||
B98DD8D62C681FDA009F40DD /* Localizable.xcstrings in Resources */ = {isa = PBXBuildFile; fileRef = B9FB948F2B2E2B0E00D81C07 /* Localizable.xcstrings */; };
|
||||
B98DD8D82C6821F7009F40DD /* CreatePostControl.swift in Sources */ = {isa = PBXBuildFile; fileRef = B98DD8D72C6821F7009F40DD /* CreatePostControl.swift */; };
|
||||
B98DD8D92C6821F7009F40DD /* CreatePostControl.swift in Sources */ = {isa = PBXBuildFile; fileRef = B98DD8D72C6821F7009F40DD /* CreatePostControl.swift */; };
|
||||
B98F47962B645DF40092000F /* EmojiSelector.swift in Sources */ = {isa = PBXBuildFile; fileRef = B98F47952B645DF40092000F /* EmojiSelector.swift */; };
|
||||
B98F47982B64670F0092000F /* ShopView.swift in Sources */ = {isa = PBXBuildFile; fileRef = B98F47972B64670F0092000F /* ShopView.swift */; };
|
||||
B98F479A2B653CAE0092000F /* Compressor.swift in Sources */ = {isa = PBXBuildFile; fileRef = B98F47992B653CAE0092000F /* Compressor.swift */; };
|
||||
@ -50,24 +53,100 @@
|
||||
B999DE5E2B76F9D100509868 /* Message.swift in Sources */ = {isa = PBXBuildFile; fileRef = B999DE5D2B76F9D100509868 /* Message.swift */; };
|
||||
B999DE602B76FB3E00509868 /* ContactRow.swift in Sources */ = {isa = PBXBuildFile; fileRef = B999DE5F2B76FB3E00509868 /* ContactRow.swift */; };
|
||||
B9A80DDA2C66DE1000DE3D88 /* ReportStatusView.swift in Sources */ = {isa = PBXBuildFile; fileRef = B9A80DD92C66DE1000DE3D88 /* ReportStatusView.swift */; };
|
||||
B9A80DDE2C67BFF800DE3D88 /* CreatePostWidget.swift in Sources */ = {isa = PBXBuildFile; fileRef = B9A80DDD2C67BFF800DE3D88 /* CreatePostWidget.swift */; };
|
||||
B9A80DDF2C67C27B00DE3D88 /* AppIntent.swift in Sources */ = {isa = PBXBuildFile; fileRef = B9C20D132B921C78004DC9B3 /* AppIntent.swift */; };
|
||||
B9A80DE02C67C2D000DE3D88 /* Navigator.swift in Sources */ = {isa = PBXBuildFile; fileRef = B9FB946F2B2DF3CD00D81C07 /* Navigator.swift */; };
|
||||
B9A80DE22C67C38E00DE3D88 /* URLNavigator.swift in Sources */ = {isa = PBXBuildFile; fileRef = B9A80DE12C67C38E00DE3D88 /* URLNavigator.swift */; };
|
||||
B9A80DE72C67C3FC00DE3D88 /* Account+Elms.swift in Sources */ = {isa = PBXBuildFile; fileRef = B9FB94852B2E211200D81C07 /* Account+Elms.swift */; };
|
||||
B9A80DE82C67C3FC00DE3D88 /* Account.swift in Sources */ = {isa = PBXBuildFile; fileRef = B9FB947E2B2E1D5F00D81C07 /* Account.swift */; };
|
||||
B9A80DE92C67C3FC00DE3D88 /* LoggedAccounts.swift in Sources */ = {isa = PBXBuildFile; fileRef = B98627302B86F23500844245 /* LoggedAccounts.swift */; };
|
||||
B9A80DEA2C67C3FC00DE3D88 /* AccountManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = B9FB947C2B2E19E300D81C07 /* AccountManager.swift */; };
|
||||
B9A80DEB2C67C3FC00DE3D88 /* AccountsList.swift in Sources */ = {isa = PBXBuildFile; fileRef = B9842C172B2F36F500D9F3C1 /* AccountsList.swift */; };
|
||||
B9A80DF02C67C40900DE3D88 /* SearchResults.swift in Sources */ = {isa = PBXBuildFile; fileRef = B9B63B262B449CDC00BBC82D /* SearchResults.swift */; };
|
||||
B9A80DF12C67C40900DE3D88 /* ContentFilter.swift in Sources */ = {isa = PBXBuildFile; fileRef = B93126E92C29C63000BF16E9 /* ContentFilter.swift */; };
|
||||
B9A80DF22C67C40900DE3D88 /* FetchTimeline.swift in Sources */ = {isa = PBXBuildFile; fileRef = B9842C132B2F310C00D9F3C1 /* FetchTimeline.swift */; };
|
||||
B9A80DF32C67C40900DE3D88 /* HTMLString.swift in Sources */ = {isa = PBXBuildFile; fileRef = B9FB94802B2E1FEF00D81C07 /* HTMLString.swift */; };
|
||||
B9A80DF42C67C40900DE3D88 /* TimelineFilter.swift in Sources */ = {isa = PBXBuildFile; fileRef = B9842C152B2F363600D9F3C1 /* TimelineFilter.swift */; };
|
||||
B9A80DF52C67C40900DE3D88 /* Tenor.swift in Sources */ = {isa = PBXBuildFile; fileRef = B9BCC3172B90B3BC00211976 /* Tenor.swift */; };
|
||||
B9A80DF62C67C40900DE3D88 /* Tag.swift in Sources */ = {isa = PBXBuildFile; fileRef = B9FB94BB2B2F035500D81C07 /* Tag.swift */; };
|
||||
B9A80DF72C67C40900DE3D88 /* MediaTransferables.swift in Sources */ = {isa = PBXBuildFile; fileRef = B9FB948D2B2E28E800D81C07 /* MediaTransferables.swift */; };
|
||||
B9A80DF82C67C40900DE3D88 /* Compressor.swift in Sources */ = {isa = PBXBuildFile; fileRef = B98F47992B653CAE0092000F /* Compressor.swift */; };
|
||||
B9A80DF92C67C40900DE3D88 /* Status.swift in Sources */ = {isa = PBXBuildFile; fileRef = B9842C0F2B2F228C00D9F3C1 /* Status.swift */; };
|
||||
B9A80DFA2C67C40E00DE3D88 /* URLNavigator.swift in Sources */ = {isa = PBXBuildFile; fileRef = B9A80DE12C67C38E00DE3D88 /* URLNavigator.swift */; };
|
||||
B9A80DFB2C67C40E00DE3D88 /* AltClients.swift in Sources */ = {isa = PBXBuildFile; fileRef = B93757102B7FB8D400652F91 /* AltClients.swift */; };
|
||||
B9A80DFC2C67C40E00DE3D88 /* MastodonRequest.swift in Sources */ = {isa = PBXBuildFile; fileRef = B9FB949E2B2EF0F200D81C07 /* MastodonRequest.swift */; };
|
||||
B9A80DFD2C67C40E00DE3D88 /* UserPreferences.swift in Sources */ = {isa = PBXBuildFile; fileRef = B98BC74C2B46CFCE00595441 /* UserPreferences.swift */; };
|
||||
B9A80DFF2C67C40E00DE3D88 /* HapticManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = B97BCE232B3DD8400044756D /* HapticManager.swift */; };
|
||||
B9A80E002C67C40E00DE3D88 /* Instance.swift in Sources */ = {isa = PBXBuildFile; fileRef = B9FB949C2B2EF0D600D81C07 /* Instance.swift */; };
|
||||
B9A80E0A2C67C48D00DE3D88 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = B9EBE8572B474FD600FB594D /* AppDelegate.swift */; };
|
||||
B9A80E0B2C67C4A600DE3D88 /* AccountRow.swift in Sources */ = {isa = PBXBuildFile; fileRef = B9FA6E762B82788A00D63E30 /* AccountRow.swift */; };
|
||||
B9A80E0C2C67C4A600DE3D88 /* ComingSoonView.swift in Sources */ = {isa = PBXBuildFile; fileRef = B9B469DA2B9B2EDB00AD5585 /* ComingSoonView.swift */; };
|
||||
B9A80E0D2C67C4A600DE3D88 /* OnlineImage.swift in Sources */ = {isa = PBXBuildFile; fileRef = B9FB948B2B2E232300D81C07 /* OnlineImage.swift */; };
|
||||
B9A80E0E2C67C4A600DE3D88 /* DynamicTextEditor.swift in Sources */ = {isa = PBXBuildFile; fileRef = B9B63B202B442D1500BBC82D /* DynamicTextEditor.swift */; };
|
||||
B9A80E0F2C67C4A600DE3D88 /* ContactRow.swift in Sources */ = {isa = PBXBuildFile; fileRef = B999DE5F2B76FB3E00509868 /* ContactRow.swift */; };
|
||||
B9A80E102C67C4A600DE3D88 /* WarningView.swift in Sources */ = {isa = PBXBuildFile; fileRef = B9C7F46B2C387D3B009C36DC /* WarningView.swift */; };
|
||||
B9A80E112C67C4A600DE3D88 /* ThreadedStyle.swift in Sources */ = {isa = PBXBuildFile; fileRef = B98BC74A2B46CF0400595441 /* ThreadedStyle.swift */; };
|
||||
B9A80E122C67C4A600DE3D88 /* NotificationRow.swift in Sources */ = {isa = PBXBuildFile; fileRef = B9D9C6C42B6A587700C26A41 /* NotificationRow.swift */; };
|
||||
B9A80E132C67C4A600DE3D88 /* TextEmoji.swift in Sources */ = {isa = PBXBuildFile; fileRef = B93B67772B42E8F0000892E9 /* TextEmoji.swift */; };
|
||||
B9A80E142C67C4A600DE3D88 /* SearchResultView.swift in Sources */ = {isa = PBXBuildFile; fileRef = B9DC69282B78D9A500E625B9 /* SearchResultView.swift */; };
|
||||
B9A80E152C67C4A600DE3D88 /* SymbolWidth.swift in Sources */ = {isa = PBXBuildFile; fileRef = B97491E22B6E96700098BC48 /* SymbolWidth.swift */; };
|
||||
B9A80E162C67C4A600DE3D88 /* TabsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = B9FB94752B2E023D00D81C07 /* TabsView.swift */; };
|
||||
B9A80E172C67C4A600DE3D88 /* ShareSheetController.swift in Sources */ = {isa = PBXBuildFile; fileRef = B9BED5192B5D662D00C9B715 /* ShareSheetController.swift */; };
|
||||
B9A80E182C67C4A600DE3D88 /* ButtonStyles.swift in Sources */ = {isa = PBXBuildFile; fileRef = B9FB94732B2DF6A100D81C07 /* ButtonStyles.swift */; };
|
||||
B9A80E192C67C4A600DE3D88 /* ProfilePicture.swift in Sources */ = {isa = PBXBuildFile; fileRef = B9D9C6C62B6A590F00C26A41 /* ProfilePicture.swift */; };
|
||||
B9A80E1A2C67C4A600DE3D88 /* MailView.swift in Sources */ = {isa = PBXBuildFile; fileRef = B9D365602B79A1BE004C1255 /* MailView.swift */; };
|
||||
B9A80E1B2C67C4AE00DE3D88 /* PostCardView.swift in Sources */ = {isa = PBXBuildFile; fileRef = B9B63B222B447B8000BBC82D /* PostCardView.swift */; };
|
||||
B9A80E1C2C67C4AE00DE3D88 /* CompactPostView.swift in Sources */ = {isa = PBXBuildFile; fileRef = B9842C0D2B2F21B700D9F3C1 /* CompactPostView.swift */; };
|
||||
B9A80E1D2C67C4AE00DE3D88 /* PostMenu.swift in Sources */ = {isa = PBXBuildFile; fileRef = B9BED5172B5D649C00C9B715 /* PostMenu.swift */; };
|
||||
B9A80E1E2C67C4AE00DE3D88 /* PostInteractor.swift in Sources */ = {isa = PBXBuildFile; fileRef = B9BED5152B5D5E6500C9B715 /* PostInteractor.swift */; };
|
||||
B9A80E1F2C67C4AE00DE3D88 /* EmojiSelector.swift in Sources */ = {isa = PBXBuildFile; fileRef = B98F47952B645DF40092000F /* EmojiSelector.swift */; };
|
||||
B9A80E202C67C4AE00DE3D88 /* PostPoll.swift in Sources */ = {isa = PBXBuildFile; fileRef = B964F8052B9B78F4005C193D /* PostPoll.swift */; };
|
||||
B9A80E212C67C4AE00DE3D88 /* PostAttachment.swift in Sources */ = {isa = PBXBuildFile; fileRef = B9EBE8552B47256900FB594D /* PostAttachment.swift */; };
|
||||
B9A80E222C67C4AE00DE3D88 /* QuotePostView.swift in Sources */ = {isa = PBXBuildFile; fileRef = B9B63B242B44997400BBC82D /* QuotePostView.swift */; };
|
||||
B9A80E232C67C4B700DE3D88 /* AttachmentView.swift in Sources */ = {isa = PBXBuildFile; fileRef = B9FA6E742B82367B00D63E30 /* AttachmentView.swift */; };
|
||||
B9A80E242C67C4B700DE3D88 /* SettingsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = B9FB94912B2E35D000D81C07 /* SettingsView.swift */; };
|
||||
B9A80E252C67C4B700DE3D88 /* ConnectView.swift in Sources */ = {isa = PBXBuildFile; fileRef = B9FB94712B2DF49700D81C07 /* ConnectView.swift */; };
|
||||
B9A80E262C67C4B700DE3D88 /* PostingView.swift in Sources */ = {isa = PBXBuildFile; fileRef = B93B677B2B433A6E000892E9 /* PostingView.swift */; };
|
||||
B9A80E272C67C4B700DE3D88 /* PostDetailsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = B98BC7462B46CE6300595441 /* PostDetailsView.swift */; };
|
||||
B9A80E282C67C4B700DE3D88 /* IconView.swift in Sources */ = {isa = PBXBuildFile; fileRef = B9FD18992C57DE9200A74A71 /* IconView.swift */; };
|
||||
B9A80E292C67C4B700DE3D88 /* UpdateView.swift in Sources */ = {isa = PBXBuildFile; fileRef = B97798882B853E6600DC869F /* UpdateView.swift */; };
|
||||
B9A80E2A2C67C4B700DE3D88 /* ReportStatusView.swift in Sources */ = {isa = PBXBuildFile; fileRef = B9A80DD92C66DE1000DE3D88 /* ReportStatusView.swift */; };
|
||||
B9A80E2B2C67C4B700DE3D88 /* PrivacyView.swift in Sources */ = {isa = PBXBuildFile; fileRef = B9B469B12B9A6E8300AD5585 /* PrivacyView.swift */; };
|
||||
B9A80E2C2C67C4B700DE3D88 /* SafariView.swift in Sources */ = {isa = PBXBuildFile; fileRef = B9F8FA152B5D3AC30044DAB4 /* SafariView.swift */; };
|
||||
B9A80E2D2C67C4B700DE3D88 /* FilterView.swift in Sources */ = {isa = PBXBuildFile; fileRef = B93126EF2C2AEB8300BF16E9 /* FilterView.swift */; };
|
||||
B9A80E2E2C67C4B700DE3D88 /* AppearenceView.swift in Sources */ = {isa = PBXBuildFile; fileRef = B98BC7482B46CEDA00595441 /* AppearenceView.swift */; };
|
||||
B9A80E2F2C67C4B700DE3D88 /* ContactsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = B999DE5B2B76F8CB00509868 /* ContactsView.swift */; };
|
||||
B9A80E302C67C4B700DE3D88 /* PostsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = B9A8DAB92BB7364300A890CC /* PostsView.swift */; };
|
||||
B9A80E312C67C4B700DE3D88 /* NotificationsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = B9D9C6C22B6A576C00C26A41 /* NotificationsView.swift */; };
|
||||
B9A80E322C67C4B700DE3D88 /* EditProfileView.swift in Sources */ = {isa = PBXBuildFile; fileRef = B9FD18972C55108F00A74A71 /* EditProfileView.swift */; };
|
||||
B9A80E332C67C4B700DE3D88 /* ContentView.swift in Sources */ = {isa = PBXBuildFile; fileRef = B9FB945C2B2DEECE00D81C07 /* ContentView.swift */; };
|
||||
B9A80E342C67C4B700DE3D88 /* DiscoveryView.swift in Sources */ = {isa = PBXBuildFile; fileRef = B93ADFCA2B7625CD00FF9172 /* DiscoveryView.swift */; };
|
||||
B9A80E352C67C4B700DE3D88 /* AccountView.swift in Sources */ = {isa = PBXBuildFile; fileRef = B97BCE252B3DE5A10044756D /* AccountView.swift */; };
|
||||
B9A80E362C67C4B700DE3D88 /* SupportView.swift in Sources */ = {isa = PBXBuildFile; fileRef = B9FB94962B2EDABF00D81C07 /* SupportView.swift */; };
|
||||
B9A80E372C67C4B700DE3D88 /* AddInstanceView.swift in Sources */ = {isa = PBXBuildFile; fileRef = B9FB94982B2EEB9400D81C07 /* AddInstanceView.swift */; };
|
||||
B9A80E382C67C4B700DE3D88 /* ShopView.swift in Sources */ = {isa = PBXBuildFile; fileRef = B98F47972B64670F0092000F /* ShopView.swift */; };
|
||||
B9A80E392C67C4B700DE3D88 /* AboutView.swift in Sources */ = {isa = PBXBuildFile; fileRef = B9CC45B72B40A2D6001E4FA5 /* AboutView.swift */; };
|
||||
B9A80E3A2C67C4B700DE3D88 /* RestrictedView.swift in Sources */ = {isa = PBXBuildFile; fileRef = B934EA232BAB5E7F001F4345 /* RestrictedView.swift */; };
|
||||
B9A80E3B2C67C4B700DE3D88 /* TimelineView.swift in Sources */ = {isa = PBXBuildFile; fileRef = B9842C112B2F2A5800D9F3C1 /* TimelineView.swift */; };
|
||||
B9A80E3C2C67C4B700DE3D88 /* ProfileView.swift in Sources */ = {isa = PBXBuildFile; fileRef = B915C4412B6F908C00042DDB /* ProfileView.swift */; };
|
||||
B9A80E6D2C67C61E00DE3D88 /* Notification.swift in Sources */ = {isa = PBXBuildFile; fileRef = B9D9C6C02B6A56E000C26A41 /* Notification.swift */; };
|
||||
B9A80E6F2C67C62800DE3D88 /* Message.swift in Sources */ = {isa = PBXBuildFile; fileRef = B999DE5D2B76F9D100509868 /* Message.swift */; };
|
||||
B9A80E852C67C7C300DE3D88 /* SwiftSoup in Frameworks */ = {isa = PBXBuildFile; productRef = B9A80E842C67C7C300DE3D88 /* SwiftSoup */; };
|
||||
B9A80E872C67C7C300DE3D88 /* Nuke in Frameworks */ = {isa = PBXBuildFile; productRef = B9A80E862C67C7C300DE3D88 /* Nuke */; };
|
||||
B9A80E892C67C7C300DE3D88 /* NukeExtensions in Frameworks */ = {isa = PBXBuildFile; productRef = B9A80E882C67C7C300DE3D88 /* NukeExtensions */; };
|
||||
B9A80E8B2C67C7C300DE3D88 /* NukeUI in Frameworks */ = {isa = PBXBuildFile; productRef = B9A80E8A2C67C7C300DE3D88 /* NukeUI */; };
|
||||
B9A80E8D2C67C7C300DE3D88 /* NukeVideo in Frameworks */ = {isa = PBXBuildFile; productRef = B9A80E8C2C67C7C300DE3D88 /* NukeVideo */; };
|
||||
B9A80E8F2C67C7C300DE3D88 /* EmojiText in Frameworks */ = {isa = PBXBuildFile; productRef = B9A80E8E2C67C7C300DE3D88 /* EmojiText */; };
|
||||
B9A80E912C67C7C300DE3D88 /* KeychainSwift in Frameworks */ = {isa = PBXBuildFile; productRef = B9A80E902C67C7C300DE3D88 /* KeychainSwift */; };
|
||||
B9A80E932C67C7C300DE3D88 /* ReceiptParser in Frameworks */ = {isa = PBXBuildFile; productRef = B9A80E922C67C7C300DE3D88 /* ReceiptParser */; };
|
||||
B9A80E952C67C7C300DE3D88 /* RevenueCat in Frameworks */ = {isa = PBXBuildFile; productRef = B9A80E942C67C7C300DE3D88 /* RevenueCat */; };
|
||||
B9A80E972C67C7C300DE3D88 /* RevenueCatUI in Frameworks */ = {isa = PBXBuildFile; productRef = B9A80E962C67C7C300DE3D88 /* RevenueCatUI */; };
|
||||
B9A80E9A2C67D56900DE3D88 /* FollowCountWidget.swift in Sources */ = {isa = PBXBuildFile; fileRef = B9C20D112B921C78004DC9B3 /* FollowCountWidget.swift */; };
|
||||
B9A80E9B2C67D56900DE3D88 /* FollowGoalWidget.swift in Sources */ = {isa = PBXBuildFile; fileRef = B9B469AF2B9A275F00AD5585 /* FollowGoalWidget.swift */; };
|
||||
B9A80E9C2C67D56900DE3D88 /* CreatePostWidget.swift in Sources */ = {isa = PBXBuildFile; fileRef = B9A80DDD2C67BFF800DE3D88 /* CreatePostWidget.swift */; };
|
||||
B9A8DABA2BB7364300A890CC /* PostsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = B9A8DAB92BB7364300A890CC /* PostsView.swift */; };
|
||||
B9B469B02B9A275F00AD5585 /* FollowGoalWidget.swift in Sources */ = {isa = PBXBuildFile; fileRef = B9B469AF2B9A275F00AD5585 /* FollowGoalWidget.swift */; };
|
||||
B9B469B22B9A6E8300AD5585 /* PrivacyView.swift in Sources */ = {isa = PBXBuildFile; fileRef = B9B469B12B9A6E8300AD5585 /* PrivacyView.swift */; };
|
||||
B9B469BA2B9A7E6800AD5585 /* ThreadedWatchApp.swift in Sources */ = {isa = PBXBuildFile; fileRef = B9B469B92B9A7E6800AD5585 /* ThreadedWatchApp.swift */; };
|
||||
B9B469BC2B9A7E6800AD5585 /* ContentView.swift in Sources */ = {isa = PBXBuildFile; fileRef = B9B469BB2B9A7E6800AD5585 /* ContentView.swift */; };
|
||||
B9B469BE2B9A7E6B00AD5585 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = B9B469BD2B9A7E6B00AD5585 /* Assets.xcassets */; };
|
||||
B9B469C12B9A7E6B00AD5585 /* Preview Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = B9B469C02B9A7E6B00AD5585 /* Preview Assets.xcassets */; };
|
||||
B9B469C42B9A7E6B00AD5585 /* Threaded.app in Embed Watch Content */ = {isa = PBXBuildFile; fileRef = B9B469B72B9A7E6800AD5585 /* Threaded.app */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; };
|
||||
B9B469C92B9A804800AD5585 /* Redeclarations.swift in Sources */ = {isa = PBXBuildFile; fileRef = B9C20D602B949AD7004DC9B3 /* Redeclarations.swift */; };
|
||||
B9B469CA2B9A811200AD5585 /* AppInfo.swift in Sources */ = {isa = PBXBuildFile; fileRef = B9FB94A12B2EF24A00D81C07 /* AppInfo.swift */; };
|
||||
B9B469CB2B9A816D00AD5585 /* LoggedAccounts.swift in Sources */ = {isa = PBXBuildFile; fileRef = B98627302B86F23500844245 /* LoggedAccounts.swift */; };
|
||||
B9B469CD2B9A823600AD5585 /* Localizable.xcstrings in Resources */ = {isa = PBXBuildFile; fileRef = B9B469CC2B9A823600AD5585 /* Localizable.xcstrings */; };
|
||||
B9B469CF2B9A82ED00AD5585 /* KeychainSwift in Frameworks */ = {isa = PBXBuildFile; productRef = B9B469CE2B9A82ED00AD5585 /* KeychainSwift */; };
|
||||
B9B469D42B9A871C00AD5585 /* WatchConnectivity.swift in Sources */ = {isa = PBXBuildFile; fileRef = B9B469D32B9A871C00AD5585 /* WatchConnectivity.swift */; };
|
||||
B9B469D52B9A871C00AD5585 /* WatchConnectivity.swift in Sources */ = {isa = PBXBuildFile; fileRef = B9B469D32B9A871C00AD5585 /* WatchConnectivity.swift */; };
|
||||
B9B469D72B9A8B0700AD5585 /* GivenAccount.swift in Sources */ = {isa = PBXBuildFile; fileRef = B9B469D62B9A8B0700AD5585 /* GivenAccount.swift */; };
|
||||
B9B469D82B9A8B1600AD5585 /* GivenAccount.swift in Sources */ = {isa = PBXBuildFile; fileRef = B9B469D62B9A8B0700AD5585 /* GivenAccount.swift */; };
|
||||
B9B469D92B9AA4DF00AD5585 /* Client.swift in Sources */ = {isa = PBXBuildFile; fileRef = B9FB949A2B2EF09A00D81C07 /* Client.swift */; };
|
||||
B9B469DB2B9B2EDB00AD5585 /* ComingSoonView.swift in Sources */ = {isa = PBXBuildFile; fileRef = B9B469DA2B9B2EDB00AD5585 /* ComingSoonView.swift */; };
|
||||
B9B63B212B442D1500BBC82D /* DynamicTextEditor.swift in Sources */ = {isa = PBXBuildFile; fileRef = B9B63B202B442D1500BBC82D /* DynamicTextEditor.swift */; };
|
||||
B9B63B232B447B8000BBC82D /* PostCardView.swift in Sources */ = {isa = PBXBuildFile; fileRef = B9B63B222B447B8000BBC82D /* PostCardView.swift */; };
|
||||
@ -85,13 +164,9 @@
|
||||
B9C20D142B921C78004DC9B3 /* AppIntent.swift in Sources */ = {isa = PBXBuildFile; fileRef = B9C20D132B921C78004DC9B3 /* AppIntent.swift */; };
|
||||
B9C20D162B921C7B004DC9B3 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = B9C20D152B921C7B004DC9B3 /* Assets.xcassets */; };
|
||||
B9C20D1A2B921C7B004DC9B3 /* ThreadedWidgetsExtension.appex in Embed Foundation Extensions */ = {isa = PBXBuildFile; fileRef = B9C20D092B921C78004DC9B3 /* ThreadedWidgetsExtension.appex */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; };
|
||||
B9C20D1F2B921E81004DC9B3 /* Localizable.xcstrings in Resources */ = {isa = PBXBuildFile; fileRef = B9C20D1E2B921E81004DC9B3 /* Localizable.xcstrings */; };
|
||||
B9C20D282B9229DF004DC9B3 /* LoggedAccounts.swift in Sources */ = {isa = PBXBuildFile; fileRef = B98627302B86F23500844245 /* LoggedAccounts.swift */; };
|
||||
B9C20D342B9229EC004DC9B3 /* Client.swift in Sources */ = {isa = PBXBuildFile; fileRef = B9FB949A2B2EF09A00D81C07 /* Client.swift */; };
|
||||
B9C20D372B9229EC004DC9B3 /* AppInfo.swift in Sources */ = {isa = PBXBuildFile; fileRef = B9FB94A12B2EF24A00D81C07 /* AppInfo.swift */; };
|
||||
B9C20D3D2B9229EC004DC9B3 /* Emoji.swift in Sources */ = {isa = PBXBuildFile; fileRef = B9FB94872B2E223E00D81C07 /* Emoji.swift */; };
|
||||
B9C20D562B922DAC004DC9B3 /* KeychainSwift in Frameworks */ = {isa = PBXBuildFile; productRef = B9C20D552B922DAC004DC9B3 /* KeychainSwift */; };
|
||||
B9C20D612B949AD7004DC9B3 /* Redeclarations.swift in Sources */ = {isa = PBXBuildFile; fileRef = B9C20D602B949AD7004DC9B3 /* Redeclarations.swift */; };
|
||||
B9C7F46C2C387D3B009C36DC /* WarningView.swift in Sources */ = {isa = PBXBuildFile; fileRef = B9C7F46B2C387D3B009C36DC /* WarningView.swift */; };
|
||||
B9CC45B82B40A2D6001E4FA5 /* AboutView.swift in Sources */ = {isa = PBXBuildFile; fileRef = B9CC45B72B40A2D6001E4FA5 /* AboutView.swift */; };
|
||||
B9CFC43B2B4F08C9004CFCB7 /* LaunchStoryboard.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = B9CFC43A2B4F08C9004CFCB7 /* LaunchStoryboard.storyboard */; };
|
||||
@ -142,13 +217,6 @@
|
||||
/* End PBXBuildFile section */
|
||||
|
||||
/* Begin PBXContainerItemProxy section */
|
||||
B9B469C22B9A7E6B00AD5585 /* PBXContainerItemProxy */ = {
|
||||
isa = PBXContainerItemProxy;
|
||||
containerPortal = B9FB944F2B2DEECE00D81C07 /* Project object */;
|
||||
proxyType = 1;
|
||||
remoteGlobalIDString = B9B469B62B9A7E6800AD5585;
|
||||
remoteInfo = "ThreadedWatch Watch App";
|
||||
};
|
||||
B9C20D182B921C7B004DC9B3 /* PBXContainerItemProxy */ = {
|
||||
isa = PBXContainerItemProxy;
|
||||
containerPortal = B9FB944F2B2DEECE00D81C07 /* Project object */;
|
||||
@ -172,7 +240,6 @@
|
||||
dstPath = "$(CONTENTS_FOLDER_PATH)/Watch";
|
||||
dstSubfolderSpec = 16;
|
||||
files = (
|
||||
B9B469C42B9A7E6B00AD5585 /* Threaded.app in Embed Watch Content */,
|
||||
);
|
||||
name = "Embed Watch Content";
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
@ -221,6 +288,7 @@
|
||||
B98BC7482B46CEDA00595441 /* AppearenceView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppearenceView.swift; sourceTree = "<group>"; };
|
||||
B98BC74A2B46CF0400595441 /* ThreadedStyle.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ThreadedStyle.swift; sourceTree = "<group>"; };
|
||||
B98BC74C2B46CFCE00595441 /* UserPreferences.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UserPreferences.swift; sourceTree = "<group>"; };
|
||||
B98DD8D72C6821F7009F40DD /* CreatePostControl.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CreatePostControl.swift; sourceTree = "<group>"; };
|
||||
B98F47952B645DF40092000F /* EmojiSelector.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EmojiSelector.swift; sourceTree = "<group>"; };
|
||||
B98F47972B64670F0092000F /* ShopView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ShopView.swift; sourceTree = "<group>"; };
|
||||
B98F47992B653CAE0092000F /* Compressor.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Compressor.swift; sourceTree = "<group>"; };
|
||||
@ -228,18 +296,11 @@
|
||||
B999DE5D2B76F9D100509868 /* Message.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Message.swift; sourceTree = "<group>"; };
|
||||
B999DE5F2B76FB3E00509868 /* ContactRow.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContactRow.swift; sourceTree = "<group>"; };
|
||||
B9A80DD92C66DE1000DE3D88 /* ReportStatusView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReportStatusView.swift; sourceTree = "<group>"; };
|
||||
B9A80DDD2C67BFF800DE3D88 /* CreatePostWidget.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CreatePostWidget.swift; sourceTree = "<group>"; };
|
||||
B9A80DE12C67C38E00DE3D88 /* URLNavigator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = URLNavigator.swift; sourceTree = "<group>"; };
|
||||
B9A8DAB92BB7364300A890CC /* PostsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PostsView.swift; sourceTree = "<group>"; };
|
||||
B9B469AF2B9A275F00AD5585 /* FollowGoalWidget.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FollowGoalWidget.swift; sourceTree = "<group>"; };
|
||||
B9B469B12B9A6E8300AD5585 /* PrivacyView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PrivacyView.swift; sourceTree = "<group>"; };
|
||||
B9B469B72B9A7E6800AD5585 /* Threaded.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Threaded.app; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
B9B469B92B9A7E6800AD5585 /* ThreadedWatchApp.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ThreadedWatchApp.swift; sourceTree = "<group>"; };
|
||||
B9B469BB2B9A7E6800AD5585 /* ContentView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContentView.swift; sourceTree = "<group>"; };
|
||||
B9B469BD2B9A7E6B00AD5585 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; };
|
||||
B9B469C02B9A7E6B00AD5585 /* Preview Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = "Preview Assets.xcassets"; sourceTree = "<group>"; };
|
||||
B9B469CC2B9A823600AD5585 /* Localizable.xcstrings */ = {isa = PBXFileReference; lastKnownFileType = text.json.xcstrings; path = Localizable.xcstrings; sourceTree = "<group>"; };
|
||||
B9B469D22B9A838500AD5585 /* ThreadedWatch Watch App.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = "ThreadedWatch Watch App.entitlements"; sourceTree = "<group>"; };
|
||||
B9B469D32B9A871C00AD5585 /* WatchConnectivity.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WatchConnectivity.swift; sourceTree = "<group>"; };
|
||||
B9B469D62B9A8B0700AD5585 /* GivenAccount.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GivenAccount.swift; sourceTree = "<group>"; };
|
||||
B9B469DA2B9B2EDB00AD5585 /* ComingSoonView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ComingSoonView.swift; sourceTree = "<group>"; };
|
||||
B9B63B202B442D1500BBC82D /* DynamicTextEditor.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DynamicTextEditor.swift; sourceTree = "<group>"; };
|
||||
B9B63B222B447B8000BBC82D /* PostCardView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PostCardView.swift; sourceTree = "<group>"; };
|
||||
@ -257,10 +318,8 @@
|
||||
B9C20D132B921C78004DC9B3 /* AppIntent.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppIntent.swift; sourceTree = "<group>"; };
|
||||
B9C20D152B921C7B004DC9B3 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; };
|
||||
B9C20D172B921C7B004DC9B3 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
|
||||
B9C20D1E2B921E81004DC9B3 /* Localizable.xcstrings */ = {isa = PBXFileReference; lastKnownFileType = text.json.xcstrings; path = Localizable.xcstrings; sourceTree = "<group>"; };
|
||||
B9C20D582B923CDD004DC9B3 /* ThreadedWidgetsExtension.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = ThreadedWidgetsExtension.entitlements; sourceTree = "<group>"; };
|
||||
B9C20D592B923D53004DC9B3 /* Threaded.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = Threaded.entitlements; sourceTree = "<group>"; };
|
||||
B9C20D602B949AD7004DC9B3 /* Redeclarations.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Redeclarations.swift; sourceTree = "<group>"; };
|
||||
B9C7F46B2C387D3B009C36DC /* WarningView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WarningView.swift; sourceTree = "<group>"; };
|
||||
B9CC45B72B40A2D6001E4FA5 /* AboutView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AboutView.swift; sourceTree = "<group>"; };
|
||||
B9CC45B92B40AA1E001E4FA5 /* README.md */ = {isa = PBXFileReference; lastKnownFileType = net.daringfireball.markdown; path = README.md; sourceTree = "<group>"; };
|
||||
@ -314,21 +373,22 @@
|
||||
/* End PBXFileReference section */
|
||||
|
||||
/* Begin PBXFrameworksBuildPhase section */
|
||||
B9B469B42B9A7E6800AD5585 /* Frameworks */ = {
|
||||
isa = PBXFrameworksBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
B9B469CF2B9A82ED00AD5585 /* KeychainSwift in Frameworks */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
B9C20D062B921C78004DC9B3 /* Frameworks */ = {
|
||||
isa = PBXFrameworksBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
B9A80E912C67C7C300DE3D88 /* KeychainSwift in Frameworks */,
|
||||
B9C20D0D2B921C78004DC9B3 /* SwiftUI.framework in Frameworks */,
|
||||
B9C20D0B2B921C78004DC9B3 /* WidgetKit.framework in Frameworks */,
|
||||
B9C20D562B922DAC004DC9B3 /* KeychainSwift in Frameworks */,
|
||||
B9A80E8F2C67C7C300DE3D88 /* EmojiText in Frameworks */,
|
||||
B9A80E952C67C7C300DE3D88 /* RevenueCat in Frameworks */,
|
||||
B9A80E932C67C7C300DE3D88 /* ReceiptParser in Frameworks */,
|
||||
B9A80E8D2C67C7C300DE3D88 /* NukeVideo in Frameworks */,
|
||||
B9A80E852C67C7C300DE3D88 /* SwiftSoup in Frameworks */,
|
||||
B9A80E972C67C7C300DE3D88 /* RevenueCatUI in Frameworks */,
|
||||
B9A80E8B2C67C7C300DE3D88 /* NukeUI in Frameworks */,
|
||||
B9A80E872C67C7C300DE3D88 /* Nuke in Frameworks */,
|
||||
B9A80E892C67C7C300DE3D88 /* NukeExtensions in Frameworks */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
@ -377,29 +437,6 @@
|
||||
path = Content;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
B9B469B82B9A7E6800AD5585 /* ThreadedWatch */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
B9B469B92B9A7E6800AD5585 /* ThreadedWatchApp.swift */,
|
||||
B9B469BB2B9A7E6800AD5585 /* ContentView.swift */,
|
||||
B9B469D32B9A871C00AD5585 /* WatchConnectivity.swift */,
|
||||
B9B469D62B9A8B0700AD5585 /* GivenAccount.swift */,
|
||||
B9B469BD2B9A7E6B00AD5585 /* Assets.xcassets */,
|
||||
B9B469D22B9A838500AD5585 /* ThreadedWatch Watch App.entitlements */,
|
||||
B9B469BF2B9A7E6B00AD5585 /* Preview Content */,
|
||||
B9B469CC2B9A823600AD5585 /* Localizable.xcstrings */,
|
||||
);
|
||||
path = ThreadedWatch;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
B9B469BF2B9A7E6B00AD5585 /* Preview Content */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
B9B469C02B9A7E6B00AD5585 /* Preview Assets.xcassets */,
|
||||
);
|
||||
path = "Preview Content";
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
B9BED5142B5D5CCD00C9B715 /* Post */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
@ -422,10 +459,10 @@
|
||||
B9C20D0F2B921C78004DC9B3 /* ThreadedWidgetsBundle.swift */,
|
||||
B9C20D112B921C78004DC9B3 /* FollowCountWidget.swift */,
|
||||
B9B469AF2B9A275F00AD5585 /* FollowGoalWidget.swift */,
|
||||
B9A80DDD2C67BFF800DE3D88 /* CreatePostWidget.swift */,
|
||||
B98DD8D72C6821F7009F40DD /* CreatePostControl.swift */,
|
||||
B9C20D132B921C78004DC9B3 /* AppIntent.swift */,
|
||||
B9C20D602B949AD7004DC9B3 /* Redeclarations.swift */,
|
||||
B9C20D152B921C7B004DC9B3 /* Assets.xcassets */,
|
||||
B9C20D1E2B921E81004DC9B3 /* Localizable.xcstrings */,
|
||||
B9C20D172B921C7B004DC9B3 /* Info.plist */,
|
||||
);
|
||||
path = ThreadedWidgets;
|
||||
@ -454,7 +491,6 @@
|
||||
children = (
|
||||
B9CC45B92B40AA1E001E4FA5 /* README.md */,
|
||||
B9FB94592B2DEECE00D81C07 /* Threaded */,
|
||||
B9B469B82B9A7E6800AD5585 /* ThreadedWatch */,
|
||||
B9C20D0E2B921C78004DC9B3 /* ThreadedWidgets */,
|
||||
B9FB94AB2B2F009F00D81C07 /* AuthService */,
|
||||
B9FB94A82B2F009F00D81C07 /* Frameworks */,
|
||||
@ -470,7 +506,6 @@
|
||||
B9FB94572B2DEECE00D81C07 /* Threaded.app */,
|
||||
B9FB94A72B2F009F00D81C07 /* ThreadedAuthService.appex */,
|
||||
B9C20D092B921C78004DC9B3 /* ThreadedWidgetsExtension.appex */,
|
||||
B9B469B72B9A7E6800AD5585 /* Threaded.app */,
|
||||
);
|
||||
name = Products;
|
||||
sourceTree = "<group>";
|
||||
@ -510,6 +545,7 @@
|
||||
B93BCC3F2B5E38E5008EEA19 /* Content */,
|
||||
B9D9C6BF2B6A56D500C26A41 /* Notifications */,
|
||||
B9FB946F2B2DF3CD00D81C07 /* Navigator.swift */,
|
||||
B9A80DE12C67C38E00DE3D88 /* URLNavigator.swift */,
|
||||
B9FB94A12B2EF24A00D81C07 /* AppInfo.swift */,
|
||||
B9029FC32B8125CE00AA9B68 /* HuggingFace.swift */,
|
||||
B98BC74C2B46CFCE00595441 /* UserPreferences.swift */,
|
||||
@ -624,26 +660,6 @@
|
||||
/* End PBXGroup section */
|
||||
|
||||
/* Begin PBXNativeTarget section */
|
||||
B9B469B62B9A7E6800AD5585 /* ThreadedWatch Watch App */ = {
|
||||
isa = PBXNativeTarget;
|
||||
buildConfigurationList = B9B469C52B9A7E6B00AD5585 /* Build configuration list for PBXNativeTarget "ThreadedWatch Watch App" */;
|
||||
buildPhases = (
|
||||
B9B469B32B9A7E6800AD5585 /* Sources */,
|
||||
B9B469B42B9A7E6800AD5585 /* Frameworks */,
|
||||
B9B469B52B9A7E6800AD5585 /* Resources */,
|
||||
);
|
||||
buildRules = (
|
||||
);
|
||||
dependencies = (
|
||||
);
|
||||
name = "ThreadedWatch Watch App";
|
||||
packageProductDependencies = (
|
||||
B9B469CE2B9A82ED00AD5585 /* KeychainSwift */,
|
||||
);
|
||||
productName = "ThreadedWatch Watch App";
|
||||
productReference = B9B469B72B9A7E6800AD5585 /* Threaded.app */;
|
||||
productType = "com.apple.product-type.application";
|
||||
};
|
||||
B9C20D082B921C78004DC9B3 /* ThreadedWidgetsExtension */ = {
|
||||
isa = PBXNativeTarget;
|
||||
buildConfigurationList = B9C20D1D2B921C7B004DC9B3 /* Build configuration list for PBXNativeTarget "ThreadedWidgetsExtension" */;
|
||||
@ -658,7 +674,16 @@
|
||||
);
|
||||
name = ThreadedWidgetsExtension;
|
||||
packageProductDependencies = (
|
||||
B9C20D552B922DAC004DC9B3 /* KeychainSwift */,
|
||||
B9A80E842C67C7C300DE3D88 /* SwiftSoup */,
|
||||
B9A80E862C67C7C300DE3D88 /* Nuke */,
|
||||
B9A80E882C67C7C300DE3D88 /* NukeExtensions */,
|
||||
B9A80E8A2C67C7C300DE3D88 /* NukeUI */,
|
||||
B9A80E8C2C67C7C300DE3D88 /* NukeVideo */,
|
||||
B9A80E8E2C67C7C300DE3D88 /* EmojiText */,
|
||||
B9A80E902C67C7C300DE3D88 /* KeychainSwift */,
|
||||
B9A80E922C67C7C300DE3D88 /* ReceiptParser */,
|
||||
B9A80E942C67C7C300DE3D88 /* RevenueCat */,
|
||||
B9A80E962C67C7C300DE3D88 /* RevenueCatUI */,
|
||||
);
|
||||
productName = ThreadedWidgetsExtension;
|
||||
productReference = B9C20D092B921C78004DC9B3 /* ThreadedWidgetsExtension.appex */;
|
||||
@ -679,7 +704,6 @@
|
||||
dependencies = (
|
||||
B9FB94B32B2F009F00D81C07 /* PBXTargetDependency */,
|
||||
B9C20D192B921C7B004DC9B3 /* PBXTargetDependency */,
|
||||
B9B469C32B9A7E6B00AD5585 /* PBXTargetDependency */,
|
||||
);
|
||||
name = Threaded;
|
||||
packageProductDependencies = (
|
||||
@ -724,9 +748,6 @@
|
||||
LastSwiftUpdateCheck = 1600;
|
||||
LastUpgradeCheck = 1510;
|
||||
TargetAttributes = {
|
||||
B9B469B62B9A7E6800AD5585 = {
|
||||
CreatedOnToolsVersion = 15.3;
|
||||
};
|
||||
B9C20D082B921C78004DC9B3 = {
|
||||
CreatedOnToolsVersion = 15.2;
|
||||
};
|
||||
@ -760,7 +781,6 @@
|
||||
projectRoot = "";
|
||||
targets = (
|
||||
B9FB94562B2DEECE00D81C07 /* Threaded */,
|
||||
B9B469B62B9A7E6800AD5585 /* ThreadedWatch Watch App */,
|
||||
B9C20D082B921C78004DC9B3 /* ThreadedWidgetsExtension */,
|
||||
B9FB94A62B2F009F00D81C07 /* ThreadedAuthService */,
|
||||
);
|
||||
@ -768,21 +788,11 @@
|
||||
/* End PBXProject section */
|
||||
|
||||
/* Begin PBXResourcesBuildPhase section */
|
||||
B9B469B52B9A7E6800AD5585 /* Resources */ = {
|
||||
isa = PBXResourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
B9B469C12B9A7E6B00AD5585 /* Preview Assets.xcassets in Resources */,
|
||||
B9B469BE2B9A7E6B00AD5585 /* Assets.xcassets in Resources */,
|
||||
B9B469CD2B9A823600AD5585 /* Localizable.xcstrings in Resources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
B9C20D072B921C78004DC9B3 /* Resources */ = {
|
||||
isa = PBXResourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
B9C20D1F2B921E81004DC9B3 /* Localizable.xcstrings in Resources */,
|
||||
B98DD8D62C681FDA009F40DD /* Localizable.xcstrings in Resources */,
|
||||
B9C20D162B921C7B004DC9B3 /* Assets.xcassets in Resources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
@ -814,34 +824,94 @@
|
||||
/* End PBXResourcesBuildPhase section */
|
||||
|
||||
/* Begin PBXSourcesBuildPhase section */
|
||||
B9B469B32B9A7E6800AD5585 /* Sources */ = {
|
||||
isa = PBXSourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
B9B469D72B9A8B0700AD5585 /* GivenAccount.swift in Sources */,
|
||||
B9B469D52B9A871C00AD5585 /* WatchConnectivity.swift in Sources */,
|
||||
B9B469C92B9A804800AD5585 /* Redeclarations.swift in Sources */,
|
||||
B9B469CB2B9A816D00AD5585 /* LoggedAccounts.swift in Sources */,
|
||||
B9B469CA2B9A811200AD5585 /* AppInfo.swift in Sources */,
|
||||
B9B469BC2B9A7E6800AD5585 /* ContentView.swift in Sources */,
|
||||
B9B469D92B9AA4DF00AD5585 /* Client.swift in Sources */,
|
||||
B9B469BA2B9A7E6800AD5585 /* ThreadedWatchApp.swift in Sources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
B9C20D052B921C78004DC9B3 /* Sources */ = {
|
||||
isa = PBXSourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
B9C20D282B9229DF004DC9B3 /* LoggedAccounts.swift in Sources */,
|
||||
B9C20D612B949AD7004DC9B3 /* Redeclarations.swift in Sources */,
|
||||
B9C20D122B921C78004DC9B3 /* FollowCountWidget.swift in Sources */,
|
||||
B9A80DDE2C67BFF800DE3D88 /* CreatePostWidget.swift in Sources */,
|
||||
B9C20D102B921C78004DC9B3 /* ThreadedWidgetsBundle.swift in Sources */,
|
||||
B9A80DE02C67C2D000DE3D88 /* Navigator.swift in Sources */,
|
||||
B9C20D142B921C78004DC9B3 /* AppIntent.swift in Sources */,
|
||||
B9C20D372B9229EC004DC9B3 /* AppInfo.swift in Sources */,
|
||||
B9A80DF02C67C40900DE3D88 /* SearchResults.swift in Sources */,
|
||||
B9A80DF12C67C40900DE3D88 /* ContentFilter.swift in Sources */,
|
||||
B9A80E232C67C4B700DE3D88 /* AttachmentView.swift in Sources */,
|
||||
B9A80E242C67C4B700DE3D88 /* SettingsView.swift in Sources */,
|
||||
B9A80E252C67C4B700DE3D88 /* ConnectView.swift in Sources */,
|
||||
B9A80E262C67C4B700DE3D88 /* PostingView.swift in Sources */,
|
||||
B9A80E272C67C4B700DE3D88 /* PostDetailsView.swift in Sources */,
|
||||
B9A80E282C67C4B700DE3D88 /* IconView.swift in Sources */,
|
||||
B9A80E292C67C4B700DE3D88 /* UpdateView.swift in Sources */,
|
||||
B9A80E2A2C67C4B700DE3D88 /* ReportStatusView.swift in Sources */,
|
||||
B9A80E2B2C67C4B700DE3D88 /* PrivacyView.swift in Sources */,
|
||||
B9A80E2C2C67C4B700DE3D88 /* SafariView.swift in Sources */,
|
||||
B9A80E2D2C67C4B700DE3D88 /* FilterView.swift in Sources */,
|
||||
B9A80E2E2C67C4B700DE3D88 /* AppearenceView.swift in Sources */,
|
||||
B9A80E2F2C67C4B700DE3D88 /* ContactsView.swift in Sources */,
|
||||
B9A80E302C67C4B700DE3D88 /* PostsView.swift in Sources */,
|
||||
B9A80E312C67C4B700DE3D88 /* NotificationsView.swift in Sources */,
|
||||
B9A80E322C67C4B700DE3D88 /* EditProfileView.swift in Sources */,
|
||||
B9A80E332C67C4B700DE3D88 /* ContentView.swift in Sources */,
|
||||
B9A80E342C67C4B700DE3D88 /* DiscoveryView.swift in Sources */,
|
||||
B9A80E352C67C4B700DE3D88 /* AccountView.swift in Sources */,
|
||||
B9A80E362C67C4B700DE3D88 /* SupportView.swift in Sources */,
|
||||
B9A80E372C67C4B700DE3D88 /* AddInstanceView.swift in Sources */,
|
||||
B9A80E382C67C4B700DE3D88 /* ShopView.swift in Sources */,
|
||||
B9A80E392C67C4B700DE3D88 /* AboutView.swift in Sources */,
|
||||
B9A80E3A2C67C4B700DE3D88 /* RestrictedView.swift in Sources */,
|
||||
B9A80E3B2C67C4B700DE3D88 /* TimelineView.swift in Sources */,
|
||||
B9A80E3C2C67C4B700DE3D88 /* ProfileView.swift in Sources */,
|
||||
B9A80E0A2C67C48D00DE3D88 /* AppDelegate.swift in Sources */,
|
||||
B9A80DF22C67C40900DE3D88 /* FetchTimeline.swift in Sources */,
|
||||
B9A80DF32C67C40900DE3D88 /* HTMLString.swift in Sources */,
|
||||
B9A80DF42C67C40900DE3D88 /* TimelineFilter.swift in Sources */,
|
||||
B9A80DF52C67C40900DE3D88 /* Tenor.swift in Sources */,
|
||||
B9A80DF62C67C40900DE3D88 /* Tag.swift in Sources */,
|
||||
B9A80DF72C67C40900DE3D88 /* MediaTransferables.swift in Sources */,
|
||||
B9A80DF82C67C40900DE3D88 /* Compressor.swift in Sources */,
|
||||
B9A80DF92C67C40900DE3D88 /* Status.swift in Sources */,
|
||||
B9C20D3D2B9229EC004DC9B3 /* Emoji.swift in Sources */,
|
||||
B9B469B02B9A275F00AD5585 /* FollowGoalWidget.swift in Sources */,
|
||||
B9C20D342B9229EC004DC9B3 /* Client.swift in Sources */,
|
||||
B9A80DFA2C67C40E00DE3D88 /* URLNavigator.swift in Sources */,
|
||||
B9A80DFB2C67C40E00DE3D88 /* AltClients.swift in Sources */,
|
||||
B9A80DFC2C67C40E00DE3D88 /* MastodonRequest.swift in Sources */,
|
||||
B9A80DFD2C67C40E00DE3D88 /* UserPreferences.swift in Sources */,
|
||||
B9A80E0B2C67C4A600DE3D88 /* AccountRow.swift in Sources */,
|
||||
B9A80E0C2C67C4A600DE3D88 /* ComingSoonView.swift in Sources */,
|
||||
B9A80E0D2C67C4A600DE3D88 /* OnlineImage.swift in Sources */,
|
||||
B98DD8D92C6821F7009F40DD /* CreatePostControl.swift in Sources */,
|
||||
B9A80E0E2C67C4A600DE3D88 /* DynamicTextEditor.swift in Sources */,
|
||||
B9A80E6F2C67C62800DE3D88 /* Message.swift in Sources */,
|
||||
B9A80E0F2C67C4A600DE3D88 /* ContactRow.swift in Sources */,
|
||||
B9A80E1B2C67C4AE00DE3D88 /* PostCardView.swift in Sources */,
|
||||
B9A80E1C2C67C4AE00DE3D88 /* CompactPostView.swift in Sources */,
|
||||
B9A80E1D2C67C4AE00DE3D88 /* PostMenu.swift in Sources */,
|
||||
B9A80E1E2C67C4AE00DE3D88 /* PostInteractor.swift in Sources */,
|
||||
B9A80E1F2C67C4AE00DE3D88 /* EmojiSelector.swift in Sources */,
|
||||
B9A80E202C67C4AE00DE3D88 /* PostPoll.swift in Sources */,
|
||||
B9A80E212C67C4AE00DE3D88 /* PostAttachment.swift in Sources */,
|
||||
B9A80E222C67C4AE00DE3D88 /* QuotePostView.swift in Sources */,
|
||||
B9A80E102C67C4A600DE3D88 /* WarningView.swift in Sources */,
|
||||
B9A80E112C67C4A600DE3D88 /* ThreadedStyle.swift in Sources */,
|
||||
B9A80E122C67C4A600DE3D88 /* NotificationRow.swift in Sources */,
|
||||
B9A80E132C67C4A600DE3D88 /* TextEmoji.swift in Sources */,
|
||||
B9A80E142C67C4A600DE3D88 /* SearchResultView.swift in Sources */,
|
||||
B9A80E152C67C4A600DE3D88 /* SymbolWidth.swift in Sources */,
|
||||
B9A80E162C67C4A600DE3D88 /* TabsView.swift in Sources */,
|
||||
B9A80E172C67C4A600DE3D88 /* ShareSheetController.swift in Sources */,
|
||||
B9A80E182C67C4A600DE3D88 /* ButtonStyles.swift in Sources */,
|
||||
B9A80E192C67C4A600DE3D88 /* ProfilePicture.swift in Sources */,
|
||||
B9A80E1A2C67C4A600DE3D88 /* MailView.swift in Sources */,
|
||||
B9A80E6D2C67C61E00DE3D88 /* Notification.swift in Sources */,
|
||||
B9A80DFF2C67C40E00DE3D88 /* HapticManager.swift in Sources */,
|
||||
B9A80E002C67C40E00DE3D88 /* Instance.swift in Sources */,
|
||||
B9A80DE72C67C3FC00DE3D88 /* Account+Elms.swift in Sources */,
|
||||
B9A80DE82C67C3FC00DE3D88 /* Account.swift in Sources */,
|
||||
B9A80DE92C67C3FC00DE3D88 /* LoggedAccounts.swift in Sources */,
|
||||
B9A80DEA2C67C3FC00DE3D88 /* AccountManager.swift in Sources */,
|
||||
B9A80DEB2C67C3FC00DE3D88 /* AccountsList.swift in Sources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
@ -856,6 +926,7 @@
|
||||
B98F47962B645DF40092000F /* EmojiSelector.swift in Sources */,
|
||||
B9B469B22B9A6E8300AD5585 /* PrivacyView.swift in Sources */,
|
||||
B9FB94882B2E223E00D81C07 /* Emoji.swift in Sources */,
|
||||
B9A80DE22C67C38E00DE3D88 /* URLNavigator.swift in Sources */,
|
||||
B93B67782B42E8F0000892E9 /* TextEmoji.swift in Sources */,
|
||||
B9FB94762B2E023D00D81C07 /* TabsView.swift in Sources */,
|
||||
B9FB947D2B2E19E300D81C07 /* AccountManager.swift in Sources */,
|
||||
@ -875,7 +946,6 @@
|
||||
B9FB94972B2EDABF00D81C07 /* SupportView.swift in Sources */,
|
||||
B9F8FA162B5D3AC30044DAB4 /* SafariView.swift in Sources */,
|
||||
B97798892B853E6600DC869F /* UpdateView.swift in Sources */,
|
||||
B9B469D82B9A8B1600AD5585 /* GivenAccount.swift in Sources */,
|
||||
B9842C142B2F310C00D9F3C1 /* FetchTimeline.swift in Sources */,
|
||||
B9842C162B2F363600D9F3C1 /* TimelineFilter.swift in Sources */,
|
||||
B9B63B232B447B8000BBC82D /* PostCardView.swift in Sources */,
|
||||
@ -884,12 +954,14 @@
|
||||
B93ADFCB2B7625CD00FF9172 /* DiscoveryView.swift in Sources */,
|
||||
B9D9C6C72B6A590F00C26A41 /* ProfilePicture.swift in Sources */,
|
||||
B9842C102B2F228C00D9F3C1 /* Status.swift in Sources */,
|
||||
B98DD8D82C6821F7009F40DD /* CreatePostControl.swift in Sources */,
|
||||
B9D9C6C32B6A576C00C26A41 /* NotificationsView.swift in Sources */,
|
||||
B9FA6E772B82788A00D63E30 /* AccountRow.swift in Sources */,
|
||||
B934EA242BAB5E7F001F4345 /* RestrictedView.swift in Sources */,
|
||||
B9FB94722B2DF49700D81C07 /* ConnectView.swift in Sources */,
|
||||
B9FB945B2B2DEECE00D81C07 /* ThreadedApp.swift in Sources */,
|
||||
B9FB94862B2E211200D81C07 /* Account+Elms.swift in Sources */,
|
||||
B9A80DDF2C67C27B00DE3D88 /* AppIntent.swift in Sources */,
|
||||
B97491E32B6E96700098BC48 /* SymbolWidth.swift in Sources */,
|
||||
B9FB94BC2B2F035500D81C07 /* Tag.swift in Sources */,
|
||||
B9029FC42B8125CE00AA9B68 /* HuggingFace.swift in Sources */,
|
||||
@ -902,13 +974,15 @@
|
||||
B9FB94812B2E1FEF00D81C07 /* HTMLString.swift in Sources */,
|
||||
B9FB947F2B2E1D5F00D81C07 /* Account.swift in Sources */,
|
||||
B9842C122B2F2A5800D9F3C1 /* TimelineView.swift in Sources */,
|
||||
B9B469D42B9A871C00AD5585 /* WatchConnectivity.swift in Sources */,
|
||||
B9FB948C2B2E232300D81C07 /* OnlineImage.swift in Sources */,
|
||||
B9BED5182B5D649C00C9B715 /* PostMenu.swift in Sources */,
|
||||
B9FB94742B2DF6A100D81C07 /* ButtonStyles.swift in Sources */,
|
||||
B999DE5E2B76F9D100509868 /* Message.swift in Sources */,
|
||||
B915C4422B6F908C00042DDB /* ProfileView.swift in Sources */,
|
||||
B9FB94702B2DF3CD00D81C07 /* Navigator.swift in Sources */,
|
||||
B9A80E9A2C67D56900DE3D88 /* FollowCountWidget.swift in Sources */,
|
||||
B9A80E9B2C67D56900DE3D88 /* FollowGoalWidget.swift in Sources */,
|
||||
B9A80E9C2C67D56900DE3D88 /* CreatePostWidget.swift in Sources */,
|
||||
B9C7F46C2C387D3B009C36DC /* WarningView.swift in Sources */,
|
||||
B9EBE8562B47256900FB594D /* PostAttachment.swift in Sources */,
|
||||
B9EBE8582B474FD600FB594D /* AppDelegate.swift in Sources */,
|
||||
@ -944,11 +1018,6 @@
|
||||
/* End PBXSourcesBuildPhase section */
|
||||
|
||||
/* Begin PBXTargetDependency section */
|
||||
B9B469C32B9A7E6B00AD5585 /* PBXTargetDependency */ = {
|
||||
isa = PBXTargetDependency;
|
||||
target = B9B469B62B9A7E6800AD5585 /* ThreadedWatch Watch App */;
|
||||
targetProxy = B9B469C22B9A7E6B00AD5585 /* PBXContainerItemProxy */;
|
||||
};
|
||||
B9C20D192B921C7B004DC9B3 /* PBXTargetDependency */ = {
|
||||
isa = PBXTargetDependency;
|
||||
target = B9C20D082B921C78004DC9B3 /* ThreadedWidgetsExtension */;
|
||||
@ -973,68 +1042,6 @@
|
||||
/* End PBXVariantGroup section */
|
||||
|
||||
/* Begin XCBuildConfiguration section */
|
||||
B9B469C62B9A7E6B00AD5585 /* Debug */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||
ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
|
||||
CODE_SIGN_ENTITLEMENTS = "ThreadedWatch/ThreadedWatch Watch App.entitlements";
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
CURRENT_PROJECT_VERSION = 1;
|
||||
DEVELOPMENT_ASSET_PATHS = "\"ThreadedWatch/Preview Content\"";
|
||||
DEVELOPMENT_TEAM = HB5P3BML86;
|
||||
ENABLE_PREVIEWS = YES;
|
||||
GENERATE_INFOPLIST_FILE = YES;
|
||||
INFOPLIST_KEY_CFBundleDisplayName = Threaded;
|
||||
INFOPLIST_KEY_UISupportedInterfaceOrientations = "UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown";
|
||||
INFOPLIST_KEY_WKCompanionAppBundleIdentifier = fr.lumaa.Threaded;
|
||||
LD_RUNPATH_SEARCH_PATHS = (
|
||||
"$(inherited)",
|
||||
"@executable_path/Frameworks",
|
||||
);
|
||||
MARKETING_VERSION = 1.2.0;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = fr.lumaa.Threaded.watchkitapp;
|
||||
PRODUCT_NAME = Threaded;
|
||||
SDKROOT = watchos;
|
||||
SKIP_INSTALL = YES;
|
||||
SWIFT_EMIT_LOC_STRINGS = YES;
|
||||
SWIFT_VERSION = 5.0;
|
||||
TARGETED_DEVICE_FAMILY = 4;
|
||||
WATCHOS_DEPLOYMENT_TARGET = 10.0;
|
||||
};
|
||||
name = Debug;
|
||||
};
|
||||
B9B469C72B9A7E6B00AD5585 /* Release */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||
ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
|
||||
CODE_SIGN_ENTITLEMENTS = "ThreadedWatch/ThreadedWatch Watch App.entitlements";
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
CURRENT_PROJECT_VERSION = 1;
|
||||
DEVELOPMENT_ASSET_PATHS = "\"ThreadedWatch/Preview Content\"";
|
||||
DEVELOPMENT_TEAM = HB5P3BML86;
|
||||
ENABLE_PREVIEWS = YES;
|
||||
GENERATE_INFOPLIST_FILE = YES;
|
||||
INFOPLIST_KEY_CFBundleDisplayName = Threaded;
|
||||
INFOPLIST_KEY_UISupportedInterfaceOrientations = "UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown";
|
||||
INFOPLIST_KEY_WKCompanionAppBundleIdentifier = fr.lumaa.Threaded;
|
||||
LD_RUNPATH_SEARCH_PATHS = (
|
||||
"$(inherited)",
|
||||
"@executable_path/Frameworks",
|
||||
);
|
||||
MARKETING_VERSION = 1.2.0;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = fr.lumaa.Threaded.watchkitapp;
|
||||
PRODUCT_NAME = Threaded;
|
||||
SDKROOT = watchos;
|
||||
SKIP_INSTALL = YES;
|
||||
SWIFT_EMIT_LOC_STRINGS = YES;
|
||||
SWIFT_VERSION = 5.0;
|
||||
TARGETED_DEVICE_FAMILY = 4;
|
||||
WATCHOS_DEPLOYMENT_TARGET = 10.0;
|
||||
};
|
||||
name = Release;
|
||||
};
|
||||
B9C20D1B2B921C7B004DC9B3 /* Debug */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
@ -1058,13 +1065,13 @@
|
||||
PRODUCT_BUNDLE_IDENTIFIER = fr.lumaa.Threaded.ThreadedWidgets;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SKIP_INSTALL = YES;
|
||||
SUPPORTED_PLATFORMS = "iphoneos iphonesimulator watchos watchsimulator";
|
||||
SUPPORTED_PLATFORMS = "iphoneos iphonesimulator";
|
||||
SUPPORTS_MACCATALYST = NO;
|
||||
SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD = NO;
|
||||
SUPPORTS_XR_DESIGNED_FOR_IPHONE_IPAD = NO;
|
||||
SWIFT_EMIT_LOC_STRINGS = YES;
|
||||
SWIFT_VERSION = 5.0;
|
||||
TARGETED_DEVICE_FAMILY = "1,4";
|
||||
TARGETED_DEVICE_FAMILY = 1;
|
||||
WATCHOS_DEPLOYMENT_TARGET = 10.0;
|
||||
};
|
||||
name = Debug;
|
||||
@ -1092,13 +1099,13 @@
|
||||
PRODUCT_BUNDLE_IDENTIFIER = fr.lumaa.Threaded.ThreadedWidgets;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SKIP_INSTALL = YES;
|
||||
SUPPORTED_PLATFORMS = "iphoneos iphonesimulator watchos watchsimulator";
|
||||
SUPPORTED_PLATFORMS = "iphoneos iphonesimulator";
|
||||
SUPPORTS_MACCATALYST = NO;
|
||||
SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD = NO;
|
||||
SUPPORTS_XR_DESIGNED_FOR_IPHONE_IPAD = NO;
|
||||
SWIFT_EMIT_LOC_STRINGS = YES;
|
||||
SWIFT_VERSION = 5.0;
|
||||
TARGETED_DEVICE_FAMILY = "1,4";
|
||||
TARGETED_DEVICE_FAMILY = 1;
|
||||
WATCHOS_DEPLOYMENT_TARGET = 10.0;
|
||||
};
|
||||
name = Release;
|
||||
@ -1163,6 +1170,7 @@
|
||||
ONLY_ACTIVE_ARCH = YES;
|
||||
SDKROOT = iphoneos;
|
||||
SWIFT_ACTIVE_COMPILATION_CONDITIONS = "DEBUG $(inherited)";
|
||||
SWIFT_EMIT_LOC_STRINGS = YES;
|
||||
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
|
||||
WATCHOS_DEPLOYMENT_TARGET = 10.0;
|
||||
};
|
||||
@ -1221,6 +1229,7 @@
|
||||
MTL_FAST_MATH = YES;
|
||||
SDKROOT = iphoneos;
|
||||
SWIFT_COMPILATION_MODE = wholemodule;
|
||||
SWIFT_EMIT_LOC_STRINGS = YES;
|
||||
VALIDATE_PRODUCT = YES;
|
||||
WATCHOS_DEPLOYMENT_TARGET = 10.0;
|
||||
};
|
||||
@ -1373,15 +1382,6 @@
|
||||
/* End XCBuildConfiguration section */
|
||||
|
||||
/* Begin XCConfigurationList section */
|
||||
B9B469C52B9A7E6B00AD5585 /* Build configuration list for PBXNativeTarget "ThreadedWatch Watch App" */ = {
|
||||
isa = XCConfigurationList;
|
||||
buildConfigurations = (
|
||||
B9B469C62B9A7E6B00AD5585 /* Debug */,
|
||||
B9B469C72B9A7E6B00AD5585 /* Release */,
|
||||
);
|
||||
defaultConfigurationIsVisible = 0;
|
||||
defaultConfigurationName = Release;
|
||||
};
|
||||
B9C20D1D2B921C7B004DC9B3 /* Build configuration list for PBXNativeTarget "ThreadedWidgetsExtension" */ = {
|
||||
isa = XCConfigurationList;
|
||||
buildConfigurations = (
|
||||
@ -1499,21 +1499,61 @@
|
||||
package = B95ED2312B8707D60055F5BD /* XCRemoteSwiftPackageReference "purchases-ios" */;
|
||||
productName = RevenueCatUI;
|
||||
};
|
||||
B9B469CE2B9A82ED00AD5585 /* KeychainSwift */ = {
|
||||
B9A80E842C67C7C300DE3D88 /* SwiftSoup */ = {
|
||||
isa = XCSwiftPackageProductDependency;
|
||||
package = B9FB94822B2E20AF00D81C07 /* XCRemoteSwiftPackageReference "SwiftSoup" */;
|
||||
productName = SwiftSoup;
|
||||
};
|
||||
B9A80E862C67C7C300DE3D88 /* Nuke */ = {
|
||||
isa = XCSwiftPackageProductDependency;
|
||||
package = B93B676B2B42C94F000892E9 /* XCRemoteSwiftPackageReference "Nuke" */;
|
||||
productName = Nuke;
|
||||
};
|
||||
B9A80E882C67C7C300DE3D88 /* NukeExtensions */ = {
|
||||
isa = XCSwiftPackageProductDependency;
|
||||
package = B93B676B2B42C94F000892E9 /* XCRemoteSwiftPackageReference "Nuke" */;
|
||||
productName = NukeExtensions;
|
||||
};
|
||||
B9A80E8A2C67C7C300DE3D88 /* NukeUI */ = {
|
||||
isa = XCSwiftPackageProductDependency;
|
||||
package = B93B676B2B42C94F000892E9 /* XCRemoteSwiftPackageReference "Nuke" */;
|
||||
productName = NukeUI;
|
||||
};
|
||||
B9A80E8C2C67C7C300DE3D88 /* NukeVideo */ = {
|
||||
isa = XCSwiftPackageProductDependency;
|
||||
package = B93B676B2B42C94F000892E9 /* XCRemoteSwiftPackageReference "Nuke" */;
|
||||
productName = NukeVideo;
|
||||
};
|
||||
B9A80E8E2C67C7C300DE3D88 /* EmojiText */ = {
|
||||
isa = XCSwiftPackageProductDependency;
|
||||
package = B93B67742B42E8AB000892E9 /* XCRemoteSwiftPackageReference "EmojiText" */;
|
||||
productName = EmojiText;
|
||||
};
|
||||
B9A80E902C67C7C300DE3D88 /* KeychainSwift */ = {
|
||||
isa = XCSwiftPackageProductDependency;
|
||||
package = B9BF54052B6B6823004B24E7 /* XCRemoteSwiftPackageReference "keychain-swift" */;
|
||||
productName = KeychainSwift;
|
||||
};
|
||||
B9A80E922C67C7C300DE3D88 /* ReceiptParser */ = {
|
||||
isa = XCSwiftPackageProductDependency;
|
||||
package = B95ED2312B8707D60055F5BD /* XCRemoteSwiftPackageReference "purchases-ios" */;
|
||||
productName = ReceiptParser;
|
||||
};
|
||||
B9A80E942C67C7C300DE3D88 /* RevenueCat */ = {
|
||||
isa = XCSwiftPackageProductDependency;
|
||||
package = B95ED2312B8707D60055F5BD /* XCRemoteSwiftPackageReference "purchases-ios" */;
|
||||
productName = RevenueCat;
|
||||
};
|
||||
B9A80E962C67C7C300DE3D88 /* RevenueCatUI */ = {
|
||||
isa = XCSwiftPackageProductDependency;
|
||||
package = B95ED2312B8707D60055F5BD /* XCRemoteSwiftPackageReference "purchases-ios" */;
|
||||
productName = RevenueCatUI;
|
||||
};
|
||||
B9BF54062B6B6823004B24E7 /* KeychainSwift */ = {
|
||||
isa = XCSwiftPackageProductDependency;
|
||||
package = B9BF54052B6B6823004B24E7 /* XCRemoteSwiftPackageReference "keychain-swift" */;
|
||||
productName = KeychainSwift;
|
||||
};
|
||||
B9C20D552B922DAC004DC9B3 /* KeychainSwift */ = {
|
||||
isa = XCSwiftPackageProductDependency;
|
||||
package = B9BF54052B6B6823004B24E7 /* XCRemoteSwiftPackageReference "keychain-swift" */;
|
||||
productName = KeychainSwift;
|
||||
};
|
||||
B9FB94832B2E20AF00D81C07 /* SwiftSoup */ = {
|
||||
isa = XCSwiftPackageProductDependency;
|
||||
package = B9FB94822B2E20AF00D81C07 /* XCRemoteSwiftPackageReference "SwiftSoup" */;
|
||||
|
@ -85,6 +85,15 @@
|
||||
ReferencedContainer = "container:Threaded.xcodeproj">
|
||||
</BuildableReference>
|
||||
</BuildableProductRunnable>
|
||||
<MacroExpansion>
|
||||
<BuildableReference
|
||||
BuildableIdentifier = "primary"
|
||||
BlueprintIdentifier = "B9B469B62B9A7E6800AD5585"
|
||||
BuildableName = "Threaded.app"
|
||||
BlueprintName = "ThreadedWatch Watch App"
|
||||
ReferencedContainer = "container:Threaded.xcodeproj">
|
||||
</BuildableReference>
|
||||
</MacroExpansion>
|
||||
</ProfileAction>
|
||||
<AnalyzeAction
|
||||
buildConfiguration = "Debug">
|
||||
|
@ -34,5 +34,8 @@
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
},
|
||||
"properties" : {
|
||||
"localizable" : true
|
||||
}
|
||||
}
|
||||
|
@ -48,8 +48,8 @@ struct PostCardView: View {
|
||||
.stroke(.gray.opacity(0.3), lineWidth: 1)
|
||||
)
|
||||
.onTapGesture {
|
||||
if UIApplication.shared.canOpenURL(URL(string: card.url)!) {
|
||||
openURL(URL(string: card.url)!)
|
||||
if let url = URL(string: card.url) {
|
||||
openURL(url)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -3,15 +3,19 @@
|
||||
import SwiftUI
|
||||
|
||||
struct TabsView: View {
|
||||
@Binding var selectedTab: TabDestination
|
||||
|
||||
@State var selectedTab: TabDestination = Navigator.shared.selectedTab
|
||||
|
||||
var canTap: Binding<Bool> = .constant(true)
|
||||
|
||||
var postButton: () -> Void = {}
|
||||
var tapAction: () -> Void = {}
|
||||
var retapAction: () -> Void = {}
|
||||
|
||||
|
||||
var body: some View {
|
||||
HStack(alignment: .center) {
|
||||
Button {
|
||||
guard canTap.wrappedValue else { return }
|
||||
|
||||
if selectedTab == .timeline {
|
||||
retapAction()
|
||||
} else {
|
||||
@ -25,11 +29,14 @@ struct TabsView: View {
|
||||
Tabs.timeline.image
|
||||
}
|
||||
}
|
||||
.disabled(!canTap.wrappedValue)
|
||||
.buttonStyle(NoTapAnimationStyle())
|
||||
|
||||
Spacer()
|
||||
|
||||
Button {
|
||||
guard canTap.wrappedValue else { return }
|
||||
|
||||
if selectedTab == .search {
|
||||
retapAction()
|
||||
} else {
|
||||
@ -43,20 +50,26 @@ struct TabsView: View {
|
||||
Tabs.search.image
|
||||
}
|
||||
}
|
||||
.disabled(!canTap.wrappedValue)
|
||||
.buttonStyle(NoTapAnimationStyle())
|
||||
|
||||
Spacer()
|
||||
|
||||
Button {
|
||||
guard canTap.wrappedValue else { return }
|
||||
|
||||
postButton()
|
||||
} label: {
|
||||
Tabs.post.image
|
||||
}
|
||||
.disabled(!canTap.wrappedValue)
|
||||
.buttonStyle(NoTapAnimationStyle())
|
||||
|
||||
Spacer()
|
||||
|
||||
Button {
|
||||
guard canTap.wrappedValue else { return }
|
||||
|
||||
if selectedTab == .activity {
|
||||
retapAction()
|
||||
} else {
|
||||
@ -70,11 +83,14 @@ struct TabsView: View {
|
||||
Tabs.activity.image
|
||||
}
|
||||
}
|
||||
.disabled(!canTap.wrappedValue)
|
||||
.buttonStyle(NoTapAnimationStyle())
|
||||
|
||||
Spacer()
|
||||
|
||||
Button {
|
||||
guard canTap.wrappedValue else { return }
|
||||
|
||||
if selectedTab == .profile {
|
||||
retapAction()
|
||||
} else {
|
||||
@ -88,10 +104,14 @@ struct TabsView: View {
|
||||
Tabs.profile.image
|
||||
}
|
||||
}
|
||||
.disabled(!canTap.wrappedValue)
|
||||
.buttonStyle(NoTapAnimationStyle())
|
||||
}
|
||||
.padding(.horizontal, 30)
|
||||
.background(Color.appBackground)
|
||||
.onChange(of: selectedTab) { _, newValue in
|
||||
Navigator.shared.selectedTab = newValue
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2,6 +2,7 @@
|
||||
|
||||
import Foundation
|
||||
|
||||
/// Mastodon visibility strings
|
||||
public enum Visibility: String, Codable, CaseIterable, Hashable, Equatable, Sendable {
|
||||
case pub = "public"
|
||||
case unlisted
|
||||
|
@ -9,3 +9,7 @@ public enum AppInfo {
|
||||
public static let defaultServer = "mastodon.social"
|
||||
public static let website = "https://apps.lumaa.fr/app/threaded"
|
||||
}
|
||||
|
||||
extension AppInfo {
|
||||
static var appVersion = Bundle.main.infoDictionary?["CFBundleShortVersionString"] as? String ?? "Unknown"
|
||||
}
|
||||
|
@ -275,3 +275,9 @@ public final class Client: Equatable, Identifiable, Hashable {
|
||||
}
|
||||
|
||||
extension Client: Sendable {}
|
||||
|
||||
extension CGFloat {
|
||||
static func getFontSize(from font: UIFont.TextStyle) -> CGFloat {
|
||||
return UIFont.preferredFont(forTextStyle: font).pointSize
|
||||
}
|
||||
}
|
||||
|
@ -5,74 +5,80 @@ import SwiftUI
|
||||
|
||||
@Observable
|
||||
public class Navigator: ObservableObject {
|
||||
public static var shared: Navigator = Navigator()
|
||||
|
||||
public var path: [RouterDestination] = []
|
||||
public var presentedSheet: SheetDestination?
|
||||
public var presentedCover: SheetDestination?
|
||||
public var selectedTab: TabDestination = .timeline
|
||||
|
||||
public var selectedTab: TabDestination {
|
||||
set {
|
||||
change(to: newValue)
|
||||
}
|
||||
get {
|
||||
return self.currentTab
|
||||
}
|
||||
}
|
||||
private var currentTab: TabDestination = .timeline
|
||||
|
||||
public var inSettings: Bool {
|
||||
self.path.contains(RouterDestination.allSettings)
|
||||
}
|
||||
|
||||
public private(set) var memorizedNav: [TabDestination : [RouterDestination]] = [:]
|
||||
public var showTabbar: Bool {
|
||||
get {
|
||||
self.visiTabbar
|
||||
}
|
||||
set {
|
||||
withAnimation(.spring) {
|
||||
self.visiTabbar = newValue
|
||||
}
|
||||
}
|
||||
}
|
||||
private var visiTabbar: Bool = true
|
||||
|
||||
public var client: Client?
|
||||
|
||||
public func navigate(to: RouterDestination) {
|
||||
path.append(to)
|
||||
}
|
||||
|
||||
public func handle(url: URL) -> OpenURLAction.Result {
|
||||
guard let client = self.client else { return .systemAction }
|
||||
let path: String = url.absoluteString.replacingOccurrences(of: AppInfo.scheme, with: "") // remove all path
|
||||
let urlPath: URL = URL(string: path)!
|
||||
|
||||
let server: String = urlPath.host() ?? client.server
|
||||
let lastIndex = urlPath.pathComponents.count - 1
|
||||
|
||||
let actionType = urlPath.pathComponents[lastIndex - 1]
|
||||
|
||||
if client.isAuth && client.hasConnection(with: url) {
|
||||
if urlPath.lastPathComponent.starts(with: "@") {
|
||||
Task {
|
||||
do {
|
||||
print("\(urlPath.lastPathComponent)@\(server.replacingOccurrences(of: "www.", with: ""))")
|
||||
let search: SearchResults = try await client.get(endpoint: Search.search(query: "\(urlPath.lastPathComponent)@\(server.replacingOccurrences(of: "www.", with: ""))", type: "accounts", offset: nil, following: nil), forceVersion: .v2)
|
||||
print(search)
|
||||
let acc: Account = search.accounts.first ?? .placeholder()
|
||||
self.navigate(to: .account(acc: acc))
|
||||
} catch {
|
||||
print(error)
|
||||
}
|
||||
}
|
||||
return OpenURLAction.Result.handled
|
||||
} else {
|
||||
self.presentedSheet = .safari(url: url)
|
||||
}
|
||||
} else {
|
||||
Task {
|
||||
do {
|
||||
let connections: [String] = try await client.get(endpoint: Instances.peers)
|
||||
client.addConnections(connections)
|
||||
|
||||
|
||||
if client.hasConnection(with: url) {
|
||||
_ = self.handle(url: url)
|
||||
} else {
|
||||
self.presentedSheet = .safari(url: url)
|
||||
}
|
||||
} catch {
|
||||
self.presentedSheet = .safari(url: url)
|
||||
}
|
||||
}
|
||||
|
||||
return OpenURLAction.Result.handled
|
||||
|
||||
/// Changes the current tab from the current ``Navigator`` class
|
||||
func change(to tab: TabDestination) {
|
||||
savePath()
|
||||
|
||||
withAnimation(.spring) {
|
||||
loadPath(from: tab)
|
||||
}
|
||||
return OpenURLAction.Result.handled
|
||||
}
|
||||
|
||||
|
||||
private func savePath() {
|
||||
let lastTab: TabDestination = self.currentTab
|
||||
let lastPath: [RouterDestination] = self.path
|
||||
|
||||
memorizedNav.updateValue(lastPath, forKey: lastTab)
|
||||
}
|
||||
|
||||
private func loadPath(from tab: TabDestination) {
|
||||
if let (newTab, newPath) = memorizedNav.first(where: { $0.key == tab }).map({ [$0.key : $0.value] })?.first {
|
||||
self.currentTab = newTab
|
||||
self.path = newPath
|
||||
} else {
|
||||
print("Couldn't find Navigator data from \(tab.id), created new ones")
|
||||
self.currentTab = tab
|
||||
self.path = []
|
||||
}
|
||||
}
|
||||
|
||||
/// This only applies on the current path, not the saved ones in ``memorizedNav``
|
||||
public func removeSettingsOfPath() {
|
||||
self.path = self.path.filter({ !RouterDestination.allSettings.contains($0) })
|
||||
}
|
||||
}
|
||||
|
||||
/// This can be used for universal ``SheetDestination``s
|
||||
public class UniversalNavigator: Navigator {
|
||||
static var shared: UniversalNavigator = UniversalNavigator()
|
||||
public var tabNavigator: Navigator?
|
||||
public static var `static`: UniversalNavigator = UniversalNavigator()
|
||||
}
|
||||
|
||||
public enum TabDestination: Identifiable {
|
||||
|
55
Threaded/Data/URLNavigator.swift
Normal file
55
Threaded/Data/URLNavigator.swift
Normal file
@ -0,0 +1,55 @@
|
||||
// Made by Lumaa
|
||||
|
||||
import Foundation
|
||||
import SwiftUI
|
||||
|
||||
extension Navigator {
|
||||
public func handle(url: URL) -> OpenURLAction.Result {
|
||||
guard let client = self.client else { return .systemAction }
|
||||
let path: String = url.absoluteString.replacingOccurrences(of: AppInfo.scheme, with: "") // remove all path
|
||||
let urlPath: URL = URL(string: path)!
|
||||
|
||||
let server: String = urlPath.host() ?? client.server
|
||||
let lastIndex = urlPath.pathComponents.count - 1
|
||||
|
||||
let actionType = urlPath.pathComponents[lastIndex - 1]
|
||||
|
||||
if client.isAuth && client.hasConnection(with: url) {
|
||||
if urlPath.lastPathComponent.starts(with: "@") {
|
||||
Task {
|
||||
do {
|
||||
print("\(urlPath.lastPathComponent)@\(server.replacingOccurrences(of: "www.", with: ""))")
|
||||
let search: SearchResults = try await client.get(endpoint: Search.search(query: "\(urlPath.lastPathComponent)@\(server.replacingOccurrences(of: "www.", with: ""))", type: "accounts", offset: nil, following: nil), forceVersion: .v2)
|
||||
print(search)
|
||||
let acc: Account = search.accounts.first ?? .placeholder()
|
||||
self.navigate(to: .account(acc: acc))
|
||||
} catch {
|
||||
print(error)
|
||||
}
|
||||
}
|
||||
return OpenURLAction.Result.handled
|
||||
} else {
|
||||
self.presentedSheet = .safari(url: url)
|
||||
}
|
||||
} else {
|
||||
Task {
|
||||
do {
|
||||
let connections: [String] = try await client.get(endpoint: Instances.peers)
|
||||
client.addConnections(connections)
|
||||
|
||||
|
||||
if client.hasConnection(with: url) {
|
||||
_ = self.handle(url: url)
|
||||
} else {
|
||||
self.presentedSheet = .safari(url: url)
|
||||
}
|
||||
} catch {
|
||||
self.presentedSheet = .safari(url: url)
|
||||
}
|
||||
}
|
||||
|
||||
return OpenURLAction.Result.handled
|
||||
}
|
||||
return OpenURLAction.Result.handled
|
||||
}
|
||||
}
|
@ -209,6 +209,22 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"account" : {
|
||||
"localizations" : {
|
||||
"en" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "Account"
|
||||
}
|
||||
},
|
||||
"fr" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "Compte"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"account.block" : {
|
||||
"localizations" : {
|
||||
"en" : {
|
||||
@ -1093,6 +1109,38 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"control.open.composer" : {
|
||||
"localizations" : {
|
||||
"en" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "New post"
|
||||
}
|
||||
},
|
||||
"fr" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "Nouvelle publication"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"control.open.composer.description" : {
|
||||
"localizations" : {
|
||||
"en" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "Create a new post"
|
||||
}
|
||||
},
|
||||
"fr" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "Créer une nouvelle publication"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"discovery" : {
|
||||
"localizations" : {
|
||||
"en" : {
|
||||
@ -1541,6 +1589,150 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"intent.open.composer" : {
|
||||
"localizations" : {
|
||||
"en" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "Start a new post"
|
||||
}
|
||||
},
|
||||
"fr" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "Démarrer une nouvelle publication"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"intent.open.composer.description" : {
|
||||
"localizations" : {
|
||||
"en" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "Opens the Threaded app with the post composer "
|
||||
}
|
||||
},
|
||||
"fr" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "Ouvre l’application Threaded avec le compositeur de publications"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"intent.publish.any.issue" : {
|
||||
"localizations" : {
|
||||
"en" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "There was an issue while posting."
|
||||
}
|
||||
},
|
||||
"fr" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "Il y a eu un soucis lors de la publication."
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"intent.publish.any.visibility-dialog" : {
|
||||
"localizations" : {
|
||||
"en" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "How visible do you want your post to be?"
|
||||
}
|
||||
},
|
||||
"fr" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "Quelle visibilité voulez-vous que cette publication ai ?"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"intent.publish.text" : {
|
||||
"localizations" : {
|
||||
"en" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "Publish a text-based post"
|
||||
}
|
||||
},
|
||||
"fr" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "Publier du texte dans une publication"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"intent.publish.text.account-dialog" : {
|
||||
"localizations" : {
|
||||
"en" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "Select the account the post will be published on"
|
||||
}
|
||||
},
|
||||
"fr" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "Sélectionnez le compte sur lequel la publication sera publiée"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"intent.publish.text.content-dialog" : {
|
||||
"localizations" : {
|
||||
"en" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "Write the content of your post"
|
||||
}
|
||||
},
|
||||
"fr" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "Écrivez le contenu de votre publication"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"intent.publish.text.description" : {
|
||||
"localizations" : {
|
||||
"en" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "Publish a text-based post on Mastodon"
|
||||
}
|
||||
},
|
||||
"fr" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "Publie du texte dans une publication sur Mastodon"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"intent.publish.text.summary-${content}" : {
|
||||
"localizations" : {
|
||||
"en" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "Post \"${content}\""
|
||||
}
|
||||
},
|
||||
"fr" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "Publier « ${content} »"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"login.instance.unsafe" : {
|
||||
"localizations" : {
|
||||
"en" : {
|
||||
@ -2425,6 +2617,7 @@
|
||||
}
|
||||
},
|
||||
"settings.account-switcher.send-to-watch" : {
|
||||
"extractionState" : "stale",
|
||||
"localizations" : {
|
||||
"en" : {
|
||||
"stringUnit" : {
|
||||
@ -2438,7 +2631,8 @@
|
||||
"value" : "Envoyer vers l'Apple Watch"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"shouldTranslate" : false
|
||||
},
|
||||
"settings.cancel" : {
|
||||
"localizations" : {
|
||||
@ -4439,6 +4633,151 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"widget.composer" : {
|
||||
"localizations" : {
|
||||
"en" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "Quick Post"
|
||||
}
|
||||
},
|
||||
"fr" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "Publication Rapide"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"widget.follow-count" : {
|
||||
"localizations" : {
|
||||
"en" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "Follow Count"
|
||||
}
|
||||
},
|
||||
"fr" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "Compteur de Followers"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"widget.follow-count.description" : {
|
||||
"localizations" : {
|
||||
"en" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "Keep track of your follower count"
|
||||
}
|
||||
},
|
||||
"fr" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "Garder trace de votre nombre de followers"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"widget.follow-goal" : {
|
||||
"localizations" : {
|
||||
"en" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "Follow Goal"
|
||||
}
|
||||
},
|
||||
"fr" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "Objectif de Followers"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"widget.follow-goal.description" : {
|
||||
"localizations" : {
|
||||
"en" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "Keep track of your follower count and set a goal for it"
|
||||
}
|
||||
},
|
||||
"fr" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "Gardez trace de votre nombre de followers et faites en un objectif"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"widget.followers" : {
|
||||
"comment" : "Lowercase, shown in the \"Follow Count\" widget",
|
||||
"localizations" : {
|
||||
"en" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "followers"
|
||||
}
|
||||
},
|
||||
"fr" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "followers"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"widget.open.composer" : {
|
||||
"localizations" : {
|
||||
"en" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "Create a new post"
|
||||
}
|
||||
},
|
||||
"fr" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "Créez une nouvelle publication"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"widget.select-account" : {
|
||||
"localizations" : {
|
||||
"en" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "Select an account"
|
||||
}
|
||||
},
|
||||
"fr" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "Sélectionnez un compte"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"widget.set-goal" : {
|
||||
"localizations" : {
|
||||
"en" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "Follower goal"
|
||||
}
|
||||
},
|
||||
"fr" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "Objectif de follower"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"version" : "1.0"
|
||||
|
@ -7,7 +7,8 @@ import RevenueCat
|
||||
@main
|
||||
struct ThreadedApp: App {
|
||||
init() {
|
||||
guard let plist = AppDelegate.readSecret() else { return }
|
||||
guard let plist = AppDelegate.readSecret() else { fatalError("Missing Secret.plist file") }
|
||||
|
||||
if let apiKey = plist["RevenueCat_public"], let deviceId = UIDevice.current.identifierForVendor?.uuidString {
|
||||
#if DEBUG
|
||||
Purchases.logLevel = .debug
|
||||
@ -16,6 +17,8 @@ struct ThreadedApp: App {
|
||||
Purchases.configure(withAPIKey: apiKey, appUserID: deviceId)
|
||||
}
|
||||
}
|
||||
|
||||
ThreadedShortcuts.updateAppShortcutParameters()
|
||||
}
|
||||
|
||||
var body: some Scene {
|
||||
@ -48,7 +51,3 @@ public extension View {
|
||||
.modelContainer(for: [LoggedAccount.self, ModelFilter.self])
|
||||
}
|
||||
}
|
||||
|
||||
extension AppInfo {
|
||||
static var appVersion = Bundle.main.infoDictionary?["CFBundleShortVersionString"] as? String ?? "Unknown"
|
||||
}
|
||||
|
@ -5,7 +5,7 @@ import SwiftUI
|
||||
struct AccountView: View {
|
||||
@Environment(AccountManager.self) private var accountManager: AccountManager
|
||||
|
||||
@State private var navigator: Navigator = Navigator()
|
||||
@State private var navigator: Navigator = Navigator.shared
|
||||
@State public var account: Account
|
||||
|
||||
var body: some View {
|
||||
|
@ -6,14 +6,15 @@ import SwiftUI
|
||||
struct ContentView: View {
|
||||
@UIApplicationDelegateAdaptor private var appDelegate: AppDelegate
|
||||
|
||||
private var huggingFace: HuggingFace = HuggingFace()
|
||||
// private var huggingFace: HuggingFace = HuggingFace()
|
||||
@State private var preferences: UserPreferences = .defaultPreferences
|
||||
@StateObject private var uniNavigator = UniversalNavigator.shared
|
||||
@State private var navigator: Navigator = .shared
|
||||
@StateObject private var uniNavigator = UniversalNavigator.static
|
||||
@StateObject private var accountManager: AccountManager = AccountManager.shared
|
||||
|
||||
var body: some View {
|
||||
ZStack {
|
||||
TabView(selection: $uniNavigator.selectedTab, content: {
|
||||
TabView(selection: $navigator.selectedTab, content: {
|
||||
if accountManager.getAccount() != nil {
|
||||
TimelineView(timelineModel: FetchTimeline(client: accountManager.forceClient()))
|
||||
.background(Color.appBackground)
|
||||
@ -40,18 +41,25 @@ struct ContentView: View {
|
||||
}
|
||||
.frame(maxWidth: appDelegate.windowWidth)
|
||||
.overlay(alignment: .bottom) {
|
||||
TabsView(selectedTab: $uniNavigator.selectedTab, postButton: {
|
||||
TabsView(canTap: $navigator.showTabbar, postButton: {
|
||||
uniNavigator.presentedSheet = .post(content: "", replyId: nil, editId: nil)
|
||||
}, retapAction: {
|
||||
navigator.path = []
|
||||
// Navigator.shared.showTabbar.toggle()
|
||||
})
|
||||
.safeAreaPadding(.vertical, 10)
|
||||
.zIndex(10)
|
||||
.offset(
|
||||
y: navigator.showTabbar ? 0 : CGFloat
|
||||
.getFontSize(from: .extraLargeTitle) * 7.5
|
||||
)
|
||||
.allowsHitTesting(navigator.showTabbar)
|
||||
}
|
||||
.withSheets(sheetDestination: $uniNavigator.presentedSheet)
|
||||
.withCovers(sheetDestination: $uniNavigator.presentedCover)
|
||||
.environment(uniNavigator)
|
||||
.environment(accountManager)
|
||||
.environment(appDelegate)
|
||||
.environment(huggingFace)
|
||||
.environmentObject(preferences)
|
||||
.navigationBarTitleDisplayMode(.inline)
|
||||
.onAppear {
|
||||
@ -69,8 +77,6 @@ struct ContentView: View {
|
||||
await recognizeAccount()
|
||||
}
|
||||
}
|
||||
|
||||
_ = HuggingFace.getToken()
|
||||
}
|
||||
.onOpenURL(perform: { url in
|
||||
guard preferences.browserType == .inApp else { return }
|
||||
|
@ -5,8 +5,8 @@ import SwiftUI
|
||||
struct DiscoveryView: View {
|
||||
@Environment(AccountManager.self) private var accountManager: AccountManager
|
||||
|
||||
@State private var navigator: Navigator = Navigator()
|
||||
|
||||
@State private var navigator: Navigator = Navigator.shared
|
||||
|
||||
@State private var searchQuery: String = ""
|
||||
@State private var results: [String : SearchResults] = [:]
|
||||
@State private var querying: Bool = false
|
||||
|
@ -6,7 +6,7 @@ import TipKit
|
||||
struct NotificationsView: View {
|
||||
@Environment(AccountManager.self) private var accountManager
|
||||
|
||||
@State private var navigator: Navigator = Navigator()
|
||||
@State private var navigator: Navigator = Navigator.shared
|
||||
@State private var notifications: [GroupedNotification] = []
|
||||
@State private var loadingNotifs: Bool = true
|
||||
@State private var lastId: Int? = nil
|
||||
|
@ -194,7 +194,8 @@ struct PostingView: View {
|
||||
.pickerStyle(.menu)
|
||||
.foregroundStyle(Color.gray)
|
||||
}
|
||||
|
||||
|
||||
// MARK: Post function
|
||||
private func postText() {
|
||||
Task {
|
||||
if let client = accountManager.getClient() {
|
||||
@ -772,7 +773,7 @@ extension PostingView {
|
||||
|
||||
struct AltTextView: View {
|
||||
@Environment(AccountManager.self) private var accountManager: AccountManager
|
||||
@Environment(HuggingFace.self) private var huggingFace: HuggingFace
|
||||
// @Environment(HuggingFace.self) private var huggingFace: HuggingFace
|
||||
@Environment(\.dismiss) private var dismiss
|
||||
|
||||
var container: MediaContainer
|
||||
|
@ -6,6 +6,7 @@ struct ProfileView: View {
|
||||
@Environment(AccountManager.self) private var accountManager: AccountManager
|
||||
@Environment(UniversalNavigator.self) private var uniNav: UniversalNavigator
|
||||
@Environment(AppDelegate.self) private var appDelegate: AppDelegate
|
||||
@Environment(\.openURL) private var openURL: OpenURLAction
|
||||
@EnvironmentObject private var navigator: Navigator
|
||||
|
||||
@Namespace var accountAnims
|
||||
@ -284,9 +285,9 @@ struct ProfileView: View {
|
||||
TextEmoji(field.value, emojis: account.emojis)
|
||||
}
|
||||
.onTapGesture {
|
||||
if let url = URL(string: field.value.asRawText), UIApplication.shared.canOpenURL(url) {
|
||||
if let url = URL(string: field.value.asRawText) {
|
||||
HapticManager.playHaptics(haptics: Haptic.success)
|
||||
UIApplication.shared.open(url)
|
||||
openURL(url)
|
||||
} else {
|
||||
HapticManager.playHaptics(haptics: Haptic.error)
|
||||
}
|
||||
|
@ -4,6 +4,7 @@ import SwiftUI
|
||||
|
||||
struct AboutView: View {
|
||||
@Environment(AppDelegate.self) private var appDelegate: AppDelegate
|
||||
@Environment(\.openURL) private var openURL: OpenURLAction
|
||||
@EnvironmentObject private var navigator: Navigator
|
||||
@ObservedObject private var userPreferences: UserPreferences = .defaultPreferences
|
||||
|
||||
@ -19,7 +20,9 @@ struct AboutView: View {
|
||||
.listRowThreaded()
|
||||
|
||||
Button {
|
||||
UIApplication.shared.open(URL(string: "https://lumaa.fr/?utm_source=ThreadedApp")!)
|
||||
if let url = URL(string: "https://lumaa.fr/?utm_source=ThreadedApp") {
|
||||
openURL(url)
|
||||
}
|
||||
} label: {
|
||||
Text("about.lumaa")
|
||||
}
|
||||
|
@ -8,7 +8,9 @@ struct IconView: View {
|
||||
ForEach(AppIcons.allCases, id: \.self) { icon in
|
||||
Button {
|
||||
HapticManager.playHaptics(haptics: Haptic.tap)
|
||||
#if NS_EXTENSION_UNAVAILABLE
|
||||
changeAppIcon(to: icon.assetName)
|
||||
#endif
|
||||
} label: {
|
||||
HStack {
|
||||
Image(icon.assetName)
|
||||
@ -28,7 +30,8 @@ struct IconView: View {
|
||||
.navigationBarTitleDisplayMode(.inline)
|
||||
.listThreaded()
|
||||
}
|
||||
|
||||
|
||||
#if NS_EXTENSION_UNAVAILABLE
|
||||
private func changeAppIcon(to iconName: String) {
|
||||
UIApplication.shared.setAlternateIconName(iconName) { error in
|
||||
if let error = error {
|
||||
@ -37,6 +40,7 @@ struct IconView: View {
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
private enum AppIcons: CaseIterable {
|
||||
@ -112,7 +116,3 @@ private enum AppIcons: CaseIterable {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#Preview {
|
||||
IconView()
|
||||
}
|
||||
|
@ -151,6 +151,14 @@ struct SettingsView: View {
|
||||
.listThreaded()
|
||||
.navigationTitle("settings")
|
||||
.navigationBarTitleDisplayMode(.inline)
|
||||
.onAppear {
|
||||
navigator.showTabbar = false
|
||||
}
|
||||
.onChange(of: navigator.path) { _, newValue in
|
||||
guard !newValue.isEmpty else { navigator.showTabbar = true; return }
|
||||
navigator.showTabbar = newValue
|
||||
.filter({ $0 == RouterDestination.settings }).first == nil
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -164,7 +172,7 @@ extension SettingsView {
|
||||
var logged: LoggedAccount
|
||||
var app: AppAccount
|
||||
|
||||
private let connectivity: SessionDelegator = .init()
|
||||
// private let connectivity: SessionDelegator = .init()
|
||||
|
||||
@State private var account: Account? = nil
|
||||
@State private var error: Bool = false
|
||||
@ -248,23 +256,23 @@ extension SettingsView {
|
||||
|
||||
Divider()
|
||||
|
||||
if connectivity.isWorking {
|
||||
Button {
|
||||
// double check in case states change in between
|
||||
if connectivity.isWorking {
|
||||
let message = GivenAccount(acct: app.accountName!, bearerToken: app.oauthToken?.accessToken ?? "")
|
||||
connectivity.session.sendMessageData(message.turnToMessage(), replyHandler: { data in
|
||||
let str = String(data: data, encoding: .utf8)
|
||||
print(str ?? "No data?")
|
||||
HapticManager.playHaptics(haptics: Haptic.success)
|
||||
})
|
||||
} else {
|
||||
print("No Watch?")
|
||||
}
|
||||
} label: {
|
||||
Label("settings.account-switcher.send-to-watch", systemImage: "applewatch.and.arrow.forward")
|
||||
}
|
||||
}
|
||||
// if connectivity.isWorking {
|
||||
// Button {
|
||||
// // double check in case states change in between
|
||||
// if connectivity.isWorking {
|
||||
// let message = GivenAccount(acct: app.accountName!, bearerToken: app.oauthToken?.accessToken ?? "")
|
||||
// connectivity.session.sendMessageData(message.turnToMessage(), replyHandler: { data in
|
||||
// let str = String(data: data, encoding: .utf8)
|
||||
// print(str ?? "No data?")
|
||||
// HapticManager.playHaptics(haptics: Haptic.success)
|
||||
// })
|
||||
// } else {
|
||||
// print("No Watch?")
|
||||
// }
|
||||
// } label: {
|
||||
// Label("settings.account-switcher.send-to-watch", systemImage: "applewatch.and.arrow.forward")
|
||||
// }
|
||||
// }
|
||||
}
|
||||
} else {
|
||||
Circle()
|
||||
@ -297,7 +305,7 @@ extension SettingsView {
|
||||
.task {
|
||||
account = await findAccount(acct: app.accountName!)
|
||||
|
||||
connectivity.initialize()
|
||||
// connectivity.initialize()
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -5,7 +5,7 @@ import SwiftData
|
||||
|
||||
struct TimelineView: View {
|
||||
@Environment(AccountManager.self) private var accountManager: AccountManager
|
||||
@State var navigator: Navigator = Navigator()
|
||||
@State var navigator: Navigator = Navigator.shared
|
||||
|
||||
@State private var showPicker: Bool = false
|
||||
@State private var timelines: [TimelineFilter] = [.home, .trending, .local, .federated]
|
||||
|
@ -1,11 +0,0 @@
|
||||
{
|
||||
"colors" : [
|
||||
{
|
||||
"idiom" : "universal"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
}
|
||||
}
|
@ -1,14 +0,0 @@
|
||||
{
|
||||
"images" : [
|
||||
{
|
||||
"filename" : "ThreadedApp.png",
|
||||
"idiom" : "universal",
|
||||
"platform" : "watchos",
|
||||
"size" : "1024x1024"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
}
|
||||
}
|
Binary file not shown.
Before Width: | Height: | Size: 39 KiB |
@ -1,6 +0,0 @@
|
||||
{
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
}
|
||||
}
|
@ -1,152 +0,0 @@
|
||||
//Made by Lumaa
|
||||
|
||||
import SwiftUI
|
||||
import SwiftData
|
||||
|
||||
struct ContentView: View {
|
||||
@State private var givenAccounts: [GivenAccount] = []
|
||||
private let connectivity: SessionDelegator = .init()
|
||||
|
||||
@State private var fetching: Bool = false
|
||||
@State private var currentAccount: (UIImage, Int)? = nil
|
||||
|
||||
var body: some View {
|
||||
NavigationStack {
|
||||
TabView {
|
||||
if givenAccounts.isEmpty || givenAccounts.count < 1 {
|
||||
ContentUnavailableView("iphone.login", systemImage: "iphone", description: Text("iphone.login.description"))
|
||||
.containerBackground(Color.yellow.gradient, for: .tabView)
|
||||
.scrollDisabled(true)
|
||||
} else {
|
||||
ForEach(givenAccounts, id: \.bearerToken) { acc in
|
||||
ZStack {
|
||||
if currentAccount == nil {
|
||||
ProgressView()
|
||||
.task {
|
||||
self.currentAccount = await getData(givenAccount: acc)
|
||||
}
|
||||
} else {
|
||||
let username: String = String(acc.acct.split(separator: "@")[0])
|
||||
let server: String = String(acc.acct.split(separator: "@")[1])
|
||||
|
||||
VStack {
|
||||
Image(uiImage: currentAccount!.0)
|
||||
.resizable()
|
||||
.scaledToFit()
|
||||
.frame(width: 60, height: 60)
|
||||
.clipShape(Circle())
|
||||
.padding(.top, 7.5)
|
||||
.onDisappear() {
|
||||
guard !fetching else { print("Fetching..."); return }
|
||||
self.currentAccount = nil
|
||||
}
|
||||
|
||||
Text(String("@\(username)"))
|
||||
.font(.title2.bold())
|
||||
Text(server)
|
||||
.font(.caption)
|
||||
.foregroundStyle(Color.gray)
|
||||
|
||||
ScrollView(.horizontal) {
|
||||
HStack {
|
||||
VStack {
|
||||
Text(currentAccount!.1, format: .number.notation(.compactName))
|
||||
.font(.headline)
|
||||
|
||||
Text("account.followers")
|
||||
.font(.caption)
|
||||
.foregroundStyle(Color.gray)
|
||||
}
|
||||
.safeAreaPadding()
|
||||
}
|
||||
}
|
||||
.padding(.top, 7.5)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
.tabViewStyle(.verticalPage(transitionStyle: .blur))
|
||||
.navigationBarTitleDisplayMode(.inline)
|
||||
.toolbar {
|
||||
ToolbarItemGroup(placement: .topBarLeading) {
|
||||
Button {
|
||||
refresh()
|
||||
} label: {
|
||||
Image(systemName: "arrow.clockwise")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
.onAppear {
|
||||
connectivity.initialize()
|
||||
self.refresh()
|
||||
}
|
||||
}
|
||||
|
||||
private func refresh() {
|
||||
self.givenAccounts = self.getAccounts()
|
||||
|
||||
if connectivity.isWorking {
|
||||
withAnimation {
|
||||
self.givenAccounts.append(contentsOf: connectivity.allMessage.filter({ !self.givenAccounts.contains($0) }))
|
||||
if let _givenAccounts = connectivity.lastMessage, self.givenAccounts.isEmpty {
|
||||
self.givenAccounts = [_givenAccounts] // fallback
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
self.givenAccounts = self.givenAccounts.uniqued()
|
||||
self.saveCurrentModels()
|
||||
}
|
||||
|
||||
private func getAccounts() -> [GivenAccount] {
|
||||
guard let modelContainer: ModelContainer = try? ModelContainer(for: LoggedAccount.self, configurations: ModelConfiguration(isStoredInMemoryOnly: false)) else { return [] }
|
||||
let modelContext = ModelContext(modelContainer)
|
||||
let loggedAccounts: [LoggedAccount]? = try? modelContext.fetch(FetchDescriptor<LoggedAccount>())
|
||||
let given: [GivenAccount] = loggedAccounts?.map({ $0.toGiven() }) ?? []
|
||||
|
||||
return given
|
||||
}
|
||||
|
||||
private func getData(givenAccount: GivenAccount) async -> (UIImage, Int) {
|
||||
let server = givenAccount.acct.split(separator: "@")[1]
|
||||
let client: Client = Client(server: String(server), oauthToken: OauthToken(accessToken: givenAccount.bearerToken, tokenType: "Bearer", scope: "", createdAt: .nan))
|
||||
|
||||
var pfp: UIImage
|
||||
do {
|
||||
fetching = true
|
||||
let acc = try await client.getString(endpoint: Accounts.verifyCredentials, forceVersion: .v1)
|
||||
fetching = false
|
||||
|
||||
if let serialized: [String : Any] = try JSONSerialization.jsonObject(with: acc.data(using: String.Encoding.utf8) ?? Data()) as? [String : Any] {
|
||||
let avatar: String = serialized["avatar"] as! String
|
||||
let task = try await URLSession.shared.data(from: URL(string: avatar)!)
|
||||
pfp = UIImage(data: task.0) ?? UIImage()
|
||||
|
||||
let followers: Int = serialized["followers_count"] as! Int
|
||||
return (pfp, followers)
|
||||
}
|
||||
} catch {
|
||||
print(error)
|
||||
}
|
||||
return (UIImage(), 0)
|
||||
}
|
||||
|
||||
private func saveModel(model: LoggedAccount) {
|
||||
guard let modelContainer: ModelContainer = try? ModelContainer(for: LoggedAccount.self, configurations: ModelConfiguration(isStoredInMemoryOnly: false)) else { return }
|
||||
let modelContext = ModelContext(modelContainer)
|
||||
modelContext.insert(model)
|
||||
}
|
||||
|
||||
private func saveCurrentModels() {
|
||||
for given in self.givenAccounts {
|
||||
saveModel(model: given.toLogged())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#Preview {
|
||||
ContentView()
|
||||
}
|
@ -1,59 +0,0 @@
|
||||
//Made by Lumaa
|
||||
|
||||
import Foundation
|
||||
|
||||
struct GivenAccount: Hashable {
|
||||
static let messageSeparator: String = "||"
|
||||
|
||||
let acct: String
|
||||
let bearerToken: String
|
||||
|
||||
init(acct: String, bearerToken: String) {
|
||||
self.acct = acct
|
||||
self.bearerToken = bearerToken
|
||||
}
|
||||
|
||||
private func messageString() -> String {
|
||||
return "\(self.acct)\(Self.messageSeparator)\(self.bearerToken)"
|
||||
}
|
||||
|
||||
func turnToMessage() -> Data {
|
||||
let str = self.messageString()
|
||||
return str.data(using: .utf8) ?? Data()
|
||||
}
|
||||
|
||||
func turnToDictionary() -> [String : Any] {
|
||||
let str = self.messageString()
|
||||
return ["givenAccount" : str]
|
||||
}
|
||||
|
||||
func toLogged() -> LoggedAccount {
|
||||
let oauth = OauthToken(accessToken: self.bearerToken, tokenType: "Bearer", scope: "", createdAt: .nan)
|
||||
return LoggedAccount(token: oauth, acct: self.acct)
|
||||
}
|
||||
|
||||
static func makeFromMessage(_ message: Data) -> GivenAccount {
|
||||
if let string = String(data: message, encoding: .utf8) {
|
||||
let decomposed = string.split(separator: Self.messageSeparator)
|
||||
let acct = decomposed[0]
|
||||
let bearerToken = decomposed[1]
|
||||
|
||||
return GivenAccount(acct: String(acct), bearerToken: String(bearerToken))
|
||||
}
|
||||
fatalError("Message couldn't be stringified")
|
||||
}
|
||||
|
||||
static func makeFromMessage(_ message: String) -> GivenAccount {
|
||||
let decomposed = message.split(separator: Self.messageSeparator)
|
||||
let acct = decomposed[0]
|
||||
let bearerToken = decomposed[1]
|
||||
|
||||
return GivenAccount(acct: String(acct), bearerToken: String(bearerToken))
|
||||
}
|
||||
}
|
||||
|
||||
extension LoggedAccount {
|
||||
func toGiven() -> GivenAccount {
|
||||
return GivenAccount(acct: self.acct, bearerToken: self.token.accessToken)
|
||||
}
|
||||
}
|
@ -1,54 +0,0 @@
|
||||
{
|
||||
"sourceLanguage" : "en",
|
||||
"strings" : {
|
||||
"account.followers" : {
|
||||
"localizations" : {
|
||||
"en" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "followers"
|
||||
}
|
||||
},
|
||||
"fr" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "followers"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"iphone.login" : {
|
||||
"localizations" : {
|
||||
"en" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "Login with your iPhone"
|
||||
}
|
||||
},
|
||||
"fr" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "Connexion via l'iPhone"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"iphone.login.description" : {
|
||||
"localizations" : {
|
||||
"en" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "Use your iPhone to see your account on your Apple Watch"
|
||||
}
|
||||
},
|
||||
"fr" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "Utilisez votre iPhone pour voir vos comptes sur votre Apple Watch"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"version" : "1.0"
|
||||
}
|
@ -1,6 +0,0 @@
|
||||
{
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
}
|
||||
}
|
@ -1,10 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>com.apple.security.application-groups</key>
|
||||
<array>
|
||||
<string>group.lumaa.ThreadedApp</string>
|
||||
</array>
|
||||
</dict>
|
||||
</plist>
|
@ -1,20 +0,0 @@
|
||||
//Made by Lumaa
|
||||
|
||||
import SwiftUI
|
||||
|
||||
@main
|
||||
struct ThreadedWatch_Watch_AppApp: App {
|
||||
var body: some Scene {
|
||||
WindowGroup {
|
||||
ContentView()
|
||||
.modelData()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
extension View {
|
||||
func modelData() -> some View {
|
||||
self
|
||||
.modelContainer(for: LoggedAccount.self)
|
||||
}
|
||||
}
|
@ -1,122 +0,0 @@
|
||||
//Made by Lumaa
|
||||
|
||||
import Foundation
|
||||
import WatchConnectivity
|
||||
|
||||
#if os(watchOS)
|
||||
import ClockKit
|
||||
#endif
|
||||
|
||||
// Implement WCSessionDelegate methods to receive Watch Connectivity data and notify clients.
|
||||
// Handle WCSession status changes.
|
||||
//
|
||||
class SessionDelegator: NSObject, WCSessionDelegate {
|
||||
public var session: WCSession = .default
|
||||
public var lastMessage: GivenAccount? = nil
|
||||
public var allMessage: [GivenAccount] = []
|
||||
public var isWorking: Bool {
|
||||
self.session.isReachable
|
||||
}
|
||||
|
||||
func initialize() {
|
||||
guard WCSession.isSupported() else { fatalError("Doesn't support WCSession") }
|
||||
session.delegate = self
|
||||
session.activate()
|
||||
}
|
||||
|
||||
// Monitor WCSession activation state changes.
|
||||
//
|
||||
func session(_ session: WCSession, activationDidCompleteWith activationState: WCSessionActivationState, error: Error?) {
|
||||
return
|
||||
}
|
||||
|
||||
// Monitor WCSession reachability state changes.
|
||||
//
|
||||
func sessionReachabilityDidChange(_ session: WCSession) {
|
||||
self.session = session
|
||||
}
|
||||
|
||||
// Did receive an app context.
|
||||
//
|
||||
func session(_ session: WCSession, didReceiveApplicationContext applicationContext: [String: Any]) {
|
||||
if let givenAccount = applicationContext["givenAccount"] as? String {
|
||||
self.lastMessage = GivenAccount.makeFromMessage(givenAccount)
|
||||
guard !self.allMessage.contains(where: { $0.bearerToken == self.lastMessage!.bearerToken }) else { return }
|
||||
self.allMessage.append(self.lastMessage!)
|
||||
}
|
||||
}
|
||||
|
||||
// Did receive a message, and the peer doesn't need a response.
|
||||
//
|
||||
func session(_ session: WCSession, didReceiveMessage message: [String: Any]) {
|
||||
if let givenAccount = message["givenAccount"] as? String {
|
||||
self.lastMessage = GivenAccount.makeFromMessage(givenAccount)
|
||||
guard !self.allMessage.contains(where: { $0.bearerToken == self.lastMessage!.bearerToken }) else { return }
|
||||
self.allMessage.append(self.lastMessage!)
|
||||
}
|
||||
}
|
||||
|
||||
// Did receive a message, and the peer needs a response.
|
||||
//
|
||||
func session(_ session: WCSession, didReceiveMessage message: [String: Any], replyHandler: @escaping ([String: Any]) -> Void) {
|
||||
self.session(session, didReceiveMessage: message)
|
||||
let response = ["success" : true, "timestamp": Int(Date.now.timeIntervalSince1970)] as [String : Any]
|
||||
replyHandler(response)
|
||||
}
|
||||
|
||||
// Did receive a piece of message data, and the peer doesn't need a response.
|
||||
//
|
||||
func session(_ session: WCSession, didReceiveMessageData messageData: Data) {
|
||||
self.lastMessage = GivenAccount.makeFromMessage(messageData)
|
||||
guard !self.allMessage.contains(where: { $0.bearerToken == self.lastMessage!.bearerToken }) else { return }
|
||||
self.allMessage.append(self.lastMessage!)
|
||||
}
|
||||
|
||||
// Did receive a piece of message data, and the peer needs a response.
|
||||
//
|
||||
func session(_ session: WCSession, didReceiveMessageData messageData: Data, replyHandler: @escaping (Data) -> Void) {
|
||||
self.session(session, didReceiveMessageData: messageData)
|
||||
replyHandler(messageData) // Echo back the data.
|
||||
}
|
||||
|
||||
// Did receive a piece of userInfo.
|
||||
//
|
||||
func session(_ session: WCSession, didReceiveUserInfo userInfo: [String: Any] = [:]) {
|
||||
return
|
||||
}
|
||||
|
||||
// Did finish sending a piece of userInfo.
|
||||
//
|
||||
func session(_ session: WCSession, didFinish userInfoTransfer: WCSessionUserInfoTransfer, error: Error?) {
|
||||
return
|
||||
}
|
||||
|
||||
// Did receive a file.
|
||||
//
|
||||
func session(_ session: WCSession, didReceive file: WCSessionFile) {
|
||||
return
|
||||
}
|
||||
|
||||
// Did finish a file transfer.
|
||||
//
|
||||
func session(_ session: WCSession, didFinish fileTransfer: WCSessionFileTransfer, error: Error?) {
|
||||
return
|
||||
}
|
||||
|
||||
// WCSessionDelegate methods for iOS only.
|
||||
//
|
||||
#if os(iOS)
|
||||
func sessionDidBecomeInactive(_ session: WCSession) {
|
||||
print("\(#function): activationState = \(session.activationState.rawValue)")
|
||||
}
|
||||
|
||||
func sessionDidDeactivate(_ session: WCSession) {
|
||||
// Activate the new session after having switched to a new watch.
|
||||
session.activate()
|
||||
}
|
||||
|
||||
func sessionWatchStateDidChange(_ session: WCSession) {
|
||||
print("\(#function): activationState = \(session.activationState.rawValue)")
|
||||
}
|
||||
#endif
|
||||
}
|
@ -5,6 +5,23 @@ import SwiftData
|
||||
import WidgetKit
|
||||
import AppIntents
|
||||
|
||||
// MARK: - Shortcuts
|
||||
|
||||
struct ThreadedShortcuts: AppShortcutsProvider {
|
||||
static var appShortcuts: [AppShortcut] = [
|
||||
.init(
|
||||
intent: OpenComposerIntent(),
|
||||
phrases: [
|
||||
"Start a \(.applicationName) post",
|
||||
"Post on \(.applicationName)"
|
||||
],
|
||||
shortTitle: "status.posting",
|
||||
systemImageName: "square.and.pencil"
|
||||
)
|
||||
]
|
||||
static var shortcutTileColor: ShortcutTileColor = .grayBlue
|
||||
}
|
||||
|
||||
// MARK: - Account Intents
|
||||
|
||||
/// Widgets that require to select only an account will use this `ConfigurationIntent`
|
||||
@ -31,6 +48,7 @@ struct AccountEntity: AppEntity {
|
||||
let client: Client
|
||||
let id: String
|
||||
let username: String
|
||||
let server: String
|
||||
/// Bearer token
|
||||
let token: OauthToken
|
||||
|
||||
@ -42,14 +60,16 @@ struct AccountEntity: AppEntity {
|
||||
}
|
||||
|
||||
init(acct: String, username: String, token: OauthToken) {
|
||||
self.client = Client(server: String(acct.split(separator: "@")[1]), version: .v2, oauthToken: token)
|
||||
self.server = String(acct.split(separator: "@")[1])
|
||||
self.client = Client(server: self.server, version: .v2, oauthToken: token)
|
||||
self.id = acct
|
||||
self.username = username
|
||||
self.token = token
|
||||
}
|
||||
|
||||
init(loggedAccount: LoggedAccount) {
|
||||
self.client = Client(server: String(loggedAccount.acct.split(separator: "@")[1]), version: .v2, oauthToken: loggedAccount.token)
|
||||
self.server = loggedAccount.app?.server ?? ""
|
||||
self.client = Client(server: self.server, version: .v2, oauthToken: loggedAccount.token)
|
||||
self.id = loggedAccount.acct
|
||||
self.username = String(loggedAccount.acct.split(separator: "@")[0])
|
||||
self.token = loggedAccount.token
|
||||
@ -103,3 +123,120 @@ struct AccountQuery: EntityQuery {
|
||||
try? await suggestedEntities().first
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - Post Intents
|
||||
|
||||
extension Visibility: AppEnum {
|
||||
public static var caseDisplayRepresentations: [Visibility : DisplayRepresentation] {
|
||||
[
|
||||
.pub : DisplayRepresentation(title: "status.posting.visibility.public"),
|
||||
.priv : DisplayRepresentation(title: "status.posting.visibility.private"),
|
||||
.unlisted : DisplayRepresentation(title: "status.posting.visibility.unlisted"),
|
||||
.direct : DisplayRepresentation(title: "status.posting.visibility.direct")
|
||||
]
|
||||
|
||||
}
|
||||
|
||||
public static var typeDisplayRepresentation: TypeDisplayRepresentation {
|
||||
TypeDisplayRepresentation(name: "status.posting.visibility")
|
||||
}
|
||||
}
|
||||
|
||||
struct OpenComposerIntent: AppIntent {
|
||||
static var title: LocalizedStringResource = "intent.open.composer"
|
||||
static var description: IntentDescription? = IntentDescription("intent.open.composer.description")
|
||||
|
||||
static var isDiscoverable: Bool = true
|
||||
static var openAppWhenRun: Bool = true
|
||||
|
||||
static var authenticationPolicy: IntentAuthenticationPolicy = .requiresLocalDeviceAuthentication
|
||||
|
||||
func perform() async throws -> some IntentResult {
|
||||
UniversalNavigator.static.presentedSheet =
|
||||
.post(content: "", replyId: nil, editId: nil)
|
||||
return .result()
|
||||
}
|
||||
}
|
||||
|
||||
struct PublishTextIntent: AppIntent {
|
||||
static var title: LocalizedStringResource = "intent.publish.text"
|
||||
static var description: IntentDescription? = IntentDescription("intent.publish.text.description")
|
||||
|
||||
static var isDiscoverable: Bool = true
|
||||
static var openAppWhenRun: Bool = false
|
||||
|
||||
static var authenticationPolicy: IntentAuthenticationPolicy = .requiresLocalDeviceAuthentication
|
||||
|
||||
@Parameter(title: "account", requestDisambiguationDialog: IntentDialog("intent.publish.text.account-dialog"))
|
||||
var account: AccountEntity?
|
||||
|
||||
@Parameter(title: "status.posting.placeholder", requestValueDialog: IntentDialog("intent.publish.text.content-dialog"))
|
||||
var content: String
|
||||
|
||||
@Parameter(title: "status.posting.visibility", requestDisambiguationDialog: IntentDialog("intent.publish.any.visibility-dialog"))
|
||||
var visibility: Visibility
|
||||
|
||||
static var parameterSummary: any ParameterSummary {
|
||||
Summary("intent.publish.text.summary-\(\.$content)") {
|
||||
\.$account
|
||||
\.$visibility
|
||||
}
|
||||
}
|
||||
|
||||
func perform() async throws -> some IntentResult & ShowsSnippetView & ReturnsValue<String> {
|
||||
if let client = account?.client, !client.server.isEmpty {
|
||||
let data: StatusData = .init(
|
||||
status: self.content,
|
||||
visibility: self.visibility
|
||||
)
|
||||
|
||||
// posting requires v1
|
||||
if let res = try? await client.post(endpoint: Statuses.postStatus(json: data), forceVersion: .v1), res.statusCode == 200 {
|
||||
return .result(
|
||||
value: self.content,
|
||||
view: Self.StatusSuccess(acc: account!, json: data)
|
||||
)
|
||||
}
|
||||
}
|
||||
return await .result(value: "", view: IssueView())
|
||||
}
|
||||
|
||||
private struct IssueView: View {
|
||||
var body: some View {
|
||||
Label("intent.publish.any.issue", systemImage: "exclamationmark.triangle.fill")
|
||||
.foregroundStyle(Color.red)
|
||||
.frame(maxWidth: .infinity, maxHeight: .infinity, alignment: .leading)
|
||||
.padding()
|
||||
.background(Color.black)
|
||||
.clipShape(Capsule())
|
||||
.padding(.horizontal)
|
||||
}
|
||||
}
|
||||
|
||||
private struct StatusSuccess: View {
|
||||
var acc: AccountEntity
|
||||
var json: StatusData
|
||||
|
||||
var body: some View {
|
||||
HStack {
|
||||
VStack(alignment: .leading, spacing: 7.5) {
|
||||
Text("@\(acc.username)")
|
||||
.foregroundStyle(Color.white)
|
||||
.bold()
|
||||
|
||||
Text(json.status)
|
||||
.foregroundStyle(Color.white)
|
||||
.lineLimit(2)
|
||||
}
|
||||
|
||||
Spacer()
|
||||
}
|
||||
.frame(maxWidth: .infinity, maxHeight: .infinity)
|
||||
.padding(.vertical)
|
||||
.padding(.horizontal, 25)
|
||||
.background(Color.black)
|
||||
.clipShape(Capsule())
|
||||
.padding(.horizontal)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,38 @@
|
||||
{
|
||||
"colors" : [
|
||||
{
|
||||
"color" : {
|
||||
"color-space" : "display-p3",
|
||||
"components" : {
|
||||
"alpha" : "1.000",
|
||||
"blue" : "0xFF",
|
||||
"green" : "0xFF",
|
||||
"red" : "0xFF"
|
||||
}
|
||||
},
|
||||
"idiom" : "universal"
|
||||
},
|
||||
{
|
||||
"appearances" : [
|
||||
{
|
||||
"appearance" : "luminosity",
|
||||
"value" : "dark"
|
||||
}
|
||||
],
|
||||
"color" : {
|
||||
"color-space" : "display-p3",
|
||||
"components" : {
|
||||
"alpha" : "1.000",
|
||||
"blue" : "0x10",
|
||||
"green" : "0x10",
|
||||
"red" : "0x10"
|
||||
}
|
||||
},
|
||||
"idiom" : "universal"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
}
|
||||
}
|
25
ThreadedWidgets/Assets.xcassets/HeroIcon.imageset/Contents.json
vendored
Normal file
25
ThreadedWidgets/Assets.xcassets/HeroIcon.imageset/Contents.json
vendored
Normal file
@ -0,0 +1,25 @@
|
||||
{
|
||||
"images" : [
|
||||
{
|
||||
"filename" : "HeroIcon_black.png",
|
||||
"idiom" : "universal"
|
||||
},
|
||||
{
|
||||
"appearances" : [
|
||||
{
|
||||
"appearance" : "luminosity",
|
||||
"value" : "dark"
|
||||
}
|
||||
],
|
||||
"filename" : "HeroIcon_white.png",
|
||||
"idiom" : "universal"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
},
|
||||
"properties" : {
|
||||
"localizable" : true
|
||||
}
|
||||
}
|
BIN
ThreadedWidgets/Assets.xcassets/HeroIcon.imageset/HeroIcon_black.png
vendored
Normal file
BIN
ThreadedWidgets/Assets.xcassets/HeroIcon.imageset/HeroIcon_black.png
vendored
Normal file
Binary file not shown.
After Width: | Height: | Size: 25 KiB |
BIN
ThreadedWidgets/Assets.xcassets/HeroIcon.imageset/HeroIcon_white.png
vendored
Normal file
BIN
ThreadedWidgets/Assets.xcassets/HeroIcon.imageset/HeroIcon_white.png
vendored
Normal file
Binary file not shown.
After Width: | Height: | Size: 49 KiB |
19
ThreadedWidgets/CreatePostControl.swift
Normal file
19
ThreadedWidgets/CreatePostControl.swift
Normal file
@ -0,0 +1,19 @@
|
||||
// Made by Lumaa
|
||||
|
||||
import SwiftUI
|
||||
import WidgetKit
|
||||
|
||||
@available(iOS 18.0, *)
|
||||
struct CreatePostControl: ControlWidget {
|
||||
let kind: String = "CreatePostControl"
|
||||
|
||||
var body: some ControlWidgetConfiguration {
|
||||
StaticControlConfiguration(kind: kind) {
|
||||
ControlWidgetButton(action: OpenComposerIntent()) {
|
||||
Label("control.open.composer", systemImage: "square.and.pencil")
|
||||
}
|
||||
}
|
||||
.displayName("control.open.composer")
|
||||
.description("control.open.composer.description")
|
||||
}
|
||||
}
|
85
ThreadedWidgets/CreatePostWidget.swift
Normal file
85
ThreadedWidgets/CreatePostWidget.swift
Normal file
@ -0,0 +1,85 @@
|
||||
// Made by Lumaa
|
||||
|
||||
import SwiftUI
|
||||
import WidgetKit
|
||||
|
||||
struct CreatePostWidget: Widget {
|
||||
let kind: String = "CreatePostWidget"
|
||||
|
||||
var body: some WidgetConfiguration {
|
||||
StaticConfiguration(
|
||||
kind: kind,
|
||||
provider: Provider()
|
||||
) { entry in
|
||||
CreatePostWidget.WidgetView()
|
||||
}
|
||||
.configurationDisplayName("widget.open.composer")
|
||||
.description("widget.open.composer")
|
||||
.supportedFamilies([.systemSmall])
|
||||
}
|
||||
|
||||
struct WidgetView: View {
|
||||
@Environment(\.widgetFamily) private var family: WidgetFamily
|
||||
@Environment(\.colorScheme) private var colorScheme: ColorScheme
|
||||
|
||||
var body: some View {
|
||||
ZStack {
|
||||
if family == .systemSmall {
|
||||
VStack {
|
||||
Button(intent: OpenComposerIntent()) {
|
||||
Image(systemName: "square.and.pencil")
|
||||
.resizable()
|
||||
.scaledToFit()
|
||||
.frame(width: 80, height: 80)
|
||||
}
|
||||
.buttonStyle(.plain)
|
||||
|
||||
Text("widget.composer")
|
||||
.font(.caption)
|
||||
}
|
||||
}
|
||||
}
|
||||
.containerBackground(Color.appBackground, for: .widget)
|
||||
}
|
||||
}
|
||||
|
||||
struct Provider: TimelineProvider {
|
||||
func getSnapshot(
|
||||
in context: Context,
|
||||
completion: @escaping @Sendable (CreatePostWidget.Entry) -> Void
|
||||
) {
|
||||
completion(.init(date: .now))
|
||||
}
|
||||
|
||||
func getTimeline(
|
||||
in context: Context,
|
||||
completion: @escaping (Timeline<CreatePostWidget.Entry>) -> Void
|
||||
) {
|
||||
var entries: [CreatePostWidget.Entry] = []
|
||||
|
||||
// Generate a timeline consisting of two entries an hour apart, starting from the current date.
|
||||
let currentDate = Date()
|
||||
for hourOffset in 0 ..< 2 {
|
||||
let entryDate = Calendar.current.date(byAdding: .hour, value: hourOffset, to: currentDate)!
|
||||
let entry = CreatePostWidget.Entry(date: entryDate)
|
||||
entries.append(entry)
|
||||
}
|
||||
|
||||
completion(Timeline(entries: entries, policy: .atEnd))
|
||||
}
|
||||
|
||||
func placeholder(in context: Context) -> CreatePostWidget.Entry {
|
||||
return .init(date: .now)
|
||||
}
|
||||
}
|
||||
|
||||
struct Entry: TimelineEntry {
|
||||
let date: Date
|
||||
}
|
||||
}
|
||||
|
||||
#Preview(as: .systemSmall) {
|
||||
CreatePostWidget()
|
||||
} timeline: {
|
||||
CreatePostWidget.Entry(date: .now)
|
||||
}
|
@ -1,89 +0,0 @@
|
||||
{
|
||||
"sourceLanguage" : "en",
|
||||
"strings" : {
|
||||
"@%@" : {
|
||||
|
||||
},
|
||||
"account" : {
|
||||
"localizations" : {
|
||||
"en" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "Account"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"widget.follow-count" : {
|
||||
"localizations" : {
|
||||
"en" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "Follower Count"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"widget.follow-count.description" : {
|
||||
"localizations" : {
|
||||
"en" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "Get the current amount of followers of the accounts you have logged in Threaded"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"widget.follow-goal" : {
|
||||
"localizations" : {
|
||||
"en" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "Follower Goal"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"widget.follow-goal.description" : {
|
||||
"localizations" : {
|
||||
"en" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "Set a follower goal and see the progress"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"widget.followers" : {
|
||||
"localizations" : {
|
||||
"en" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "Followers"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"widget.select-account" : {
|
||||
"localizations" : {
|
||||
"en" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "Select an account"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"widget.set-goal" : {
|
||||
"localizations" : {
|
||||
"en" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "Goal"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"version" : "1.0"
|
||||
}
|
@ -1,233 +0,0 @@
|
||||
//Made by Lumaa
|
||||
|
||||
import Foundation
|
||||
import SwiftUI
|
||||
import UIKit
|
||||
|
||||
// this is messy but it's alr
|
||||
|
||||
#if os(iOS)
|
||||
public class AppDelegate: NSObject, UIWindowSceneDelegate, Sendable, UIApplicationDelegate {
|
||||
public var window: UIWindow?
|
||||
public private(set) var windowWidth: CGFloat = UIScreen.main.bounds.size.width
|
||||
public private(set) var windowHeight: CGFloat = UIScreen.main.bounds.size.height
|
||||
public private(set) var secret: [String: String] = [:]
|
||||
|
||||
public func scene(_ scene: UIScene, willConnectTo _: UISceneSession, options _: UIScene.ConnectionOptions) {
|
||||
guard let windowScene = scene as? UIWindowScene else { return }
|
||||
window = windowScene.keyWindow
|
||||
}
|
||||
|
||||
override public init() {
|
||||
super.init()
|
||||
|
||||
if let path = Bundle.main.path(forResource: "Secret", ofType: "plist") {
|
||||
let url = URL(fileURLWithPath: path)
|
||||
let data = try! Data(contentsOf: url)
|
||||
if let plist = try! PropertyListSerialization.propertyList(from: data, options: .mutableContainers, format: nil) as? [String: String] {
|
||||
secret = plist
|
||||
}
|
||||
}
|
||||
|
||||
windowWidth = window?.bounds.size.width ?? UIScreen.main.bounds.size.width
|
||||
windowHeight = window?.bounds.size.height ?? UIScreen.main.bounds.size.height
|
||||
Self.observedSceneDelegate.insert(self)
|
||||
_ = Self.observer // just for activating the lazy static property
|
||||
}
|
||||
|
||||
static func readSecret() -> [String: String]? {
|
||||
if let path = Bundle.main.path(forResource: "Secret", ofType: "plist") {
|
||||
let url = URL(fileURLWithPath: path)
|
||||
let data = try! Data(contentsOf: url)
|
||||
if let plist = try! PropertyListSerialization.propertyList(from: data, options: .mutableContainers, format: nil) as? [String: String] {
|
||||
return plist
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
deinit {
|
||||
Task { @MainActor in
|
||||
Self.observedSceneDelegate.remove(self)
|
||||
}
|
||||
}
|
||||
|
||||
private static var observedSceneDelegate: Set<AppDelegate> = []
|
||||
private static let observer = Task {
|
||||
while true {
|
||||
try? await Task.sleep(for: .seconds(0.1))
|
||||
for delegate in observedSceneDelegate {
|
||||
let newWidth = delegate.window?.bounds.size.width ?? UIScreen.main.bounds.size.width
|
||||
if delegate.windowWidth != newWidth {
|
||||
delegate.windowWidth = newWidth
|
||||
}
|
||||
let newHeight = delegate.window?.bounds.size.height ?? UIScreen.main.bounds.size.height
|
||||
if delegate.windowHeight != newHeight {
|
||||
delegate.windowHeight = newHeight
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
public extension URL {
|
||||
static let placeholder: URL = URL(string: "https://cdn.pixabay.com/photo/2023/08/28/20/32/flower-8220018_1280.jpg")!
|
||||
}
|
||||
|
||||
extension AppInfo {
|
||||
static var appVersion = Bundle.main.infoDictionary?["CFBundleShortVersionString"] as? String ?? "Unknown"
|
||||
}
|
||||
|
||||
public protocol Endpoint: Sendable {
|
||||
func path() -> String
|
||||
func queryItems() -> [URLQueryItem]?
|
||||
var jsonValue: Encodable? { get }
|
||||
}
|
||||
|
||||
public extension Endpoint {
|
||||
var jsonValue: Encodable? {
|
||||
nil
|
||||
}
|
||||
}
|
||||
|
||||
extension Endpoint {
|
||||
func makePaginationParam(sinceId: String?, maxId: String?, mindId: String?) -> [URLQueryItem]? {
|
||||
if let sinceId {
|
||||
return [.init(name: "since_id", value: sinceId)]
|
||||
} else if let maxId {
|
||||
return [.init(name: "max_id", value: maxId)]
|
||||
} else if let mindId {
|
||||
return [.init(name: "min_id", value: mindId)]
|
||||
}
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
public enum Oauth: Endpoint {
|
||||
case authorize(clientId: String)
|
||||
case token(code: String, clientId: String, clientSecret: String)
|
||||
|
||||
public func path() -> String {
|
||||
switch self {
|
||||
case .authorize:
|
||||
"oauth/authorize"
|
||||
case .token:
|
||||
"oauth/token"
|
||||
}
|
||||
}
|
||||
|
||||
public var jsonValue: Encodable? {
|
||||
switch self {
|
||||
case let .token(code, clientId, clientSecret):
|
||||
TokenData(clientId: clientId, clientSecret: clientSecret, code: code)
|
||||
default:
|
||||
nil
|
||||
}
|
||||
}
|
||||
|
||||
public struct TokenData: Encodable {
|
||||
public let grantType = "authorization_code"
|
||||
public let clientId: String
|
||||
public let clientSecret: String
|
||||
public let redirectUri = AppInfo.scheme
|
||||
public let code: String
|
||||
public let scope = AppInfo.scopes
|
||||
}
|
||||
|
||||
public func queryItems() -> [URLQueryItem]? {
|
||||
switch self {
|
||||
case let .authorize(clientId):
|
||||
return [
|
||||
.init(name: "response_type", value: "code"),
|
||||
.init(name: "client_id", value: clientId),
|
||||
.init(name: "redirect_uri", value: AppInfo.scheme),
|
||||
.init(name: "scope", value: AppInfo.scopes),
|
||||
]
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public enum Accounts: Endpoint {
|
||||
case verifyCredentials
|
||||
|
||||
public func path() -> String {
|
||||
switch self {
|
||||
case .verifyCredentials:
|
||||
"accounts/verify_credentials"
|
||||
}
|
||||
}
|
||||
|
||||
public func queryItems() -> [URLQueryItem]? {
|
||||
nil
|
||||
}
|
||||
}
|
||||
|
||||
public struct InstanceApp: Codable, Identifiable {
|
||||
public let id: String
|
||||
public let name: String
|
||||
public let website: URL?
|
||||
public let redirectUri: String
|
||||
public let clientId: String
|
||||
public let clientSecret: String
|
||||
public let vapidKey: String?
|
||||
}
|
||||
|
||||
extension InstanceApp: Sendable {}
|
||||
|
||||
public struct ServerError: Decodable, Error {
|
||||
public let error: String?
|
||||
public var httpCode: Int?
|
||||
}
|
||||
|
||||
public enum Apps: Endpoint {
|
||||
case registerApp
|
||||
|
||||
public func path() -> String {
|
||||
switch self {
|
||||
case .registerApp:
|
||||
"apps"
|
||||
}
|
||||
}
|
||||
|
||||
public func queryItems() -> [URLQueryItem]? {
|
||||
switch self {
|
||||
case .registerApp:
|
||||
return [
|
||||
.init(name: "client_name", value: AppInfo.clientName),
|
||||
.init(name: "redirect_uris", value: AppInfo.scheme),
|
||||
.init(name: "scopes", value: AppInfo.scopes),
|
||||
.init(name: "website", value: AppInfo.website),
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public struct LinkHandler {
|
||||
public let rawLink: String
|
||||
|
||||
public var maxId: String? {
|
||||
do {
|
||||
let regex = try Regex("max_id=[0-9]+")
|
||||
if let match = rawLink.firstMatch(of: regex) {
|
||||
return match.output.first?.substring?.replacingOccurrences(of: "max_id=", with: "")
|
||||
}
|
||||
} catch {
|
||||
return nil
|
||||
}
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
extension LinkHandler: Sendable {}
|
||||
|
||||
public extension Array where Element: Hashable {
|
||||
func uniqued() -> [Element] {
|
||||
var seen = Set<Element>()
|
||||
return filter { seen.insert($0).inserted }
|
||||
}
|
||||
}
|
@ -9,5 +9,10 @@ struct ThreadedWidgetsBundle: WidgetBundle {
|
||||
var body: some Widget {
|
||||
FollowCountWidget()
|
||||
FollowGoalWidget()
|
||||
CreatePostWidget()
|
||||
|
||||
if #available(iOS 18.0, *) {
|
||||
CreatePostControl()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user