Merge pull request #1126 from mastodon/ios-20-server-details

Server Details in Settings (IOS-20)
This commit is contained in:
Nathan Mattes 2023-10-11 09:20:57 +02:00 committed by GitHub
commit d0e1c616f6
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
51 changed files with 923 additions and 425 deletions

View File

@ -715,6 +715,7 @@
"notifications": "Notifications",
"support_mastodon": "Support Mastodon",
"about_mastodon": "About Mastodon",
"server_details": "Server Details",
"logout": "Logout %@"
}
@ -725,6 +726,9 @@
"privacy_policy": "Privacy Policy",
"clear_media_storage": "Clear Media Storage"
},
"about_instance": {
"message_admin": "Message Admin"
},
"general": {
"title": "General",
"appearance": {

View File

@ -715,6 +715,7 @@
"notifications": "Notifications",
"support_mastodon": "Support Mastodon",
"about_mastodon": "About Mastodon",
"server_details": "Server Details",
"logout": "Logout %@"
}

View File

@ -715,6 +715,7 @@
"notifications": "Notifications",
"support_mastodon": "Support Mastodon",
"about_mastodon": "About Mastodon",
"server_details": "Server Details",
"logout": "Logout %@"
}
@ -725,6 +726,16 @@
"privacy_policy": "Privacy Policy",
"clear_media_storage": "Clear Media Storage"
},
"server_details": {
"about": "About",
"rules": "Rules"
"about_instance": {
"title": "Adminstrator"
"message_admin": "Message Admin",
"legal_notice": "A legal notice"
}
},
"general": {
"title": "General",
"appearance": {

View File

@ -3,7 +3,7 @@
archiveVersion = 1;
classes = {
};
objectVersion = 54;
objectVersion = 60;
objects = {
/* Begin PBXBuildFile section */
@ -20,7 +20,6 @@
0FB3D31E25E534C700AAD544 /* PickServerCategoryCollectionViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0FB3D31D25E534C700AAD544 /* PickServerCategoryCollectionViewCell.swift */; };
0FB3D33825E6401400AAD544 /* PickServerCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0FB3D33725E6401400AAD544 /* PickServerCell.swift */; };
164F0EBC267D4FE400249499 /* BoopSound.caf in Resources */ = {isa = PBXBuildFile; fileRef = 164F0EBB267D4FE400249499 /* BoopSound.caf */; };
18BC7629F65E6DB12CB8416D /* Pods_Mastodon_MastodonUITests.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 3C030226D3C73DCC23D67452 /* Pods_Mastodon_MastodonUITests.framework */; };
27D701F5292FC2D60031BCBB /* DataSourceFacade+URL.swift in Sources */ = {isa = PBXBuildFile; fileRef = 27D701F4292FC2D60031BCBB /* DataSourceFacade+URL.swift */; };
2A1BF99529F7E68400FA1BA5 /* DataSourceFacade+UserView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2A1BF99429F7E68400FA1BA5 /* DataSourceFacade+UserView.swift */; };
2A1FE47C2938BB2600784BF1 /* FollowedTagsViewModel+DiffableDataSource.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2A1FE47B2938BB2600784BF1 /* FollowedTagsViewModel+DiffableDataSource.swift */; };
@ -109,29 +108,31 @@
5D0393962612D266007FE196 /* WebViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5D0393952612D266007FE196 /* WebViewModel.swift */; };
5DA732CC2629CEF500A92342 /* UIView+Remove.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5DA732CB2629CEF500A92342 /* UIView+Remove.swift */; };
5DF1056425F887CB00D6C0D4 /* AVPlayer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5DF1056325F887CB00D6C0D4 /* AVPlayer.swift */; };
5E0DEC05797A7E6933788DDB /* Pods_MastodonTests.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 452147B2903DF38070FE56A2 /* Pods_MastodonTests.framework */; };
5E44BF88AD33646E64727BCF /* Pods_MastodonTests.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = CD92E0F10BDE4FE7C4B999F2 /* Pods_MastodonTests.framework */; };
6213AF5A28939C8400BCADB6 /* BookmarkViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6213AF5928939C8400BCADB6 /* BookmarkViewModel.swift */; };
6213AF5C28939C8A00BCADB6 /* BookmarkViewModel+State.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6213AF5B28939C8A00BCADB6 /* BookmarkViewModel+State.swift */; };
6213AF5E2893A8B200BCADB6 /* DataSourceFacade+Bookmark.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6213AF5D2893A8B200BCADB6 /* DataSourceFacade+Bookmark.swift */; };
62FD27D12893707600B205C5 /* BookmarkViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 62FD27D02893707600B205C5 /* BookmarkViewController.swift */; };
62FD27D32893707B00B205C5 /* BookmarkViewController+DataSourceProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = 62FD27D22893707B00B205C5 /* BookmarkViewController+DataSourceProvider.swift */; };
62FD27D52893708A00B205C5 /* BookmarkViewModel+Diffable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 62FD27D42893708A00B205C5 /* BookmarkViewModel+Diffable.swift */; };
71458AF57697DB405CFEC37C /* Pods_Mastodon.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 8C2A2448AEEDA65B4CD099FC /* Pods_Mastodon.framework */; };
7910197261F9D06EFCDCCDBC /* Pods_MastodonTests.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 89FE8B85A00419CEF4678056 /* Pods_MastodonTests.framework */; };
855149C8295F1C5F00943D96 /* UIInterfaceOrientationMask.swift in Sources */ = {isa = PBXBuildFile; fileRef = 855149C7295F1C5F00943D96 /* UIInterfaceOrientationMask.swift */; };
855149CA29606D6400943D96 /* PortraitAlertController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 855149C929606D6400943D96 /* PortraitAlertController.swift */; };
85904C02293BC0EB0011C817 /* ImageProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = 85904C01293BC0EB0011C817 /* ImageProvider.swift */; };
85904C04293BC1940011C817 /* URLActivityItemWithMetadata.swift in Sources */ = {isa = PBXBuildFile; fileRef = 85904C03293BC1940011C817 /* URLActivityItemWithMetadata.swift */; };
85BC11B32932414900E191CD /* AltTextViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 85BC11B22932414900E191CD /* AltTextViewController.swift */; };
87FFDA5D898A5C42ADCB35E7 /* Pods_Mastodon.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = A4ABE34829701A4496C5BB64 /* Pods_Mastodon.framework */; };
9E44C7202967AD17004B2A72 /* MastodonSDKDynamic in Frameworks */ = {isa = PBXBuildFile; productRef = 9E44C71F2967AD17004B2A72 /* MastodonSDKDynamic */; };
9E44C7222967AD17004B2A72 /* MastodonSDKDynamic in Embed Frameworks */ = {isa = PBXBuildFile; productRef = 9E44C71F2967AD17004B2A72 /* MastodonSDKDynamic */; settings = {ATTRIBUTES = (CodeSignOnCopy, ); }; };
C24C97032922F30500BAE8CB /* RefreshControl.swift in Sources */ = {isa = PBXBuildFile; fileRef = C24C97022922F30500BAE8CB /* RefreshControl.swift */; };
D807C6C029DE197900A4E17C /* EducationViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D807C6BF29DE197900A4E17C /* EducationViewController.swift */; };
D808B94C296ECFDC0031EB1E /* StatusEditHistoryViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = D808B94B296ECFDC0031EB1E /* StatusEditHistoryViewModel.swift */; };
D808B94E296EFBBA0031EB1E /* StatusEditHistoryTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = D808B94D296EFBBA0031EB1E /* StatusEditHistoryTableViewCell.swift */; };
D80911082AC4BFDE00EB4D15 /* ServerDetailsViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D80911072AC4BFDE00EB4D15 /* ServerDetailsViewController.swift */; };
D8099078294BC8A30050219F /* PrivacyTableViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D8099077294BC8A30050219F /* PrivacyTableViewController.swift */; };
D809907A294BC9390050219F /* PrivacyTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = D8099079294BC9390050219F /* PrivacyTableViewCell.swift */; };
D809907C294D25510050219F /* PrivacyViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = D809907B294D25510050219F /* PrivacyViewModel.swift */; };
D81439862AD415DE0071A88F /* AboutInstance.swift in Sources */ = {isa = PBXBuildFile; fileRef = D81439852AD415DE0071A88F /* AboutInstance.swift */; };
D81439882AD450A40071A88F /* AboutInstanceTableViewDataSource.swift in Sources */ = {isa = PBXBuildFile; fileRef = D81439872AD450A40071A88F /* AboutInstanceTableViewDataSource.swift */; };
D81A22752AB4643200905D71 /* SearchResultsOverviewTableViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D81A22742AB4643200905D71 /* SearchResultsOverviewTableViewController.swift */; };
D81A22782AB4782400905D71 /* SearchResultOverviewSection.swift in Sources */ = {isa = PBXBuildFile; fileRef = D81A22772AB4782400905D71 /* SearchResultOverviewSection.swift */; };
D81A227B2AB47B9A00905D71 /* SearchResultDefaultSectionTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = D81A227A2AB47B9A00905D71 /* SearchResultDefaultSectionTableViewCell.swift */; };
@ -144,6 +145,8 @@
D8318A882A4468D300C0FB73 /* NotificationSettingsViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D8318A872A4468D300C0FB73 /* NotificationSettingsViewController.swift */; };
D8318A8A2A4468DC00C0FB73 /* AboutViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D8318A892A4468DC00C0FB73 /* AboutViewController.swift */; };
D8363B1629469CE200A74079 /* OnboardingNextView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D8363B1529469CE200A74079 /* OnboardingNextView.swift */; };
D852C23C2AC5D02C00309232 /* AboutInstanceViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D852C23B2AC5D02C00309232 /* AboutInstanceViewController.swift */; };
D852C23E2AC5D03300309232 /* InstanceRulesViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D852C23D2AC5D03300309232 /* InstanceRulesViewController.swift */; };
D87BFC8B291D5C6B00FEE264 /* MastodonLoginView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D87BFC8A291D5C6B00FEE264 /* MastodonLoginView.swift */; };
D87BFC8D291EB81200FEE264 /* MastodonLoginViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = D87BFC8C291EB81200FEE264 /* MastodonLoginViewModel.swift */; };
D87BFC8F291EC26A00FEE264 /* MastodonLoginServerTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = D87BFC8E291EC26A00FEE264 /* MastodonLoginServerTableViewCell.swift */; };
@ -173,6 +176,10 @@
D8F917112A4C6B40008A5370 /* GeneralSettingToggleTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = D8F917102A4C6B40008A5370 /* GeneralSettingToggleTableViewCell.swift */; };
D8F917122A4C6B67008A5370 /* GeneralSettingsViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D8318A832A4468A800C0FB73 /* GeneralSettingsViewController.swift */; };
D8F917142A4D74C3008A5370 /* GeneralSettingsDiffableTableViewDataSource.swift in Sources */ = {isa = PBXBuildFile; fileRef = D8F917132A4D74C3008A5370 /* GeneralSettingsDiffableTableViewDataSource.swift */; };
D8FAAE3D2AD042E700DC1832 /* AdminTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = D8FAAE3C2AD042E700DC1832 /* AdminTableViewCell.swift */; };
D8FAAE3F2AD0430E00DC1832 /* ContactAdminTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = D8FAAE3E2AD0430E00DC1832 /* ContactAdminTableViewCell.swift */; };
D8FAAE412AD0475900DC1832 /* AboutInstanceTableViewHeader.swift in Sources */ = {isa = PBXBuildFile; fileRef = D8FAAE402AD0475900DC1832 /* AboutInstanceTableViewHeader.swift */; };
D8FAAE432AD047B200DC1832 /* AboutInstanceTableFooterView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D8FAAE422AD047B200DC1832 /* AboutInstanceTableFooterView.swift */; };
DB0009A626AEE5DC009B9D2D /* Intents.intentdefinition in Sources */ = {isa = PBXBuildFile; fileRef = DB0009A926AEE5DC009B9D2D /* Intents.intentdefinition */; settings = {ATTRIBUTES = (codegen, ); }; };
DB0009A726AEE5DC009B9D2D /* Intents.intentdefinition in Sources */ = {isa = PBXBuildFile; fileRef = DB0009A926AEE5DC009B9D2D /* Intents.intentdefinition */; };
DB023D26279FFB0A005AC798 /* ShareActivityProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB023D25279FFB0A005AC798 /* ShareActivityProvider.swift */; };
@ -489,6 +496,7 @@
DBFEEC99279BDCDE004F81DD /* ProfileAboutViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = DBFEEC98279BDCDE004F81DD /* ProfileAboutViewModel.swift */; };
DBFEEC9B279BDDD9004F81DD /* ProfileAboutViewModel+Diffable.swift in Sources */ = {isa = PBXBuildFile; fileRef = DBFEEC9A279BDDD9004F81DD /* ProfileAboutViewModel+Diffable.swift */; };
DBFEEC9D279C12C1004F81DD /* ProfileFieldEditCollectionViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = DBFEEC9C279C12C1004F81DD /* ProfileFieldEditCollectionViewCell.swift */; };
EF7771EAA493A869D65A105C /* Pods_Mastodon_MastodonUITests.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DD12474E169668871A9F6AB4 /* Pods_Mastodon_MastodonUITests.framework */; };
/* End PBXBuildFile section */
/* Begin PBXContainerItemProxy section */
@ -714,7 +722,6 @@
2D8434FA25FF46B300EECE90 /* HomeTimelineNavigationBarTitleView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HomeTimelineNavigationBarTitleView.swift; sourceTree = "<group>"; };
2D84350425FF858100EECE90 /* UIScrollView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UIScrollView.swift; sourceTree = "<group>"; };
2D939AB425EDD8A90076FA61 /* String.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = String.swift; sourceTree = "<group>"; };
2DA7D05025CA545E00804E11 /* LoadMoreConfigurableTableViewContainer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LoadMoreConfigurableTableViewContainer.swift; sourceTree = "<group>"; };
2DAC9E37262FC2320062E1A6 /* SuggestionAccountViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SuggestionAccountViewController.swift; sourceTree = "<group>"; };
2DAC9E3D262FC2400062E1A6 /* SuggestionAccountViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SuggestionAccountViewModel.swift; sourceTree = "<group>"; };
2DAC9E45262FC9FD0062E1A6 /* SuggestionAccountTableViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SuggestionAccountTableViewCell.swift; sourceTree = "<group>"; };
@ -722,9 +729,7 @@
2DE0FACD2615F7AD00CDF649 /* RecommendAccountSection.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RecommendAccountSection.swift; sourceTree = "<group>"; };
2E1F6A67FDF9771D3E064FDC /* Pods-Mastodon.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Mastodon.debug.xcconfig"; path = "Target Support Files/Pods-Mastodon/Pods-Mastodon.debug.xcconfig"; sourceTree = "<group>"; };
3B7FD8F28DDA8FBCE5562B78 /* Pods-NotificationService.asdk - debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-NotificationService.asdk - debug.xcconfig"; path = "Target Support Files/Pods-NotificationService/Pods-NotificationService.asdk - debug.xcconfig"; sourceTree = "<group>"; };
3C030226D3C73DCC23D67452 /* Pods_Mastodon_MastodonUITests.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Mastodon_MastodonUITests.framework; sourceTree = BUILT_PRODUCTS_DIR; };
3E08A432F40BA7B9CAA9DB68 /* Pods-AppShared.release snapshot.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-AppShared.release snapshot.xcconfig"; path = "Target Support Files/Pods-AppShared/Pods-AppShared.release snapshot.xcconfig"; sourceTree = "<group>"; };
452147B2903DF38070FE56A2 /* Pods_MastodonTests.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_MastodonTests.framework; sourceTree = BUILT_PRODUCTS_DIR; };
459EA4F43058CAB47719E963 /* Pods-Mastodon-MastodonUITests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Mastodon-MastodonUITests.debug.xcconfig"; path = "Target Support Files/Pods-Mastodon-MastodonUITests/Pods-Mastodon-MastodonUITests.debug.xcconfig"; sourceTree = "<group>"; };
46DAB0EBDDFB678347CD96FF /* Pods-MastodonTests.asdk - release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-MastodonTests.asdk - release.xcconfig"; path = "Target Support Files/Pods-MastodonTests/Pods-MastodonTests.asdk - release.xcconfig"; sourceTree = "<group>"; };
5B24BBD7262DB14800A9381B /* ReportViewModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ReportViewModel.swift; sourceTree = "<group>"; };
@ -756,12 +761,13 @@
85904C03293BC1940011C817 /* URLActivityItemWithMetadata.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = URLActivityItemWithMetadata.swift; sourceTree = "<group>"; };
85BC11B22932414900E191CD /* AltTextViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AltTextViewController.swift; sourceTree = "<group>"; };
8850E70A1D5FF51432E43653 /* Pods-Mastodon-MastodonUITests.asdk - release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Mastodon-MastodonUITests.asdk - release.xcconfig"; path = "Target Support Files/Pods-Mastodon-MastodonUITests/Pods-Mastodon-MastodonUITests.asdk - release.xcconfig"; sourceTree = "<group>"; };
89FE8B85A00419CEF4678056 /* Pods_MastodonTests.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_MastodonTests.framework; sourceTree = BUILT_PRODUCTS_DIR; };
8C2A2448AEEDA65B4CD099FC /* Pods_Mastodon.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Mastodon.framework; sourceTree = BUILT_PRODUCTS_DIR; };
8E79CCBE51FBC3F7FE8CF49F /* Pods-MastodonTests.release snapshot.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-MastodonTests.release snapshot.xcconfig"; path = "Target Support Files/Pods-MastodonTests/Pods-MastodonTests.release snapshot.xcconfig"; sourceTree = "<group>"; };
8ED8C4B1F1BA2DCFF2926BB1 /* Pods-Mastodon-NotificationService.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Mastodon-NotificationService.debug.xcconfig"; path = "Target Support Files/Pods-Mastodon-NotificationService/Pods-Mastodon-NotificationService.debug.xcconfig"; sourceTree = "<group>"; };
9780A4C98FFC65B32B50D1C0 /* Pods-MastodonTests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-MastodonTests.release.xcconfig"; path = "Target Support Files/Pods-MastodonTests/Pods-MastodonTests.release.xcconfig"; sourceTree = "<group>"; };
9A0982D8F349244EB558CDFD /* Pods-AppShared.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-AppShared.debug.xcconfig"; path = "Target Support Files/Pods-AppShared/Pods-AppShared.debug.xcconfig"; sourceTree = "<group>"; };
9CFF58FD900AC059428700E7 /* Pods-NotificationService.asdk - release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-NotificationService.asdk - release.xcconfig"; path = "Target Support Files/Pods-NotificationService/Pods-NotificationService.asdk - release.xcconfig"; sourceTree = "<group>"; };
A4ABE34829701A4496C5BB64 /* Pods_Mastodon.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Mastodon.framework; sourceTree = BUILT_PRODUCTS_DIR; };
A67FD038ECDA0E411AF8DB4D /* Pods-Mastodon-MastodonUITests.asdk.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Mastodon-MastodonUITests.asdk.xcconfig"; path = "Target Support Files/Pods-Mastodon-MastodonUITests/Pods-Mastodon-MastodonUITests.asdk.xcconfig"; sourceTree = "<group>"; };
A9B1FB898DFD6063B044298C /* Pods-AppShared.asdk - debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-AppShared.asdk - debug.xcconfig"; path = "Target Support Files/Pods-AppShared/Pods-AppShared.asdk - debug.xcconfig"; sourceTree = "<group>"; };
B31D44635FCF6452F7E1B865 /* Pods-Mastodon-AppShared.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Mastodon-AppShared.release.xcconfig"; path = "Target Support Files/Pods-Mastodon-AppShared/Pods-Mastodon-AppShared.release.xcconfig"; sourceTree = "<group>"; };
@ -770,14 +776,16 @@
BD7598A87F4497045EDEF252 /* Pods-Mastodon.asdk - release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Mastodon.asdk - release.xcconfig"; path = "Target Support Files/Pods-Mastodon/Pods-Mastodon.asdk - release.xcconfig"; sourceTree = "<group>"; };
C24C97022922F30500BAE8CB /* RefreshControl.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RefreshControl.swift; sourceTree = "<group>"; };
C3789232A52F43529CA67E95 /* Pods-MastodonIntent.asdk - debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-MastodonIntent.asdk - debug.xcconfig"; path = "Target Support Files/Pods-MastodonIntent/Pods-MastodonIntent.asdk - debug.xcconfig"; sourceTree = "<group>"; };
CD92E0F10BDE4FE7C4B999F2 /* Pods_MastodonTests.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_MastodonTests.framework; sourceTree = BUILT_PRODUCTS_DIR; };
D7D7CF93E262178800077512 /* Pods-Mastodon-AppShared.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Mastodon-AppShared.debug.xcconfig"; path = "Target Support Files/Pods-Mastodon-AppShared/Pods-Mastodon-AppShared.debug.xcconfig"; sourceTree = "<group>"; };
D807C6BF29DE197900A4E17C /* EducationViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EducationViewController.swift; sourceTree = "<group>"; };
D808B94B296ECFDC0031EB1E /* StatusEditHistoryViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StatusEditHistoryViewModel.swift; sourceTree = "<group>"; };
D808B94D296EFBBA0031EB1E /* StatusEditHistoryTableViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StatusEditHistoryTableViewCell.swift; sourceTree = "<group>"; };
D80911072AC4BFDE00EB4D15 /* ServerDetailsViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ServerDetailsViewController.swift; sourceTree = "<group>"; };
D8099077294BC8A30050219F /* PrivacyTableViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PrivacyTableViewController.swift; sourceTree = "<group>"; };
D8099079294BC9390050219F /* PrivacyTableViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PrivacyTableViewCell.swift; sourceTree = "<group>"; };
D809907B294D25510050219F /* PrivacyViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PrivacyViewModel.swift; sourceTree = "<group>"; };
D81439852AD415DE0071A88F /* AboutInstance.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AboutInstance.swift; sourceTree = "<group>"; };
D81439872AD450A40071A88F /* AboutInstanceTableViewDataSource.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AboutInstanceTableViewDataSource.swift; sourceTree = "<group>"; };
D81A22742AB4643200905D71 /* SearchResultsOverviewTableViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SearchResultsOverviewTableViewController.swift; sourceTree = "<group>"; };
D81A22772AB4782400905D71 /* SearchResultOverviewSection.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SearchResultOverviewSection.swift; sourceTree = "<group>"; };
D81A227A2AB47B9A00905D71 /* SearchResultDefaultSectionTableViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SearchResultDefaultSectionTableViewCell.swift; sourceTree = "<group>"; };
@ -787,7 +795,6 @@
D82463532A52B47B00A3DBDD /* be */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = be; path = be.lproj/WidgetExtension.strings; sourceTree = "<group>"; };
D82463542A52B47B00A3DBDD /* be */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = be; path = be.lproj/InfoPlist.strings; sourceTree = "<group>"; };
D82463552A52B47B00A3DBDD /* be */ = {isa = PBXFileReference; lastKnownFileType = text.plist.stringsdict; name = be; path = be.lproj/Intents.stringsdict; sourceTree = "<group>"; };
D82BD7512ABC42D6009A374A /* Coordinator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Coordinator.swift; sourceTree = "<group>"; };
D82BD7542ABC73AF009A374A /* NotificationPolicyTableViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NotificationPolicyTableViewCell.swift; sourceTree = "<group>"; };
D8318A7F2A4466D300C0FB73 /* SettingsCoordinator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SettingsCoordinator.swift; sourceTree = "<group>"; };
D8318A832A4468A800C0FB73 /* GeneralSettingsViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GeneralSettingsViewController.swift; sourceTree = "<group>"; };
@ -795,6 +802,8 @@
D8318A872A4468D300C0FB73 /* NotificationSettingsViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NotificationSettingsViewController.swift; sourceTree = "<group>"; };
D8318A892A4468DC00C0FB73 /* AboutViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AboutViewController.swift; sourceTree = "<group>"; };
D8363B1529469CE200A74079 /* OnboardingNextView.swift */ = {isa = PBXFileReference; indentWidth = 4; lastKnownFileType = sourcecode.swift; path = OnboardingNextView.swift; sourceTree = "<group>"; tabWidth = 4; };
D852C23B2AC5D02C00309232 /* AboutInstanceViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AboutInstanceViewController.swift; sourceTree = "<group>"; };
D852C23D2AC5D03300309232 /* InstanceRulesViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InstanceRulesViewController.swift; sourceTree = "<group>"; };
D87BFC8A291D5C6B00FEE264 /* MastodonLoginView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MastodonLoginView.swift; sourceTree = "<group>"; };
D87BFC8C291EB81200FEE264 /* MastodonLoginViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MastodonLoginViewModel.swift; sourceTree = "<group>"; };
D87BFC8E291EC26A00FEE264 /* MastodonLoginServerTableViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MastodonLoginServerTableViewCell.swift; sourceTree = "<group>"; };
@ -834,6 +843,10 @@
D8F9170E2A4B47EF008A5370 /* Coordinator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Coordinator.swift; sourceTree = "<group>"; };
D8F917102A4C6B40008A5370 /* GeneralSettingToggleTableViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GeneralSettingToggleTableViewCell.swift; sourceTree = "<group>"; };
D8F917132A4D74C3008A5370 /* GeneralSettingsDiffableTableViewDataSource.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GeneralSettingsDiffableTableViewDataSource.swift; sourceTree = "<group>"; };
D8FAAE3C2AD042E700DC1832 /* AdminTableViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AdminTableViewCell.swift; sourceTree = "<group>"; };
D8FAAE3E2AD0430E00DC1832 /* ContactAdminTableViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContactAdminTableViewCell.swift; sourceTree = "<group>"; };
D8FAAE402AD0475900DC1832 /* AboutInstanceTableViewHeader.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AboutInstanceTableViewHeader.swift; sourceTree = "<group>"; };
D8FAAE422AD047B200DC1832 /* AboutInstanceTableFooterView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AboutInstanceTableFooterView.swift; sourceTree = "<group>"; };
DB0009A826AEE5DC009B9D2D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.intentdefinition; name = Base; path = Base.lproj/Intents.intentdefinition; sourceTree = "<group>"; };
DB0009AD26AEE5E4009B9D2D /* ar */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ar; path = ar.lproj/Intents.strings; sourceTree = "<group>"; };
DB023D25279FFB0A005AC798 /* ShareActivityProvider.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ShareActivityProvider.swift; sourceTree = "<group>"; };
@ -897,7 +910,6 @@
DB1FD44325F26CCC004CFCFC /* PickServerSection.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PickServerSection.swift; sourceTree = "<group>"; };
DB1FD44F25F26FA1004CFCFC /* MastodonPickServerViewModel+Diffable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "MastodonPickServerViewModel+Diffable.swift"; sourceTree = "<group>"; };
DB1FD45925F27898004CFCFC /* CategoryPickerItem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CategoryPickerItem.swift; sourceTree = "<group>"; };
DB1FD45F25F278AF004CFCFC /* CategoryPickerSection.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CategoryPickerSection.swift; sourceTree = "<group>"; };
DB2B3ABD25E37E15007045F9 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/InfoPlist.strings; sourceTree = "<group>"; };
DB2F073325E8ECF000957B2D /* AuthenticationViewModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AuthenticationViewModel.swift; sourceTree = "<group>"; };
DB336F3E278E668C0031E64B /* StatusTableViewCell+ViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "StatusTableViewCell+ViewModel.swift"; sourceTree = "<group>"; };
@ -1239,6 +1251,7 @@
DBFEEC9A279BDDD9004F81DD /* ProfileAboutViewModel+Diffable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "ProfileAboutViewModel+Diffable.swift"; sourceTree = "<group>"; };
DBFEEC9C279C12C1004F81DD /* ProfileFieldEditCollectionViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ProfileFieldEditCollectionViewCell.swift; sourceTree = "<group>"; };
DBFEF06726A58D07006D7ED1 /* ShareActionExtension.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = ShareActionExtension.entitlements; sourceTree = "<group>"; };
DD12474E169668871A9F6AB4 /* Pods_Mastodon_MastodonUITests.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Mastodon_MastodonUITests.framework; sourceTree = BUILT_PRODUCTS_DIR; };
DDB1B139FA8EA26F510D58B6 /* Pods-AppShared.asdk - release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-AppShared.asdk - release.xcconfig"; path = "Target Support Files/Pods-AppShared/Pods-AppShared.asdk - release.xcconfig"; sourceTree = "<group>"; };
DF65937EC1FF64462BC002EE /* Pods-MastodonTests.profile.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-MastodonTests.profile.xcconfig"; path = "Target Support Files/Pods-MastodonTests/Pods-MastodonTests.profile.xcconfig"; sourceTree = "<group>"; };
E5C7236E58D14A0322FE00F2 /* Pods-Mastodon-MastodonUITests.asdk - debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Mastodon-MastodonUITests.asdk - debug.xcconfig"; path = "Target Support Files/Pods-Mastodon-MastodonUITests/Pods-Mastodon-MastodonUITests.asdk - debug.xcconfig"; sourceTree = "<group>"; };
@ -1248,7 +1261,6 @@
ECA373ABA86BE3C2D7ED878E /* Pods-AppShared.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-AppShared.release.xcconfig"; path = "Target Support Files/Pods-AppShared/Pods-AppShared.release.xcconfig"; sourceTree = "<group>"; };
EE13214BC0246BE5210CCC10 /* Pods-AppShared.asdk.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-AppShared.asdk.xcconfig"; path = "Target Support Files/Pods-AppShared/Pods-AppShared.asdk.xcconfig"; sourceTree = "<group>"; };
F31E7502A7E3945B98C6CBAF /* Pods-NotificationService.asdk.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-NotificationService.asdk.xcconfig"; path = "Target Support Files/Pods-NotificationService/Pods-NotificationService.asdk.xcconfig"; sourceTree = "<group>"; };
F4A2A2D7000E477CA459ADA9 /* Pods_AppShared.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_AppShared.framework; sourceTree = BUILT_PRODUCTS_DIR; };
F920AD4EC23B0D00F5CCA58E /* Pods-MastodonIntent.asdk - release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-MastodonIntent.asdk - release.xcconfig"; path = "Target Support Files/Pods-MastodonIntent/Pods-MastodonIntent.asdk - release.xcconfig"; sourceTree = "<group>"; };
/* End PBXFileReference section */
@ -1279,7 +1291,7 @@
files = (
357FEEAF29523D470021C9DC /* MastodonSDKDynamic in Frameworks */,
DBF96326262EC0A6001D8D25 /* AuthenticationServices.framework in Frameworks */,
87FFDA5D898A5C42ADCB35E7 /* Pods_Mastodon.framework in Frameworks */,
71458AF57697DB405CFEC37C /* Pods_Mastodon.framework in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@ -1288,8 +1300,7 @@
buildActionMask = 2147483647;
files = (
9E44C7202967AD17004B2A72 /* MastodonSDKDynamic in Frameworks */,
5E44BF88AD33646E64727BCF /* Pods_MastodonTests.framework in Frameworks */,
5E0DEC05797A7E6933788DDB /* Pods_MastodonTests.framework in Frameworks */,
7910197261F9D06EFCDCCDBC /* Pods_MastodonTests.framework in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@ -1297,7 +1308,7 @@
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
18BC7629F65E6DB12CB8416D /* Pods_Mastodon_MastodonUITests.framework in Frameworks */,
EF7771EAA493A869D65A105C /* Pods_Mastodon_MastodonUITests.framework in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@ -1722,15 +1733,14 @@
isa = PBXGroup;
children = (
DBF96325262EC0A6001D8D25 /* AuthenticationServices.framework */,
A4ABE34829701A4496C5BB64 /* Pods_Mastodon.framework */,
3C030226D3C73DCC23D67452 /* Pods_Mastodon_MastodonUITests.framework */,
452147B2903DF38070FE56A2 /* Pods_MastodonTests.framework */,
F4A2A2D7000E477CA459ADA9 /* Pods_AppShared.framework */,
DB8FAB9E26AEC3A2008E5AF4 /* Intents.framework */,
DB8FABA926AEC3A2008E5AF4 /* IntentsUI.framework */,
2A6451022964223800CD8B8A /* UniformTypeIdentifiers.framework */,
2A728121297EA9D7004138C5 /* WidgetKit.framework */,
2A728123297EA9D7004138C5 /* SwiftUI.framework */,
8C2A2448AEEDA65B4CD099FC /* Pods_Mastodon.framework */,
DD12474E169668871A9F6AB4 /* Pods_Mastodon_MastodonUITests.framework */,
89FE8B85A00419CEF4678056 /* Pods_MastodonTests.framework */,
);
name = Frameworks;
sourceTree = "<group>";
@ -1756,6 +1766,7 @@
D8F916FF2A4AD898008A5370 /* Settings Overview */,
D8F917042A4B0657008A5370 /* General Settings */,
D81D12432A4E181C005009D4 /* Notification Settings */,
D80911062AC4BFD100EB4D15 /* Server Details */,
D8F917092A4B2AFF008A5370 /* About Mastodon */,
D8318A7F2A4466D300C0FB73 /* SettingsCoordinator.swift */,
);
@ -1783,6 +1794,17 @@
path = Bookmark;
sourceTree = "<group>";
};
D80911062AC4BFD100EB4D15 /* Server Details */ = {
isa = PBXGroup;
children = (
D8FAAE3B2AD042CD00DC1832 /* Table View Components */,
D80911072AC4BFDE00EB4D15 /* ServerDetailsViewController.swift */,
D852C23B2AC5D02C00309232 /* AboutInstanceViewController.swift */,
D852C23D2AC5D03300309232 /* InstanceRulesViewController.swift */,
);
path = "Server Details";
sourceTree = "<group>";
};
D8099076294BC2BA0050219F /* Privacy */ = {
isa = PBXGroup;
children = (
@ -1929,6 +1951,19 @@
path = "About Mastodon";
sourceTree = "<group>";
};
D8FAAE3B2AD042CD00DC1832 /* Table View Components */ = {
isa = PBXGroup;
children = (
D8FAAE3C2AD042E700DC1832 /* AdminTableViewCell.swift */,
D8FAAE3E2AD0430E00DC1832 /* ContactAdminTableViewCell.swift */,
D8FAAE402AD0475900DC1832 /* AboutInstanceTableViewHeader.swift */,
D8FAAE422AD047B200DC1832 /* AboutInstanceTableFooterView.swift */,
D81439852AD415DE0071A88F /* AboutInstance.swift */,
D81439872AD450A40071A88F /* AboutInstanceTableViewDataSource.swift */,
);
path = "Table View Components";
sourceTree = "<group>";
};
DB01409B25C40BB600F9F3CF /* Onboarding */ = {
isa = PBXGroup;
children = (
@ -2110,7 +2145,6 @@
DB427DD325BAA00100D1B89D /* Products */,
1EBA4F56E920856A3FC84ACB /* Pods */,
3FE14AD363ED19AE7FF210A6 /* Frameworks */,
DB98335F25C93B0400AD9700 /* Recovered References */,
D8A6FE6029325F5900666A47 /* Localization */,
);
indentWidth = 4;
@ -2638,17 +2672,6 @@
path = Thread;
sourceTree = "<group>";
};
DB98335F25C93B0400AD9700 /* Recovered References */ = {
isa = PBXGroup;
children = (
CD92E0F10BDE4FE7C4B999F2 /* Pods_MastodonTests.framework */,
2DA7D05025CA545E00804E11 /* LoadMoreConfigurableTableViewContainer.swift */,
DB1FD45F25F278AF004CFCFC /* CategoryPickerSection.swift */,
D82BD7512ABC42D6009A374A /* Coordinator.swift */,
);
name = "Recovered References";
sourceTree = "<group>";
};
DB98EB4A27B0F0F50082E365 /* Cell */ = {
isa = PBXGroup;
children = (
@ -3269,7 +3292,7 @@
};
};
buildConfigurationList = DB427DCD25BAA00100D1B89D /* Build configuration list for PBXProject "Mastodon" */;
compatibilityVersion = "Xcode 9.3";
compatibilityVersion = "Xcode 15.0";
developmentRegion = en;
hasScannedForEncodings = 0;
knownRegions = (
@ -3615,6 +3638,7 @@
DB023D26279FFB0A005AC798 /* ShareActivityProvider.swift in Sources */,
5D0393962612D266007FE196 /* WebViewModel.swift in Sources */,
5B24BBDA262DB14800A9381B /* ReportViewModel.swift in Sources */,
D80911082AC4BFDE00EB4D15 /* ServerDetailsViewController.swift in Sources */,
2D5A3D3825CF8D9F002347D6 /* ScrollViewContainer.swift in Sources */,
DB6180EF26391CA50018D199 /* MediaPreviewImageViewController.swift in Sources */,
DB1E347825F519300079D7DF /* PickServerItem.swift in Sources */,
@ -3642,11 +3666,14 @@
DB697DD6278F4C29004EF2F7 /* DataSourceProvider.swift in Sources */,
DB0FCB8E2796C0B7006C02E2 /* TrendCollectionViewCell.swift in Sources */,
0F1E2D0B2615C39400C38565 /* DoubleTitleLabelNavigationBarTitleView.swift in Sources */,
D81439862AD415DE0071A88F /* AboutInstance.swift in Sources */,
DBDFF1902805543100557A48 /* DiscoveryPostsViewController.swift in Sources */,
DB697DD9278F4CED004EF2F7 /* HomeTimelineViewController+DataSourceProvider.swift in Sources */,
DB45FAD725CA6C76005A8AC7 /* UIBarButtonItem.swift in Sources */,
D8FAAE432AD047B200DC1832 /* AboutInstanceTableFooterView.swift in Sources */,
D808B94E296EFBBA0031EB1E /* StatusEditHistoryTableViewCell.swift in Sources */,
2D8434F525FF465D00EECE90 /* HomeTimelineNavigationBarTitleViewModel.swift in Sources */,
D852C23E2AC5D03300309232 /* InstanceRulesViewController.swift in Sources */,
DB938F0F2624119800E5B6C1 /* ThreadViewModel+LoadThreadState.swift in Sources */,
DB6180F226391CF40018D199 /* MediaPreviewImageViewModel.swift in Sources */,
62FD27D12893707600B205C5 /* BookmarkViewController.swift in Sources */,
@ -3665,6 +3692,7 @@
DBDFF19C28055BD600557A48 /* DiscoveryViewModel.swift in Sources */,
DBB3BA2A26A81C020004F2D4 /* FLAnimatedImageView.swift in Sources */,
DB3E6FF32806D97400B035AE /* DiscoveryNewsViewModel+State.swift in Sources */,
D8FAAE3F2AD0430E00DC1832 /* ContactAdminTableViewCell.swift in Sources */,
DB6746ED278F45F0008A6B94 /* AutoGenerateProtocolRelayDelegate.swift in Sources */,
DB0618032785A7100030EE79 /* RegisterSection.swift in Sources */,
DB63F76B279A5ED300455B82 /* NotificationTimelineViewModel+LoadOldestState.swift in Sources */,
@ -3693,6 +3721,7 @@
DBFEEC9D279C12C1004F81DD /* ProfileFieldEditCollectionViewCell.swift in Sources */,
DB3E6FEC2806D7F100B035AE /* DiscoveryNewsViewController.swift in Sources */,
DBCBED1726132DB500B49291 /* UserTimelineViewModel+Diffable.swift in Sources */,
D8FAAE412AD0475900DC1832 /* AboutInstanceTableViewHeader.swift in Sources */,
2DE0FACE2615F7AD00CDF649 /* RecommendAccountSection.swift in Sources */,
2DAC9E3E262FC2400062E1A6 /* SuggestionAccountViewModel.swift in Sources */,
DB603113279EBEBA00A935FE /* DataSourceFacade+Block.swift in Sources */,
@ -3856,6 +3885,7 @@
DB68A04A25E9027700CFDF14 /* AdaptiveStatusBarStyleNavigationController.swift in Sources */,
0FB3D33825E6401400AAD544 /* PickServerCell.swift in Sources */,
6213AF5C28939C8A00BCADB6 /* BookmarkViewModel+State.swift in Sources */,
D81439882AD450A40071A88F /* AboutInstanceTableViewDataSource.swift in Sources */,
D807C6C029DE197900A4E17C /* EducationViewController.swift in Sources */,
2D364F7825E66D8300204FDC /* MastodonResendEmailViewModel.swift in Sources */,
DBEFCD7B282A162400C0ABEA /* ReportReasonView.swift in Sources */,
@ -3923,6 +3953,7 @@
D8B5E4F42A4ED0240008970C /* NotificationSettingsViewModel.swift in Sources */,
DBD376B2269302A4007FEC24 /* UITableViewCell.swift in Sources */,
DB4F0966269ED52200D62E92 /* SearchResultViewModel.swift in Sources */,
D852C23C2AC5D02C00309232 /* AboutInstanceViewController.swift in Sources */,
D8F917142A4D74C3008A5370 /* GeneralSettingsDiffableTableViewDataSource.swift in Sources */,
DB6180FA26391F2E0018D199 /* MediaPreviewViewModel.swift in Sources */,
2D7631A825C1535600929FB9 /* StatusTableViewCell.swift in Sources */,
@ -3938,6 +3969,7 @@
DB3E6FE42806A5B800B035AE /* DiscoverySection.swift in Sources */,
DB697DDB278F4DE3004EF2F7 /* DataSourceProvider+StatusTableViewCellDelegate.swift in Sources */,
DB87D4512609CF1E00D12C0D /* ComposeStatusPollOptionAppendEntryCollectionViewCell.swift in Sources */,
D8FAAE3D2AD042E700DC1832 /* AdminTableViewCell.swift in Sources */,
DBB45B5627B39FC9002DC5A7 /* MediaPreviewVideoViewController.swift in Sources */,
D8A6AB6C291C5136003AB663 /* MastodonLoginViewController.swift in Sources */,
DB0FCB8027968F70006C02E2 /* MastodonStatusThreadViewModel.swift in Sources */,

View File

@ -46,6 +46,15 @@
"version": "3.1.3"
}
},
{
"package": "FXPageControl",
"repositoryURL": "https://github.com/nicklockwood/FXPageControl.git",
"state": {
"branch": null,
"revision": "a94633402ba98c52f86c2a70e61ff086dec9de78",
"version": "1.6.0"
}
},
{
"package": "KeychainAccess",
"repositoryURL": "https://github.com/kishikawakatsumi/KeychainAccess.git",
@ -91,15 +100,6 @@
"version": "10.11.2"
}
},
{
"package": "NukeFLAnimatedImagePlugin",
"repositoryURL": "https://github.com/kean/Nuke-FLAnimatedImage-Plugin.git",
"state": {
"branch": null,
"revision": "b59c346a7d536336db3b0f12c72c6e53ee709e16",
"version": "8.0.0"
}
},
{
"package": "Pageboy",
"repositoryURL": "https://github.com/uias/Pageboy",
@ -216,6 +216,15 @@
"revision": "20f513ded04a040cdf5467f0891849b1763ede3b",
"version": "1.4.1"
}
},
{
"package": "XLPagerTabStrip",
"repositoryURL": "https://github.com/xmartlabs/XLPagerTabStrip.git",
"state": {
"branch": null,
"revision": "211ed62aa376722cf93c429802a8b6ff66a8bd52",
"version": "9.1.0"
}
}
]
},

View File

@ -546,7 +546,9 @@ private extension SceneCoordinator {
accountName: accountName,
setting: setting,
appContext: appContext,
authContext: authContext)
authContext: authContext,
sceneCoordinator: self
)
settingsCoordinator.delegate = self
settingsCoordinator.start()
@ -648,7 +650,5 @@ extension SceneCoordinator: SettingsCoordinatorDelegate {
authenticationController.authenticationSession?.start()
self.mastodonAuthenticationController = authenticationController
}
}

View File

@ -10,7 +10,7 @@ import MastodonAsset
import MastodonLocalization
final class ServerRulesTableViewCell: UITableViewCell {
static let reuseIdentifier = "ServerRulesTableViewCell"
static let margin: CGFloat = 23
let indexImageView: UIImageView = {

View File

@ -15,10 +15,7 @@ extension MastodonServerRulesViewModel {
var snapshot = NSDiffableDataSourceSnapshot<ServerRuleSection, ServerRuleItem>()
snapshot.appendSections([.rules])
let ruleItems: [ServerRuleItem] = rules.enumerated().map { i, rule in
let ruleContext = ServerRuleItem.RuleContext(index: i, rule: rule)
return ServerRuleItem.rule(ruleContext)
}
let ruleItems: [ServerRuleItem] = rules.enumerated().map { index, rule in return ServerRuleItem.rule(index: index, rule: rule) }
snapshot.appendItems(ruleItems, toSection: .rules)
diffableDataSource?.apply(snapshot, animatingDifferences: false)
}

View File

@ -9,12 +9,5 @@ import Foundation
import MastodonSDK
enum ServerRuleItem: Hashable {
case rule(RuleContext)
}
extension ServerRuleItem {
struct RuleContext: Hashable {
let index: Int
let rule: Mastodon.Entity.Instance.Rule
}
case rule(index: Int, rule: Mastodon.Entity.Instance.Rule)
}

View File

@ -19,11 +19,11 @@ extension ServerRuleSection {
) -> UITableViewDiffableDataSource<ServerRuleSection, ServerRuleItem> {
return UITableViewDiffableDataSource(tableView: tableView) { tableView, indexPath, item in
switch item {
case .rule(let ruleContext):
case .rule(let index, let rule):
let cell = tableView.dequeueReusableCell(withIdentifier: String(describing: ServerRulesTableViewCell.self), for: indexPath) as! ServerRulesTableViewCell
cell.indexImageView.image = UIImage(systemName: "\(ruleContext.index + 1).circle") ?? UIImage(systemName: "questionmark.circle")
cell.indexImageView.image = UIImage(systemName: "\(index + 1).circle") ?? UIImage(systemName: "questionmark.circle")
cell.indexImageView.tintColor = Asset.Colors.Brand.lightBlurple.color
cell.ruleLabel.text = ruleContext.rule.text
cell.ruleLabel.text = rule.text
return cell
}
}

View File

@ -23,7 +23,7 @@ enum AboutSettingsEntry: Hashable {
case .privacyPolicy:
return L10n.Scene.Settings.AboutMastodon.privacyPolicy
case .clearMediaCache(_):
return L10n.Scene.Settings.AboutMastodon.cleaerMediaStorage
return L10n.Scene.Settings.AboutMastodon.clearMediaStorage
}
}

View File

@ -0,0 +1,155 @@
// Copyright © 2023 Mastodon gGmbH. All rights reserved.
import UIKit
import MastodonSDK
protocol AboutInstanceViewControllerDelegate: AnyObject {
func showAdminAccount(_ viewController: AboutInstanceViewController, account: Mastodon.Entity.Account)
func sendEmailToAdmin(_ viewController: AboutInstanceViewController, emailAddress: String)
}
class AboutInstanceViewController: UIViewController {
weak var delegate: AboutInstanceViewControllerDelegate?
var dataSource: AboutInstanceTableViewDataSource?
let tableView: UITableView
let headerView: AboutInstanceTableHeaderView
let footerView: AboutInstanceTableFooterView
var instance: Mastodon.Entity.V2.Instance?
init() {
tableView = UITableView(frame: .zero, style: .insetGrouped)
tableView.translatesAutoresizingMaskIntoConstraints = false
tableView.register(ContactAdminTableViewCell.self, forCellReuseIdentifier: ContactAdminTableViewCell.reuseIdentifier)
tableView.register(AdminTableViewCell.self, forCellReuseIdentifier: AdminTableViewCell.reuseIdentifier)
headerView = AboutInstanceTableHeaderView()
footerView = AboutInstanceTableFooterView()
super.init(nibName: nil, bundle: nil)
let dataSource = AboutInstanceTableViewDataSource(tableView: tableView) { tableView, indexPath, itemIdentifier in
switch itemIdentifier {
case .adminAccount(let account):
guard let cell = tableView.dequeueReusableCell(withIdentifier: AdminTableViewCell.reuseIdentifier, for: indexPath) as? AdminTableViewCell else { fatalError("WTF?! Wrong cell.") }
cell.condensedUserView.configure(with: account, showFollowers: false)
return cell
case .contactAdmin:
guard let cell = tableView.dequeueReusableCell(withIdentifier: ContactAdminTableViewCell.reuseIdentifier, for: indexPath) as? ContactAdminTableViewCell else { fatalError("WTF?! Wrong cell.") }
cell.configure()
return cell
}
}
tableView.delegate = self
tableView.dataSource = dataSource
self.dataSource = dataSource
view.addSubview(tableView)
setupConstraints()
}
required init?(coder: NSCoder) { fatalError("init(coder:) has not been implemented") }
private func setupConstraints() {
let constraints = [
tableView.topAnchor.constraint(equalTo: view.topAnchor),
tableView.leadingAnchor.constraint(equalTo: view.leadingAnchor),
view.trailingAnchor.constraint(equalTo: tableView.trailingAnchor),
view.bottomAnchor.constraint(equalTo: tableView.bottomAnchor),
]
NSLayoutConstraint.activate(constraints)
}
override func viewDidLoad() {
super.viewDidLoad()
tableView.tableHeaderView = headerView
tableView.tableFooterView = footerView
}
override func viewWillLayoutSubviews() {
super.viewWillLayoutSubviews()
if let tableHeaderView = tableView.tableHeaderView {
let size = tableHeaderView.systemLayoutSizeFitting(.init(width: self.tableView.frame.width, height: 10_000))
tableHeaderView.frame.size = size
tableView.tableHeaderView = tableHeaderView
}
if let tableFooterView = tableView.tableFooterView {
let size = tableFooterView.systemLayoutSizeFitting(.init(width: self.tableView.frame.width, height: 10_000))
tableFooterView.frame.size = size
tableView.tableFooterView = tableFooterView
}
super.viewWillLayoutSubviews()
}
func update(with instance: Mastodon.Entity.V2.Instance) {
self.instance = instance
var snapshot = NSDiffableDataSourceSnapshot<AboutInstanceSection, AboutInstanceItem>()
snapshot.appendSections([.main])
if let account = instance.contact?.account {
snapshot.appendItems([.adminAccount(account)], toSection: .main)
}
if let email = instance.contact?.email {
snapshot.appendItems([.contactAdmin(email)], toSection: .main)
}
dataSource?.apply(snapshot, animatingDifferences: false)
guard let thumbnailUrlString = instance.thumbnail?.url, let thumbnailUrl = URL(string: thumbnailUrlString) else { return }
DispatchQueue.main.async {
self.headerView.updateImage(with: thumbnailUrl) { [weak self] in
DispatchQueue.main.async {
guard let self else { return }
self.view.setNeedsLayout()
self.view.layoutIfNeeded()
}
}
}
}
func updateFooter(with extendedDescription: Mastodon.Entity.ExtendedDescription) {
DispatchQueue.main.async {
self.footerView.update(with: extendedDescription)
self.view.setNeedsLayout()
self.view.layoutIfNeeded()
}
}
}
extension AboutInstanceViewController: UITableViewDelegate {
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
guard let snapshot = dataSource?.snapshot() else {
return tableView.deselectRow(at: indexPath, animated: true)
}
switch snapshot.itemIdentifiers(inSection: .main)[indexPath.row] {
case .adminAccount(let account):
delegate?.showAdminAccount(self, account: account)
case .contactAdmin(let email):
delegate?.sendEmailToAdmin(self, emailAddress: email)
}
tableView.deselectRow(at: indexPath, animated: true)
}
}

View File

@ -0,0 +1,58 @@
// Copyright © 2023 Mastodon gGmbH. All rights reserved.
import UIKit
import MastodonSDK
protocol InstanceRulesViewControllerDelegate: AnyObject {
}
class InstanceRulesViewController: UIViewController {
weak var delegate: InstanceRulesViewControllerDelegate?
let tableView: UITableView
var dataSource: UITableViewDiffableDataSource<ServerRuleSection, ServerRuleItem>?
var sections: [ServerRuleSection] = []
init() {
tableView = UITableView(frame: .zero, style: .insetGrouped)
tableView.translatesAutoresizingMaskIntoConstraints = false
tableView.register(ServerRulesTableViewCell.self, forCellReuseIdentifier: ServerRulesTableViewCell.reuseIdentifier)
super.init(nibName: nil, bundle: nil)
view.addSubview(tableView)
let dataSource = ServerRuleSection.tableViewDiffableDataSource(tableView: tableView)
tableView.dataSource = dataSource
self.dataSource = dataSource
setupConstraints()
}
required init?(coder: NSCoder) { fatalError("init(coder:) has not been implemented") }
private func setupConstraints() {
let constraints = [
tableView.topAnchor.constraint(equalTo: view.topAnchor),
tableView.leadingAnchor.constraint(equalTo: view.leadingAnchor),
view.trailingAnchor.constraint(equalTo: tableView.trailingAnchor),
view.bottomAnchor.constraint(equalTo: tableView.bottomAnchor),
]
NSLayoutConstraint.activate(constraints)
}
func update(with instance: Mastodon.Entity.V2.Instance) {
guard let dataSource, let rules = instance.rules, rules.isNotEmpty else { return }
var snapshot = NSDiffableDataSourceSnapshot<ServerRuleSection, ServerRuleItem>()
snapshot.appendSections([.rules])
let ruleItems = rules.enumerated().compactMap { index, rule in ServerRuleItem.rule(index: index, rule: rule) }
snapshot.appendItems(ruleItems, toSection: .rules)
dataSource.apply(snapshot)
}
}

View File

@ -0,0 +1,165 @@
// Copyright © 2023 Mastodon gGmbH. All rights reserved.
import UIKit
import MastodonSDK
import MastodonLocalization
import MetaTextKit
enum ServerDetailsTab: Int, CaseIterable {
case about = 0
case rules = 1
var title: String {
switch self {
case .about: return L10n.Scene.Settings.ServerDetails.about
case .rules: return L10n.Scene.Settings.ServerDetails.rules
}
}
}
protocol ServerDetailsViewControllerDelegate: AnyObject {}
class ServerDetailsViewController: UIViewController {
weak var delegate: (ServerDetailsViewControllerDelegate & AboutInstanceViewControllerDelegate & InstanceRulesViewControllerDelegate & MetaLabelDelegate)? {
didSet {
aboutInstanceViewController.delegate = delegate
instanceRulesViewController.delegate = delegate
aboutInstanceViewController.footerView.contentLabel.linkDelegate = delegate
}
}
let pageController: UIPageViewController
private let segmentedControlWrapper: UIView
let segmentedControl: UISegmentedControl
let aboutInstanceViewController: AboutInstanceViewController
let instanceRulesViewController: InstanceRulesViewController
let containerView: UIView
init(domain: String) {
segmentedControl = UISegmentedControl()
segmentedControl.translatesAutoresizingMaskIntoConstraints = false
segmentedControlWrapper = UIView()
segmentedControlWrapper.translatesAutoresizingMaskIntoConstraints = false
segmentedControlWrapper.addSubview(segmentedControl)
containerView = UIView()
containerView.translatesAutoresizingMaskIntoConstraints = false
aboutInstanceViewController = AboutInstanceViewController()
instanceRulesViewController = InstanceRulesViewController()
pageController = UIPageViewController(transitionStyle: .scroll, navigationOrientation: .horizontal)
pageController.setViewControllers([aboutInstanceViewController], direction: .forward, animated: false)
pageController.view.translatesAutoresizingMaskIntoConstraints = false
super.init(nibName: nil, bundle: nil)
view.addSubview(segmentedControlWrapper)
view.addSubview(containerView)
view.backgroundColor = .systemGroupedBackground
containerView.addSubview(pageController.view)
addChild(pageController)
pageController.didMove(toParent: self)
pageController.delegate = self
pageController.dataSource = self
ServerDetailsTab.allCases.forEach {
segmentedControl.insertSegment(withTitle: $0.title, at: $0.rawValue, animated: false)
}
segmentedControl.selectedSegmentIndex = ServerDetailsTab.about.rawValue
segmentedControl.addTarget(self, action: #selector(ServerDetailsViewController.segmentedControlValueChanged(_:)), for: .valueChanged)
setupConstraints()
title = domain
setupNavigationBarAppearance()
setupNavigationBarBackgroundView()
}
required init?(coder: NSCoder) { fatalError("init(coder:) has not been implemented") }
private func setupConstraints() {
let constraints = [
segmentedControlWrapper.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor),
segmentedControlWrapper.leadingAnchor.constraint(equalTo: view.leadingAnchor),
view.trailingAnchor.constraint(equalTo: segmentedControlWrapper.trailingAnchor),
containerView.topAnchor.constraint(equalTo: segmentedControlWrapper.bottomAnchor),
containerView.leadingAnchor.constraint(equalTo: view.leadingAnchor),
view.trailingAnchor.constraint(equalTo: containerView.trailingAnchor),
view.bottomAnchor.constraint(equalTo: containerView.bottomAnchor),
segmentedControl.topAnchor.constraint(equalTo: segmentedControlWrapper.topAnchor, constant: 4),
segmentedControl.leadingAnchor.constraint(equalTo: segmentedControlWrapper.leadingAnchor, constant: 16),
segmentedControlWrapper.trailingAnchor.constraint(equalTo: segmentedControl.trailingAnchor, constant: 16),
segmentedControlWrapper.bottomAnchor.constraint(equalTo: segmentedControl.bottomAnchor, constant: 8),
pageController.view.topAnchor.constraint(equalTo: containerView.topAnchor),
pageController.view.leadingAnchor.constraint(equalTo: containerView.leadingAnchor),
containerView.trailingAnchor.constraint(equalTo: pageController.view.trailingAnchor),
containerView.bottomAnchor.constraint(equalTo: pageController.view.bottomAnchor),
]
NSLayoutConstraint.activate(constraints)
}
//MARK: - Actions
@objc
func segmentedControlValueChanged(_ sender: UISegmentedControl) {
guard let selectedTab = ServerDetailsTab(rawValue: sender.selectedSegmentIndex) else { return }
switch selectedTab {
case .about:
pageController.setViewControllers([aboutInstanceViewController], direction: .reverse, animated: true)
case .rules:
pageController.setViewControllers([instanceRulesViewController], direction: .forward, animated: true)
}
}
func update(with instance: Mastodon.Entity.V2.Instance) {
aboutInstanceViewController.update(with: instance)
instanceRulesViewController.update(with: instance)
}
func updateFooter(with extendedDescription: Mastodon.Entity.ExtendedDescription) {
aboutInstanceViewController.updateFooter(with: extendedDescription)
}
}
//MARK: - UIPageViewControllerDataSource
extension ServerDetailsViewController: UIPageViewControllerDataSource {
func pageViewController(_ pageViewController: UIPageViewController, viewControllerBefore viewController: UIViewController) -> UIViewController? {
if viewController == instanceRulesViewController {
return aboutInstanceViewController
} else {
return nil
}
}
func pageViewController(_ pageViewController: UIPageViewController, viewControllerAfter viewController: UIViewController) -> UIViewController? {
if viewController == aboutInstanceViewController {
return instanceRulesViewController
} else {
return nil
}
}
}
//MARK: - UIPageViewControllerDelegate
extension ServerDetailsViewController: UIPageViewControllerDelegate {
func pageViewController(_ pageViewController: UIPageViewController, didFinishAnimating finished: Bool, previousViewControllers: [UIViewController], transitionCompleted completed: Bool) {
guard let currentViewController = pageViewController.viewControllers?.first else { return }
if currentViewController == aboutInstanceViewController {
segmentedControl.selectedSegmentIndex = ServerDetailsTab.about.rawValue
} else if currentViewController == instanceRulesViewController {
segmentedControl.selectedSegmentIndex = ServerDetailsTab.rules.rawValue
}
}
}
extension ServerDetailsViewController: OnboardingViewControllerAppearance {}

View File

@ -0,0 +1,18 @@
// Copyright © 2023 Mastodon gGmbH. All rights reserved.
import Foundation
import MastodonSDK
import MastodonLocalization
enum AboutInstanceSection: Int, Hashable {
case main = 0
var title: String {
return L10n.Scene.Settings.ServerDetails.AboutInstance.title
}
}
enum AboutInstanceItem: Hashable {
case adminAccount(Mastodon.Entity.Account)
case contactAdmin(String)
}

View File

@ -0,0 +1,68 @@
// Copyright © 2023 Mastodon gGmbH. All rights reserved.
import UIKit
import MetaTextKit
import MastodonSDK
import MastodonMeta
import MastodonCore
import MastodonAsset
import MastodonLocalization
class AboutInstanceTableFooterView: UIView {
let headlineLabel: UILabel
let contentLabel: MetaLabel
init() {
headlineLabel = UILabel()
headlineLabel.translatesAutoresizingMaskIntoConstraints = false
headlineLabel.font = UIFontMetrics(forTextStyle: .title2).scaledFont(for: .systemFont(ofSize: 22, weight: .bold))
contentLabel = MetaLabel(style: .aboutInstance)
contentLabel.numberOfLines = 0
contentLabel.translatesAutoresizingMaskIntoConstraints = false
super.init(frame: .zero)
addSubview(headlineLabel)
addSubview(contentLabel)
setupConstraints()
}
required init?(coder: NSCoder) { fatalError("init(coder:) has not been implemented") }
private func setupConstraints() {
let horizontalMargin = 16.0
let verticalMargin = 24.0
let constraints = [
headlineLabel.topAnchor.constraint(equalTo: topAnchor, constant: verticalMargin),
headlineLabel.leadingAnchor.constraint(equalTo: leadingAnchor, constant: horizontalMargin),
trailingAnchor.constraint(equalTo: headlineLabel.trailingAnchor, constant: horizontalMargin),
contentLabel.topAnchor.constraint(equalTo: headlineLabel.bottomAnchor, constant: 8),
contentLabel.leadingAnchor.constraint(equalTo: headlineLabel.leadingAnchor),
contentLabel.trailingAnchor.constraint(equalTo: headlineLabel.trailingAnchor),
bottomAnchor.constraint(equalTo: contentLabel.bottomAnchor, constant: verticalMargin),
]
NSLayoutConstraint.activate(constraints)
}
func update(with extendedDescription: Mastodon.Entity.ExtendedDescription) {
headlineLabel.text = L10n.Scene.Settings.ServerDetails.AboutInstance.legalNotice
let content = extendedDescription.content
.replacingOccurrences(of: "<br>", with: "\n")
.replacingOccurrences(of: "\n\n", with: "\n")
if let metaContent = try? MastodonMetaContent.convert(document: MastodonContent(content: content, emojis: [:])) {
contentLabel.configure(content: metaContent)
} else {
let content = PlaintextMetaContent(string: content)
contentLabel.configure(content: content)
}
}
}

View File

@ -0,0 +1,16 @@
// Copyright © 2023 Mastodon gGmbH. All rights reserved.
import UIKit
class AboutInstanceTableViewDataSource: UITableViewDiffableDataSource<AboutInstanceSection, AboutInstanceItem> {
override init(tableView: UITableView, cellProvider: @escaping UITableViewDiffableDataSource<AboutInstanceSection, AboutInstanceItem>.CellProvider) {
super.init(tableView: tableView, cellProvider: cellProvider)
}
override func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
guard let section = AboutInstanceSection(rawValue: section) else { return nil }
return section.title.uppercased()
}
}

View File

@ -0,0 +1,40 @@
// Copyright © 2023 Mastodon gGmbH. All rights reserved.
import UIKit
import MastodonAsset
import AlamofireImage
class AboutInstanceTableHeaderView: UIView {
let thumbnailImageView: UIImageView
init() {
thumbnailImageView = UIImageView(image: Asset.Settings.aboutInstancePlaceholder.image)
thumbnailImageView.contentMode = .scaleAspectFill
thumbnailImageView.translatesAutoresizingMaskIntoConstraints = false
super.init(frame: .zero)
addSubview(thumbnailImageView)
setupConstraints()
}
required init?(coder: NSCoder) { fatalError("init(coder:) has not been implemented") }
private func setupConstraints() {
let constraints = [
thumbnailImageView.topAnchor.constraint(equalTo: topAnchor),
thumbnailImageView.leadingAnchor.constraint(equalTo: leadingAnchor),
trailingAnchor.constraint(equalTo: thumbnailImageView.trailingAnchor),
bottomAnchor.constraint(equalTo: thumbnailImageView.bottomAnchor, constant: 16),
]
NSLayoutConstraint.activate(constraints)
}
func updateImage(with thumbnailURL: URL, completion: (() -> Void)? = nil) {
thumbnailImageView.af.setImage(withURL: thumbnailURL, placeholderImage: Asset.Settings.aboutInstancePlaceholder.image, completion: { _ in
completion?()
})
}
}

View File

@ -0,0 +1,5 @@
// Copyright © 2023 Mastodon gGmbH. All rights reserved.
import UIKit
typealias AdminTableViewCell = SearchResultsProfileTableViewCell

View File

@ -0,0 +1,22 @@
// Copyright © 2023 Mastodon gGmbH. All rights reserved.
import UIKit
import MastodonAsset
import MastodonLocalization
class ContactAdminTableViewCell: UITableViewCell {
static let reuseIdentifier = "ContactAdminTableViewCell"
func configure() {
var configuration = defaultContentConfiguration()
configuration.textProperties.color = Asset.Colors.Brand.blurple.color
configuration.image = UIImage(systemName: "envelope")
configuration.imageProperties.tintColor = Asset.Colors.Brand.blurple.color
configuration.text = L10n.Scene.Settings.ServerDetails.AboutInstance.messageAdmin
backgroundColor = .secondarySystemGroupedBackground
contentConfiguration = configuration
}
}

View File

@ -10,62 +10,78 @@ struct SettingsSection: Hashable {
enum SettingsEntry: Hashable {
case general
case notifications
case serverDetails(domain: String)
case aboutMastodon
case logout(accountName: String)
var title: String {
switch self {
case .general:
return L10n.Scene.Settings.Overview.general
case .notifications:
return L10n.Scene.Settings.Overview.notifications
case .aboutMastodon:
return L10n.Scene.Settings.Overview.aboutMastodon
case .logout(let accountName):
return L10n.Scene.Settings.Overview.logout(accountName)
case .general:
return L10n.Scene.Settings.Overview.general
case .notifications:
return L10n.Scene.Settings.Overview.notifications
case .serverDetails(_):
return L10n.Scene.Settings.Overview.serverDetails
case .aboutMastodon:
return L10n.Scene.Settings.Overview.aboutMastodon
case .logout(let accountName):
return L10n.Scene.Settings.Overview.logout(accountName)
}
}
var secondaryTitle: String? {
switch self {
case .serverDetails(domain: let domain):
return domain
case .general, .notifications, .aboutMastodon, .logout(_):
return nil
}
}
var accessoryType: UITableViewCell.AccessoryType {
switch self {
case .general, .notifications, .aboutMastodon, .logout(_):
return .disclosureIndicator
case .general, .notifications, .serverDetails(_), .aboutMastodon, .logout(_):
return .disclosureIndicator
}
}
var icon: UIImage? {
switch self {
case .general:
return UIImage(systemName: "gear")
case .notifications:
return UIImage(systemName: "bell.badge")
case .aboutMastodon:
return UIImage(systemName: "info.circle.fill")
case .logout(_):
return nil
case .general:
return UIImage(systemName: "gear")
case .notifications:
return UIImage(systemName: "bell.badge")
case .serverDetails(_):
return UIImage(systemName: "server.rack")
case .aboutMastodon:
return UIImage(systemName: "info.circle.fill")
case .logout(_):
return nil
}
}
var iconBackgroundColor: UIColor? {
switch self {
case .general:
return .systemGray
case .notifications:
return .systemRed
case .aboutMastodon:
return .systemPurple
case .logout(_):
return nil
case .general:
return .systemGray
case .notifications:
return .systemRed
case .serverDetails(_):
return .systemTeal
case .aboutMastodon:
return .systemPurple
case .logout(_):
return nil
}
}
var textColor: UIColor {
switch self {
case .general, .notifications, .aboutMastodon:
return .label
case .logout(_):
return .red
case .general, .notifications, .aboutMastodon, .serverDetails(_):
return .label
case .logout(_):
return .red
}
}

View File

@ -9,7 +9,9 @@ class SettingsTableViewCell: UITableViewCell {
let iconImageView: UIImageView
let iconImageBackgroundView: UIView
let titleLabel: UILabel
let secondaryLabel: UILabel
private let labelStackView: UIStackView
private let contentStackView: UIStackView
override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
@ -21,8 +23,17 @@ class SettingsTableViewCell: UITableViewCell {
iconImageBackgroundView.addSubview(iconImageView)
titleLabel = UILabel()
titleLabel.font = UIFontMetrics(forTextStyle: .body).scaledFont(for: .systemFont(ofSize: 17, weight: .regular))
secondaryLabel = UILabel()
secondaryLabel.font = UIFontMetrics(forTextStyle: .caption1).scaledFont(for: .systemFont(ofSize: 12, weight: .regular))
secondaryLabel.textColor = .secondaryLabel
contentStackView = UIStackView(arrangedSubviews: [iconImageBackgroundView, titleLabel])
labelStackView = UIStackView(arrangedSubviews: [titleLabel, secondaryLabel])
labelStackView.axis = .vertical
labelStackView.spacing = 2
labelStackView.alignment = .leading
contentStackView = UIStackView(arrangedSubviews: [iconImageBackgroundView, labelStackView])
contentStackView.translatesAutoresizingMaskIntoConstraints = false
contentStackView.axis = .horizontal
contentStackView.alignment = .center
@ -50,8 +61,8 @@ class SettingsTableViewCell: UITableViewCell {
iconImageView.centerXAnchor.constraint(equalTo: iconImageBackgroundView.centerXAnchor),
iconImageView.widthAnchor.constraint(equalToConstant: 20),
titleLabel.topAnchor.constraint(greaterThanOrEqualTo: contentView.topAnchor, constant: 12),
contentView.bottomAnchor.constraint(greaterThanOrEqualTo: titleLabel.bottomAnchor, constant: 12),
labelStackView.topAnchor.constraint(greaterThanOrEqualTo: contentView.topAnchor, constant: 12),
contentView.bottomAnchor.constraint(greaterThanOrEqualTo: labelStackView.bottomAnchor, constant: 12),
]
NSLayoutConstraint.activate(constraints)
@ -61,6 +72,13 @@ class SettingsTableViewCell: UITableViewCell {
titleLabel.textColor = entry.textColor
titleLabel.text = entry.title
if let secondaryTitle = entry.secondaryTitle {
secondaryLabel.isHidden = false
secondaryLabel.text = secondaryTitle
} else {
secondaryLabel.isHidden = true
}
if let icon = entry.icon {
iconImageView.image = icon
iconImageView.tintColor = .white
@ -73,7 +91,6 @@ class SettingsTableViewCell: UITableViewCell {
iconImageBackgroundView.backgroundColor = entry.iconBackgroundColor
accessoryType = entry.accessoryType
}
}

View File

@ -16,11 +16,11 @@ class SettingsViewController: UIViewController {
var tableViewDataSource: UITableViewDiffableDataSource<SettingsSection, SettingsEntry>?
let tableView: UITableView
init(accountName: String) {
init(accountName: String, domain: String) {
sections = [
.init(entries: [.general, .notifications]),
.init(entries: [.aboutMastodon]),
.init(entries: [.serverDetails(domain: domain), .aboutMastodon]),
.init(entries: [.logout(accountName: accountName)])
]

View File

@ -6,6 +6,7 @@ import MastodonCore
import CoreDataStack
import MastodonSDK
import Combine
import MetaTextKit
protocol SettingsCoordinatorDelegate: AnyObject {
func logout(_ settingsCoordinator: SettingsCoordinator)
@ -26,15 +27,17 @@ class SettingsCoordinator: NSObject, Coordinator {
let appContext: AppContext
let authContext: AuthContext
var disposeBag = Set<AnyCancellable>()
let sceneCoordinator: SceneCoordinator
init(presentedOn: UIViewController, accountName: String, setting: Setting, appContext: AppContext, authContext: AuthContext) {
init(presentedOn: UIViewController, accountName: String, setting: Setting, appContext: AppContext, authContext: AuthContext, sceneCoordinator: SceneCoordinator) {
self.presentedOn = presentedOn
navigationController = UINavigationController()
self.setting = setting
self.appContext = appContext
self.authContext = authContext
self.sceneCoordinator = sceneCoordinator
settingsViewController = SettingsViewController(accountName: accountName)
settingsViewController = SettingsViewController(accountName: accountName, domain: authContext.mastodonAuthenticationBox.domain)
}
func start() {
@ -65,8 +68,29 @@ extension SettingsCoordinator: SettingsViewControllerDelegate {
let notificationViewController = NotificationSettingsViewController(currentSetting: currentSetting, notificationsEnabled: notificationsEnabled)
notificationViewController.delegate = self
self.navigationController.pushViewController(notificationViewController, animated: true)
navigationController.pushViewController(notificationViewController, animated: true)
case .serverDetails(let domain):
let serverDetailsViewController = ServerDetailsViewController(domain: domain)
serverDetailsViewController.delegate = self
appContext.apiService.instanceV2(domain: domain)
.sink { _ in
} receiveValue: { content in
serverDetailsViewController.update(with: content.value)
}
.store(in: &disposeBag)
appContext.apiService.extendedDescription(domain: domain)
.sink { _ in
} receiveValue: { content in
serverDetailsViewController.updateFooter(with: content.value)
}
.store(in: &disposeBag)
navigationController.pushViewController(serverDetailsViewController, animated: true)
case .aboutMastodon:
let aboutViewController = AboutViewController()
aboutViewController.delegate = self
@ -135,6 +159,8 @@ extension SettingsCoordinator: NotificationSettingsViewControllerDelegate {
guard viewModel.updated else { return }
//Show spinner?
let authenticationBox = authContext.mastodonAuthenticationBox
guard let subscription = setting.activeSubscription,
setting.domain == authenticationBox.domain,
@ -183,3 +209,58 @@ extension SettingsCoordinator: PolicySelectionViewControllerDelegate {
try? self.appContext.managedObjectContext.save()
}
}
//MARK: - ServerDetailsViewControllerDelegate
extension SettingsCoordinator: ServerDetailsViewControllerDelegate {
}
extension SettingsCoordinator: AboutInstanceViewControllerDelegate {
@MainActor func showAdminAccount(_ viewController: AboutInstanceViewController, account: Mastodon.Entity.Account) {
Task {
let user = try await appContext.apiService.fetchUser(username: account.username, domain: authContext.mastodonAuthenticationBox.domain, authenticationBox: authContext.mastodonAuthenticationBox)
let profileViewModel = ProfileViewModel(context: appContext, authContext: authContext, optionalMastodonUser: user)
_ = await MainActor.run {
sceneCoordinator.present(scene: .profile(viewModel: profileViewModel), transition: .show)
}
}
}
func sendEmailToAdmin(_ viewController: AboutInstanceViewController, emailAddress: String) {
if let emailUrl = URL(string: "mailto:\(emailAddress)"), UIApplication.shared.canOpenURL(emailUrl) {
UIApplication.shared.open(emailUrl)
}
}
}
extension SettingsCoordinator: InstanceRulesViewControllerDelegate {
}
extension SettingsCoordinator: MetaLabelDelegate {
@MainActor
func metaLabel(_ metaLabel: MetaLabel, didSelectMeta meta: Meta) {
switch meta {
case .url(_, _, let url, _):
guard let url = URL(string: url) else { return }
_ = sceneCoordinator.present(scene: .safari(url: url), from: nil, transition: .safariPresent(animated: true, completion: nil))
case .mention(_, _, let userInfo):
guard let href = userInfo?["href"] as? String,
let url = URL(string: href) else { return }
_ = sceneCoordinator.present(scene: .safari(url: url), from: nil, transition: .safariPresent(animated: true, completion: nil))
case .hashtag(_, let hashtag, _):
let hashtagTimelineViewModel = HashtagTimelineViewModel(context: appContext, authContext: authContext, hashtag: hashtag)
_ = sceneCoordinator.present(scene: .hashtagTimeline(viewModel: hashtagTimelineViewModel), from: nil, transition: .show)
case .email(let email, _):
if let emailUrl = URL(string: "mailto:\(email)"), UIApplication.shared.canOpenURL(emailUrl) {
UIApplication.shared.open(emailUrl)
}
case .emoji:
break
}
}
}

View File

@ -1,239 +0,0 @@
{
"pins" : [
{
"identity" : "alamofire",
"kind" : "remoteSourceControl",
"location" : "https://github.com/Alamofire/Alamofire.git",
"state" : {
"revision" : "8dd85aee02e39dd280c75eef88ffdb86eed4b07b",
"version" : "5.6.2"
}
},
{
"identity" : "alamofireimage",
"kind" : "remoteSourceControl",
"location" : "https://github.com/Alamofire/AlamofireImage.git",
"state" : {
"revision" : "98cbb00ce0ec5fc8e52a5b50a6bfc08d3e5aee10",
"version" : "4.2.0"
}
},
{
"identity" : "commonoslog",
"kind" : "remoteSourceControl",
"location" : "https://github.com/MainasuK/CommonOSLog",
"state" : {
"revision" : "c121624a30698e9886efe38aebb36ff51c01b6c2",
"version" : "0.1.1"
}
},
{
"identity" : "faviconfinder",
"kind" : "remoteSourceControl",
"location" : "https://github.com/will-lumley/FaviconFinder.git",
"state" : {
"revision" : "1f74844f77f79b95c0bb0130b3a87d4f340e6d3a",
"version" : "3.3.0"
}
},
{
"identity" : "flanimatedimage",
"kind" : "remoteSourceControl",
"location" : "https://github.com/Flipboard/FLAnimatedImage.git",
"state" : {
"revision" : "d4f07b6f164d53c1212c3e54d6460738b1981e9f",
"version" : "1.0.17"
}
},
{
"identity" : "fpsindicator",
"kind" : "remoteSourceControl",
"location" : "https://github.com/MainasuK/FPSIndicator.git",
"state" : {
"revision" : "e4a5067ccd5293b024c767f09e51056afd4a4796",
"version" : "1.1.0"
}
},
{
"identity" : "fuzi",
"kind" : "remoteSourceControl",
"location" : "https://github.com/cezheng/Fuzi.git",
"state" : {
"revision" : "f08c8323da21e985f3772610753bcfc652c2103f",
"version" : "3.1.3"
}
},
{
"identity" : "keychainaccess",
"kind" : "remoteSourceControl",
"location" : "https://github.com/kishikawakatsumi/KeychainAccess.git",
"state" : {
"revision" : "84e546727d66f1adc5439debad16270d0fdd04e7",
"version" : "4.2.2"
}
},
{
"identity" : "metatextkit",
"kind" : "remoteSourceControl",
"location" : "https://github.com/TwidereProject/MetaTextKit.git",
"state" : {
"revision" : "dcd5255d6930c2fab408dc8562c577547e477624",
"version" : "2.2.5"
}
},
{
"identity" : "nextlevelsessionexporter",
"kind" : "remoteSourceControl",
"location" : "https://github.com/NextLevel/NextLevelSessionExporter.git",
"state" : {
"revision" : "b6c0cce1aa37fe1547d694f958fac3c3524b74da",
"version" : "0.4.6"
}
},
{
"identity" : "nuke",
"kind" : "remoteSourceControl",
"location" : "https://github.com/kean/Nuke.git",
"state" : {
"revision" : "a002b7fd786f2df2ed4333fe73a9727499fd9d97",
"version" : "10.11.2"
}
},
{
"identity" : "nuke-flanimatedimage-plugin",
"kind" : "remoteSourceControl",
"location" : "https://github.com/kean/Nuke-FLAnimatedImage-Plugin.git",
"state" : {
"revision" : "b59c346a7d536336db3b0f12c72c6e53ee709e16",
"version" : "8.0.0"
}
},
{
"identity" : "pageboy",
"kind" : "remoteSourceControl",
"location" : "https://github.com/uias/Pageboy",
"state" : {
"revision" : "af8fa81788b893205e1ff42ddd88c5b0b315d7c5",
"version" : "3.7.0"
}
},
{
"identity" : "panmodal",
"kind" : "remoteSourceControl",
"location" : "https://github.com/slackhq/PanModal.git",
"state" : {
"revision" : "b012aecb6b67a8e46369227f893c12544846613f",
"version" : "1.2.7"
}
},
{
"identity" : "sdwebimage",
"kind" : "remoteSourceControl",
"location" : "https://github.com/SDWebImage/SDWebImage.git",
"state" : {
"revision" : "9248fe561a2a153916fb9597e3af4434784c6d32",
"version" : "5.13.4"
}
},
{
"identity" : "stripes",
"kind" : "remoteSourceControl",
"location" : "https://github.com/eneko/Stripes.git",
"state" : {
"revision" : "d533fd44b8043a3abbf523e733599173d6f98c11",
"version" : "0.2.0"
}
},
{
"identity" : "swift-collections",
"kind" : "remoteSourceControl",
"location" : "https://github.com/apple/swift-collections.git",
"state" : {
"revision" : "f504716c27d2e5d4144fa4794b12129301d17729",
"version" : "1.0.3"
}
},
{
"identity" : "swift-nio",
"kind" : "remoteSourceControl",
"location" : "https://github.com/apple/swift-nio.git",
"state" : {
"revision" : "546610d52b19be3e19935e0880bb06b9c03f5cef",
"version" : "1.14.4"
}
},
{
"identity" : "swift-nio-zlib-support",
"kind" : "remoteSourceControl",
"location" : "https://github.com/apple/swift-nio-zlib-support.git",
"state" : {
"revision" : "37760e9a52030bb9011972c5213c3350fa9d41fd",
"version" : "1.0.0"
}
},
{
"identity" : "swiftsoup",
"kind" : "remoteSourceControl",
"location" : "https://github.com/scinfu/SwiftSoup.git",
"state" : {
"revision" : "6778575285177365cbad3e5b8a72f2a20583cfec",
"version" : "2.4.3"
}
},
{
"identity" : "swiftui-introspect",
"kind" : "remoteSourceControl",
"location" : "https://github.com/siteline/SwiftUI-Introspect.git",
"state" : {
"revision" : "f2616860a41f9d9932da412a8978fec79c06fe24",
"version" : "0.1.4"
}
},
{
"identity" : "tabbarpager",
"kind" : "remoteSourceControl",
"location" : "https://github.com/TwidereProject/TabBarPager.git",
"state" : {
"revision" : "488aa66d157a648901b61721212c0dec23d27ee5",
"version" : "0.1.0"
}
},
{
"identity" : "tabman",
"kind" : "remoteSourceControl",
"location" : "https://github.com/uias/Tabman",
"state" : {
"revision" : "4a4f7c755b875ffd4f9ef10d67a67883669d2465",
"version" : "2.13.0"
}
},
{
"identity" : "tocropviewcontroller",
"kind" : "remoteSourceControl",
"location" : "https://github.com/TimOliver/TOCropViewController.git",
"state" : {
"revision" : "d0470491f56e734731bbf77991944c0dfdee3e0e",
"version" : "2.6.1"
}
},
{
"identity" : "uihostingconfigurationbackport",
"kind" : "remoteSourceControl",
"location" : "https://github.com/woxtu/UIHostingConfigurationBackport.git",
"state" : {
"revision" : "6091f2d38faa4b24fc2ca0389c651e2f666624a3",
"version" : "0.1.0"
}
},
{
"identity" : "uitextview-placeholder",
"kind" : "remoteSourceControl",
"location" : "https://github.com/MainasuK/UITextView-Placeholder.git",
"state" : {
"revision" : "20f513ded04a040cdf5467f0891849b1763ede3b",
"version" : "1.4.1"
}
}
],
"version" : 2
}

View File

@ -42,7 +42,6 @@ let package = Package(
.package(url: "https://github.com/apple/swift-collections.git", from: "1.0.3"),
.package(url: "https://github.com/apple/swift-nio.git", from: "2.0.0"),
.package(url: "https://github.com/Flipboard/FLAnimatedImage.git", from: "1.0.0"),
.package(url: "https://github.com/kean/Nuke-FLAnimatedImage-Plugin.git", from: "8.0.0"),
.package(url: "https://github.com/kean/Nuke.git", from: "10.3.1"),
.package(url: "https://github.com/kishikawakatsumi/KeychainAccess.git", from: "4.2.2"),
.package(url: "https://github.com/slackhq/PanModal.git", from: "1.2.7"),
@ -54,6 +53,7 @@ let package = Package(
.package(url: "https://github.com/SDWebImage/SDWebImage.git", from: "5.12.0"),
.package(url: "https://github.com/eneko/Stripes.git", from: "0.2.0"),
.package(url: "https://github.com/NextLevel/NextLevelSessionExporter.git", from: "0.4.6"),
.package(url: "https://github.com/xmartlabs/XLPagerTabStrip.git", from: "9.1.0"),
],
targets: [
// Targets are the basic building blocks of a package. A target can define a module or a test suite.
@ -126,6 +126,8 @@ let package = Package(
.product(name: "PanModal", package: "PanModal"),
.product(name: "Stripes", package: "Stripes"),
.product(name: "NextLevelSessionExporter", package: "NextLevelSessionExporter"),
.product(name: "SDWebImage", package: "SDWebImage"),
.product(name: "XLPagerTabStrip", package: "XLPagerTabStrip"),
]
),
.testTarget(

View File

@ -1,17 +1,15 @@
{
"images" : [
{
"filename" : "dark.png",
"idiom" : "universal",
"scale" : "1x"
},
{
"filename" : "dark@2x.png",
"filename" : "about_instance_placeholder@2x.png",
"idiom" : "universal",
"scale" : "2x"
},
{
"filename" : "dark@3x.png",
"idiom" : "universal",
"scale" : "3x"
}

View File

@ -1,23 +0,0 @@
{
"images" : [
{
"filename" : "automatic.png",
"idiom" : "universal",
"scale" : "1x"
},
{
"filename" : "automatic@2x.png",
"idiom" : "universal",
"scale" : "2x"
},
{
"filename" : "automatic@3x.png",
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 49 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 97 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 48 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 95 KiB

View File

@ -1,23 +0,0 @@
{
"images" : [
{
"filename" : "light.png",
"idiom" : "universal",
"scale" : "1x"
},
{
"filename" : "light@2x.png",
"idiom" : "universal",
"scale" : "2x"
},
{
"filename" : "light@3x.png",
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 48 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 96 KiB

View File

@ -219,9 +219,7 @@ public enum Asset {
}
}
public enum Settings {
public static let automatic = ImageAsset(name: "Settings/automatic")
public static let dark = ImageAsset(name: "Settings/dark")
public static let light = ImageAsset(name: "Settings/light")
public static let aboutInstancePlaceholder = ImageAsset(name: "Settings/about_instance_placeholder")
}
public enum Theme {
public enum System {

View File

@ -24,4 +24,8 @@ extension APIService {
) -> AnyPublisher<Mastodon.Response.Content<Mastodon.Entity.V2.Instance>, Error> {
return Mastodon.API.V2.Instance.instance(session: session, domain: domain)
}
public func extendedDescription(domain: String) -> AnyPublisher<Mastodon.Response.Content<Mastodon.Entity.ExtendedDescription>, Error> {
return Mastodon.API.Instance.extendedDescription(session: session, domain: domain)
}
}

View File

@ -1418,7 +1418,7 @@ public enum L10n {
public enum Settings {
public enum AboutMastodon {
/// Clear Media Storage
public static let cleaerMediaStorage = L10n.tr("Localizable", "Scene.Settings.AboutMastodon.CleaerMediaStorage", fallback: "Clear Media Storage")
public static let clearMediaStorage = L10n.tr("Localizable", "Scene.Settings.AboutMastodon.ClearMediaStorage", fallback: "Clear Media Storage")
/// Contribute to Mastodon
public static let contributeToMastodon = L10n.tr("Localizable", "Scene.Settings.AboutMastodon.ContributeToMastodon", fallback: "Contribute to Mastodon")
/// Even More Settings
@ -1509,6 +1509,8 @@ public enum L10n {
}
/// Notifications
public static let notifications = L10n.tr("Localizable", "Scene.Settings.Overview.Notifications", fallback: "Notifications")
/// Server Details
public static let serverDetails = L10n.tr("Localizable", "Scene.Settings.Overview.ServerDetails", fallback: "Server Details")
/// Support Mastodon
public static let supportMastodon = L10n.tr("Localizable", "Scene.Settings.Overview.SupportMastodon", fallback: "Support Mastodon")
/// Settings
@ -1592,6 +1594,20 @@ public enum L10n {
public static let title = L10n.tr("Localizable", "Scene.Settings.Section.SpicyZone.Title", fallback: "The Spicy Zone")
}
}
public enum ServerDetails {
/// About
public static let about = L10n.tr("Localizable", "Scene.Settings.ServerDetails.About", fallback: "About")
/// Rules
public static let rules = L10n.tr("Localizable", "Scene.Settings.ServerDetails.Rules", fallback: "Rules")
public enum AboutInstance {
/// A legal notice
public static let legalNotice = L10n.tr("Localizable", "Scene.Settings.ServerDetails.AboutInstance.LegalNotice", fallback: "A legal notice")
/// Message Admin
public static let messageAdmin = L10n.tr("Localizable", "Scene.Settings.ServerDetails.AboutInstance.MessageAdmin", fallback: "Message Admin")
/// Administrator
public static let title = L10n.tr("Localizable", "Scene.Settings.ServerDetails.AboutInstance.Title", fallback: "Administrator")
}
}
}
public enum SuggestionAccount {
/// Follow all

View File

@ -527,6 +527,7 @@ uploaded to Mastodon.";
"Scene.Settings.Overview.General" = "General";
"Scene.Settings.Overview.Notifications" = "Notifications";
"Scene.Settings.Overview.SupportMastodon" = "Support Mastodon";
"Scene.Settings.Overview.ServerDetails" = "Server Details";
"Scene.Settings.Overview.AboutMastodon" = "About Mastodon";
"Scene.Settings.Overview.Logout" = "Logout %@";
@ -534,7 +535,13 @@ uploaded to Mastodon.";
"Scene.Settings.AboutMastodon.MoreSettings" = "Even More Settings";
"Scene.Settings.AboutMastodon.ContributeToMastodon" = "Contribute to Mastodon";
"Scene.Settings.AboutMastodon.PrivacyPolicy" = "Privacy Policy";
"Scene.Settings.AboutMastodon.CleaerMediaStorage" = "Clear Media Storage";
"Scene.Settings.AboutMastodon.ClearMediaStorage" = "Clear Media Storage";
"Scene.Settings.ServerDetails.About" = "About";
"Scene.Settings.ServerDetails.Rules" = "Rules";
"Scene.Settings.ServerDetails.AboutInstance.Title" = "Administrator";
"Scene.Settings.ServerDetails.AboutInstance.MessageAdmin" = "Message Admin";
"Scene.Settings.ServerDetails.AboutInstance.LegalNotice" = "A legal notice";
"Scene.Settings.General.Title" = "General";
"Scene.Settings.General.Appearance.SectionTitle" = "Appearance";

View File

@ -527,6 +527,7 @@ uploaded to Mastodon.";
"Scene.Settings.Overview.General" = "General";
"Scene.Settings.Overview.Notifications" = "Notifications";
"Scene.Settings.Overview.SupportMastodon" = "Support Mastodon";
"Scene.Settings.Overview.ServerDetails" = "Server Details";
"Scene.Settings.Overview.AboutMastodon" = "About Mastodon";
"Scene.Settings.Overview.Logout" = "Logout %@";
@ -534,7 +535,13 @@ uploaded to Mastodon.";
"Scene.Settings.AboutMastodon.MoreSettings" = "Even More Settings";
"Scene.Settings.AboutMastodon.ContributeToMastodon" = "Contribute to Mastodon";
"Scene.Settings.AboutMastodon.PrivacyPolicy" = "Privacy Policy";
"Scene.Settings.AboutMastodon.CleaerMediaStorage" = "Clear Media Storage";
"Scene.Settings.AboutMastodon.ClearMediaStorage" = "Clear Media Storage";
"Scene.Settings.ServerDetails.About" = "About";
"Scene.Settings.ServerDetails.Rules" = "Rules";
"Scene.Settings.ServerDetails.AboutInstance.Title" = "Administrator";
"Scene.Settings.ServerDetails.AboutInstance.MessageAdmin" = "Message Admin";
"Scene.Settings.ServerDetails.AboutInstance.LegalNotice" = "A legal notice";
"Scene.Settings.General.Title" = "General";
"Scene.Settings.General.Appearance.SectionTitle" = "Appearance";

View File

@ -30,11 +30,7 @@ extension Mastodon.API.Instance {
session: URLSession,
domain: String
) -> AnyPublisher<Mastodon.Response.Content<Mastodon.Entity.Instance>, Error> {
let request = Mastodon.API.get(
url: instanceEndpointURL(domain: domain),
query: nil,
authorization: nil
)
let request = Mastodon.API.get(url: instanceEndpointURL(domain: domain))
return session.dataTaskPublisher(for: request)
.tryMap { data, response in
let value: Mastodon.Entity.Instance
@ -53,5 +49,27 @@ extension Mastodon.API.Instance {
}
.eraseToAnyPublisher()
}
static func extendedDescriptionEndpointURL(domain: String) -> URL {
return Mastodon.API.endpointURL(domain: domain).appendingPathComponent("instance").appendingPathComponent("extended_description")
}
/// Extended description of the server
///
/// - Returns: A ``MastodonSDK.Mastodon.Entity.ExtendedDescription``
///
/// ## Reference:
/// [Document](https://docs.joinmastodon.org/methods/instance/#extended_description)
public static func extendedDescription(
session: URLSession,
domain: String
) -> AnyPublisher<Mastodon.Response.Content<Mastodon.Entity.ExtendedDescription>, Error> {
let request = Mastodon.API.get(url: extendedDescriptionEndpointURL(domain: domain))
return session.dataTaskPublisher(for: request)
.tryMap { data, response in
let value = try Mastodon.API.decode(type: Mastodon.Entity.ExtendedDescription.self, from: data, response: response)
return Mastodon.Response.Content(value: value, response: response)
}
.eraseToAnyPublisher()
}
}

View File

@ -0,0 +1,19 @@
// Copyright © 2023 Mastodon gGmbH. All rights reserved.
import Foundation
extension Mastodon.Entity {
/// Extended description of the server
/// ## Reference:
/// [Document](https://docs.joinmastodon.org/entities/ExtendedDescription/)
public struct ExtendedDescription: Codable {
public let updatedAt: Date
public let content: String
enum CodingKeys: String, CodingKey {
case updatedAt = "updated_at"
case content
}
}
}

View File

@ -10,12 +10,11 @@ extension Mastodon.Entity.V2 {
/// # Reference
/// [Document](https://docs.joinmastodon.org/entities/instance/)
public struct Instance: Codable {
public let domain: String?
public let title: String
public let description: String
public let shortDescription: String?
public let email: String?
public let version: String?
public let languages: [String]? // (ISO 639 Part 1-5 language codes)
public let registrations: Mastodon.Entity.V2.Instance.Registrations?
@ -25,7 +24,7 @@ extension Mastodon.Entity.V2 {
public let statistics: Mastodon.Entity.Instance.Statistics?
public let thumbnail: Thumbnail?
public let contactAccount: Mastodon.Entity.Account?
public let contact: Mastodon.Entity.V2.Instance.Contact?
public let rules: [Mastodon.Entity.Instance.Rule]?
// https://github.com/mastodon/mastodon/pull/16485
@ -36,7 +35,7 @@ extension Mastodon.Entity.V2 {
self.title = domain
self.description = ""
self.shortDescription = nil
self.email = ""
self.contact = nil
self.version = nil
self.languages = nil
self.registrations = nil
@ -45,7 +44,6 @@ extension Mastodon.Entity.V2 {
self.urls = nil
self.statistics = nil
self.thumbnail = nil
self.contactAccount = nil
self.rules = nil
self.configuration = nil
}
@ -55,7 +53,6 @@ extension Mastodon.Entity.V2 {
case title
case description
case shortDescription = "short_description"
case email
case version
case languages
case registrations
@ -65,7 +62,7 @@ extension Mastodon.Entity.V2 {
case statistics = "stats"
case thumbnail
case contactAccount = "contact_account"
case contact
case rules
case configuration
@ -106,3 +103,10 @@ extension Mastodon.Entity.V2.Instance {
public let url: String?
}
}
extension Mastodon.Entity.V2.Instance {
public struct Contact: Codable {
public let email: String?
public let account: Mastodon.Entity.Account?
}
}

View File

@ -30,6 +30,7 @@ extension MetaLabel {
case accountListUsername
case sidebarHeadline(isSelected: Bool)
case sidebarSubheadline(isSelected: Bool)
case aboutInstance
}
public convenience init(style: Style) {
@ -129,6 +130,10 @@ extension MetaLabel {
case .sidebarSubheadline(let isSelected):
font = UIFontMetrics(forTextStyle: .headline).scaledFont(for: .systemFont(ofSize: 13, weight: .regular), maximumPointSize: 18)
textColor = isSelected ? .white : Asset.Colors.Label.secondary.color
case .aboutInstance:
font = UIFontMetrics(forTextStyle: .body).scaledFont(for: .systemFont(ofSize: 17, weight: .regular))
textColor = .label
paragraphStyle.paragraphSpacing = 0
}
self.font = font

View File

@ -163,7 +163,7 @@ public class CondensedUserView: UIView {
}
}
public func configure(with account: Mastodon.Entity.Account) {
public func configure(with account: Mastodon.Entity.Account, showFollowers: Bool = true) {
let displayNameMetaContent: MetaContent
do {
let content = MastodonContent(content: account.displayNameWithFallback, emojis: account.emojis?.asDictionary ?? [:])
@ -174,10 +174,16 @@ public class CondensedUserView: UIView {
displayNameLabel.configure(content: displayNameMetaContent)
acctLabel.text = account.acct
followersLabel.attributedText = NSAttributedString(
format: NSAttributedString(string: L10n.Common.UserList.followersCount("%@"), attributes: [.font: UIFontMetrics(forTextStyle: .body).scaledFont(for: .systemFont(ofSize: 15, weight: .regular))]),
args: NSAttributedString(string: Self.metricFormatter.string(from: account.followersCount) ?? account.followersCount.formatted(), attributes: [.font: UIFontMetrics(forTextStyle: .body).scaledFont(for: .systemFont(ofSize: 15, weight: .bold))])
)
if showFollowers {
followersLabel.attributedText = NSAttributedString(
format: NSAttributedString(string: L10n.Common.UserList.followersCount("%@"), attributes: [.font: UIFontMetrics(forTextStyle: .body).scaledFont(for: .systemFont(ofSize: 15, weight: .regular))]),
args: NSAttributedString(string: Self.metricFormatter.string(from: account.followersCount) ?? account.followersCount.formatted(), attributes: [.font: UIFontMetrics(forTextStyle: .body).scaledFont(for: .systemFont(ofSize: 15, weight: .bold))])
)
followersLabel.isHidden = false
} else {
followersLabel.isHidden = false
}
avatarImageView.setImage(url: account.avatarImageURL())

View File

@ -7,11 +7,6 @@ target 'Mastodon' do
# Comment the next line if you don't want to use dynamic frameworks
use_frameworks!
# Pods for Mastodon
# UI
pod 'XLPagerTabStrip', '~> 9.0.0'
# misc
pod 'SwiftGen', '~> 6.6.2'
pod 'Kanna', '~> 5.2.2'

View File

@ -4,27 +4,23 @@ PODS:
- Sourcery/CLI-Only (= 1.9.2)
- Sourcery/CLI-Only (1.9.2)
- SwiftGen (6.6.2)
- XLPagerTabStrip (9.0.0)
DEPENDENCIES:
- Kanna (~> 5.2.2)
- Sourcery (~> 1.9)
- SwiftGen (~> 6.6.2)
- XLPagerTabStrip (~> 9.0.0)
SPEC REPOS:
trunk:
- Kanna
- Sourcery
- SwiftGen
- XLPagerTabStrip
SPEC CHECKSUMS:
Kanna: 01cfbddc127f5ff0963692f285fcbc8a9d62d234
Sourcery: 179539341c2261068528cd15a31837b7238fd901
SwiftGen: 1366a7f71aeef49954ca5a63ba4bef6b0f24138c
XLPagerTabStrip: 61c57fd61f611ee5f01ff1495ad6fbee8bf496c5
PODFILE CHECKSUM: 8c962b3cbb4c225f1e57fb2e4ca03d1f22c45e5e
PODFILE CHECKSUM: 597c21d7aa08efec996048577c3c4fbeffbb6305
COCOAPODS: 1.13.0