mirror of
https://github.com/mastodon/mastodon-ios
synced 2025-04-11 22:58:02 +02:00
IOS-168: Implement Privacy & Safety Settings (#1306)
| Rationale | Demo | |---|---| | Implements a settings screen to control your Privacy & Safety settings from within the App. |  |
This commit is contained in:
commit
dc07c65b9e
@ -751,6 +751,7 @@
|
|||||||
"title": "Settings",
|
"title": "Settings",
|
||||||
"general": "General",
|
"general": "General",
|
||||||
"notifications": "Notifications",
|
"notifications": "Notifications",
|
||||||
|
"privacy_safety": "Privacy & Safety",
|
||||||
"support_mastodon": "Support Mastodon",
|
"support_mastodon": "Support Mastodon",
|
||||||
"about_mastodon": "About Mastodon",
|
"about_mastodon": "About Mastodon",
|
||||||
"server_details": "Server Details",
|
"server_details": "Server Details",
|
||||||
@ -821,6 +822,25 @@
|
|||||||
"go_to_settings": "Go to Notification Settings"
|
"go_to_settings": "Go to Notification Settings"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
},
|
||||||
|
"privacy_safety": {
|
||||||
|
"title": "Privacy & Safety",
|
||||||
|
"preset": {
|
||||||
|
"title": "Preset",
|
||||||
|
"open_and_public": "Open & Public",
|
||||||
|
"private_and_restricted": "Private & Restricted",
|
||||||
|
"custom": "Custom"
|
||||||
|
},
|
||||||
|
"default_post_visibility": {
|
||||||
|
"title": "Default Post Visibility",
|
||||||
|
"public": "Public",
|
||||||
|
"followers_only": "Followers Only",
|
||||||
|
"only_people_mentioned": "Only People Mentioned"
|
||||||
|
},
|
||||||
|
"manually_approve_follow_requests": "Manually Approve Follow Requests",
|
||||||
|
"show_followers_and_following": "Show Followers & Following",
|
||||||
|
"suggest_my_account_to_others": "Suggest My Account to Others",
|
||||||
|
"appear_in_search_engines": "Appear in Search Engines"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"report": {
|
"report": {
|
||||||
|
@ -21,6 +21,8 @@
|
|||||||
0FB3D33825E6401400AAD544 /* PickServerCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0FB3D33725E6401400AAD544 /* PickServerCell.swift */; };
|
0FB3D33825E6401400AAD544 /* PickServerCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0FB3D33725E6401400AAD544 /* PickServerCell.swift */; };
|
||||||
164F0EBC267D4FE400249499 /* BoopSound.caf in Resources */ = {isa = PBXBuildFile; fileRef = 164F0EBB267D4FE400249499 /* BoopSound.caf */; };
|
164F0EBC267D4FE400249499 /* BoopSound.caf in Resources */ = {isa = PBXBuildFile; fileRef = 164F0EBB267D4FE400249499 /* BoopSound.caf */; };
|
||||||
27D701F5292FC2D60031BCBB /* DataSourceFacade+URL.swift in Sources */ = {isa = PBXBuildFile; fileRef = 27D701F4292FC2D60031BCBB /* DataSourceFacade+URL.swift */; };
|
27D701F5292FC2D60031BCBB /* DataSourceFacade+URL.swift in Sources */ = {isa = PBXBuildFile; fileRef = 27D701F4292FC2D60031BCBB /* DataSourceFacade+URL.swift */; };
|
||||||
|
2A0BF97F2C0622AA004A1E29 /* PrivacySafetyViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2A0BF97E2C0622AA004A1E29 /* PrivacySafetyViewController.swift */; };
|
||||||
|
2A0BF9812C06252A004A1E29 /* PrivacySafetyViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2A0BF9802C06252A004A1E29 /* PrivacySafetyViewModel.swift */; };
|
||||||
2A1BF99529F7E68400FA1BA5 /* DataSourceFacade+UserView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2A1BF99429F7E68400FA1BA5 /* DataSourceFacade+UserView.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 */; };
|
2A1FE47C2938BB2600784BF1 /* FollowedTagsViewModel+DiffableDataSource.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2A1FE47B2938BB2600784BF1 /* FollowedTagsViewModel+DiffableDataSource.swift */; };
|
||||||
2A1FE47E2938C11200784BF1 /* Collection+IsNotEmpty.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2A1FE47D2938C11200784BF1 /* Collection+IsNotEmpty.swift */; };
|
2A1FE47E2938C11200784BF1 /* Collection+IsNotEmpty.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2A1FE47D2938C11200784BF1 /* Collection+IsNotEmpty.swift */; };
|
||||||
@ -32,6 +34,9 @@
|
|||||||
2A409F832B5955290044E472 /* MastodonStatusThreadViewModel+State.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2A409F822B5955290044E472 /* MastodonStatusThreadViewModel+State.swift */; };
|
2A409F832B5955290044E472 /* MastodonStatusThreadViewModel+State.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2A409F822B5955290044E472 /* MastodonStatusThreadViewModel+State.swift */; };
|
||||||
2A506CF4292CD85800059C37 /* FollowedTagsViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2A506CF3292CD85800059C37 /* FollowedTagsViewController.swift */; };
|
2A506CF4292CD85800059C37 /* FollowedTagsViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2A506CF3292CD85800059C37 /* FollowedTagsViewController.swift */; };
|
||||||
2A506CF6292D040100059C37 /* HashtagTimelineHeaderView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2A506CF5292D040100059C37 /* HashtagTimelineHeaderView.swift */; };
|
2A506CF6292D040100059C37 /* HashtagTimelineHeaderView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2A506CF5292D040100059C37 /* HashtagTimelineHeaderView.swift */; };
|
||||||
|
2A5242732C199C96005B9E22 /* PrivacySafetyView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2A5242722C199C96005B9E22 /* PrivacySafetyView.swift */; };
|
||||||
|
2A5242752C199CBD005B9E22 /* CheckableButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2A5242742C199CBD005B9E22 /* CheckableButton.swift */; };
|
||||||
|
2A5242772C199EC2005B9E22 /* PrivacySafetySettingPreset.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2A5242762C199EC2005B9E22 /* PrivacySafetySettingPreset.swift */; };
|
||||||
2A631AE82B8C9F6600FE0778 /* LanguagePickerViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2A631AE72B8C9F6600FE0778 /* LanguagePickerViewController.swift */; };
|
2A631AE82B8C9F6600FE0778 /* LanguagePickerViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2A631AE72B8C9F6600FE0778 /* LanguagePickerViewController.swift */; };
|
||||||
2A64515E29642A8A00CD8B8A /* UniformTypeIdentifiers.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 2A6451022964223800CD8B8A /* UniformTypeIdentifiers.framework */; };
|
2A64515E29642A8A00CD8B8A /* UniformTypeIdentifiers.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 2A6451022964223800CD8B8A /* UniformTypeIdentifiers.framework */; };
|
||||||
2A64516929642A8B00CD8B8A /* OpenInActionExtension.appex in Embed Foundation Extensions */ = {isa = PBXBuildFile; fileRef = 2A64515D29642A8A00CD8B8A /* OpenInActionExtension.appex */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; };
|
2A64516929642A8B00CD8B8A /* OpenInActionExtension.appex in Embed Foundation Extensions */ = {isa = PBXBuildFile; fileRef = 2A64515D29642A8A00CD8B8A /* OpenInActionExtension.appex */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; };
|
||||||
@ -622,6 +627,8 @@
|
|||||||
0FB3D33725E6401400AAD544 /* PickServerCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PickServerCell.swift; sourceTree = "<group>"; };
|
0FB3D33725E6401400AAD544 /* PickServerCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PickServerCell.swift; sourceTree = "<group>"; };
|
||||||
164F0EBB267D4FE400249499 /* BoopSound.caf */ = {isa = PBXFileReference; lastKnownFileType = file; path = BoopSound.caf; sourceTree = "<group>"; };
|
164F0EBB267D4FE400249499 /* BoopSound.caf */ = {isa = PBXFileReference; lastKnownFileType = file; path = BoopSound.caf; sourceTree = "<group>"; };
|
||||||
27D701F4292FC2D60031BCBB /* DataSourceFacade+URL.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "DataSourceFacade+URL.swift"; sourceTree = "<group>"; };
|
27D701F4292FC2D60031BCBB /* DataSourceFacade+URL.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "DataSourceFacade+URL.swift"; sourceTree = "<group>"; };
|
||||||
|
2A0BF97E2C0622AA004A1E29 /* PrivacySafetyViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PrivacySafetyViewController.swift; sourceTree = "<group>"; };
|
||||||
|
2A0BF9802C06252A004A1E29 /* PrivacySafetyViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PrivacySafetyViewModel.swift; sourceTree = "<group>"; };
|
||||||
2A1BF99429F7E68400FA1BA5 /* DataSourceFacade+UserView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "DataSourceFacade+UserView.swift"; sourceTree = "<group>"; };
|
2A1BF99429F7E68400FA1BA5 /* DataSourceFacade+UserView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "DataSourceFacade+UserView.swift"; sourceTree = "<group>"; };
|
||||||
2A1FE47B2938BB2600784BF1 /* FollowedTagsViewModel+DiffableDataSource.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "FollowedTagsViewModel+DiffableDataSource.swift"; sourceTree = "<group>"; };
|
2A1FE47B2938BB2600784BF1 /* FollowedTagsViewModel+DiffableDataSource.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "FollowedTagsViewModel+DiffableDataSource.swift"; sourceTree = "<group>"; };
|
||||||
2A1FE47D2938C11200784BF1 /* Collection+IsNotEmpty.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Collection+IsNotEmpty.swift"; sourceTree = "<group>"; };
|
2A1FE47D2938C11200784BF1 /* Collection+IsNotEmpty.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Collection+IsNotEmpty.swift"; sourceTree = "<group>"; };
|
||||||
@ -634,6 +641,9 @@
|
|||||||
2A409F822B5955290044E472 /* MastodonStatusThreadViewModel+State.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "MastodonStatusThreadViewModel+State.swift"; sourceTree = "<group>"; };
|
2A409F822B5955290044E472 /* MastodonStatusThreadViewModel+State.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "MastodonStatusThreadViewModel+State.swift"; sourceTree = "<group>"; };
|
||||||
2A506CF3292CD85800059C37 /* FollowedTagsViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FollowedTagsViewController.swift; sourceTree = "<group>"; };
|
2A506CF3292CD85800059C37 /* FollowedTagsViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FollowedTagsViewController.swift; sourceTree = "<group>"; };
|
||||||
2A506CF5292D040100059C37 /* HashtagTimelineHeaderView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HashtagTimelineHeaderView.swift; sourceTree = "<group>"; };
|
2A506CF5292D040100059C37 /* HashtagTimelineHeaderView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HashtagTimelineHeaderView.swift; sourceTree = "<group>"; };
|
||||||
|
2A5242722C199C96005B9E22 /* PrivacySafetyView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PrivacySafetyView.swift; sourceTree = "<group>"; };
|
||||||
|
2A5242742C199CBD005B9E22 /* CheckableButton.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CheckableButton.swift; sourceTree = "<group>"; };
|
||||||
|
2A5242762C199EC2005B9E22 /* PrivacySafetySettingPreset.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PrivacySafetySettingPreset.swift; sourceTree = "<group>"; };
|
||||||
2A631AE72B8C9F6600FE0778 /* LanguagePickerViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LanguagePickerViewController.swift; sourceTree = "<group>"; };
|
2A631AE72B8C9F6600FE0778 /* LanguagePickerViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LanguagePickerViewController.swift; sourceTree = "<group>"; };
|
||||||
2A6451022964223800CD8B8A /* UniformTypeIdentifiers.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = UniformTypeIdentifiers.framework; path = System/Library/Frameworks/UniformTypeIdentifiers.framework; sourceTree = SDKROOT; };
|
2A6451022964223800CD8B8A /* UniformTypeIdentifiers.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = UniformTypeIdentifiers.framework; path = System/Library/Frameworks/UniformTypeIdentifiers.framework; sourceTree = SDKROOT; };
|
||||||
2A64515D29642A8A00CD8B8A /* OpenInActionExtension.appex */ = {isa = PBXFileReference; explicitFileType = "wrapper.app-extension"; includeInIndex = 0; path = OpenInActionExtension.appex; sourceTree = BUILT_PRODUCTS_DIR; };
|
2A64515D29642A8A00CD8B8A /* OpenInActionExtension.appex */ = {isa = PBXFileReference; explicitFileType = "wrapper.app-extension"; includeInIndex = 0; path = OpenInActionExtension.appex; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||||
@ -1372,6 +1382,18 @@
|
|||||||
path = CollectionViewCell;
|
path = CollectionViewCell;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
};
|
};
|
||||||
|
2A0BF97D2C062278004A1E29 /* Privacy and Safety */ = {
|
||||||
|
isa = PBXGroup;
|
||||||
|
children = (
|
||||||
|
2A0BF97E2C0622AA004A1E29 /* PrivacySafetyViewController.swift */,
|
||||||
|
2A0BF9802C06252A004A1E29 /* PrivacySafetyViewModel.swift */,
|
||||||
|
2A5242722C199C96005B9E22 /* PrivacySafetyView.swift */,
|
||||||
|
2A5242742C199CBD005B9E22 /* CheckableButton.swift */,
|
||||||
|
2A5242762C199EC2005B9E22 /* PrivacySafetySettingPreset.swift */,
|
||||||
|
);
|
||||||
|
path = "Privacy and Safety";
|
||||||
|
sourceTree = "<group>";
|
||||||
|
};
|
||||||
2A506CF2292CD83B00059C37 /* FollowedTags */ = {
|
2A506CF2292CD83B00059C37 /* FollowedTags */ = {
|
||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
@ -1686,6 +1708,7 @@
|
|||||||
D8F916FF2A4AD898008A5370 /* Settings Overview */,
|
D8F916FF2A4AD898008A5370 /* Settings Overview */,
|
||||||
D8F917042A4B0657008A5370 /* General Settings */,
|
D8F917042A4B0657008A5370 /* General Settings */,
|
||||||
D81D12432A4E181C005009D4 /* Notification Settings */,
|
D81D12432A4E181C005009D4 /* Notification Settings */,
|
||||||
|
2A0BF97D2C062278004A1E29 /* Privacy and Safety */,
|
||||||
D80911062AC4BFD100EB4D15 /* Server Details */,
|
D80911062AC4BFD100EB4D15 /* Server Details */,
|
||||||
D8F917092A4B2AFF008A5370 /* About Mastodon */,
|
D8F917092A4B2AFF008A5370 /* About Mastodon */,
|
||||||
D8318A7F2A4466D300C0FB73 /* SettingsCoordinator.swift */,
|
D8318A7F2A4466D300C0FB73 /* SettingsCoordinator.swift */,
|
||||||
@ -3437,6 +3460,7 @@
|
|||||||
DB5B7298273112C800081888 /* FollowingListViewModel.swift in Sources */,
|
DB5B7298273112C800081888 /* FollowingListViewModel.swift in Sources */,
|
||||||
27D701F5292FC2D60031BCBB /* DataSourceFacade+URL.swift in Sources */,
|
27D701F5292FC2D60031BCBB /* DataSourceFacade+URL.swift in Sources */,
|
||||||
0FB3D2F725E4C24D00AAD544 /* MastodonPickServerViewModel.swift in Sources */,
|
0FB3D2F725E4C24D00AAD544 /* MastodonPickServerViewModel.swift in Sources */,
|
||||||
|
2A5242752C199CBD005B9E22 /* CheckableButton.swift in Sources */,
|
||||||
DB5B54AE2833C15F00DEF8B2 /* UserListViewModel+Diffable.swift in Sources */,
|
DB5B54AE2833C15F00DEF8B2 /* UserListViewModel+Diffable.swift in Sources */,
|
||||||
DB482A3F261331E8008AE74C /* UserTimelineViewModel+State.swift in Sources */,
|
DB482A3F261331E8008AE74C /* UserTimelineViewModel+State.swift in Sources */,
|
||||||
DB3E6FE02806A4ED00B035AE /* DiscoveryHashtagsViewModel.swift in Sources */,
|
DB3E6FE02806A4ED00B035AE /* DiscoveryHashtagsViewModel.swift in Sources */,
|
||||||
@ -3534,6 +3558,7 @@
|
|||||||
2DAC9E3E262FC2400062E1A6 /* SuggestionAccountViewModel.swift in Sources */,
|
2DAC9E3E262FC2400062E1A6 /* SuggestionAccountViewModel.swift in Sources */,
|
||||||
DB603113279EBEBA00A935FE /* DataSourceFacade+Block.swift in Sources */,
|
DB603113279EBEBA00A935FE /* DataSourceFacade+Block.swift in Sources */,
|
||||||
DB63F777279A9A2A00455B82 /* NotificationView+Configuration.swift in Sources */,
|
DB63F777279A9A2A00455B82 /* NotificationView+Configuration.swift in Sources */,
|
||||||
|
2A0BF9812C06252A004A1E29 /* PrivacySafetyViewModel.swift in Sources */,
|
||||||
DB029E95266A20430062874E /* MastodonAuthenticationController.swift in Sources */,
|
DB029E95266A20430062874E /* MastodonAuthenticationController.swift in Sources */,
|
||||||
DB6180DD263918E30018D199 /* MediaPreviewViewController.swift in Sources */,
|
DB6180DD263918E30018D199 /* MediaPreviewViewController.swift in Sources */,
|
||||||
DBE3CDEC261C6B2900430CC6 /* FavoriteViewController.swift in Sources */,
|
DBE3CDEC261C6B2900430CC6 /* FavoriteViewController.swift in Sources */,
|
||||||
@ -3665,6 +3690,7 @@
|
|||||||
DB1E346825F518E20079D7DF /* CategoryPickerSection.swift in Sources */,
|
DB1E346825F518E20079D7DF /* CategoryPickerSection.swift in Sources */,
|
||||||
DB7274F4273BB9B200577D95 /* UIScrollViewDelegate.swift in Sources */,
|
DB7274F4273BB9B200577D95 /* UIScrollViewDelegate.swift in Sources */,
|
||||||
DB0618052785A73D0030EE79 /* RegisterItem.swift in Sources */,
|
DB0618052785A73D0030EE79 /* RegisterItem.swift in Sources */,
|
||||||
|
2A5242732C199C96005B9E22 /* PrivacySafetyView.swift in Sources */,
|
||||||
DB6B74EF272FB55000C70B6E /* FollowerListViewController.swift in Sources */,
|
DB6B74EF272FB55000C70B6E /* FollowerListViewController.swift in Sources */,
|
||||||
DB4AA6B327BA34B6009EC082 /* CellFrameCacheContainer.swift in Sources */,
|
DB4AA6B327BA34B6009EC082 /* CellFrameCacheContainer.swift in Sources */,
|
||||||
DB0FCB942797E2B0006C02E2 /* SearchResultViewModel+Diffable.swift in Sources */,
|
DB0FCB942797E2B0006C02E2 /* SearchResultViewModel+Diffable.swift in Sources */,
|
||||||
@ -3728,6 +3754,7 @@
|
|||||||
D809907C294D25510050219F /* PrivacyViewModel.swift in Sources */,
|
D809907C294D25510050219F /* PrivacyViewModel.swift in Sources */,
|
||||||
D8318A862A4468C700C0FB73 /* SettingsViewController.swift in Sources */,
|
D8318A862A4468C700C0FB73 /* SettingsViewController.swift in Sources */,
|
||||||
DB5B549A2833A60400DEF8B2 /* FamiliarFollowersViewController.swift in Sources */,
|
DB5B549A2833A60400DEF8B2 /* FamiliarFollowersViewController.swift in Sources */,
|
||||||
|
2A0BF97F2C0622AA004A1E29 /* PrivacySafetyViewController.swift in Sources */,
|
||||||
DB3E6FE22806A50100B035AE /* DiscoveryHashtagsViewModel+Diffable.swift in Sources */,
|
DB3E6FE22806A50100B035AE /* DiscoveryHashtagsViewModel+Diffable.swift in Sources */,
|
||||||
DB427DD625BAA00100D1B89D /* AppDelegate.swift in Sources */,
|
DB427DD625BAA00100D1B89D /* AppDelegate.swift in Sources */,
|
||||||
DB0FCB822796AC78006C02E2 /* UserTimelineViewController+DataSourceProvider.swift in Sources */,
|
DB0FCB822796AC78006C02E2 /* UserTimelineViewController+DataSourceProvider.swift in Sources */,
|
||||||
@ -3755,6 +3782,7 @@
|
|||||||
DB4F0966269ED52200D62E92 /* SearchResultViewModel.swift in Sources */,
|
DB4F0966269ED52200D62E92 /* SearchResultViewModel.swift in Sources */,
|
||||||
D852C23C2AC5D02C00309232 /* AboutInstanceViewController.swift in Sources */,
|
D852C23C2AC5D02C00309232 /* AboutInstanceViewController.swift in Sources */,
|
||||||
D8F917142A4D74C3008A5370 /* GeneralSettingsDiffableTableViewDataSource.swift in Sources */,
|
D8F917142A4D74C3008A5370 /* GeneralSettingsDiffableTableViewDataSource.swift in Sources */,
|
||||||
|
2A5242772C199EC2005B9E22 /* PrivacySafetySettingPreset.swift in Sources */,
|
||||||
DB6180FA26391F2E0018D199 /* MediaPreviewViewModel.swift in Sources */,
|
DB6180FA26391F2E0018D199 /* MediaPreviewViewModel.swift in Sources */,
|
||||||
2D7631A825C1535600929FB9 /* StatusTableViewCell.swift in Sources */,
|
2D7631A825C1535600929FB9 /* StatusTableViewCell.swift in Sources */,
|
||||||
DB6B7500272FF73800C70B6E /* UserTableViewCell.swift in Sources */,
|
DB6B7500272FF73800C70B6E /* UserTableViewCell.swift in Sources */,
|
||||||
|
@ -0,0 +1,23 @@
|
|||||||
|
// Copyright © 2024 Mastodon gGmbH. All rights reserved.
|
||||||
|
|
||||||
|
import SwiftUI
|
||||||
|
import MastodonAsset
|
||||||
|
|
||||||
|
struct CheckableButton: View {
|
||||||
|
let text: String
|
||||||
|
let isChecked: Bool
|
||||||
|
let action: () -> Void
|
||||||
|
|
||||||
|
var body: some View {
|
||||||
|
Button(action: action) {
|
||||||
|
HStack {
|
||||||
|
Text(text)
|
||||||
|
Spacer()
|
||||||
|
if isChecked {
|
||||||
|
Image(systemName: "checkmark")
|
||||||
|
.foregroundStyle(Asset.Colors.Brand.blurple.swiftUIColor)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,60 @@
|
|||||||
|
// Copyright © 2024 Mastodon gGmbH. All rights reserved.
|
||||||
|
|
||||||
|
import Foundation
|
||||||
|
|
||||||
|
enum PrivacySafetySettingPreset: PrivacySafetySettingApplicable {
|
||||||
|
case openPublic, privateRestricted
|
||||||
|
|
||||||
|
var visibility: PrivacySafetyViewModel.Visibility {
|
||||||
|
switch self {
|
||||||
|
case .openPublic:
|
||||||
|
return .public
|
||||||
|
case .privateRestricted:
|
||||||
|
return .followersOnly
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var manuallyApproveFollowRequests: Bool {
|
||||||
|
switch self {
|
||||||
|
case .openPublic:
|
||||||
|
return false
|
||||||
|
case .privateRestricted:
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var showFollowersAndFollowing: Bool {
|
||||||
|
switch self {
|
||||||
|
case .openPublic:
|
||||||
|
return true
|
||||||
|
case .privateRestricted:
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var suggestMyAccountToOthers: Bool {
|
||||||
|
switch self {
|
||||||
|
case .openPublic:
|
||||||
|
return true
|
||||||
|
case .privateRestricted:
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var appearInSearches: Bool {
|
||||||
|
switch self {
|
||||||
|
case .openPublic:
|
||||||
|
return true
|
||||||
|
case .privateRestricted:
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func equalsSettings(of viewModel: PrivacySafetyViewModel) -> Bool {
|
||||||
|
return viewModel.visibility == visibility &&
|
||||||
|
viewModel.manuallyApproveFollowRequests == manuallyApproveFollowRequests &&
|
||||||
|
viewModel.showFollowersAndFollowing == showFollowersAndFollowing &&
|
||||||
|
viewModel.suggestMyAccountToOthers == suggestMyAccountToOthers &&
|
||||||
|
viewModel.appearInSearches == appearInSearches
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,65 @@
|
|||||||
|
// Copyright © 2024 Mastodon gGmbH. All rights reserved.
|
||||||
|
|
||||||
|
import SwiftUI
|
||||||
|
import MastodonLocalization
|
||||||
|
|
||||||
|
struct PrivacySafetyView: View {
|
||||||
|
@StateObject var viewModel: PrivacySafetyViewModel
|
||||||
|
|
||||||
|
var body: some View {
|
||||||
|
Group {
|
||||||
|
if !viewModel.isUserInteractionEnabled {
|
||||||
|
ProgressView()
|
||||||
|
} else {
|
||||||
|
Form {
|
||||||
|
Section(L10n.Scene.Settings.PrivacySafety.Preset.title) {
|
||||||
|
CheckableButton(
|
||||||
|
text: L10n.Scene.Settings.PrivacySafety.Preset.openAndPublic,
|
||||||
|
isChecked: viewModel.preset == .openPublic,
|
||||||
|
action: {
|
||||||
|
viewModel.preset = .openPublic
|
||||||
|
}
|
||||||
|
)
|
||||||
|
CheckableButton(
|
||||||
|
text: L10n.Scene.Settings.PrivacySafety.Preset.privateAndRestricted,
|
||||||
|
isChecked: viewModel.preset == .privateRestricted,
|
||||||
|
action: {
|
||||||
|
viewModel.preset = .privateRestricted
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
if viewModel.preset == .custom {
|
||||||
|
CheckableButton(
|
||||||
|
text: L10n.Scene.Settings.PrivacySafety.Preset.custom,
|
||||||
|
isChecked: viewModel.preset == .custom,
|
||||||
|
action: {
|
||||||
|
viewModel.preset = .custom
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Section {
|
||||||
|
Picker(selection: $viewModel.visibility) {
|
||||||
|
ForEach(PrivacySafetyViewModel.Visibility.allCases, id: \.self) {
|
||||||
|
Text($0.title)
|
||||||
|
}
|
||||||
|
} label: {
|
||||||
|
Text(L10n.Scene.Settings.PrivacySafety.DefaultPostVisibility.title)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
Section {
|
||||||
|
Toggle(L10n.Scene.Settings.PrivacySafety.manuallyApproveFollowRequests, isOn: $viewModel.manuallyApproveFollowRequests)
|
||||||
|
Toggle(L10n.Scene.Settings.PrivacySafety.showFollowersAndFollowing, isOn: $viewModel.showFollowersAndFollowing)
|
||||||
|
Toggle(L10n.Scene.Settings.PrivacySafety.suggestMyAccountToOthers, isOn: $viewModel.suggestMyAccountToOthers)
|
||||||
|
Toggle(L10n.Scene.Settings.PrivacySafety.appearInSearchEngines, isOn: $viewModel.appearInSearches)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.onAppear(perform: viewModel.viewDidAppear)
|
||||||
|
.onDisappear(perform: viewModel.saveSettings)
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,39 @@
|
|||||||
|
// Copyright © 2024 Mastodon gGmbH. All rights reserved.
|
||||||
|
|
||||||
|
import Combine
|
||||||
|
import UIKit
|
||||||
|
import SwiftUI
|
||||||
|
import MastodonSDK
|
||||||
|
import MastodonCore
|
||||||
|
import MastodonLocalization
|
||||||
|
import MastodonAsset
|
||||||
|
|
||||||
|
final class PrivacySafetyViewController: UIHostingController<PrivacySafetyView> {
|
||||||
|
private let viewModel: PrivacySafetyViewModel
|
||||||
|
private var disposeBag = [AnyCancellable]()
|
||||||
|
|
||||||
|
init(appContext: AppContext, authContext: AuthContext, coordinator: SceneCoordinator) {
|
||||||
|
self.viewModel = PrivacySafetyViewModel(
|
||||||
|
appContext: appContext, authContext: authContext, coordinator: coordinator
|
||||||
|
)
|
||||||
|
super.init(
|
||||||
|
rootView: PrivacySafetyView(
|
||||||
|
viewModel: self.viewModel
|
||||||
|
)
|
||||||
|
)
|
||||||
|
self.viewModel.onDismiss.receive(on: DispatchQueue.main)
|
||||||
|
.sink { [weak self] _ in
|
||||||
|
self?.dismiss(animated: true)
|
||||||
|
}
|
||||||
|
.store(in: &disposeBag)
|
||||||
|
}
|
||||||
|
|
||||||
|
@MainActor required dynamic init?(coder aDecoder: NSCoder) {
|
||||||
|
fatalError("init(coder:) has not been implemented")
|
||||||
|
}
|
||||||
|
|
||||||
|
override func viewDidLoad() {
|
||||||
|
super.viewDidLoad()
|
||||||
|
title = L10n.Scene.Settings.PrivacySafety.title
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,205 @@
|
|||||||
|
// Copyright © 2024 Mastodon gGmbH. All rights reserved.
|
||||||
|
|
||||||
|
import Combine
|
||||||
|
import Foundation
|
||||||
|
import MastodonLocalization
|
||||||
|
import MastodonCore
|
||||||
|
import MastodonSDK
|
||||||
|
|
||||||
|
protocol PrivacySafetySettingApplicable {
|
||||||
|
var visibility: PrivacySafetyViewModel.Visibility { get }
|
||||||
|
var manuallyApproveFollowRequests: Bool { get }
|
||||||
|
var showFollowersAndFollowing: Bool { get }
|
||||||
|
var suggestMyAccountToOthers: Bool { get }
|
||||||
|
var appearInSearches: Bool { get }
|
||||||
|
}
|
||||||
|
|
||||||
|
class PrivacySafetyViewModel: ObservableObject, PrivacySafetySettingApplicable {
|
||||||
|
enum Preset {
|
||||||
|
case openPublic, privateRestricted, custom
|
||||||
|
}
|
||||||
|
|
||||||
|
enum Visibility: CaseIterable {
|
||||||
|
case `public`, followersOnly, onlyPeopleMentioned
|
||||||
|
|
||||||
|
var title: String {
|
||||||
|
switch self {
|
||||||
|
case .public:
|
||||||
|
return L10n.Scene.Settings.PrivacySafety.DefaultPostVisibility.public
|
||||||
|
case .followersOnly:
|
||||||
|
return L10n.Scene.Settings.PrivacySafety.DefaultPostVisibility.followersOnly
|
||||||
|
case .onlyPeopleMentioned:
|
||||||
|
return L10n.Scene.Settings.PrivacySafety.DefaultPostVisibility.onlyPeopleMentioned
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static func from(_ privacy: Mastodon.Entity.Source.Privacy) -> Self {
|
||||||
|
switch privacy {
|
||||||
|
case .public:
|
||||||
|
return .public
|
||||||
|
case .unlisted:
|
||||||
|
return .followersOnly
|
||||||
|
case .private, .direct:
|
||||||
|
return .onlyPeopleMentioned
|
||||||
|
case ._other(_):
|
||||||
|
return .public
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func toPrivacy() -> Mastodon.Entity.Source.Privacy {
|
||||||
|
switch self {
|
||||||
|
case .public:
|
||||||
|
return .public
|
||||||
|
case .followersOnly:
|
||||||
|
return .unlisted
|
||||||
|
case .onlyPeopleMentioned:
|
||||||
|
return .private
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private var appContext: AppContext?
|
||||||
|
private var authContext: AuthContext?
|
||||||
|
private var coordinator: SceneCoordinator?
|
||||||
|
|
||||||
|
init(appContext: AppContext?, authContext: AuthContext?, coordinator: SceneCoordinator?) {
|
||||||
|
self.appContext = appContext
|
||||||
|
self.authContext = authContext
|
||||||
|
self.coordinator = coordinator
|
||||||
|
}
|
||||||
|
|
||||||
|
@Published var preset: Preset = .openPublic {
|
||||||
|
didSet { applyPreset(preset) }
|
||||||
|
}
|
||||||
|
@Published var visibility: Visibility = .public {
|
||||||
|
didSet { evaluatePreset() }
|
||||||
|
}
|
||||||
|
|
||||||
|
@Published var manuallyApproveFollowRequests = false {
|
||||||
|
didSet { evaluatePreset() }
|
||||||
|
}
|
||||||
|
|
||||||
|
@Published var showFollowersAndFollowing = true {
|
||||||
|
didSet { evaluatePreset() }
|
||||||
|
}
|
||||||
|
|
||||||
|
@Published var suggestMyAccountToOthers = true {
|
||||||
|
didSet { evaluatePreset() }
|
||||||
|
}
|
||||||
|
|
||||||
|
@Published var appearInSearches = true {
|
||||||
|
didSet { evaluatePreset() }
|
||||||
|
}
|
||||||
|
|
||||||
|
private var doNotEvaluate = true
|
||||||
|
@Published var isUserInteractionEnabled = false
|
||||||
|
let onDismiss = PassthroughSubject<Void, Never>()
|
||||||
|
|
||||||
|
func viewDidAppear() {
|
||||||
|
doNotEvaluate = false
|
||||||
|
if !isUserInteractionEnabled {
|
||||||
|
loadSettings()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
extension PrivacySafetyViewModel: Equatable {
|
||||||
|
static func == (lhs: PrivacySafetyViewModel, rhs: PrivacySafetyViewModel) -> Bool {
|
||||||
|
lhs.visibility == rhs.visibility &&
|
||||||
|
lhs.manuallyApproveFollowRequests == rhs.manuallyApproveFollowRequests &&
|
||||||
|
lhs.showFollowersAndFollowing == rhs.showFollowersAndFollowing &&
|
||||||
|
lhs.suggestMyAccountToOthers == rhs.suggestMyAccountToOthers &&
|
||||||
|
lhs.appearInSearches == rhs.appearInSearches
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
extension PrivacySafetyViewModel {
|
||||||
|
func applyPreset(_ preset: Preset) {
|
||||||
|
switch preset {
|
||||||
|
case .openPublic:
|
||||||
|
self.apply(from: .openPublic)
|
||||||
|
case .privateRestricted:
|
||||||
|
self.apply(from: .privateRestricted)
|
||||||
|
case .custom:
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func evaluatePreset() {
|
||||||
|
guard !doNotEvaluate else { return }
|
||||||
|
if PrivacySafetySettingPreset.openPublic.equalsSettings(of: self) {
|
||||||
|
preset = .openPublic
|
||||||
|
} else if PrivacySafetySettingPreset.privateRestricted.equalsSettings(of: self) {
|
||||||
|
preset = .privateRestricted
|
||||||
|
} else {
|
||||||
|
preset = .custom
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private func loadSettings() {
|
||||||
|
Task { @MainActor in
|
||||||
|
guard let appContext, let authContext else {
|
||||||
|
return dismiss()
|
||||||
|
}
|
||||||
|
|
||||||
|
let domain = authContext.mastodonAuthenticationBox.domain
|
||||||
|
let userAuthorization = authContext.mastodonAuthenticationBox.userAuthorization
|
||||||
|
|
||||||
|
let account = try await appContext.apiService.accountVerifyCredentials(
|
||||||
|
domain: domain,
|
||||||
|
authorization: userAuthorization
|
||||||
|
).singleOutput().value
|
||||||
|
|
||||||
|
if let privacy = account.source?.privacy {
|
||||||
|
visibility = .from(privacy)
|
||||||
|
}
|
||||||
|
|
||||||
|
manuallyApproveFollowRequests = account.locked == true
|
||||||
|
showFollowersAndFollowing = account.source?.hideCollections == false
|
||||||
|
suggestMyAccountToOthers = account.source?.discoverable == true
|
||||||
|
appearInSearches = account.source?.indexable == true
|
||||||
|
|
||||||
|
isUserInteractionEnabled = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func saveSettings() {
|
||||||
|
Task {
|
||||||
|
guard let appContext, let authContext else {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
let domain = authContext.mastodonAuthenticationBox.domain
|
||||||
|
let userAuthorization = authContext.mastodonAuthenticationBox.userAuthorization
|
||||||
|
|
||||||
|
let _ = try await appContext.apiService.accountUpdateCredentials(
|
||||||
|
domain: domain,
|
||||||
|
query: .init(
|
||||||
|
discoverable: suggestMyAccountToOthers,
|
||||||
|
locked: manuallyApproveFollowRequests,
|
||||||
|
source: .withPrivacy(visibility.toPrivacy()),
|
||||||
|
indexable: appearInSearches,
|
||||||
|
hideCollections: !showFollowersAndFollowing
|
||||||
|
),
|
||||||
|
authorization: userAuthorization
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func dismiss() {
|
||||||
|
onDismiss.send(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Preset Rules Definition
|
||||||
|
extension PrivacySafetyViewModel {
|
||||||
|
private func apply(from source: PrivacySafetySettingPreset) {
|
||||||
|
doNotEvaluate = true
|
||||||
|
visibility = source.visibility
|
||||||
|
manuallyApproveFollowRequests = source.manuallyApproveFollowRequests
|
||||||
|
showFollowersAndFollowing = source.showFollowersAndFollowing
|
||||||
|
suggestMyAccountToOthers = source.suggestMyAccountToOthers
|
||||||
|
appearInSearches = source.appearInSearches
|
||||||
|
doNotEvaluate = false
|
||||||
|
}
|
||||||
|
}
|
@ -10,6 +10,7 @@ struct SettingsSection: Hashable {
|
|||||||
enum SettingsEntry: Hashable {
|
enum SettingsEntry: Hashable {
|
||||||
case general
|
case general
|
||||||
case notifications
|
case notifications
|
||||||
|
case privacySafety
|
||||||
case serverDetails(domain: String)
|
case serverDetails(domain: String)
|
||||||
case aboutMastodon
|
case aboutMastodon
|
||||||
case logout(accountName: String)
|
case logout(accountName: String)
|
||||||
@ -20,6 +21,8 @@ enum SettingsEntry: Hashable {
|
|||||||
return L10n.Scene.Settings.Overview.general
|
return L10n.Scene.Settings.Overview.general
|
||||||
case .notifications:
|
case .notifications:
|
||||||
return L10n.Scene.Settings.Overview.notifications
|
return L10n.Scene.Settings.Overview.notifications
|
||||||
|
case .privacySafety:
|
||||||
|
return L10n.Scene.Settings.Overview.privacySafety
|
||||||
case .serverDetails(_):
|
case .serverDetails(_):
|
||||||
return L10n.Scene.Settings.Overview.serverDetails
|
return L10n.Scene.Settings.Overview.serverDetails
|
||||||
case .aboutMastodon:
|
case .aboutMastodon:
|
||||||
@ -33,14 +36,14 @@ enum SettingsEntry: Hashable {
|
|||||||
switch self {
|
switch self {
|
||||||
case .serverDetails(domain: let domain):
|
case .serverDetails(domain: let domain):
|
||||||
return domain
|
return domain
|
||||||
case .general, .notifications, .aboutMastodon, .logout(_):
|
case .general, .notifications, .privacySafety, .aboutMastodon, .logout(_):
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var accessoryType: UITableViewCell.AccessoryType {
|
var accessoryType: UITableViewCell.AccessoryType {
|
||||||
switch self {
|
switch self {
|
||||||
case .general, .notifications, .serverDetails(_), .aboutMastodon, .logout(_):
|
case .general, .notifications, .privacySafety, .serverDetails(_), .aboutMastodon, .logout(_):
|
||||||
return .disclosureIndicator
|
return .disclosureIndicator
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -51,6 +54,8 @@ enum SettingsEntry: Hashable {
|
|||||||
return UIImage(systemName: "gear")
|
return UIImage(systemName: "gear")
|
||||||
case .notifications:
|
case .notifications:
|
||||||
return UIImage(systemName: "bell.badge")
|
return UIImage(systemName: "bell.badge")
|
||||||
|
case .privacySafety:
|
||||||
|
return UIImage(systemName: "lock.fill")
|
||||||
case .serverDetails(_):
|
case .serverDetails(_):
|
||||||
return UIImage(systemName: "server.rack")
|
return UIImage(systemName: "server.rack")
|
||||||
case .aboutMastodon:
|
case .aboutMastodon:
|
||||||
@ -66,6 +71,8 @@ enum SettingsEntry: Hashable {
|
|||||||
return .systemGray
|
return .systemGray
|
||||||
case .notifications:
|
case .notifications:
|
||||||
return .systemRed
|
return .systemRed
|
||||||
|
case .privacySafety:
|
||||||
|
return .systemBlue
|
||||||
case .serverDetails(_):
|
case .serverDetails(_):
|
||||||
return .systemTeal
|
return .systemTeal
|
||||||
case .aboutMastodon:
|
case .aboutMastodon:
|
||||||
@ -78,7 +85,7 @@ enum SettingsEntry: Hashable {
|
|||||||
|
|
||||||
var textColor: UIColor {
|
var textColor: UIColor {
|
||||||
switch self {
|
switch self {
|
||||||
case .general, .notifications, .aboutMastodon, .serverDetails(_):
|
case .general, .notifications, .privacySafety, .aboutMastodon, .serverDetails(_):
|
||||||
return .label
|
return .label
|
||||||
case .logout(_):
|
case .logout(_):
|
||||||
return .red
|
return .red
|
||||||
|
@ -19,10 +19,10 @@ class SettingsViewController: UIViewController {
|
|||||||
init(accountName: String, domain: String) {
|
init(accountName: String, domain: String) {
|
||||||
|
|
||||||
sections = [
|
sections = [
|
||||||
.init(entries: [.general, .notifications]),
|
.init(entries: [.general, .notifications, .privacySafety]),
|
||||||
.init(entries: [.serverDetails(domain: domain), .aboutMastodon]),
|
.init(entries: [.serverDetails(domain: domain), .aboutMastodon]),
|
||||||
.init(entries: [.logout(accountName: accountName)])
|
.init(entries: [.logout(accountName: accountName)])
|
||||||
]
|
]
|
||||||
|
|
||||||
tableView = UITableView(frame: .zero, style: .insetGrouped)
|
tableView = UITableView(frame: .zero, style: .insetGrouped)
|
||||||
tableView.translatesAutoresizingMaskIntoConstraints = false
|
tableView.translatesAutoresizingMaskIntoConstraints = false
|
||||||
|
@ -71,6 +71,13 @@ extension SettingsCoordinator: SettingsViewControllerDelegate {
|
|||||||
notificationViewController.delegate = self
|
notificationViewController.delegate = self
|
||||||
|
|
||||||
navigationController.pushViewController(notificationViewController, animated: true)
|
navigationController.pushViewController(notificationViewController, animated: true)
|
||||||
|
case .privacySafety:
|
||||||
|
let privacySafetyViewController = PrivacySafetyViewController(
|
||||||
|
appContext: appContext,
|
||||||
|
authContext: authContext,
|
||||||
|
coordinator: sceneCoordinator
|
||||||
|
)
|
||||||
|
navigationController.pushViewController(privacySafetyViewController, animated: true)
|
||||||
case .serverDetails(let domain):
|
case .serverDetails(let domain):
|
||||||
let serverDetailsViewController = ServerDetailsViewController(domain: domain, appContext: appContext, authContext: authContext, sceneCoordinator: sceneCoordinator)
|
let serverDetailsViewController = ServerDetailsViewController(domain: domain, appContext: appContext, authContext: authContext, sceneCoordinator: sceneCoordinator)
|
||||||
serverDetailsViewController.delegate = self
|
serverDetailsViewController.delegate = self
|
||||||
|
@ -1598,6 +1598,8 @@ public enum L10n {
|
|||||||
}
|
}
|
||||||
/// Notifications
|
/// Notifications
|
||||||
public static let notifications = L10n.tr("Localizable", "Scene.Settings.Overview.Notifications", fallback: "Notifications")
|
public static let notifications = L10n.tr("Localizable", "Scene.Settings.Overview.Notifications", fallback: "Notifications")
|
||||||
|
/// Privacy & Safety
|
||||||
|
public static let privacySafety = L10n.tr("Localizable", "Scene.Settings.Overview.PrivacySafety", fallback: "Privacy & Safety")
|
||||||
/// Server Details
|
/// Server Details
|
||||||
public static let serverDetails = L10n.tr("Localizable", "Scene.Settings.Overview.ServerDetails", fallback: "Server Details")
|
public static let serverDetails = L10n.tr("Localizable", "Scene.Settings.Overview.ServerDetails", fallback: "Server Details")
|
||||||
/// Support Mastodon
|
/// Support Mastodon
|
||||||
@ -1605,6 +1607,38 @@ public enum L10n {
|
|||||||
/// Settings
|
/// Settings
|
||||||
public static let title = L10n.tr("Localizable", "Scene.Settings.Overview.Title", fallback: "Settings")
|
public static let title = L10n.tr("Localizable", "Scene.Settings.Overview.Title", fallback: "Settings")
|
||||||
}
|
}
|
||||||
|
public enum PrivacySafety {
|
||||||
|
/// Appear in Search Engines
|
||||||
|
public static let appearInSearchEngines = L10n.tr("Localizable", "Scene.Settings.PrivacySafety.AppearInSearchEngines", fallback: "Appear in Search Engines")
|
||||||
|
/// Manually Approve Follow Requests
|
||||||
|
public static let manuallyApproveFollowRequests = L10n.tr("Localizable", "Scene.Settings.PrivacySafety.ManuallyApproveFollowRequests", fallback: "Manually Approve Follow Requests")
|
||||||
|
/// Show Followers & Following
|
||||||
|
public static let showFollowersAndFollowing = L10n.tr("Localizable", "Scene.Settings.PrivacySafety.ShowFollowersAndFollowing", fallback: "Show Followers & Following")
|
||||||
|
/// Suggest My Account to Others
|
||||||
|
public static let suggestMyAccountToOthers = L10n.tr("Localizable", "Scene.Settings.PrivacySafety.SuggestMyAccountToOthers", fallback: "Suggest My Account to Others")
|
||||||
|
/// Privacy & Safety
|
||||||
|
public static let title = L10n.tr("Localizable", "Scene.Settings.PrivacySafety.Title", fallback: "Privacy & Safety")
|
||||||
|
public enum DefaultPostVisibility {
|
||||||
|
/// Followers Only
|
||||||
|
public static let followersOnly = L10n.tr("Localizable", "Scene.Settings.PrivacySafety.DefaultPostVisibility.FollowersOnly", fallback: "Followers Only")
|
||||||
|
/// Only People Mentioned
|
||||||
|
public static let onlyPeopleMentioned = L10n.tr("Localizable", "Scene.Settings.PrivacySafety.DefaultPostVisibility.OnlyPeopleMentioned", fallback: "Only People Mentioned")
|
||||||
|
/// Public
|
||||||
|
public static let `public` = L10n.tr("Localizable", "Scene.Settings.PrivacySafety.DefaultPostVisibility.Public", fallback: "Public")
|
||||||
|
/// Default Post Visibility
|
||||||
|
public static let title = L10n.tr("Localizable", "Scene.Settings.PrivacySafety.DefaultPostVisibility.Title", fallback: "Default Post Visibility")
|
||||||
|
}
|
||||||
|
public enum Preset {
|
||||||
|
/// Custom
|
||||||
|
public static let custom = L10n.tr("Localizable", "Scene.Settings.PrivacySafety.Preset.Custom", fallback: "Custom")
|
||||||
|
/// Open & Public
|
||||||
|
public static let openAndPublic = L10n.tr("Localizable", "Scene.Settings.PrivacySafety.Preset.OpenAndPublic", fallback: "Open & Public")
|
||||||
|
/// Private & Restricted
|
||||||
|
public static let privateAndRestricted = L10n.tr("Localizable", "Scene.Settings.PrivacySafety.Preset.PrivateAndRestricted", fallback: "Private & Restricted")
|
||||||
|
/// Preset
|
||||||
|
public static let title = L10n.tr("Localizable", "Scene.Settings.PrivacySafety.Preset.Title", fallback: "Preset")
|
||||||
|
}
|
||||||
|
}
|
||||||
public enum ServerDetails {
|
public enum ServerDetails {
|
||||||
/// About
|
/// About
|
||||||
public static let about = L10n.tr("Localizable", "Scene.Settings.ServerDetails.About", fallback: "About")
|
public static let about = L10n.tr("Localizable", "Scene.Settings.ServerDetails.About", fallback: "About")
|
||||||
|
@ -558,9 +558,23 @@ If you disagree with the policy for **%@**, you can go back and pick a different
|
|||||||
"Scene.Settings.Overview.General" = "General";
|
"Scene.Settings.Overview.General" = "General";
|
||||||
"Scene.Settings.Overview.Logout" = "Logout %@";
|
"Scene.Settings.Overview.Logout" = "Logout %@";
|
||||||
"Scene.Settings.Overview.Notifications" = "Notifications";
|
"Scene.Settings.Overview.Notifications" = "Notifications";
|
||||||
|
"Scene.Settings.Overview.PrivacySafety" = "Privacy & Safety";
|
||||||
"Scene.Settings.Overview.ServerDetails" = "Server Details";
|
"Scene.Settings.Overview.ServerDetails" = "Server Details";
|
||||||
"Scene.Settings.Overview.SupportMastodon" = "Support Mastodon";
|
"Scene.Settings.Overview.SupportMastodon" = "Support Mastodon";
|
||||||
"Scene.Settings.Overview.Title" = "Settings";
|
"Scene.Settings.Overview.Title" = "Settings";
|
||||||
|
"Scene.Settings.PrivacySafety.Title" = "Privacy & Safety";
|
||||||
|
"Scene.Settings.PrivacySafety.Preset.Title" = "Preset";
|
||||||
|
"Scene.Settings.PrivacySafety.Preset.OpenAndPublic" = "Open & Public";
|
||||||
|
"Scene.Settings.PrivacySafety.Preset.PrivateAndRestricted" = "Private & Restricted";
|
||||||
|
"Scene.Settings.PrivacySafety.Preset.Custom" = "Custom";
|
||||||
|
"Scene.Settings.PrivacySafety.DefaultPostVisibility.Title" = "Default Post Visibility";
|
||||||
|
"Scene.Settings.PrivacySafety.DefaultPostVisibility.Public" = "Public";
|
||||||
|
"Scene.Settings.PrivacySafety.DefaultPostVisibility.FollowersOnly" = "Followers Only";
|
||||||
|
"Scene.Settings.PrivacySafety.DefaultPostVisibility.OnlyPeopleMentioned" = "Only People Mentioned";
|
||||||
|
"Scene.Settings.PrivacySafety.ManuallyApproveFollowRequests" = "Manually Approve Follow Requests";
|
||||||
|
"Scene.Settings.PrivacySafety.ShowFollowersAndFollowing" = "Show Followers & Following";
|
||||||
|
"Scene.Settings.PrivacySafety.SuggestMyAccountToOthers" = "Suggest My Account to Others";
|
||||||
|
"Scene.Settings.PrivacySafety.AppearInSearchEngines" = "Appear in Search Engines";
|
||||||
"Scene.Settings.ServerDetails.About" = "About";
|
"Scene.Settings.ServerDetails.About" = "About";
|
||||||
"Scene.Settings.ServerDetails.AboutInstance.LegalNotice" = "A legal notice";
|
"Scene.Settings.ServerDetails.AboutInstance.LegalNotice" = "A legal notice";
|
||||||
"Scene.Settings.ServerDetails.AboutInstance.MessageAdmin" = "Message Admin";
|
"Scene.Settings.ServerDetails.AboutInstance.MessageAdmin" = "Message Admin";
|
||||||
@ -601,4 +615,4 @@ If you disagree with the policy for **%@**, you can go back and pick a different
|
|||||||
"Widget.MultipleFollowers.ConfigurationDescription" = "Show number of followers for multiple accounts.";
|
"Widget.MultipleFollowers.ConfigurationDescription" = "Show number of followers for multiple accounts.";
|
||||||
"Widget.MultipleFollowers.ConfigurationDisplayName" = "Multiple followers";
|
"Widget.MultipleFollowers.ConfigurationDisplayName" = "Multiple followers";
|
||||||
"Widget.MultipleFollowers.MockUser.AccountName" = "another@follower.social";
|
"Widget.MultipleFollowers.MockUser.AccountName" = "another@follower.social";
|
||||||
"Widget.MultipleFollowers.MockUser.DisplayName" = "Another follower";
|
"Widget.MultipleFollowers.MockUser.DisplayName" = "Another follower";
|
||||||
|
@ -158,7 +158,9 @@ extension Mastodon.API.Account {
|
|||||||
public let locked: Bool?
|
public let locked: Bool?
|
||||||
public let source: Mastodon.Entity.Source?
|
public let source: Mastodon.Entity.Source?
|
||||||
public let fieldsAttributes: [Mastodon.Entity.Field]?
|
public let fieldsAttributes: [Mastodon.Entity.Field]?
|
||||||
|
public let indexable: Bool?
|
||||||
|
public let hideCollections: Bool?
|
||||||
|
|
||||||
enum CodingKeys: String, CodingKey {
|
enum CodingKeys: String, CodingKey {
|
||||||
case discoverable
|
case discoverable
|
||||||
case bot
|
case bot
|
||||||
@ -170,6 +172,8 @@ extension Mastodon.API.Account {
|
|||||||
case locked
|
case locked
|
||||||
case source
|
case source
|
||||||
case fieldsAttributes = "fields_attributes"
|
case fieldsAttributes = "fields_attributes"
|
||||||
|
case indexable
|
||||||
|
case hideCollections = "hide_collections"
|
||||||
}
|
}
|
||||||
|
|
||||||
public init(
|
public init(
|
||||||
@ -181,7 +185,9 @@ extension Mastodon.API.Account {
|
|||||||
header: Mastodon.Query.MediaAttachment? = nil,
|
header: Mastodon.Query.MediaAttachment? = nil,
|
||||||
locked: Bool? = nil,
|
locked: Bool? = nil,
|
||||||
source: Mastodon.Entity.Source? = nil,
|
source: Mastodon.Entity.Source? = nil,
|
||||||
fieldsAttributes: [Mastodon.Entity.Field]? = nil
|
fieldsAttributes: [Mastodon.Entity.Field]? = nil,
|
||||||
|
indexable: Bool? = nil,
|
||||||
|
hideCollections: Bool? = nil
|
||||||
) {
|
) {
|
||||||
self.discoverable = discoverable
|
self.discoverable = discoverable
|
||||||
self.bot = bot
|
self.bot = bot
|
||||||
@ -192,6 +198,8 @@ extension Mastodon.API.Account {
|
|||||||
self.locked = locked
|
self.locked = locked
|
||||||
self.source = source
|
self.source = source
|
||||||
self.fieldsAttributes = fieldsAttributes
|
self.fieldsAttributes = fieldsAttributes
|
||||||
|
self.indexable = indexable
|
||||||
|
self.hideCollections = hideCollections
|
||||||
}
|
}
|
||||||
|
|
||||||
var contentType: String? {
|
var contentType: String? {
|
||||||
@ -205,6 +213,7 @@ extension Mastodon.API.Account {
|
|||||||
var body: Data? {
|
var body: Data? {
|
||||||
var data = Data()
|
var data = Data()
|
||||||
|
|
||||||
|
hideCollections.flatMap { data.append(Data.multipart(key: "hide_collections", value: $0)) }
|
||||||
discoverable.flatMap { data.append(Data.multipart(key: "discoverable", value: $0)) }
|
discoverable.flatMap { data.append(Data.multipart(key: "discoverable", value: $0)) }
|
||||||
bot.flatMap { data.append(Data.multipart(key: "bot", value: $0)) }
|
bot.flatMap { data.append(Data.multipart(key: "bot", value: $0)) }
|
||||||
displayName.flatMap { data.append(Data.multipart(key: "display_name", value: $0)) }
|
displayName.flatMap { data.append(Data.multipart(key: "display_name", value: $0)) }
|
||||||
@ -212,6 +221,7 @@ extension Mastodon.API.Account {
|
|||||||
avatar.flatMap { data.append(Data.multipart(key: "avatar", value: $0)) }
|
avatar.flatMap { data.append(Data.multipart(key: "avatar", value: $0)) }
|
||||||
header.flatMap { data.append(Data.multipart(key: "header", value: $0)) }
|
header.flatMap { data.append(Data.multipart(key: "header", value: $0)) }
|
||||||
locked.flatMap { data.append(Data.multipart(key: "locked", value: $0)) }
|
locked.flatMap { data.append(Data.multipart(key: "locked", value: $0)) }
|
||||||
|
indexable.flatMap { data.append(Data.multipart(key: "indexable", value: $0)) }
|
||||||
if let source = source {
|
if let source = source {
|
||||||
source.privacy.flatMap { data.append(Data.multipart(key: "source[privacy]", value: $0.rawValue)) }
|
source.privacy.flatMap { data.append(Data.multipart(key: "source[privacy]", value: $0.rawValue)) }
|
||||||
source.sensitive.flatMap { data.append(Data.multipart(key: "source[privacy]", value: $0)) }
|
source.sensitive.flatMap { data.append(Data.multipart(key: "source[privacy]", value: $0)) }
|
||||||
|
@ -71,7 +71,7 @@ extension Mastodon.Entity.Account: Codable {
|
|||||||
case locked
|
case locked
|
||||||
case emojis
|
case emojis
|
||||||
case discoverable
|
case discoverable
|
||||||
|
|
||||||
case createdAt = "created_at"
|
case createdAt = "created_at"
|
||||||
case lastStatusAt = "last_status_at"
|
case lastStatusAt = "last_status_at"
|
||||||
case statusesCount = "statuses_count"
|
case statusesCount = "statuses_count"
|
||||||
|
@ -26,7 +26,10 @@ extension Mastodon.Entity {
|
|||||||
public let sensitive: Bool?
|
public let sensitive: Bool?
|
||||||
public let language: String? // (ISO 639-1 language two-letter code)
|
public let language: String? // (ISO 639-1 language two-letter code)
|
||||||
public let followRequestsCount: Int?
|
public let followRequestsCount: Int?
|
||||||
|
public let hideCollections: Bool?
|
||||||
|
public let indexable: Bool?
|
||||||
|
public let discoverable: Bool?
|
||||||
|
|
||||||
enum CodingKeys: String, CodingKey {
|
enum CodingKeys: String, CodingKey {
|
||||||
case note
|
case note
|
||||||
case fields
|
case fields
|
||||||
@ -35,6 +38,13 @@ extension Mastodon.Entity {
|
|||||||
case sensitive
|
case sensitive
|
||||||
case language
|
case language
|
||||||
case followRequestsCount = "follow_requests_count"
|
case followRequestsCount = "follow_requests_count"
|
||||||
|
case hideCollections = "hide_collections"
|
||||||
|
case indexable
|
||||||
|
case discoverable
|
||||||
|
}
|
||||||
|
|
||||||
|
public static func withPrivacy(_ privacy: Privacy) -> Self {
|
||||||
|
Source(note: "", fields: nil, privacy: privacy, sensitive: nil, language: nil, followRequestsCount: nil, hideCollections: nil, indexable: nil, discoverable: nil)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user