forked from zelo72/mastodon-ios
Merge branch 'release/0.8.5' into main
This commit is contained in:
commit
b7de9dd224
|
@ -129,14 +129,6 @@
|
|||
"media_content_warning": "Tap anywhere to reveal",
|
||||
"poll": {
|
||||
"vote": "Vote",
|
||||
"vote_count": {
|
||||
"single": "%d vote",
|
||||
"multiple": "%d votes"
|
||||
},
|
||||
"voter_count": {
|
||||
"single": "%d voter",
|
||||
"multiple": "%d voters"
|
||||
},
|
||||
"time_left": "%s left",
|
||||
"closed": "Closed"
|
||||
},
|
||||
|
@ -200,12 +192,6 @@
|
|||
"count_favorites": "%s favorites"
|
||||
}
|
||||
}
|
||||
},
|
||||
"countable": {
|
||||
"photo": {
|
||||
"single": "photo",
|
||||
"multiple": "photos"
|
||||
}
|
||||
}
|
||||
},
|
||||
"scene": {
|
||||
|
@ -386,8 +372,6 @@
|
|||
"direct": "Only people I mention"
|
||||
},
|
||||
"auto_complete": {
|
||||
"single_people_talking": "%ld people talking",
|
||||
"multiple_people_talking": "%ld people talking",
|
||||
"space_to_add": "Space to add"
|
||||
},
|
||||
"accessibility": {
|
||||
|
@ -411,7 +395,6 @@
|
|||
}
|
||||
},
|
||||
"profile": {
|
||||
"subtitle": "%s posts",
|
||||
"dashboard": {
|
||||
"posts": "posts",
|
||||
"following": "following",
|
||||
|
@ -499,15 +482,7 @@
|
|||
},
|
||||
"thread": {
|
||||
"back_title": "Post",
|
||||
"title": "Post from %s",
|
||||
"reblog": {
|
||||
"single": "%s reblog",
|
||||
"multiple": "%s reblogs"
|
||||
},
|
||||
"favorite": {
|
||||
"single": "%s favorite",
|
||||
"multiple": "%s favorites"
|
||||
}
|
||||
"title": "Post from %s"
|
||||
},
|
||||
"settings": {
|
||||
"title": "Settings",
|
||||
|
@ -548,6 +523,9 @@
|
|||
"signout": "Sign Out"
|
||||
}
|
||||
},
|
||||
"footer": {
|
||||
"mastodon_description": "Mastodon is open source software. You can contribute or report issues on GitHub at %s (%s)"
|
||||
},
|
||||
"keyboard": {
|
||||
"close_settings_window": "Close Settings Window"
|
||||
}
|
||||
|
|
|
@ -55,7 +55,6 @@
|
|||
2D34D9DB261494120081BFC0 /* APIService+Search.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2D34D9DA261494120081BFC0 /* APIService+Search.swift */; };
|
||||
2D34D9E226149C920081BFC0 /* SearchRecommendTagsCollectionViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2D34D9E126149C920081BFC0 /* SearchRecommendTagsCollectionViewCell.swift */; };
|
||||
2D35237A26256D920031AF25 /* NotificationSection.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2D35237926256D920031AF25 /* NotificationSection.swift */; };
|
||||
2D35238126256F690031AF25 /* NotificationTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2D35238026256F690031AF25 /* NotificationTableViewCell.swift */; };
|
||||
2D364F7225E66D7500204FDC /* MastodonResendEmailViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2D364F7125E66D7500204FDC /* MastodonResendEmailViewController.swift */; };
|
||||
2D364F7825E66D8300204FDC /* MastodonResendEmailViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2D364F7725E66D8300204FDC /* MastodonResendEmailViewModel.swift */; };
|
||||
2D38F1C625CD37F400561493 /* ContentOffsetAdjustableTimelineViewControllerDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2D38F1C525CD37F400561493 /* ContentOffsetAdjustableTimelineViewControllerDelegate.swift */; };
|
||||
|
@ -242,6 +241,8 @@
|
|||
DB427DED25BAA00100D1B89D /* MastodonTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB427DEC25BAA00100D1B89D /* MastodonTests.swift */; };
|
||||
DB427DF825BAA00100D1B89D /* MastodonUITests.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB427DF725BAA00100D1B89D /* MastodonUITests.swift */; };
|
||||
DB44384F25E8C1FA008912A2 /* CALayer.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB44384E25E8C1FA008912A2 /* CALayer.swift */; };
|
||||
DB443CD22694326A00159B29 /* Localizable.stringsdict in Resources */ = {isa = PBXBuildFile; fileRef = DB443CD0269415D200159B29 /* Localizable.stringsdict */; };
|
||||
DB443CD42694627B00159B29 /* AppearanceView.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB443CD32694627B00159B29 /* AppearanceView.swift */; };
|
||||
DB44767B260B3B8C00B66B82 /* CustomEmojiPickerInputView.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB44767A260B3B8C00B66B82 /* CustomEmojiPickerInputView.swift */; };
|
||||
DB447681260B3ED600B66B82 /* CustomEmojiPickerSection.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB447680260B3ED600B66B82 /* CustomEmojiPickerSection.swift */; };
|
||||
DB44768B260B3F2100B66B82 /* CustomEmojiPickerItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB44768A260B3F2100B66B82 /* CustomEmojiPickerItem.swift */; };
|
||||
|
@ -665,7 +666,6 @@
|
|||
2D34D9DA261494120081BFC0 /* APIService+Search.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "APIService+Search.swift"; sourceTree = "<group>"; };
|
||||
2D34D9E126149C920081BFC0 /* SearchRecommendTagsCollectionViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SearchRecommendTagsCollectionViewCell.swift; sourceTree = "<group>"; };
|
||||
2D35237926256D920031AF25 /* NotificationSection.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NotificationSection.swift; sourceTree = "<group>"; };
|
||||
2D35238026256F690031AF25 /* NotificationTableViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NotificationTableViewCell.swift; sourceTree = "<group>"; };
|
||||
2D364F7125E66D7500204FDC /* MastodonResendEmailViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MastodonResendEmailViewController.swift; sourceTree = "<group>"; };
|
||||
2D364F7725E66D8300204FDC /* MastodonResendEmailViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MastodonResendEmailViewModel.swift; sourceTree = "<group>"; };
|
||||
2D38F1C525CD37F400561493 /* ContentOffsetAdjustableTimelineViewControllerDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContentOffsetAdjustableTimelineViewControllerDelegate.swift; sourceTree = "<group>"; };
|
||||
|
@ -875,6 +875,9 @@
|
|||
DB427DF725BAA00100D1B89D /* MastodonUITests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MastodonUITests.swift; sourceTree = "<group>"; };
|
||||
DB427DF925BAA00100D1B89D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
|
||||
DB44384E25E8C1FA008912A2 /* CALayer.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CALayer.swift; sourceTree = "<group>"; };
|
||||
DB443CCF269415D200159B29 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.stringsdict; name = en; path = en.lproj/Localizable.stringsdict; sourceTree = "<group>"; };
|
||||
DB443CD1269415D800159B29 /* ar */ = {isa = PBXFileReference; lastKnownFileType = text.plist.stringsdict; name = ar; path = ar.lproj/Localizable.stringsdict; sourceTree = "<group>"; };
|
||||
DB443CD32694627B00159B29 /* AppearanceView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppearanceView.swift; sourceTree = "<group>"; };
|
||||
DB44767A260B3B8C00B66B82 /* CustomEmojiPickerInputView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CustomEmojiPickerInputView.swift; sourceTree = "<group>"; };
|
||||
DB447680260B3ED600B66B82 /* CustomEmojiPickerSection.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CustomEmojiPickerSection.swift; sourceTree = "<group>"; };
|
||||
DB44768A260B3F2100B66B82 /* CustomEmojiPickerItem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CustomEmojiPickerItem.swift; sourceTree = "<group>"; };
|
||||
|
@ -1359,7 +1362,6 @@
|
|||
2D35237F26256F470031AF25 /* TableViewCell */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
2D35238026256F690031AF25 /* NotificationTableViewCell.swift */,
|
||||
2D24E11C2626D8B100A59D4F /* NotificationStatusTableViewCell.swift */,
|
||||
);
|
||||
path = TableViewCell;
|
||||
|
@ -1722,6 +1724,7 @@
|
|||
children = (
|
||||
5B90C458262599800002E742 /* Cell */,
|
||||
5B90C45C262599800002E742 /* SettingsSectionHeader.swift */,
|
||||
DB443CD32694627B00159B29 /* AppearanceView.swift */,
|
||||
);
|
||||
path = View;
|
||||
sourceTree = "<group>";
|
||||
|
@ -1831,6 +1834,7 @@
|
|||
164F0EBB267D4FE400249499 /* BoopSound.caf */,
|
||||
DB427DDE25BAA00100D1B89D /* Assets.xcassets */,
|
||||
DB118A8125E4B6E600FAB162 /* Preview Assets.xcassets */,
|
||||
DB443CD0269415D200159B29 /* Localizable.stringsdict */,
|
||||
DB3D100F25BAA75E00EAA174 /* Localizable.strings */,
|
||||
DB2B3ABE25E37E15007045F9 /* InfoPlist.strings */,
|
||||
);
|
||||
|
@ -2933,6 +2937,7 @@
|
|||
files = (
|
||||
164F0EBC267D4FE400249499 /* BoopSound.caf in Resources */,
|
||||
DB427DE225BAA00100D1B89D /* LaunchScreen.storyboard in Resources */,
|
||||
DB443CD22694326A00159B29 /* Localizable.stringsdict in Resources */,
|
||||
DB3D100D25BAA75E00EAA174 /* Localizable.strings in Resources */,
|
||||
DB427DDF25BAA00100D1B89D /* Assets.xcassets in Resources */,
|
||||
DB427DDD25BAA00100D1B89D /* Main.storyboard in Resources */,
|
||||
|
@ -3198,6 +3203,7 @@
|
|||
2D571B2F26004EC000540450 /* NavigationBarProgressView.swift in Sources */,
|
||||
DBD376AA2692EA4F007FEC24 /* Theme.swift in Sources */,
|
||||
0FAA101225E105390017CCDE /* PrimaryActionButton.swift in Sources */,
|
||||
DB443CD42694627B00159B29 /* AppearanceView.swift in Sources */,
|
||||
DB8AF53025C13561002E6C99 /* AppContext.swift in Sources */,
|
||||
DB92CF7225E7BB98002C1017 /* PollOptionTableViewCell.swift in Sources */,
|
||||
DB72602725E36A6F00235243 /* MastodonServerRulesViewModel.swift in Sources */,
|
||||
|
@ -3273,7 +3279,6 @@
|
|||
DBF9814A265E24F500E4BA07 /* ProfileFieldCollectionViewHeaderFooterView.swift in Sources */,
|
||||
2D939AB525EDD8A90076FA61 /* String.swift in Sources */,
|
||||
DB4481B925EE289600BEFB67 /* UITableView.swift in Sources */,
|
||||
2D35238126256F690031AF25 /* NotificationTableViewCell.swift in Sources */,
|
||||
DBE3CDBB261C427900430CC6 /* TimelineHeaderTableViewCell.swift in Sources */,
|
||||
DBCBCBFF2680AE98000F5B51 /* AsyncHomeTimelineViewModel.swift in Sources */,
|
||||
0FAA101C25E10E760017CCDE /* UIFont.swift in Sources */,
|
||||
|
@ -3749,6 +3754,16 @@
|
|||
name = LaunchScreen.storyboard;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
DB443CD0269415D200159B29 /* Localizable.stringsdict */ = {
|
||||
isa = PBXVariantGroup;
|
||||
children = (
|
||||
DB443CCF269415D200159B29 /* en */,
|
||||
DB443CD1269415D800159B29 /* ar */,
|
||||
);
|
||||
name = Localizable.stringsdict;
|
||||
path = /Users/mainasuk/Developer/Mastodon/Mastodon/Resources;
|
||||
sourceTree = "<absolute>";
|
||||
};
|
||||
/* End PBXVariantGroup section */
|
||||
|
||||
/* Begin XCBuildConfiguration section */
|
||||
|
@ -3879,7 +3894,7 @@
|
|||
CLANG_ENABLE_MODULES = YES;
|
||||
CODE_SIGN_ENTITLEMENTS = Mastodon/Mastodon.entitlements;
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
CURRENT_PROJECT_VERSION = 29;
|
||||
CURRENT_PROJECT_VERSION = 30;
|
||||
DEVELOPMENT_ASSET_PATHS = "Mastodon/Resources/Preview\\ Assets.xcassets";
|
||||
DEVELOPMENT_TEAM = 5Z4GVSS33P;
|
||||
INFOPLIST_FILE = Mastodon/Info.plist;
|
||||
|
@ -3887,7 +3902,7 @@
|
|||
"$(inherited)",
|
||||
"@executable_path/Frameworks",
|
||||
);
|
||||
MARKETING_VERSION = 0.8.4;
|
||||
MARKETING_VERSION = 0.8.5;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = org.joinmastodon.app;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
PROVISIONING_PROFILE_SPECIFIER = "";
|
||||
|
@ -3906,7 +3921,7 @@
|
|||
CLANG_ENABLE_MODULES = YES;
|
||||
CODE_SIGN_ENTITLEMENTS = Mastodon/Mastodon.entitlements;
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
CURRENT_PROJECT_VERSION = 29;
|
||||
CURRENT_PROJECT_VERSION = 30;
|
||||
DEVELOPMENT_ASSET_PATHS = "Mastodon/Resources/Preview\\ Assets.xcassets";
|
||||
DEVELOPMENT_TEAM = 5Z4GVSS33P;
|
||||
INFOPLIST_FILE = Mastodon/Info.plist;
|
||||
|
@ -3914,7 +3929,7 @@
|
|||
"$(inherited)",
|
||||
"@executable_path/Frameworks",
|
||||
);
|
||||
MARKETING_VERSION = 0.8.4;
|
||||
MARKETING_VERSION = 0.8.5;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = org.joinmastodon.app;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
PROVISIONING_PROFILE_SPECIFIER = "";
|
||||
|
@ -4234,7 +4249,7 @@
|
|||
CLANG_ENABLE_MODULES = YES;
|
||||
CODE_SIGN_ENTITLEMENTS = Mastodon/Mastodon.entitlements;
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
CURRENT_PROJECT_VERSION = 29;
|
||||
CURRENT_PROJECT_VERSION = 30;
|
||||
DEVELOPMENT_ASSET_PATHS = "Mastodon/Resources/Preview\\ Assets.xcassets";
|
||||
DEVELOPMENT_TEAM = 5Z4GVSS33P;
|
||||
INFOPLIST_FILE = Mastodon/Info.plist;
|
||||
|
@ -4242,7 +4257,7 @@
|
|||
"$(inherited)",
|
||||
"@executable_path/Frameworks",
|
||||
);
|
||||
MARKETING_VERSION = 0.8.4;
|
||||
MARKETING_VERSION = 0.8.5;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = org.joinmastodon.app;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
PROVISIONING_PROFILE_SPECIFIER = "";
|
||||
|
@ -4348,7 +4363,7 @@
|
|||
buildSettings = {
|
||||
CODE_SIGN_ENTITLEMENTS = NotificationService/NotificationService.entitlements;
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
CURRENT_PROJECT_VERSION = 29;
|
||||
CURRENT_PROJECT_VERSION = 30;
|
||||
DEVELOPMENT_TEAM = 5Z4GVSS33P;
|
||||
INFOPLIST_FILE = NotificationService/Info.plist;
|
||||
LD_RUNPATH_SEARCH_PATHS = (
|
||||
|
@ -4356,7 +4371,7 @@
|
|||
"@executable_path/Frameworks",
|
||||
"@executable_path/../../Frameworks",
|
||||
);
|
||||
MARKETING_VERSION = 0.8.4;
|
||||
MARKETING_VERSION = 0.8.5;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = org.joinmastodon.app.NotificationService;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SKIP_INSTALL = YES;
|
||||
|
@ -4467,7 +4482,7 @@
|
|||
CLANG_ENABLE_MODULES = YES;
|
||||
CODE_SIGN_ENTITLEMENTS = Mastodon/Mastodon.entitlements;
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
CURRENT_PROJECT_VERSION = 29;
|
||||
CURRENT_PROJECT_VERSION = 30;
|
||||
DEVELOPMENT_ASSET_PATHS = "Mastodon/Resources/Preview\\ Assets.xcassets";
|
||||
DEVELOPMENT_TEAM = 5Z4GVSS33P;
|
||||
INFOPLIST_FILE = Mastodon/Info.plist;
|
||||
|
@ -4475,7 +4490,7 @@
|
|||
"$(inherited)",
|
||||
"@executable_path/Frameworks",
|
||||
);
|
||||
MARKETING_VERSION = 0.8.4;
|
||||
MARKETING_VERSION = 0.8.5;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = org.joinmastodon.app;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
PROVISIONING_PROFILE_SPECIFIER = "";
|
||||
|
@ -4581,7 +4596,7 @@
|
|||
buildSettings = {
|
||||
CODE_SIGN_ENTITLEMENTS = NotificationService/NotificationService.entitlements;
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
CURRENT_PROJECT_VERSION = 29;
|
||||
CURRENT_PROJECT_VERSION = 30;
|
||||
DEVELOPMENT_TEAM = 5Z4GVSS33P;
|
||||
INFOPLIST_FILE = NotificationService/Info.plist;
|
||||
LD_RUNPATH_SEARCH_PATHS = (
|
||||
|
@ -4589,7 +4604,7 @@
|
|||
"@executable_path/Frameworks",
|
||||
"@executable_path/../../Frameworks",
|
||||
);
|
||||
MARKETING_VERSION = 0.8.4;
|
||||
MARKETING_VERSION = 0.8.5;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = org.joinmastodon.app.NotificationService;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SKIP_INSTALL = YES;
|
||||
|
@ -4635,7 +4650,7 @@
|
|||
buildSettings = {
|
||||
CODE_SIGN_ENTITLEMENTS = NotificationService/NotificationService.entitlements;
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
CURRENT_PROJECT_VERSION = 29;
|
||||
CURRENT_PROJECT_VERSION = 30;
|
||||
DEVELOPMENT_TEAM = 5Z4GVSS33P;
|
||||
INFOPLIST_FILE = NotificationService/Info.plist;
|
||||
LD_RUNPATH_SEARCH_PATHS = (
|
||||
|
@ -4643,7 +4658,7 @@
|
|||
"@executable_path/Frameworks",
|
||||
"@executable_path/../../Frameworks",
|
||||
);
|
||||
MARKETING_VERSION = 0.8.4;
|
||||
MARKETING_VERSION = 0.8.5;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = org.joinmastodon.app.NotificationService;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SKIP_INSTALL = YES;
|
||||
|
@ -4658,7 +4673,7 @@
|
|||
buildSettings = {
|
||||
CODE_SIGN_ENTITLEMENTS = NotificationService/NotificationService.entitlements;
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
CURRENT_PROJECT_VERSION = 29;
|
||||
CURRENT_PROJECT_VERSION = 30;
|
||||
DEVELOPMENT_TEAM = 5Z4GVSS33P;
|
||||
INFOPLIST_FILE = NotificationService/Info.plist;
|
||||
LD_RUNPATH_SEARCH_PATHS = (
|
||||
|
@ -4666,7 +4681,7 @@
|
|||
"@executable_path/Frameworks",
|
||||
"@executable_path/../../Frameworks",
|
||||
);
|
||||
MARKETING_VERSION = 0.8.4;
|
||||
MARKETING_VERSION = 0.8.5;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = org.joinmastodon.app.NotificationService;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SKIP_INSTALL = YES;
|
||||
|
@ -4814,7 +4829,7 @@
|
|||
repositoryURL = "https://github.com/TwidereProject/MetaTextView.git";
|
||||
requirement = {
|
||||
kind = exactVersion;
|
||||
version = 1.2.4;
|
||||
version = 1.2.5;
|
||||
};
|
||||
};
|
||||
DB0E2D2C26833FF600865C3C /* XCRemoteSwiftPackageReference "Nuke-FLAnimatedImage-Plugin" */ = {
|
||||
|
|
|
@ -12,7 +12,7 @@
|
|||
<key>CoreDataStack.xcscheme_^#shared#^_</key>
|
||||
<dict>
|
||||
<key>orderHint</key>
|
||||
<integer>21</integer>
|
||||
<integer>20</integer>
|
||||
</dict>
|
||||
<key>Mastodon - ASDK.xcscheme_^#shared#^_</key>
|
||||
<dict>
|
||||
|
@ -37,7 +37,7 @@
|
|||
<key>NotificationService.xcscheme_^#shared#^_</key>
|
||||
<dict>
|
||||
<key>orderHint</key>
|
||||
<integer>20</integer>
|
||||
<integer>21</integer>
|
||||
</dict>
|
||||
</dict>
|
||||
<key>SuppressBuildableAutocreation</key>
|
||||
|
|
|
@ -114,8 +114,8 @@
|
|||
"repositoryURL": "https://github.com/TwidereProject/MetaTextView.git",
|
||||
"state": {
|
||||
"branch": null,
|
||||
"revision": "28e53130d16f12e0eeb479d83b77a0a718ef2088",
|
||||
"version": "1.2.4"
|
||||
"revision": "9ba4027ed0a88185ce95bb1773620c2ceaa9f3bb",
|
||||
"version": "1.2.5"
|
||||
}
|
||||
},
|
||||
{
|
||||
|
|
|
@ -55,11 +55,7 @@ extension AutoCompleteSection {
|
|||
.prefix(2)
|
||||
.compactMap { Int($0.accounts) }
|
||||
.reduce(0, +)
|
||||
if count > 1 {
|
||||
return L10n.Scene.Compose.AutoComplete.multiplePeopleTalking(count)
|
||||
} else {
|
||||
return L10n.Scene.Compose.AutoComplete.singlePeopleTalking(count)
|
||||
}
|
||||
return L10n.Plural.peopleTalking(count)
|
||||
}()
|
||||
cell.avatarImageView.isHidden = true
|
||||
}
|
||||
|
|
|
@ -46,10 +46,6 @@ extension NotificationSection {
|
|||
),
|
||||
into: cell.avatarImageView
|
||||
)
|
||||
cell.avatarImageView.gesture().sink { [weak cell] _ in
|
||||
cell?.delegate?.userAvatarDidPressed(notification: notification)
|
||||
}
|
||||
.store(in: &cell.disposeBag)
|
||||
cell.actionImageView.image = UIImage(
|
||||
systemName: notification.notificationType.actionImageName,
|
||||
withConfiguration: UIImage.SymbolConfiguration(
|
||||
|
|
|
@ -479,21 +479,13 @@ extension StatusSection {
|
|||
cell.threadMetaView.dateLabel.accessibilityLabel = DateFormatter.localizedString(from: status.createdAt, dateStyle: .medium, timeStyle: .short)
|
||||
let reblogCountTitle: String = {
|
||||
let count = status.reblogsCount.intValue
|
||||
if count > 1 {
|
||||
return L10n.Scene.Thread.Reblog.multiple(String(count))
|
||||
} else {
|
||||
return L10n.Scene.Thread.Reblog.single(String(count))
|
||||
}
|
||||
return L10n.Plural.Count.reblog(count)
|
||||
}()
|
||||
cell.threadMetaView.reblogButton.setTitle(reblogCountTitle, for: .normal)
|
||||
|
||||
let favoriteCountTitle: String = {
|
||||
let count = status.favouritesCount.intValue
|
||||
if count > 1 {
|
||||
return L10n.Scene.Thread.Favorite.multiple(String(count))
|
||||
} else {
|
||||
return L10n.Scene.Thread.Favorite.single(String(count))
|
||||
}
|
||||
return L10n.Plural.Count.favorite(count)
|
||||
}()
|
||||
cell.threadMetaView.favoriteButton.setTitle(favoriteCountTitle, for: .normal)
|
||||
|
||||
|
@ -832,18 +824,10 @@ extension StatusSection {
|
|||
cell.statusView.pollVoteCountLabel.text = {
|
||||
if poll.multiple {
|
||||
let count = poll.votersCount?.intValue ?? 0
|
||||
if count > 1 {
|
||||
return L10n.Common.Controls.Status.Poll.VoterCount.single(count)
|
||||
} else {
|
||||
return L10n.Common.Controls.Status.Poll.VoterCount.multiple(count)
|
||||
}
|
||||
return L10n.Plural.Count.voter(count)
|
||||
} else {
|
||||
let count = poll.votesCount.intValue
|
||||
if count > 1 {
|
||||
return L10n.Common.Controls.Status.Poll.VoteCount.single(count)
|
||||
} else {
|
||||
return L10n.Common.Controls.Status.Poll.VoteCount.multiple(count)
|
||||
}
|
||||
return L10n.Plural.Count.vote(count)
|
||||
}
|
||||
}()
|
||||
if poll.expired {
|
||||
|
|
|
@ -299,26 +299,6 @@ internal enum L10n {
|
|||
}
|
||||
/// Vote
|
||||
internal static let vote = L10n.tr("Localizable", "Common.Controls.Status.Poll.Vote")
|
||||
internal enum VoteCount {
|
||||
/// %d votes
|
||||
internal static func multiple(_ p1: Int) -> String {
|
||||
return L10n.tr("Localizable", "Common.Controls.Status.Poll.VoteCount.Multiple", p1)
|
||||
}
|
||||
/// %d vote
|
||||
internal static func single(_ p1: Int) -> String {
|
||||
return L10n.tr("Localizable", "Common.Controls.Status.Poll.VoteCount.Single", p1)
|
||||
}
|
||||
}
|
||||
internal enum VoterCount {
|
||||
/// %d voters
|
||||
internal static func multiple(_ p1: Int) -> String {
|
||||
return L10n.tr("Localizable", "Common.Controls.Status.Poll.VoterCount.Multiple", p1)
|
||||
}
|
||||
/// %d voter
|
||||
internal static func single(_ p1: Int) -> String {
|
||||
return L10n.tr("Localizable", "Common.Controls.Status.Poll.VoterCount.Single", p1)
|
||||
}
|
||||
}
|
||||
}
|
||||
internal enum Tag {
|
||||
/// Email
|
||||
|
@ -400,14 +380,6 @@ internal enum L10n {
|
|||
}
|
||||
}
|
||||
}
|
||||
internal enum Countable {
|
||||
internal enum Photo {
|
||||
/// photos
|
||||
internal static let multiple = L10n.tr("Localizable", "Common.Countable.Photo.Multiple")
|
||||
/// photo
|
||||
internal static let single = L10n.tr("Localizable", "Common.Countable.Photo.Single")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal enum Scene {
|
||||
|
@ -459,14 +431,6 @@ internal enum L10n {
|
|||
internal static let video = L10n.tr("Localizable", "Scene.Compose.Attachment.Video")
|
||||
}
|
||||
internal enum AutoComplete {
|
||||
/// %ld people talking
|
||||
internal static func multiplePeopleTalking(_ p1: Int) -> String {
|
||||
return L10n.tr("Localizable", "Scene.Compose.AutoComplete.MultiplePeopleTalking", p1)
|
||||
}
|
||||
/// %ld people talking
|
||||
internal static func singlePeopleTalking(_ p1: Int) -> String {
|
||||
return L10n.tr("Localizable", "Scene.Compose.AutoComplete.SinglePeopleTalking", p1)
|
||||
}
|
||||
/// Space to add
|
||||
internal static let spaceToAdd = L10n.tr("Localizable", "Scene.Compose.AutoComplete.SpaceToAdd")
|
||||
}
|
||||
|
@ -634,10 +598,6 @@ internal enum L10n {
|
|||
}
|
||||
}
|
||||
internal enum Profile {
|
||||
/// %@ posts
|
||||
internal static func subtitle(_ p1: Any) -> String {
|
||||
return L10n.tr("Localizable", "Scene.Profile.Subtitle", String(describing: p1))
|
||||
}
|
||||
internal enum Dashboard {
|
||||
/// followers
|
||||
internal static let followers = L10n.tr("Localizable", "Scene.Profile.Dashboard.Followers")
|
||||
|
@ -950,6 +910,12 @@ internal enum L10n {
|
|||
internal enum Settings {
|
||||
/// Settings
|
||||
internal static let title = L10n.tr("Localizable", "Scene.Settings.Title")
|
||||
internal enum Footer {
|
||||
/// Mastodon is open source software. You can contribute or report issues on GitHub at %@ (%@)
|
||||
internal static func mastodonDescription(_ p1: Any, _ p2: Any) -> String {
|
||||
return L10n.tr("Localizable", "Scene.Settings.Footer.MastodonDescription", String(describing: p1), String(describing: p2))
|
||||
}
|
||||
}
|
||||
internal enum Keyboard {
|
||||
/// Close Settings Window
|
||||
internal static let closeSettingsWindow = L10n.tr("Localizable", "Scene.Settings.Keyboard.CloseSettingsWindow")
|
||||
|
@ -1026,32 +992,43 @@ internal enum L10n {
|
|||
internal static func title(_ p1: Any) -> String {
|
||||
return L10n.tr("Localizable", "Scene.Thread.Title", String(describing: p1))
|
||||
}
|
||||
internal enum Favorite {
|
||||
/// %@ favorites
|
||||
internal static func multiple(_ p1: Any) -> String {
|
||||
return L10n.tr("Localizable", "Scene.Thread.Favorite.Multiple", String(describing: p1))
|
||||
}
|
||||
/// %@ favorite
|
||||
internal static func single(_ p1: Any) -> String {
|
||||
return L10n.tr("Localizable", "Scene.Thread.Favorite.Single", String(describing: p1))
|
||||
}
|
||||
}
|
||||
internal enum Reblog {
|
||||
/// %@ reblogs
|
||||
internal static func multiple(_ p1: Any) -> String {
|
||||
return L10n.tr("Localizable", "Scene.Thread.Reblog.Multiple", String(describing: p1))
|
||||
}
|
||||
/// %@ reblog
|
||||
internal static func single(_ p1: Any) -> String {
|
||||
return L10n.tr("Localizable", "Scene.Thread.Reblog.Single", String(describing: p1))
|
||||
}
|
||||
}
|
||||
}
|
||||
internal enum Welcome {
|
||||
/// Social networking\nback in your hands.
|
||||
internal static let slogan = L10n.tr("Localizable", "Scene.Welcome.Slogan")
|
||||
}
|
||||
}
|
||||
|
||||
internal enum Plural {
|
||||
/// Plural format key: "%#@count_people_talking@"
|
||||
internal static func peopleTalking(_ p1: Int) -> String {
|
||||
return L10n.tr("Localizable", "plural.people_talking", p1)
|
||||
}
|
||||
internal enum Count {
|
||||
/// Plural format key: "%#@favorite_count@"
|
||||
internal static func favorite(_ p1: Int) -> String {
|
||||
return L10n.tr("Localizable", "plural.count.favorite", p1)
|
||||
}
|
||||
/// Plural format key: "%#@reblog_count@"
|
||||
internal static func reblog(_ p1: Int) -> String {
|
||||
return L10n.tr("Localizable", "plural.count.reblog", p1)
|
||||
}
|
||||
/// Plural format key: "%#@vote_count@"
|
||||
internal static func vote(_ p1: Int) -> String {
|
||||
return L10n.tr("Localizable", "plural.count.vote", p1)
|
||||
}
|
||||
/// Plural format key: "%#@voter_count@"
|
||||
internal static func voter(_ p1: Int) -> String {
|
||||
return L10n.tr("Localizable", "plural.count.voter", p1)
|
||||
}
|
||||
internal enum MetricFormatted {
|
||||
/// Plural format key: "%@ %#@post_count@"
|
||||
internal static func post(_ p1: Any, _ p2: Int) -> String {
|
||||
return L10n.tr("Localizable", "plural.count.metric_formatted.post", String(describing: p1), p2)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// swiftlint:enable explicit_type_interface function_parameter_count identifier_name line_length
|
||||
// swiftlint:enable nesting type_body_length type_name vertical_whitespace_opening_braces
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
{
|
||||
"images" : [
|
||||
{
|
||||
"filename" : "mastodon.with.mail.svg",
|
||||
"filename" : "c1 1.svg",
|
||||
"idiom" : "universal"
|
||||
}
|
||||
],
|
||||
|
|
Before Width: | Height: | Size: 40 KiB After Width: | Height: | Size: 40 KiB |
|
@ -101,10 +101,6 @@ Please check your internet connection.";
|
|||
"Common.Controls.Status.Poll.Closed" = "Closed";
|
||||
"Common.Controls.Status.Poll.TimeLeft" = "%@ left";
|
||||
"Common.Controls.Status.Poll.Vote" = "Vote";
|
||||
"Common.Controls.Status.Poll.VoteCount.Multiple" = "%d votes";
|
||||
"Common.Controls.Status.Poll.VoteCount.Single" = "%d vote";
|
||||
"Common.Controls.Status.Poll.VoterCount.Multiple" = "%d voters";
|
||||
"Common.Controls.Status.Poll.VoterCount.Single" = "%d voter";
|
||||
"Common.Controls.Status.ShowPost" = "Show Post";
|
||||
"Common.Controls.Status.ShowUserProfile" = "Show user profile";
|
||||
"Common.Controls.Status.Tag.Email" = "Email";
|
||||
|
@ -140,8 +136,6 @@ Your account looks like this to them.";
|
|||
"Common.Controls.Timeline.Loader.ShowMoreReplies" = "Show more replies";
|
||||
"Common.Controls.Timeline.Timestamp.Now" = "Now";
|
||||
"Common.Controls.Timeline.Timestamp.TimeAgo" = "%@ ago";
|
||||
"Common.Countable.Photo.Multiple" = "photos";
|
||||
"Common.Countable.Photo.Single" = "photo";
|
||||
"Scene.Compose.Accessibility.AppendAttachment" = "Append attachment";
|
||||
"Scene.Compose.Accessibility.AppendPoll" = "Append poll";
|
||||
"Scene.Compose.Accessibility.CustomEmojiPicker" = "Custom emoji picker";
|
||||
|
@ -157,8 +151,6 @@ uploaded to Mastodon.";
|
|||
"Scene.Compose.Attachment.DescriptionVideo" = "Describe what’s happening for low vision people...";
|
||||
"Scene.Compose.Attachment.Photo" = "photo";
|
||||
"Scene.Compose.Attachment.Video" = "video";
|
||||
"Scene.Compose.AutoComplete.MultiplePeopleTalking" = "%ld people talking";
|
||||
"Scene.Compose.AutoComplete.SinglePeopleTalking" = "%ld people talking";
|
||||
"Scene.Compose.AutoComplete.SpaceToAdd" = "Space to add";
|
||||
"Scene.Compose.ComposeAction" = "Publish";
|
||||
"Scene.Compose.ContentInputPlaceholder" = "Type or paste what’s on your mind";
|
||||
|
@ -235,7 +227,6 @@ tap the link to confirm your account.";
|
|||
"Scene.Profile.SegmentedControl.Media" = "Media";
|
||||
"Scene.Profile.SegmentedControl.Posts" = "Posts";
|
||||
"Scene.Profile.SegmentedControl.Replies" = "Replies";
|
||||
"Scene.Profile.Subtitle" = "%@ posts";
|
||||
"Scene.PublicTimeline.Title" = "Public";
|
||||
"Scene.Register.Error.Item.Agreement" = "Agreement";
|
||||
"Scene.Register.Error.Item.Email" = "Email";
|
||||
|
@ -319,6 +310,7 @@ any server.";
|
|||
"Scene.ServerRules.Subtitle" = "These rules are set by the admins of %@.";
|
||||
"Scene.ServerRules.TermsOfService" = "terms of service";
|
||||
"Scene.ServerRules.Title" = "Some ground rules.";
|
||||
"Scene.Settings.Footer.MastodonDescription" = "Mastodon is open source software. You can contribute or report issues on GitHub at %@ (%@)";
|
||||
"Scene.Settings.Keyboard.CloseSettingsWindow" = "Close Settings Window";
|
||||
"Scene.Settings.Section.Appearance.Automatic" = "Automatic";
|
||||
"Scene.Settings.Section.Appearance.Dark" = "Always Dark";
|
||||
|
@ -345,10 +337,6 @@ any server.";
|
|||
"Scene.SuggestionAccount.FollowExplain" = "When you follow someone, you’ll see their posts in your home feed.";
|
||||
"Scene.SuggestionAccount.Title" = "Find People to Follow";
|
||||
"Scene.Thread.BackTitle" = "Post";
|
||||
"Scene.Thread.Favorite.Multiple" = "%@ favorites";
|
||||
"Scene.Thread.Favorite.Single" = "%@ favorite";
|
||||
"Scene.Thread.Reblog.Multiple" = "%@ reblogs";
|
||||
"Scene.Thread.Reblog.Single" = "%@ reblog";
|
||||
"Scene.Thread.Title" = "Post from %@";
|
||||
"Scene.Welcome.Slogan" = "Social networking
|
||||
back in your hands.";
|
|
@ -0,0 +1,138 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>plural.count.metric_formatted.post</key>
|
||||
<dict>
|
||||
<key>NSStringLocalizedFormatKey</key>
|
||||
<string>%@ %#@post_count@</string>
|
||||
<key>post_count</key>
|
||||
<dict>
|
||||
<key>NSStringFormatSpecTypeKey</key>
|
||||
<string>NSStringPluralRuleType</string>
|
||||
<key>NSStringFormatValueTypeKey</key>
|
||||
<string>ld</string>
|
||||
<key>zero</key>
|
||||
<string>posts</string>
|
||||
<key>one</key>
|
||||
<string>post</string>
|
||||
<key>few</key>
|
||||
<string>posts</string>
|
||||
<key>many</key>
|
||||
<string>posts</string>
|
||||
<key>other</key>
|
||||
<string>posts</string>
|
||||
</dict>
|
||||
</dict>
|
||||
<key>plural.count.favorite</key>
|
||||
<dict>
|
||||
<key>NSStringLocalizedFormatKey</key>
|
||||
<string>%#@favorite_count@</string>
|
||||
<key>favorite_count</key>
|
||||
<dict>
|
||||
<key>NSStringFormatSpecTypeKey</key>
|
||||
<string>NSStringPluralRuleType</string>
|
||||
<key>NSStringFormatValueTypeKey</key>
|
||||
<string>ld</string>
|
||||
<key>zero</key>
|
||||
<string>0 favorites</string>
|
||||
<key>one</key>
|
||||
<string>1 favorite</string>
|
||||
<key>few</key>
|
||||
<string>%ld favorites</string>
|
||||
<key>many</key>
|
||||
<string>%ld favorites</string>
|
||||
<key>other</key>
|
||||
<string>%ld favorites</string>
|
||||
</dict>
|
||||
</dict>
|
||||
<key>plural.count.reblog</key>
|
||||
<dict>
|
||||
<key>NSStringLocalizedFormatKey</key>
|
||||
<string>%#@reblog_count@</string>
|
||||
<key>reblog_count</key>
|
||||
<dict>
|
||||
<key>NSStringFormatSpecTypeKey</key>
|
||||
<string>NSStringPluralRuleType</string>
|
||||
<key>NSStringFormatValueTypeKey</key>
|
||||
<string>ld</string>
|
||||
<key>zero</key>
|
||||
<string>0 reblogs</string>
|
||||
<key>one</key>
|
||||
<string>1 reblog</string>
|
||||
<key>few</key>
|
||||
<string>%ld reblogs</string>
|
||||
<key>many</key>
|
||||
<string>%ld reblogs</string>
|
||||
<key>other</key>
|
||||
<string>%ld reblogs</string>
|
||||
</dict>
|
||||
</dict>
|
||||
<key>plural.count.vote</key>
|
||||
<dict>
|
||||
<key>NSStringLocalizedFormatKey</key>
|
||||
<string>%#@vote_count@</string>
|
||||
<key>vote_count</key>
|
||||
<dict>
|
||||
<key>NSStringFormatSpecTypeKey</key>
|
||||
<string>NSStringPluralRuleType</string>
|
||||
<key>NSStringFormatValueTypeKey</key>
|
||||
<string>ld</string>
|
||||
<key>zero</key>
|
||||
<string>0 votes</string>
|
||||
<key>one</key>
|
||||
<string>1 vote</string>
|
||||
<key>few</key>
|
||||
<string>%ld votes</string>
|
||||
<key>many</key>
|
||||
<string>%ld votes</string>
|
||||
<key>other</key>
|
||||
<string>%ld votes</string>
|
||||
</dict>
|
||||
</dict>
|
||||
<key>plural.count.voter</key>
|
||||
<dict>
|
||||
<key>NSStringLocalizedFormatKey</key>
|
||||
<string>%#@voter_count@</string>
|
||||
<key>voter_count</key>
|
||||
<dict>
|
||||
<key>NSStringFormatSpecTypeKey</key>
|
||||
<string>NSStringPluralRuleType</string>
|
||||
<key>NSStringFormatValueTypeKey</key>
|
||||
<string>ld</string>
|
||||
<key>zero</key>
|
||||
<string>0 voters</string>
|
||||
<key>one</key>
|
||||
<string>1 voter</string>
|
||||
<key>few</key>
|
||||
<string>%ld voters</string>
|
||||
<key>many</key>
|
||||
<string>%ld voters</string>
|
||||
<key>other</key>
|
||||
<string>%ld voters</string>
|
||||
</dict>
|
||||
</dict>
|
||||
<key>plural.people_talking</key>
|
||||
<dict>
|
||||
<key>NSStringLocalizedFormatKey</key>
|
||||
<string>%#@count_people_talking@</string>
|
||||
<key>count_people_talking</key>
|
||||
<dict>
|
||||
<key>NSStringFormatSpecTypeKey</key>
|
||||
<string>NSStringPluralRuleType</string>
|
||||
<key>NSStringFormatValueTypeKey</key>
|
||||
<string>ld</string>
|
||||
<key>zero</key>
|
||||
<string>0 people talking</string>
|
||||
<key>one</key>
|
||||
<string>1 people talking</string>
|
||||
<key>few</key>
|
||||
<string>%ld people talking</string>
|
||||
<key>many</key>
|
||||
<string>%ld people talking</string>
|
||||
<key>other</key>
|
||||
<string>%ld people talking</string>
|
||||
</dict>
|
||||
</dict>
|
||||
</dict>
|
||||
</plist>
|
|
@ -101,10 +101,6 @@ Please check your internet connection.";
|
|||
"Common.Controls.Status.Poll.Closed" = "Closed";
|
||||
"Common.Controls.Status.Poll.TimeLeft" = "%@ left";
|
||||
"Common.Controls.Status.Poll.Vote" = "Vote";
|
||||
"Common.Controls.Status.Poll.VoteCount.Multiple" = "%d votes";
|
||||
"Common.Controls.Status.Poll.VoteCount.Single" = "%d vote";
|
||||
"Common.Controls.Status.Poll.VoterCount.Multiple" = "%d voters";
|
||||
"Common.Controls.Status.Poll.VoterCount.Single" = "%d voter";
|
||||
"Common.Controls.Status.ShowPost" = "Show Post";
|
||||
"Common.Controls.Status.ShowUserProfile" = "Show user profile";
|
||||
"Common.Controls.Status.Tag.Email" = "Email";
|
||||
|
@ -140,8 +136,6 @@ Your account looks like this to them.";
|
|||
"Common.Controls.Timeline.Loader.ShowMoreReplies" = "Show more replies";
|
||||
"Common.Controls.Timeline.Timestamp.Now" = "Now";
|
||||
"Common.Controls.Timeline.Timestamp.TimeAgo" = "%@ ago";
|
||||
"Common.Countable.Photo.Multiple" = "photos";
|
||||
"Common.Countable.Photo.Single" = "photo";
|
||||
"Scene.Compose.Accessibility.AppendAttachment" = "Append attachment";
|
||||
"Scene.Compose.Accessibility.AppendPoll" = "Append poll";
|
||||
"Scene.Compose.Accessibility.CustomEmojiPicker" = "Custom emoji picker";
|
||||
|
@ -157,8 +151,6 @@ uploaded to Mastodon.";
|
|||
"Scene.Compose.Attachment.DescriptionVideo" = "Describe what’s happening for low vision people...";
|
||||
"Scene.Compose.Attachment.Photo" = "photo";
|
||||
"Scene.Compose.Attachment.Video" = "video";
|
||||
"Scene.Compose.AutoComplete.MultiplePeopleTalking" = "%ld people talking";
|
||||
"Scene.Compose.AutoComplete.SinglePeopleTalking" = "%ld people talking";
|
||||
"Scene.Compose.AutoComplete.SpaceToAdd" = "Space to add";
|
||||
"Scene.Compose.ComposeAction" = "Publish";
|
||||
"Scene.Compose.ContentInputPlaceholder" = "Type or paste what’s on your mind";
|
||||
|
@ -235,7 +227,6 @@ tap the link to confirm your account.";
|
|||
"Scene.Profile.SegmentedControl.Media" = "Media";
|
||||
"Scene.Profile.SegmentedControl.Posts" = "Posts";
|
||||
"Scene.Profile.SegmentedControl.Replies" = "Replies";
|
||||
"Scene.Profile.Subtitle" = "%@ posts";
|
||||
"Scene.PublicTimeline.Title" = "Public";
|
||||
"Scene.Register.Error.Item.Agreement" = "Agreement";
|
||||
"Scene.Register.Error.Item.Email" = "Email";
|
||||
|
@ -319,6 +310,7 @@ any server.";
|
|||
"Scene.ServerRules.Subtitle" = "These rules are set by the admins of %@.";
|
||||
"Scene.ServerRules.TermsOfService" = "terms of service";
|
||||
"Scene.ServerRules.Title" = "Some ground rules.";
|
||||
"Scene.Settings.Footer.MastodonDescription" = "Mastodon is open source software. You can contribute or report issues on GitHub at %@ (%@)";
|
||||
"Scene.Settings.Keyboard.CloseSettingsWindow" = "Close Settings Window";
|
||||
"Scene.Settings.Section.Appearance.Automatic" = "Automatic";
|
||||
"Scene.Settings.Section.Appearance.Dark" = "Always Dark";
|
||||
|
@ -345,10 +337,6 @@ any server.";
|
|||
"Scene.SuggestionAccount.FollowExplain" = "When you follow someone, you’ll see their posts in your home feed.";
|
||||
"Scene.SuggestionAccount.Title" = "Find People to Follow";
|
||||
"Scene.Thread.BackTitle" = "Post";
|
||||
"Scene.Thread.Favorite.Multiple" = "%@ favorites";
|
||||
"Scene.Thread.Favorite.Single" = "%@ favorite";
|
||||
"Scene.Thread.Reblog.Multiple" = "%@ reblogs";
|
||||
"Scene.Thread.Reblog.Single" = "%@ reblog";
|
||||
"Scene.Thread.Title" = "Post from %@";
|
||||
"Scene.Welcome.Slogan" = "Social networking
|
||||
back in your hands.";
|
|
@ -0,0 +1,138 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>plural.count.metric_formatted.post</key>
|
||||
<dict>
|
||||
<key>NSStringLocalizedFormatKey</key>
|
||||
<string>%@ %#@post_count@</string>
|
||||
<key>post_count</key>
|
||||
<dict>
|
||||
<key>NSStringFormatSpecTypeKey</key>
|
||||
<string>NSStringPluralRuleType</string>
|
||||
<key>NSStringFormatValueTypeKey</key>
|
||||
<string>ld</string>
|
||||
<key>zero</key>
|
||||
<string>posts</string>
|
||||
<key>one</key>
|
||||
<string>post</string>
|
||||
<key>few</key>
|
||||
<string>posts</string>
|
||||
<key>many</key>
|
||||
<string>posts</string>
|
||||
<key>other</key>
|
||||
<string>posts</string>
|
||||
</dict>
|
||||
</dict>
|
||||
<key>plural.count.favorite</key>
|
||||
<dict>
|
||||
<key>NSStringLocalizedFormatKey</key>
|
||||
<string>%#@favorite_count@</string>
|
||||
<key>favorite_count</key>
|
||||
<dict>
|
||||
<key>NSStringFormatSpecTypeKey</key>
|
||||
<string>NSStringPluralRuleType</string>
|
||||
<key>NSStringFormatValueTypeKey</key>
|
||||
<string>ld</string>
|
||||
<key>zero</key>
|
||||
<string>0 favorites</string>
|
||||
<key>one</key>
|
||||
<string>1 favorite</string>
|
||||
<key>few</key>
|
||||
<string>%ld favorites</string>
|
||||
<key>many</key>
|
||||
<string>%ld favorites</string>
|
||||
<key>other</key>
|
||||
<string>%ld favorites</string>
|
||||
</dict>
|
||||
</dict>
|
||||
<key>plural.count.reblog</key>
|
||||
<dict>
|
||||
<key>NSStringLocalizedFormatKey</key>
|
||||
<string>%#@reblog_count@</string>
|
||||
<key>reblog_count</key>
|
||||
<dict>
|
||||
<key>NSStringFormatSpecTypeKey</key>
|
||||
<string>NSStringPluralRuleType</string>
|
||||
<key>NSStringFormatValueTypeKey</key>
|
||||
<string>ld</string>
|
||||
<key>zero</key>
|
||||
<string>0 reblogs</string>
|
||||
<key>one</key>
|
||||
<string>1 reblog</string>
|
||||
<key>few</key>
|
||||
<string>%ld reblogs</string>
|
||||
<key>many</key>
|
||||
<string>%ld reblogs</string>
|
||||
<key>other</key>
|
||||
<string>%ld reblogs</string>
|
||||
</dict>
|
||||
</dict>
|
||||
<key>plural.count.vote</key>
|
||||
<dict>
|
||||
<key>NSStringLocalizedFormatKey</key>
|
||||
<string>%#@vote_count@</string>
|
||||
<key>vote_count</key>
|
||||
<dict>
|
||||
<key>NSStringFormatSpecTypeKey</key>
|
||||
<string>NSStringPluralRuleType</string>
|
||||
<key>NSStringFormatValueTypeKey</key>
|
||||
<string>ld</string>
|
||||
<key>zero</key>
|
||||
<string>0 votes</string>
|
||||
<key>one</key>
|
||||
<string>1 vote</string>
|
||||
<key>few</key>
|
||||
<string>%ld votes</string>
|
||||
<key>many</key>
|
||||
<string>%ld votes</string>
|
||||
<key>other</key>
|
||||
<string>%ld votes</string>
|
||||
</dict>
|
||||
</dict>
|
||||
<key>plural.count.voter</key>
|
||||
<dict>
|
||||
<key>NSStringLocalizedFormatKey</key>
|
||||
<string>%#@voter_count@</string>
|
||||
<key>voter_count</key>
|
||||
<dict>
|
||||
<key>NSStringFormatSpecTypeKey</key>
|
||||
<string>NSStringPluralRuleType</string>
|
||||
<key>NSStringFormatValueTypeKey</key>
|
||||
<string>ld</string>
|
||||
<key>zero</key>
|
||||
<string>0 voters</string>
|
||||
<key>one</key>
|
||||
<string>1 voter</string>
|
||||
<key>few</key>
|
||||
<string>%ld voters</string>
|
||||
<key>many</key>
|
||||
<string>%ld voters</string>
|
||||
<key>other</key>
|
||||
<string>%ld voters</string>
|
||||
</dict>
|
||||
</dict>
|
||||
<key>plural.people_talking</key>
|
||||
<dict>
|
||||
<key>NSStringLocalizedFormatKey</key>
|
||||
<string>%#@count_people_talking@</string>
|
||||
<key>count_people_talking</key>
|
||||
<dict>
|
||||
<key>NSStringFormatSpecTypeKey</key>
|
||||
<string>NSStringPluralRuleType</string>
|
||||
<key>NSStringFormatValueTypeKey</key>
|
||||
<string>ld</string>
|
||||
<key>zero</key>
|
||||
<string>0 people talking</string>
|
||||
<key>one</key>
|
||||
<string>1 people talking</string>
|
||||
<key>few</key>
|
||||
<string>%ld people talking</string>
|
||||
<key>many</key>
|
||||
<string>%ld people talking</string>
|
||||
<key>other</key>
|
||||
<string>%ld people talking</string>
|
||||
</dict>
|
||||
</dict>
|
||||
</dict>
|
||||
</plist>
|
|
@ -144,13 +144,12 @@ extension ComposeViewController {
|
|||
self.title = title
|
||||
}
|
||||
.store(in: &disposeBag)
|
||||
view.backgroundColor = ThemeService.shared.currentTheme.value.systemElevatedBackgroundColor
|
||||
self.setupBackgroundColor(theme: ThemeService.shared.currentTheme.value)
|
||||
ThemeService.shared.currentTheme
|
||||
.receive(on: RunLoop.main)
|
||||
.sink { [weak self] theme in
|
||||
guard let self = self else { return }
|
||||
self.view.backgroundColor = theme.systemElevatedBackgroundColor
|
||||
self.tableView.backgroundColor = theme.systemElevatedBackgroundColor
|
||||
self.setupBackgroundColor(theme: theme)
|
||||
}
|
||||
.store(in: &disposeBag)
|
||||
navigationItem.leftBarButtonItem = cancelBarButtonItem
|
||||
|
@ -607,6 +606,11 @@ extension ComposeViewController {
|
|||
// })
|
||||
}
|
||||
|
||||
private func setupBackgroundColor(theme: Theme) {
|
||||
view.backgroundColor = theme.systemElevatedBackgroundColor
|
||||
tableView.backgroundColor = theme.systemElevatedBackgroundColor
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
extension ComposeViewController {
|
||||
|
@ -809,7 +813,11 @@ extension ComposeViewController: ComposeToolbarViewDelegate {
|
|||
}
|
||||
|
||||
func composeToolbarView(_ composeToolbarView: ComposeToolbarView, pollButtonDidPressed sender: UIButton) {
|
||||
// toggle poll composing state
|
||||
viewModel.isPollComposing.value.toggle()
|
||||
|
||||
// cancel custom picker input
|
||||
viewModel.isCustomEmojiComposing.value = false
|
||||
|
||||
// setup initial poll option if needs
|
||||
if viewModel.isPollComposing.value, viewModel.pollOptionAttributes.value.isEmpty {
|
||||
|
@ -831,6 +839,9 @@ extension ComposeViewController: ComposeToolbarViewDelegate {
|
|||
}
|
||||
|
||||
func composeToolbarView(_ composeToolbarView: ComposeToolbarView, contentWarningButtonDidPressed sender: UIButton) {
|
||||
// cancel custom picker input
|
||||
viewModel.isCustomEmojiComposing.value = false
|
||||
|
||||
// restore first responder for text editor when content warning dismiss
|
||||
if viewModel.isContentWarningComposing.value {
|
||||
if contentWarningEditorTextView()?.isFirstResponder == true {
|
||||
|
@ -860,20 +871,45 @@ extension ComposeViewController {
|
|||
|
||||
let repliedToCellFrame = viewModel.repliedToCellFrame.value
|
||||
guard repliedToCellFrame != .zero else { return }
|
||||
let throttle = viewModel.repliedToCellFrame.value.height - scrollView.adjustedContentInset.top
|
||||
// print("\(throttle) - \(scrollView.contentOffset.y)")
|
||||
|
||||
// try to find some patterns:
|
||||
// print("""
|
||||
// repliedToCellFrame: \(viewModel.repliedToCellFrame.value.height)
|
||||
// scrollView.contentOffset.y: \(scrollView.contentOffset.y)
|
||||
// scrollView.contentSize.height: \(scrollView.contentSize.height)
|
||||
// scrollView.frame: \(scrollView.frame)
|
||||
// scrollView.adjustedContentInset.top: \(scrollView.adjustedContentInset.top)
|
||||
// scrollView.adjustedContentInset.bottom: \(scrollView.adjustedContentInset.bottom)
|
||||
// """)
|
||||
|
||||
switch viewModel.collectionViewState.value {
|
||||
case .fold:
|
||||
if scrollView.contentOffset.y < throttle {
|
||||
os_log("%{public}s[%{public}ld], %{public}s: fold", ((#file as NSString).lastPathComponent), #line, #function)
|
||||
guard velocity.y < 0 else { return }
|
||||
let offsetY = scrollView.contentOffset.y + scrollView.adjustedContentInset.top
|
||||
if offsetY < -44 {
|
||||
tableView.contentInset.top = 0
|
||||
targetContentOffset.pointee = CGPoint(x: 0, y: -scrollView.adjustedContentInset.top)
|
||||
viewModel.collectionViewState.value = .expand
|
||||
}
|
||||
os_log("%{public}s[%{public}ld], %{public}s: fold", ((#file as NSString).lastPathComponent), #line, #function)
|
||||
|
||||
case .expand:
|
||||
if scrollView.contentOffset.y > -44 {
|
||||
os_log("%{public}s[%{public}ld], %{public}s: expand", ((#file as NSString).lastPathComponent), #line, #function)
|
||||
guard velocity.y > 0 else { return }
|
||||
// check if top across
|
||||
let topOffset = (scrollView.contentOffset.y + scrollView.adjustedContentInset.top) - repliedToCellFrame.height
|
||||
|
||||
// check if bottom bounce
|
||||
let bottomOffsetY = scrollView.contentOffset.y + (scrollView.frame.height - scrollView.adjustedContentInset.bottom)
|
||||
let bottomOffset = bottomOffsetY - scrollView.contentSize.height
|
||||
|
||||
if topOffset > 44 {
|
||||
// do not interrupt user scrolling
|
||||
viewModel.collectionViewState.value = .fold
|
||||
} else if bottomOffset > 44 {
|
||||
tableView.contentInset.top = -repliedToCellFrame.height
|
||||
targetContentOffset.pointee = CGPoint(x: 0, y: -repliedToCellFrame.height)
|
||||
viewModel.collectionViewState.value = .fold
|
||||
os_log("%{public}s[%{public}ld], %{public}s: expand", ((#file as NSString).lastPathComponent), #line, #function)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -910,7 +946,8 @@ extension ComposeViewController: UICollectionViewDelegate {
|
|||
extension ComposeViewController: UIAdaptivePresentationControllerDelegate {
|
||||
|
||||
func adaptivePresentationStyle(for controller: UIPresentationController, traitCollection: UITraitCollection) -> UIModalPresentationStyle {
|
||||
return traitCollection.userInterfaceIdiom == .pad ? .formSheet : .automatic
|
||||
return .fullScreen
|
||||
//return traitCollection.userInterfaceIdiom == .pad ? .formSheet : .automatic
|
||||
}
|
||||
|
||||
func presentationControllerShouldDismiss(_ presentationController: UIPresentationController) -> Bool {
|
||||
|
|
|
@ -253,6 +253,8 @@ extension ComposeViewModel: UITableViewDataSource {
|
|||
cell.statusContentWarningEditorView.alpha = 0
|
||||
UIView.animate(withDuration: 0.33, delay: 0, options: [.curveEaseOut]) {
|
||||
cell.statusContentWarningEditorView.alpha = 1
|
||||
tableView.beginUpdates()
|
||||
tableView.endUpdates()
|
||||
} completion: { _ in
|
||||
// do nothing
|
||||
}
|
||||
|
|
|
@ -29,7 +29,7 @@ final class ComposeViewModel: NSObject {
|
|||
let selectedStatusVisibility: CurrentValueSubject<ComposeToolbarView.VisibilitySelectionType, Never>
|
||||
let activeAuthentication: CurrentValueSubject<MastodonAuthentication?, Never>
|
||||
let activeAuthenticationBox: CurrentValueSubject<AuthenticationService.MastodonAuthenticationBox?, Never>
|
||||
let traitCollectionDidChangePublisher = CurrentValueSubject<Void, Never>(Void()) // use CurrentValueSubject to make intial event emit
|
||||
let traitCollectionDidChangePublisher = CurrentValueSubject<Void, Never>(Void()) // use CurrentValueSubject to make initial event emit
|
||||
let repliedToCellFrame = CurrentValueSubject<CGRect, Never>(.zero)
|
||||
let autoCompleteRetryLayoutTimes = CurrentValueSubject<Int, Never>(0)
|
||||
let autoCompleteInfo = CurrentValueSubject<ComposeViewController.AutoCompleteInfo?, Never>(nil)
|
||||
|
|
|
@ -13,7 +13,7 @@ final class StatusContentWarningEditorView: UIView {
|
|||
// default hidden
|
||||
let containerBackgroundView: UIView = {
|
||||
let view = UIView()
|
||||
view.backgroundColor = Asset.Colors.Background.secondarySystemBackground.color
|
||||
view.backgroundColor = ThemeService.shared.currentTheme.value.secondarySystemBackgroundColor
|
||||
return view
|
||||
}()
|
||||
|
||||
|
@ -57,29 +57,43 @@ extension StatusContentWarningEditorView {
|
|||
containerBackgroundView.trailingAnchor.constraint(equalTo: trailingAnchor, constant: 1024),
|
||||
containerBackgroundView.bottomAnchor.constraint(equalTo: bottomAnchor),
|
||||
])
|
||||
|
||||
iconImageView.translatesAutoresizingMaskIntoConstraints = false
|
||||
addSubview(iconImageView)
|
||||
|
||||
let containerStackView = UIStackView()
|
||||
containerStackView.axis = .horizontal
|
||||
containerStackView.translatesAutoresizingMaskIntoConstraints = false
|
||||
addSubview(containerStackView)
|
||||
NSLayoutConstraint.activate([
|
||||
iconImageView.centerYAnchor.constraint(equalTo: centerYAnchor),
|
||||
iconImageView.leadingAnchor.constraint(equalTo: layoutMarginsGuide.leadingAnchor),
|
||||
iconImageView.widthAnchor.constraint(equalToConstant: StatusView.avatarImageSize.width).priority(.defaultHigh), // center alignment to avatar
|
||||
])
|
||||
iconImageView.setContentHuggingPriority(.required - 2, for: .horizontal)
|
||||
|
||||
textView.translatesAutoresizingMaskIntoConstraints = false
|
||||
addSubview(textView)
|
||||
NSLayoutConstraint.activate([
|
||||
textView.centerYAnchor.constraint(equalTo: centerYAnchor),
|
||||
textView.topAnchor.constraint(greaterThanOrEqualTo: topAnchor, constant: 6).priority(.required - 1),
|
||||
textView.leadingAnchor.constraint(equalTo: iconImageView.trailingAnchor, constant: StatusView.avatarToLabelSpacing - 4), // align to name label. minus magic 4pt to remove addition inset
|
||||
textView.trailingAnchor.constraint(equalTo: layoutMarginsGuide.trailingAnchor),
|
||||
bottomAnchor.constraint(greaterThanOrEqualTo: textView.bottomAnchor, constant: 6).priority(.required - 1),
|
||||
//textView.heightAnchor.constraint(greaterThanOrEqualToConstant: 44).priority(.defaultHigh),
|
||||
containerStackView.topAnchor.constraint(equalTo: topAnchor, constant: 6),
|
||||
containerStackView.leadingAnchor.constraint(equalTo: layoutMarginsGuide.leadingAnchor),
|
||||
containerStackView.trailingAnchor.constraint(equalTo: layoutMarginsGuide.trailingAnchor),
|
||||
bottomAnchor.constraint(equalTo: containerStackView.bottomAnchor, constant: 6),
|
||||
])
|
||||
|
||||
textView.setContentHuggingPriority(.required - 1, for: .vertical)
|
||||
textView.setContentCompressionResistancePriority(.required - 1, for: .vertical)
|
||||
containerStackView.addArrangedSubview(iconImageView)
|
||||
iconImageView.setContentHuggingPriority(.required - 1, for: .horizontal)
|
||||
containerStackView.addArrangedSubview(textView)
|
||||
|
||||
// iconImageView.translatesAutoresizingMaskIntoConstraints = false
|
||||
// addSubview(iconImageView)
|
||||
// NSLayoutConstraint.activate([
|
||||
// iconImageView.leadingAnchor.constraint(equalTo: layoutMarginsGuide.leadingAnchor),
|
||||
// iconImageView.widthAnchor.constraint(equalToConstant: StatusView.avatarImageSize.width).priority(.defaultHigh), // center alignment to avatar
|
||||
// ])
|
||||
// iconImageView.setContentHuggingPriority(.required - 2, for: .horizontal)
|
||||
//
|
||||
// textView.translatesAutoresizingMaskIntoConstraints = false
|
||||
// addSubview(textView)
|
||||
// NSLayoutConstraint.activate([
|
||||
// textView.centerYAnchor.constraint(equalTo: centerYAnchor),
|
||||
// textView.topAnchor.constraint(equalTo: topAnchor, constant: 6),
|
||||
// textView.leadingAnchor.constraint(equalTo: iconImageView.trailingAnchor, constant: StatusView.avatarToLabelSpacing - 4), // align to name label. minus magic 4pt to remove addition inset
|
||||
// textView.trailingAnchor.constraint(equalTo: layoutMarginsGuide.trailingAnchor),
|
||||
// bottomAnchor.constraint(equalTo: textView.bottomAnchor, constant: 6),
|
||||
// textView.heightAnchor.constraint(greaterThanOrEqualToConstant: 44).priority(.defaultHigh),
|
||||
// ])
|
||||
//
|
||||
// textView.setContentHuggingPriority(.required - 1, for: .vertical)
|
||||
// textView.setContentCompressionResistancePriority(.required - 1, for: .vertical)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -58,7 +58,8 @@ extension HashtagTimelineViewController {
|
|||
title = "#\(viewModel.hashtag)"
|
||||
titleView.update(title: viewModel.hashtag, subtitle: nil, emojiDict: [:])
|
||||
navigationItem.titleView = titleView
|
||||
|
||||
|
||||
view.backgroundColor = ThemeService.shared.currentTheme.value.secondarySystemBackgroundColor
|
||||
ThemeService.shared.currentTheme
|
||||
.receive(on: RunLoop.main)
|
||||
.sink { [weak self] theme in
|
||||
|
|
|
@ -31,7 +31,11 @@ extension HomeTimelineViewController {
|
|||
guard let self = self else { return }
|
||||
self.showWelcomeAction(action)
|
||||
},
|
||||
UIAction(title: "Show Or Remove EmptyView", image: UIImage(systemName: "clear"), attributes: []) { [weak self] action in
|
||||
UIAction(title: "Show Confirm Email", image: UIImage(systemName: "envelope"), attributes: []) { [weak self] action in
|
||||
guard let self = self else { return }
|
||||
self.showConfirmEmail(action)
|
||||
},
|
||||
UIAction(title: "Toggle EmptyView", image: UIImage(systemName: "clear"), attributes: []) { [weak self] action in
|
||||
guard let self = self else { return }
|
||||
if self.emptyView.superview != nil {
|
||||
self.emptyView.removeFromSuperview()
|
||||
|
@ -310,6 +314,11 @@ extension HomeTimelineViewController {
|
|||
@objc private func showWelcomeAction(_ sender: UIAction) {
|
||||
coordinator.present(scene: .welcome, from: self, transition: .modal(animated: true, completion: nil))
|
||||
}
|
||||
|
||||
@objc private func showConfirmEmail(_ sender: UIAction) {
|
||||
let mastodonConfirmEmailViewModel = MastodonConfirmEmailViewModel()
|
||||
coordinator.present(scene: .mastodonConfirmEmail(viewModel: mastodonConfirmEmailViewModel), from: nil, transition: .modal(animated: true, completion: nil))
|
||||
}
|
||||
|
||||
@objc private func showPublicTimelineAction(_ sender: UIAction) {
|
||||
coordinator.present(scene: .publicTimeline, from: self, transition: .show)
|
||||
|
|
|
@ -80,8 +80,8 @@ extension HomeTimelineViewController {
|
|||
override func viewDidLoad() {
|
||||
super.viewDidLoad()
|
||||
|
||||
|
||||
title = L10n.Scene.HomeTimeline.title
|
||||
view.backgroundColor = ThemeService.shared.currentTheme.value.secondarySystemBackgroundColor
|
||||
ThemeService.shared.currentTheme
|
||||
.receive(on: RunLoop.main)
|
||||
.sink { [weak self] theme in
|
||||
|
|
|
@ -12,6 +12,7 @@ import GameplayKit
|
|||
import MastodonSDK
|
||||
import OSLog
|
||||
import UIKit
|
||||
import ActiveLabel
|
||||
import Meta
|
||||
import MetaTextView
|
||||
|
||||
|
@ -47,7 +48,8 @@ final class NotificationViewController: UIViewController, NeedsDependency {
|
|||
extension NotificationViewController {
|
||||
override func viewDidLoad() {
|
||||
super.viewDidLoad()
|
||||
|
||||
|
||||
view.backgroundColor = ThemeService.shared.currentTheme.value.secondarySystemBackgroundColor
|
||||
ThemeService.shared.currentTheme
|
||||
.receive(on: RunLoop.main)
|
||||
.sink { [weak self] theme in
|
||||
|
@ -277,6 +279,35 @@ extension NotificationViewController: ContentOffsetAdjustableTimelineViewControl
|
|||
// MARK: - NotificationTableViewCellDelegate
|
||||
extension NotificationViewController: NotificationTableViewCellDelegate {
|
||||
|
||||
func notificationStatusTableViewCell(_ cell: NotificationStatusTableViewCell, avatarImageViewDidPressed imageView: UIImageView) {
|
||||
guard let diffableDataSource = viewModel.diffableDataSource else { return }
|
||||
guard let indexPath = tableView.indexPath(for: cell) else { return }
|
||||
guard let item = diffableDataSource.itemIdentifier(for: indexPath) else { return }
|
||||
switch item {
|
||||
case .notification(let objectID, _):
|
||||
guard let notification = try? viewModel.fetchedResultsController.managedObjectContext.existingObject(with: objectID) as? MastodonNotification else { return }
|
||||
let viewModel = ProfileViewModel(context: context, optionalMastodonUser: notification.account)
|
||||
coordinator.present(scene: .profile(viewModel: viewModel), from: self, transition: .show)
|
||||
default:
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
func notificationStatusTableViewCell(_ cell: NotificationStatusTableViewCell, authorNameLabelDidPressed label: ActiveLabel) {
|
||||
guard let diffableDataSource = viewModel.diffableDataSource else { return }
|
||||
guard let indexPath = tableView.indexPath(for: cell) else { return }
|
||||
guard let item = diffableDataSource.itemIdentifier(for: indexPath) else { return }
|
||||
switch item {
|
||||
case .notification(let objectID, _):
|
||||
guard let notification = try? viewModel.fetchedResultsController.managedObjectContext.existingObject(with: objectID) as? MastodonNotification else { return }
|
||||
let viewModel = ProfileViewModel(context: context, optionalMastodonUser: notification.account)
|
||||
coordinator.present(scene: .profile(viewModel: viewModel), from: self, transition: .show)
|
||||
default:
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
func notificationTableViewCell(_ cell: NotificationStatusTableViewCell, notification: MastodonNotification, acceptButtonDidPressed button: UIButton) {
|
||||
viewModel.acceptFollowRequest(notification: notification)
|
||||
}
|
||||
|
@ -284,13 +315,6 @@ extension NotificationViewController: NotificationTableViewCellDelegate {
|
|||
func notificationTableViewCell(_ cell: NotificationStatusTableViewCell, notification: MastodonNotification, rejectButtonDidPressed button: UIButton) {
|
||||
viewModel.rejectFollowRequest(notification: notification)
|
||||
}
|
||||
|
||||
func userAvatarDidPressed(notification: MastodonNotification) {
|
||||
let viewModel = ProfileViewModel(context: context, optionalMastodonUser: notification.account)
|
||||
DispatchQueue.main.async {
|
||||
self.coordinator.present(scene: .profile(viewModel: viewModel), from: self, transition: .show)
|
||||
}
|
||||
}
|
||||
|
||||
func userNameLabelDidPressed(notification: MastodonNotification) {
|
||||
let viewModel = CachedProfileViewModel(context: context, mastodonUser: notification.account)
|
||||
|
|
|
@ -5,8 +5,10 @@
|
|||
// Created by sxiaojian on 2021/4/14.
|
||||
//
|
||||
|
||||
import os.log
|
||||
import Combine
|
||||
import Foundation
|
||||
import CoreDataStack
|
||||
import UIKit
|
||||
import ActiveLabel
|
||||
import MetaTextView
|
||||
|
@ -14,6 +16,23 @@ import Meta
|
|||
import FLAnimatedImage
|
||||
import Nuke
|
||||
|
||||
protocol NotificationTableViewCellDelegate: AnyObject {
|
||||
var context: AppContext! { get }
|
||||
func parent() -> UIViewController
|
||||
|
||||
func notificationStatusTableViewCell(_ cell: NotificationStatusTableViewCell, avatarImageViewDidPressed imageView: UIImageView)
|
||||
func notificationStatusTableViewCell(_ cell: NotificationStatusTableViewCell, authorNameLabelDidPressed label: ActiveLabel)
|
||||
|
||||
func notificationStatusTableViewCell(_ cell: NotificationStatusTableViewCell, statusView: StatusView, revealContentWarningButtonDidPressed button: UIButton)
|
||||
func notificationStatusTableViewCell(_ cell: NotificationStatusTableViewCell, statusView: StatusView, contentWarningOverlayViewDidPressed contentWarningOverlayView: ContentWarningOverlayView)
|
||||
func notificationStatusTableViewCell(_ cell: NotificationStatusTableViewCell, statusView: StatusView, playerContainerView: PlayerContainerView, contentWarningOverlayViewDidPressed contentWarningOverlayView: ContentWarningOverlayView)
|
||||
func notificationStatusTableViewCell(_ cell: NotificationStatusTableViewCell, statusView: StatusView, metaText: MetaText, didSelectMeta meta: Meta)
|
||||
|
||||
func notificationTableViewCell(_ cell: NotificationStatusTableViewCell, notification: MastodonNotification, acceptButtonDidPressed button: UIButton)
|
||||
func notificationTableViewCell(_ cell: NotificationStatusTableViewCell, notification: MastodonNotification, rejectButtonDidPressed button: UIButton)
|
||||
|
||||
}
|
||||
|
||||
final class NotificationStatusTableViewCell: UITableViewCell, StatusCell {
|
||||
|
||||
static let actionImageBorderWidth: CGFloat = 2
|
||||
|
@ -219,13 +238,12 @@ extension NotificationStatusTableViewCell {
|
|||
statusView.bottomAnchor.constraint(equalTo: statusContainerView.layoutMarginsGuide.bottomAnchor),
|
||||
])
|
||||
|
||||
setupBackgroundColor(theme: ThemeService.shared.currentTheme.value)
|
||||
ThemeService.shared.currentTheme
|
||||
.receive(on: RunLoop.main)
|
||||
.sink { [weak self] theme in
|
||||
guard let self = self else { return }
|
||||
self.statusContainerView.backgroundColor = UIColor(dynamicProvider: { traitCollection in
|
||||
return traitCollection.userInterfaceStyle == .light ? theme.systemBackgroundColor : theme.tertiarySystemGroupedBackgroundColor
|
||||
})
|
||||
self.setupBackgroundColor(theme: theme)
|
||||
}
|
||||
.store(in: &disposeBag)
|
||||
// remove item don't display
|
||||
|
@ -246,7 +264,14 @@ extension NotificationStatusTableViewCell {
|
|||
])
|
||||
|
||||
statusView.delegate = self
|
||||
|
||||
|
||||
let avatarImageViewTapGestureRecognizer = UITapGestureRecognizer.singleTapGestureRecognizer
|
||||
avatarImageViewTapGestureRecognizer.addTarget(self, action: #selector(NotificationStatusTableViewCell.avatarImageViewTapGestureRecognizerHandler(_:)))
|
||||
avatarImageView.addGestureRecognizer(avatarImageViewTapGestureRecognizer)
|
||||
let authorNameLabelTapGestureRecognizer = UITapGestureRecognizer.singleTapGestureRecognizer
|
||||
authorNameLabelTapGestureRecognizer.addTarget(self, action: #selector(NotificationStatusTableViewCell.authorNameLabelTapGestureRecognizerHandler(_:)))
|
||||
nameLabel.addGestureRecognizer(authorNameLabelTapGestureRecognizer)
|
||||
|
||||
resetSeparatorLineLayout()
|
||||
}
|
||||
|
||||
|
@ -260,6 +285,28 @@ extension NotificationStatusTableViewCell {
|
|||
|
||||
}
|
||||
|
||||
extension NotificationStatusTableViewCell {
|
||||
|
||||
private func setupBackgroundColor(theme: Theme) {
|
||||
statusContainerView.backgroundColor = UIColor(dynamicProvider: { traitCollection in
|
||||
return traitCollection.userInterfaceStyle == .light ? theme.systemBackgroundColor : theme.tertiarySystemGroupedBackgroundColor
|
||||
})
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
extension NotificationStatusTableViewCell {
|
||||
@objc private func avatarImageViewTapGestureRecognizerHandler(_ sender: UITapGestureRecognizer) {
|
||||
os_log(.info, log: .debug, "%{public}s[%{public}ld], %{public}s", ((#file as NSString).lastPathComponent), #line, #function)
|
||||
delegate?.notificationStatusTableViewCell(self, avatarImageViewDidPressed: avatarImageView)
|
||||
}
|
||||
|
||||
@objc private func authorNameLabelTapGestureRecognizerHandler(_ sender: UITapGestureRecognizer) {
|
||||
os_log(.info, log: .debug, "%{public}s[%{public}ld], %{public}s", ((#file as NSString).lastPathComponent), #line, #function)
|
||||
delegate?.notificationStatusTableViewCell(self, authorNameLabelDidPressed: nameLabel)
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - StatusViewDelegate
|
||||
extension NotificationStatusTableViewCell: StatusViewDelegate {
|
||||
|
||||
|
|
|
@ -1,265 +0,0 @@
|
|||
//
|
||||
// NotificationTableViewCell.swift
|
||||
// Mastodon
|
||||
//
|
||||
// Created by sxiaojian on 2021/4/13.
|
||||
//
|
||||
|
||||
import Combine
|
||||
import CoreDataStack
|
||||
import Foundation
|
||||
import UIKit
|
||||
import Meta
|
||||
import MetaTextView
|
||||
import ActiveLabel
|
||||
import FLAnimatedImage
|
||||
import Nuke
|
||||
|
||||
protocol NotificationTableViewCellDelegate: AnyObject {
|
||||
var context: AppContext! { get }
|
||||
|
||||
func parent() -> UIViewController
|
||||
|
||||
func userAvatarDidPressed(notification: MastodonNotification)
|
||||
func userNameLabelDidPressed(notification: MastodonNotification)
|
||||
|
||||
func notificationStatusTableViewCell(_ cell: NotificationStatusTableViewCell, statusView: StatusView, revealContentWarningButtonDidPressed button: UIButton)
|
||||
func notificationStatusTableViewCell(_ cell: NotificationStatusTableViewCell, statusView: StatusView, contentWarningOverlayViewDidPressed contentWarningOverlayView: ContentWarningOverlayView)
|
||||
func notificationStatusTableViewCell(_ cell: NotificationStatusTableViewCell, statusView: StatusView, playerContainerView: PlayerContainerView, contentWarningOverlayViewDidPressed contentWarningOverlayView: ContentWarningOverlayView)
|
||||
func notificationStatusTableViewCell(_ cell: NotificationStatusTableViewCell, statusView: StatusView, metaText: MetaText, didSelectMeta meta: Meta)
|
||||
|
||||
func notificationTableViewCell(_ cell: NotificationStatusTableViewCell, notification: MastodonNotification, acceptButtonDidPressed button: UIButton)
|
||||
func notificationTableViewCell(_ cell: NotificationStatusTableViewCell, notification: MastodonNotification, rejectButtonDidPressed button: UIButton)
|
||||
|
||||
}
|
||||
|
||||
//final class NotificationTableViewCell: UITableViewCell {
|
||||
// static let actionImageBorderWidth: CGFloat = 2
|
||||
//
|
||||
// var disposeBag = Set<AnyCancellable>()
|
||||
//
|
||||
// var delegate: NotificationTableViewCellDelegate?
|
||||
//
|
||||
// var avatarImageViewTask: ImageTask?
|
||||
// let avatarImageView: UIImageView = {
|
||||
// let imageView = FLAnimatedImageView()
|
||||
// imageView.layer.cornerRadius = 4
|
||||
// imageView.layer.cornerCurve = .continuous
|
||||
// imageView.clipsToBounds = true
|
||||
// return imageView
|
||||
// }()
|
||||
//
|
||||
// let actionImageView: UIImageView = {
|
||||
// let imageView = UIImageView()
|
||||
// imageView.tintColor = Asset.Colors.Background.systemBackground.color
|
||||
// return imageView
|
||||
// }()
|
||||
//
|
||||
// let actionImageBackground: UIView = {
|
||||
// let view = UIView()
|
||||
// view.layer.cornerRadius = (24 + NotificationTableViewCell.actionImageBorderWidth) / 2
|
||||
// view.layer.cornerCurve = .continuous
|
||||
// view.clipsToBounds = true
|
||||
// view.layer.borderWidth = NotificationTableViewCell.actionImageBorderWidth
|
||||
// view.layer.borderColor = Asset.Colors.Background.systemBackground.color.cgColor
|
||||
// view.tintColor = Asset.Colors.Background.systemBackground.color
|
||||
// return view
|
||||
// }()
|
||||
//
|
||||
// let avatarContainer: UIView = {
|
||||
// let view = UIView()
|
||||
// return view
|
||||
// }()
|
||||
//
|
||||
// let actionLabel: UILabel = {
|
||||
// let label = UILabel()
|
||||
// label.textColor = Asset.Colors.Label.secondary.color
|
||||
// label.font = UIFontMetrics(forTextStyle: .body).scaledFont(for: .systemFont(ofSize: 15, weight: .regular), maximumPointSize: 20)
|
||||
// label.lineBreakMode = .byTruncatingTail
|
||||
// return label
|
||||
// }()
|
||||
//
|
||||
// let nameLabel: ActiveLabel = {
|
||||
// let label = ActiveLabel()
|
||||
// label.textColor = Asset.Colors.brandBlue.color
|
||||
// label.font = UIFontMetrics(forTextStyle: .headline).scaledFont(for: .systemFont(ofSize: 15, weight: .semibold), maximumPointSize: 20)
|
||||
// label.lineBreakMode = .byTruncatingTail
|
||||
// return label
|
||||
// }()
|
||||
//
|
||||
// let acceptButton: UIButton = {
|
||||
// let button = UIButton(type: .custom)
|
||||
// let actionImage = UIImage(systemName: "checkmark.circle.fill", withConfiguration: UIImage.SymbolConfiguration(pointSize: 28, weight: .semibold))?.withRenderingMode(.alwaysTemplate)
|
||||
// button.setImage(actionImage, for: .normal)
|
||||
// button.tintColor = Asset.Colors.Label.secondary.color
|
||||
// return button
|
||||
// }()
|
||||
//
|
||||
// let rejectButton: UIButton = {
|
||||
// let button = UIButton(type: .custom)
|
||||
// let actionImage = UIImage(systemName: "xmark.circle.fill", withConfiguration: UIImage.SymbolConfiguration(pointSize: 28, weight: .semibold))?.withRenderingMode(.alwaysTemplate)
|
||||
// button.setImage(actionImage, for: .normal)
|
||||
// button.tintColor = Asset.Colors.Label.secondary.color
|
||||
// return button
|
||||
// }()
|
||||
//
|
||||
// let buttonStackView = UIStackView()
|
||||
//
|
||||
// let separatorLine = UIView.separatorLine
|
||||
//
|
||||
// var separatorLineToEdgeLeadingLayoutConstraint: NSLayoutConstraint!
|
||||
// var separatorLineToEdgeTrailingLayoutConstraint: NSLayoutConstraint!
|
||||
//
|
||||
// var separatorLineToMarginLeadingLayoutConstraint: NSLayoutConstraint!
|
||||
// var separatorLineToMarginTrailingLayoutConstraint: NSLayoutConstraint!
|
||||
//
|
||||
// override func prepareForReuse() {
|
||||
// super.prepareForReuse()
|
||||
// avatarImageViewTask?.cancel()
|
||||
// avatarImageViewTask = nil
|
||||
// disposeBag.removeAll()
|
||||
// }
|
||||
//
|
||||
// override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
|
||||
// super.init(style: style, reuseIdentifier: reuseIdentifier)
|
||||
// configure()
|
||||
// }
|
||||
//
|
||||
// required init?(coder: NSCoder) {
|
||||
// super.init(coder: coder)
|
||||
// configure()
|
||||
// }
|
||||
//}
|
||||
//
|
||||
//extension NotificationTableViewCell {
|
||||
// func configure() {
|
||||
// backgroundColor = Asset.Colors.Background.systemBackground.color
|
||||
// selectedBackgroundView = {
|
||||
// let view = UIView()
|
||||
// view.backgroundColor = Asset.Colors.Background.Cell.highlight.color
|
||||
// return view
|
||||
// }()
|
||||
//
|
||||
// let containerStackView = UIStackView()
|
||||
// containerStackView.axis = .vertical
|
||||
// containerStackView.alignment = .fill
|
||||
// containerStackView.layoutMargins = UIEdgeInsets(top: 14, left: 0, bottom: 12, right: 0)
|
||||
// containerStackView.isLayoutMarginsRelativeArrangement = true
|
||||
// containerStackView.translatesAutoresizingMaskIntoConstraints = false
|
||||
// contentView.addSubview(containerStackView)
|
||||
// NSLayoutConstraint.activate([
|
||||
// containerStackView.topAnchor.constraint(equalTo: contentView.topAnchor),
|
||||
// containerStackView.leadingAnchor.constraint(equalTo: contentView.readableContentGuide.leadingAnchor),
|
||||
// contentView.readableContentGuide.trailingAnchor.constraint(equalTo: containerStackView.trailingAnchor),
|
||||
// contentView.bottomAnchor.constraint(equalTo: containerStackView.bottomAnchor),
|
||||
// ])
|
||||
//
|
||||
// let horizontalStackView = UIStackView()
|
||||
// horizontalStackView.translatesAutoresizingMaskIntoConstraints = false
|
||||
// horizontalStackView.axis = .horizontal
|
||||
// horizontalStackView.spacing = 6
|
||||
//
|
||||
// horizontalStackView.addArrangedSubview(avatarContainer)
|
||||
// avatarContainer.translatesAutoresizingMaskIntoConstraints = false
|
||||
// NSLayoutConstraint.activate([
|
||||
// avatarContainer.heightAnchor.constraint(equalToConstant: 47).priority(.required - 1),
|
||||
// avatarContainer.widthAnchor.constraint(equalToConstant: 47).priority(.required - 1)
|
||||
// ])
|
||||
//
|
||||
// avatarContainer.addSubview(avatarImageView)
|
||||
// avatarImageView.translatesAutoresizingMaskIntoConstraints = false
|
||||
// NSLayoutConstraint.activate([
|
||||
// avatarImageView.heightAnchor.constraint(equalToConstant: 35).priority(.required - 1),
|
||||
// avatarImageView.widthAnchor.constraint(equalToConstant: 35).priority(.required - 1),
|
||||
// avatarImageView.topAnchor.constraint(equalTo: avatarContainer.topAnchor),
|
||||
// avatarImageView.leadingAnchor.constraint(equalTo: avatarContainer.leadingAnchor)
|
||||
// ])
|
||||
//
|
||||
// avatarContainer.addSubview(actionImageBackground)
|
||||
// actionImageBackground.translatesAutoresizingMaskIntoConstraints = false
|
||||
// NSLayoutConstraint.activate([
|
||||
// actionImageBackground.heightAnchor.constraint(equalToConstant: 24 + NotificationTableViewCell.actionImageBorderWidth).priority(.required - 1),
|
||||
// actionImageBackground.widthAnchor.constraint(equalToConstant: 24 + NotificationTableViewCell.actionImageBorderWidth).priority(.required - 1),
|
||||
// actionImageBackground.bottomAnchor.constraint(equalTo: avatarContainer.bottomAnchor),
|
||||
// actionImageBackground.trailingAnchor.constraint(equalTo: avatarContainer.trailingAnchor)
|
||||
// ])
|
||||
//
|
||||
// avatarContainer.addSubview(actionImageView)
|
||||
// actionImageView.translatesAutoresizingMaskIntoConstraints = false
|
||||
// NSLayoutConstraint.activate([
|
||||
// actionImageView.centerXAnchor.constraint(equalTo: actionImageBackground.centerXAnchor),
|
||||
// actionImageView.centerYAnchor.constraint(equalTo: actionImageBackground.centerYAnchor)
|
||||
// ])
|
||||
//
|
||||
// nameLabel.translatesAutoresizingMaskIntoConstraints = false
|
||||
// horizontalStackView.addArrangedSubview(nameLabel)
|
||||
// actionLabel.translatesAutoresizingMaskIntoConstraints = false
|
||||
// horizontalStackView.addArrangedSubview(actionLabel)
|
||||
// nameLabel.setContentCompressionResistancePriority(.required - 1, for: .horizontal)
|
||||
// nameLabel.setContentHuggingPriority(.required - 1, for: .horizontal)
|
||||
// actionLabel.setContentHuggingPriority(.defaultLow, for: .horizontal)
|
||||
//
|
||||
// containerStackView.addArrangedSubview(horizontalStackView)
|
||||
//
|
||||
// buttonStackView.translatesAutoresizingMaskIntoConstraints = false
|
||||
// buttonStackView.axis = .horizontal
|
||||
// buttonStackView.distribution = .fillEqually
|
||||
// acceptButton.translatesAutoresizingMaskIntoConstraints = false
|
||||
// rejectButton.translatesAutoresizingMaskIntoConstraints = false
|
||||
// buttonStackView.addArrangedSubview(acceptButton)
|
||||
// buttonStackView.addArrangedSubview(rejectButton)
|
||||
// containerStackView.addArrangedSubview(buttonStackView)
|
||||
//
|
||||
// separatorLine.translatesAutoresizingMaskIntoConstraints = false
|
||||
// contentView.addSubview(separatorLine)
|
||||
// separatorLineToEdgeLeadingLayoutConstraint = separatorLine.leadingAnchor.constraint(equalTo: contentView.leadingAnchor)
|
||||
// separatorLineToEdgeTrailingLayoutConstraint = separatorLine.trailingAnchor.constraint(equalTo: contentView.trailingAnchor)
|
||||
// separatorLineToMarginLeadingLayoutConstraint = separatorLine.leadingAnchor.constraint(equalTo: contentView.readableContentGuide.leadingAnchor)
|
||||
// separatorLineToMarginTrailingLayoutConstraint = separatorLine.trailingAnchor.constraint(equalTo: contentView.readableContentGuide.trailingAnchor)
|
||||
// NSLayoutConstraint.activate([
|
||||
// separatorLine.bottomAnchor.constraint(equalTo: contentView.bottomAnchor),
|
||||
// separatorLine.heightAnchor.constraint(equalToConstant: UIView.separatorLineHeight(of: contentView)),
|
||||
// ])
|
||||
// resetSeparatorLineLayout()
|
||||
// }
|
||||
//
|
||||
// override func traitCollectionDidChange(_ previousTraitCollection: UITraitCollection?) {
|
||||
// super.traitCollectionDidChange(previousTraitCollection)
|
||||
//
|
||||
// actionImageBackground.layer.borderColor = Asset.Colors.Background.systemBackground.color.cgColor
|
||||
// resetSeparatorLineLayout()
|
||||
// }
|
||||
//}
|
||||
//
|
||||
//extension NotificationTableViewCell {
|
||||
//
|
||||
// private func resetSeparatorLineLayout() {
|
||||
// separatorLineToEdgeLeadingLayoutConstraint.isActive = false
|
||||
// separatorLineToEdgeTrailingLayoutConstraint.isActive = false
|
||||
// separatorLineToMarginLeadingLayoutConstraint.isActive = false
|
||||
// separatorLineToMarginTrailingLayoutConstraint.isActive = false
|
||||
//
|
||||
// if traitCollection.userInterfaceIdiom == .phone {
|
||||
// // to edge
|
||||
// NSLayoutConstraint.activate([
|
||||
// separatorLineToEdgeLeadingLayoutConstraint,
|
||||
// separatorLineToEdgeTrailingLayoutConstraint,
|
||||
// ])
|
||||
// } else {
|
||||
// if traitCollection.horizontalSizeClass == .compact {
|
||||
// // to edge
|
||||
// NSLayoutConstraint.activate([
|
||||
// separatorLineToEdgeLeadingLayoutConstraint,
|
||||
// separatorLineToEdgeTrailingLayoutConstraint,
|
||||
// ])
|
||||
// } else {
|
||||
// // to margin
|
||||
// NSLayoutConstraint.activate([
|
||||
// separatorLineToMarginLeadingLayoutConstraint,
|
||||
// separatorLineToMarginTrailingLayoutConstraint,
|
||||
// ])
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
//
|
||||
//}
|
|
@ -37,4 +37,17 @@ final class MastodonConfirmEmailViewModel {
|
|||
self.userToken = userToken
|
||||
self.updateCredentialQuery = updateCredentialQuery
|
||||
}
|
||||
|
||||
#if DEBUG
|
||||
init() {
|
||||
self.context = AppContext.shared
|
||||
self.email = "example.com"
|
||||
self.authenticateInfo = AuthenticationViewModel.AuthenticateInfo(
|
||||
domain: "",
|
||||
application: Mastodon.Entity.Application(name: "", website: nil, vapidKey: nil, redirectURI: nil, clientID: "clientID", clientSecret: "clientSecret")
|
||||
)!
|
||||
self.userToken = Mastodon.Entity.Token(accessToken: "", tokenType: "", scope: "", createdAt: Date())
|
||||
self.updateCredentialQuery = Mastodon.API.Account.UpdateCredentialQuery(discoverable: nil, bot: nil, displayName: nil, note: nil, avatar: nil, header: nil, locked: nil, source: nil, fieldsAttributes: nil)
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
|
|
@ -88,6 +88,7 @@ extension ProfileHeaderViewController {
|
|||
override func viewDidLoad() {
|
||||
super.viewDidLoad()
|
||||
|
||||
view.backgroundColor = ThemeService.shared.currentTheme.value.systemGroupedBackgroundColor
|
||||
ThemeService.shared.currentTheme
|
||||
.receive(on: RunLoop.main)
|
||||
.sink { [weak self] theme in
|
||||
|
@ -222,13 +223,18 @@ extension ProfileHeaderViewController {
|
|||
}
|
||||
.store(in: &disposeBag)
|
||||
|
||||
Publishers.CombineLatest(
|
||||
Publishers.CombineLatest3(
|
||||
viewModel.isEditing,
|
||||
viewModel.displayProfileInfo.fields
|
||||
viewModel.displayProfileInfo.fields,
|
||||
viewModel.needsFiledCollectionViewHidden
|
||||
)
|
||||
.receive(on: RunLoop.main)
|
||||
.sink { [weak self] isEditing, fields in
|
||||
.sink { [weak self] isEditing, fields, needsHidden in
|
||||
guard let self = self else { return }
|
||||
guard !needsHidden else {
|
||||
self.profileHeaderView.fieldCollectionView.isHidden = true
|
||||
return
|
||||
}
|
||||
self.profileHeaderView.fieldCollectionView.isHidden = isEditing ? false : fields.isEmpty
|
||||
}
|
||||
.store(in: &disposeBag)
|
||||
|
|
|
@ -22,6 +22,7 @@ final class ProfileHeaderViewModel {
|
|||
let isEditing = CurrentValueSubject<Bool, Never>(false)
|
||||
let viewDidAppear = CurrentValueSubject<Bool, Never>(false)
|
||||
let needsSetupBottomShadow = CurrentValueSubject<Bool, Never>(true)
|
||||
let needsFiledCollectionViewHidden = CurrentValueSubject<Bool, Never>(false)
|
||||
let isTitleViewContentOffsetSet = CurrentValueSubject<Bool, Never>(false)
|
||||
let emojiDict = CurrentValueSubject<MastodonStatusContent.EmojiDict, Never>([:])
|
||||
let accountForEdit = CurrentValueSubject<Mastodon.Entity.Account?, Never>(nil)
|
||||
|
|
|
@ -218,7 +218,7 @@ final class ProfileHeaderView: UIView {
|
|||
collectionView.isScrollEnabled = false
|
||||
return collectionView
|
||||
}()
|
||||
var fieldCollectionViewHeightLaoutConstraint: NSLayoutConstraint!
|
||||
var fieldCollectionViewHeightLayoutConstraint: NSLayoutConstraint!
|
||||
var fieldCollectionViewHeightObservation: NSKeyValueObservation?
|
||||
|
||||
override init(frame: CGRect) {
|
||||
|
@ -239,6 +239,8 @@ final class ProfileHeaderView: UIView {
|
|||
|
||||
extension ProfileHeaderView {
|
||||
private func _init() {
|
||||
backgroundColor = ThemeService.shared.currentTheme.value.systemGroupedBackgroundColor
|
||||
fieldCollectionView.backgroundColor = ThemeService.shared.currentTheme.value.profileFieldCollectionViewBackgroundColor
|
||||
ThemeService.shared.currentTheme
|
||||
.receive(on: RunLoop.main)
|
||||
.sink { [weak self] theme in
|
||||
|
@ -427,17 +429,17 @@ extension ProfileHeaderView {
|
|||
|
||||
fieldCollectionView.translatesAutoresizingMaskIntoConstraints = false
|
||||
metaContainerStackView.addArrangedSubview(fieldCollectionView)
|
||||
fieldCollectionViewHeightLaoutConstraint = fieldCollectionView.heightAnchor.constraint(equalToConstant: 44).priority(.defaultHigh)
|
||||
fieldCollectionViewHeightLayoutConstraint = fieldCollectionView.heightAnchor.constraint(equalToConstant: 44).priority(.defaultHigh)
|
||||
NSLayoutConstraint.activate([
|
||||
fieldCollectionViewHeightLaoutConstraint,
|
||||
fieldCollectionViewHeightLayoutConstraint,
|
||||
])
|
||||
fieldCollectionViewHeightObservation = fieldCollectionView.observe(\.contentSize, options: .new, changeHandler: { [weak self] tableView, _ in
|
||||
guard let self = self else { return }
|
||||
guard self.fieldCollectionView.contentSize.height != .zero else {
|
||||
self.fieldCollectionViewHeightLaoutConstraint.constant = 44
|
||||
self.fieldCollectionViewHeightLayoutConstraint.constant = 44
|
||||
return
|
||||
}
|
||||
self.fieldCollectionViewHeightLaoutConstraint.constant = self.fieldCollectionView.contentSize.height
|
||||
self.fieldCollectionViewHeightLayoutConstraint.constant = self.fieldCollectionView.contentSize.height
|
||||
})
|
||||
|
||||
bringSubviewToFront(bannerContainerView)
|
||||
|
|
|
@ -141,7 +141,8 @@ extension ProfileViewController {
|
|||
|
||||
override func viewDidLoad() {
|
||||
super.viewDidLoad()
|
||||
|
||||
|
||||
view.backgroundColor = ThemeService.shared.currentTheme.value.secondarySystemBackgroundColor
|
||||
ThemeService.shared.currentTheme
|
||||
.receive(on: RunLoop.main)
|
||||
.sink { [weak self] theme in
|
||||
|
@ -322,7 +323,7 @@ extension ProfileViewController {
|
|||
self.titleView.isHidden = true
|
||||
return
|
||||
}
|
||||
let subtitle = L10n.Scene.Profile.subtitle(formattedStatusCount)
|
||||
let subtitle = L10n.Plural.Count.MetricFormatted.post(formattedStatusCount, statusesCount)
|
||||
self.titleView.update(title: title, subtitle: subtitle, emojiDict: emojiDict)
|
||||
self.titleView.isHidden = false
|
||||
}
|
||||
|
@ -495,7 +496,8 @@ extension ProfileViewController {
|
|||
let isNeedSetHidden = isBlocking || isBlockedBy || suspended
|
||||
self.profileHeaderViewController.viewModel.needsSetupBottomShadow.value = !isNeedSetHidden
|
||||
self.profileHeaderViewController.profileHeaderView.bioContainerView.isHidden = isNeedSetHidden
|
||||
self.profileHeaderViewController.pageSegmentedControl.isHidden = isNeedSetHidden
|
||||
self.profileHeaderViewController.viewModel.needsFiledCollectionViewHidden.value = isNeedSetHidden
|
||||
self.profileHeaderViewController.pageSegmentedControl.isEnabled = !isNeedSetHidden
|
||||
self.viewModel.needsPagePinToTop.value = isNeedSetHidden
|
||||
}
|
||||
.store(in: &disposeBag)
|
||||
|
@ -530,7 +532,7 @@ extension ProfileViewController {
|
|||
self.profileHeaderViewController.profileHeaderView.statusDashboardView.followersDashboardMeterView.accessibilityLabel = L10n.Scene.Profile.Dashboard.Accessibility.countFollowers(count ?? 0)
|
||||
}
|
||||
.store(in: &disposeBag)
|
||||
viewModel.needsPaingEnabled
|
||||
viewModel.needsPagingEnabled
|
||||
.receive(on: RunLoop.main)
|
||||
.sink { [weak self] needsPaingEnabled in
|
||||
guard let self = self else { return }
|
||||
|
|
|
@ -63,7 +63,7 @@ class ProfileViewModel: NSObject {
|
|||
let isMeBarButtonItemsHidden = CurrentValueSubject<Bool, Never>(true)
|
||||
|
||||
let needsPagePinToTop = CurrentValueSubject<Bool, Never>(false)
|
||||
let needsPaingEnabled = CurrentValueSubject<Bool, Never>(true)
|
||||
let needsPagingEnabled = CurrentValueSubject<Bool, Never>(true)
|
||||
let needsImageOverlayBlurred = CurrentValueSubject<Bool, Never>(false)
|
||||
|
||||
init(context: AppContext, optionalMastodonUser mastodonUser: MastodonUser?) {
|
||||
|
@ -161,7 +161,7 @@ class ProfileViewModel: NSObject {
|
|||
|
||||
isBlockingOrBlocked
|
||||
.map { !$0 }
|
||||
.assign(to: \.value, on: needsPaingEnabled)
|
||||
.assign(to: \.value, on: needsPagingEnabled)
|
||||
.store(in: &disposeBag)
|
||||
|
||||
isBlockingOrBlocked
|
||||
|
|
|
@ -135,14 +135,12 @@ extension SearchViewController {
|
|||
navigationItem.compactAppearance = barAppearance
|
||||
navigationItem.scrollEdgeAppearance = barAppearance
|
||||
|
||||
setupBackgroundColor(theme: ThemeService.shared.currentTheme.value)
|
||||
ThemeService.shared.currentTheme
|
||||
.receive(on: RunLoop.main)
|
||||
.sink { [weak self] theme in
|
||||
guard let self = self else { return }
|
||||
self.view.backgroundColor = theme.systemGroupedBackgroundColor
|
||||
self.searchHeader.backgroundColor = theme.systemGroupedBackgroundColor
|
||||
self.searchingTableView.backgroundColor = theme.systemBackgroundColor
|
||||
self.statusBar.backgroundColor = theme.navigationBarBackgroundColor
|
||||
self.setupBackgroundColor(theme: theme)
|
||||
}
|
||||
.store(in: &disposeBag)
|
||||
|
||||
|
@ -171,6 +169,13 @@ extension SearchViewController {
|
|||
viewModel.viewDidAppeared.send()
|
||||
}
|
||||
|
||||
private func setupBackgroundColor(theme: Theme) {
|
||||
view.backgroundColor = theme.systemGroupedBackgroundColor
|
||||
searchHeader.backgroundColor = theme.systemGroupedBackgroundColor
|
||||
searchingTableView.backgroundColor = theme.systemBackgroundColor
|
||||
statusBar.backgroundColor = theme.navigationBarBackgroundColor
|
||||
}
|
||||
|
||||
func setupSearchBar() {
|
||||
searchBar.delegate = self
|
||||
view.addSubview(searchBar)
|
||||
|
|
|
@ -102,7 +102,13 @@ class SettingsViewController: UIViewController, NeedsDependency {
|
|||
tableView.register(SettingsLinkTableViewCell.self, forCellReuseIdentifier: String(describing: SettingsLinkTableViewCell.self))
|
||||
return tableView
|
||||
}()
|
||||
|
||||
|
||||
let tableFooterActiveLabel: ActiveLabel = {
|
||||
let label = ActiveLabel(style: .default)
|
||||
label.adjustsFontForContentSizeCategory = true
|
||||
label.textAlignment = .center
|
||||
return label
|
||||
}()
|
||||
lazy var tableFooterView: UIView = {
|
||||
// init with a frame to fix a conflict ('UIView-Encapsulated-Layout-Height' UIStackView:0x7ffe41e47da0.height == 0)
|
||||
let view = UIStackView(frame: CGRect(x: 0, y: 0, width: 320, height: 320))
|
||||
|
@ -110,14 +116,9 @@ class SettingsViewController: UIViewController, NeedsDependency {
|
|||
view.layoutMargins = UIEdgeInsets(top: 20, left: 20, bottom: 20, right: 20)
|
||||
view.axis = .vertical
|
||||
view.alignment = .center
|
||||
|
||||
let label = ActiveLabel(style: .default)
|
||||
label.adjustsFontForContentSizeCategory = true
|
||||
label.textAlignment = .center
|
||||
label.configure(content: "Mastodon is open source software. You can contribute or report issues on GitHub at <a href=\"https://github.com/tootsuite/mastodon\">tootsuite/mastodon</a> (v3.3.0).", emojiDict: [:])
|
||||
label.delegate = self
|
||||
|
||||
view.addArrangedSubview(label)
|
||||
|
||||
tableFooterActiveLabel.delegate = self
|
||||
view.addArrangedSubview(tableFooterActiveLabel)
|
||||
return view
|
||||
}()
|
||||
|
||||
|
@ -190,30 +191,26 @@ class SettingsViewController: UIViewController, NeedsDependency {
|
|||
}
|
||||
}
|
||||
.store(in: &disposeBag)
|
||||
|
||||
viewModel.currentInstance
|
||||
.receive(on: RunLoop.main)
|
||||
.sink { [weak self] instance in
|
||||
guard let self = self else { return }
|
||||
let version = instance?.version ?? "-"
|
||||
let link = #"<a href="https://github.com/tootsuite/mastodon">tootsuite/mastodon</a>"#
|
||||
let content = L10n.Scene.Settings.Footer.mastodonDescription(link, version)
|
||||
self.tableFooterActiveLabel.configure(content: content, emojiDict: [:])
|
||||
}
|
||||
.store(in: &disposeBag)
|
||||
}
|
||||
|
||||
private func setupView() {
|
||||
self.view.backgroundColor = UIColor(dynamicProvider: { traitCollection in
|
||||
switch traitCollection.userInterfaceLevel {
|
||||
case .elevated where traitCollection.userInterfaceStyle == .dark:
|
||||
return ThemeService.shared.currentTheme.value.systemElevatedBackgroundColor
|
||||
default:
|
||||
return ThemeService.shared.currentTheme.value.secondarySystemBackgroundColor
|
||||
}
|
||||
})
|
||||
setupBackgroundColor(theme: ThemeService.shared.currentTheme.value)
|
||||
ThemeService.shared.currentTheme
|
||||
.receive(on: RunLoop.main)
|
||||
.sink { [weak self] theme in
|
||||
guard let self = self else { return }
|
||||
self.view.backgroundColor = UIColor(dynamicProvider: { traitCollection in
|
||||
switch traitCollection.userInterfaceLevel {
|
||||
case .elevated where traitCollection.userInterfaceStyle == .dark:
|
||||
return theme.systemElevatedBackgroundColor
|
||||
default:
|
||||
return theme.secondarySystemBackgroundColor
|
||||
}
|
||||
})
|
||||
|
||||
self.setupBackgroundColor(theme: theme)
|
||||
}
|
||||
.store(in: &disposeBag)
|
||||
|
||||
|
@ -229,6 +226,17 @@ class SettingsViewController: UIViewController, NeedsDependency {
|
|||
|
||||
updateSectionHeaderStackViewLayout()
|
||||
}
|
||||
|
||||
private func setupBackgroundColor(theme: Theme) {
|
||||
view.backgroundColor = UIColor(dynamicProvider: { traitCollection in
|
||||
switch traitCollection.userInterfaceLevel {
|
||||
case .elevated where traitCollection.userInterfaceStyle == .dark:
|
||||
return theme.systemElevatedBackgroundColor
|
||||
default:
|
||||
return theme.secondarySystemBackgroundColor
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
private func setupNavigation() {
|
||||
navigationController?.navigationBar.prefersLargeTitles = true
|
||||
|
|
|
@ -32,6 +32,7 @@ class SettingsViewModel {
|
|||
/// - does not has one
|
||||
/// - does not find subscription for selected trigger when change trigger
|
||||
let createSubscriptionSubject = PassthroughSubject<(triggerBy: String, values: [Bool?]), Never>()
|
||||
let currentInstance = CurrentValueSubject<Mastodon.Entity.Instance?, Never>(nil)
|
||||
|
||||
/// update a subscription when:
|
||||
/// - change switch for specified alerts
|
||||
|
@ -55,6 +56,26 @@ class SettingsViewModel {
|
|||
self.processDataSource(setting)
|
||||
})
|
||||
.store(in: &disposeBag)
|
||||
|
||||
context.authenticationService.activeMastodonAuthenticationBox
|
||||
.compactMap { $0?.domain }
|
||||
.map { context.apiService.instance(domain: $0) }
|
||||
.switchToLatest()
|
||||
.sink { [weak self] completion in
|
||||
guard let self = self else { return }
|
||||
switch completion {
|
||||
case .failure(let error):
|
||||
os_log(.info, log: .debug, "%{public}s[%{public}ld], %{public}s: fetch instance fail: %s", ((#file as NSString).lastPathComponent), #line, #function, error.localizedDescription)
|
||||
self.currentInstance.value = nil
|
||||
case .finished:
|
||||
os_log(.info, log: .debug, "%{public}s[%{public}ld], %{public}s: fetch instance success", ((#file as NSString).lastPathComponent), #line, #function)
|
||||
|
||||
}
|
||||
} receiveValue: { [weak self] response in
|
||||
guard let self = self else { return }
|
||||
self.currentInstance.value = response.value
|
||||
}
|
||||
.store(in: &disposeBag)
|
||||
}
|
||||
|
||||
deinit {
|
||||
|
|
|
@ -0,0 +1,102 @@
|
|||
//
|
||||
// AppearanceView.swift
|
||||
// Mastodon
|
||||
//
|
||||
// Created by MainasuK Cirno on 2021-7-6.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
|
||||
class AppearanceView: UIView {
|
||||
lazy var imageView: UIImageView = {
|
||||
let view = UIImageView()
|
||||
// accessibility
|
||||
view.accessibilityIgnoresInvertColors = true
|
||||
return view
|
||||
}()
|
||||
lazy var titleLabel: UILabel = {
|
||||
let label = UILabel()
|
||||
label.font = .systemFont(ofSize: 12, weight: .regular)
|
||||
label.textColor = Asset.Colors.Label.primary.color
|
||||
label.textAlignment = .center
|
||||
return label
|
||||
}()
|
||||
lazy var checkBox: UIButton = {
|
||||
let button = UIButton()
|
||||
button.isUserInteractionEnabled = false
|
||||
button.setImage(UIImage(systemName: "circle"), for: .normal)
|
||||
button.setImage(UIImage(systemName: "checkmark.circle.fill"), for: .selected)
|
||||
button.imageView?.preferredSymbolConfiguration = UIImage.SymbolConfiguration(textStyle: .body)
|
||||
button.imageView?.tintColor = Asset.Colors.Label.secondary.color
|
||||
button.imageView?.contentMode = .scaleAspectFill
|
||||
return button
|
||||
}()
|
||||
lazy var stackView: UIStackView = {
|
||||
let view = UIStackView()
|
||||
view.axis = .vertical
|
||||
view.spacing = 10
|
||||
view.distribution = .equalSpacing
|
||||
return view
|
||||
}()
|
||||
|
||||
var selected: Bool = false {
|
||||
didSet {
|
||||
checkBox.isSelected = selected
|
||||
if selected {
|
||||
checkBox.imageView?.tintColor = Asset.Colors.brandBlue.color
|
||||
} else {
|
||||
checkBox.imageView?.tintColor = Asset.Colors.Label.secondary.color
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - Methods
|
||||
init(image: UIImage?, title: String) {
|
||||
super.init(frame: .zero)
|
||||
setupUI()
|
||||
|
||||
imageView.image = image
|
||||
titleLabel.text = title
|
||||
}
|
||||
|
||||
required init?(coder: NSCoder) {
|
||||
fatalError("init(coder:) has not been implemented")
|
||||
}
|
||||
|
||||
// MARK: - Private methods
|
||||
private func setupUI() {
|
||||
stackView.addArrangedSubview(imageView)
|
||||
stackView.addArrangedSubview(titleLabel)
|
||||
stackView.addArrangedSubview(checkBox)
|
||||
|
||||
addSubview(stackView)
|
||||
translatesAutoresizingMaskIntoConstraints = false
|
||||
stackView.translatesAutoresizingMaskIntoConstraints = false
|
||||
NSLayoutConstraint.activate([
|
||||
stackView.topAnchor.constraint(equalTo: self.topAnchor),
|
||||
stackView.leadingAnchor.constraint(equalTo: self.leadingAnchor),
|
||||
stackView.bottomAnchor.constraint(equalTo: self.bottomAnchor),
|
||||
stackView.trailingAnchor.constraint(equalTo: self.trailingAnchor),
|
||||
imageView.heightAnchor.constraint(equalTo: imageView.widthAnchor, multiplier: 218.0 / 100.0),
|
||||
])
|
||||
}
|
||||
|
||||
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
|
||||
super.touchesBegan(touches, with: event)
|
||||
self.alpha = 0.5
|
||||
}
|
||||
|
||||
override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {
|
||||
super.touchesEnded(touches, with: event)
|
||||
UIView.animate(withDuration: 0.33) {
|
||||
self.alpha = 1
|
||||
}
|
||||
}
|
||||
|
||||
override func touchesCancelled(_ touches: Set<UITouch>, with event: UIEvent?) {
|
||||
super.touchesCancelled(touches, with: event)
|
||||
UIView.animate(withDuration: 0.33) {
|
||||
self.alpha = 1
|
||||
}
|
||||
}
|
||||
}
|
|
@ -12,81 +12,6 @@ protocol SettingsAppearanceTableViewCellDelegate: AnyObject {
|
|||
func settingsAppearanceCell(_ cell: SettingsAppearanceTableViewCell, didSelectAppearanceMode appearanceMode: SettingsItem.AppearanceMode)
|
||||
}
|
||||
|
||||
class AppearanceView: UIView {
|
||||
lazy var imageView: UIImageView = {
|
||||
let view = UIImageView()
|
||||
// accessibility
|
||||
view.accessibilityIgnoresInvertColors = true
|
||||
return view
|
||||
}()
|
||||
lazy var titleLabel: UILabel = {
|
||||
let label = UILabel()
|
||||
label.font = .systemFont(ofSize: 12, weight: .regular)
|
||||
label.textColor = Asset.Colors.Label.primary.color
|
||||
label.textAlignment = .center
|
||||
return label
|
||||
}()
|
||||
lazy var checkBox: UIButton = {
|
||||
let button = UIButton()
|
||||
button.isUserInteractionEnabled = false
|
||||
button.setImage(UIImage(systemName: "circle"), for: .normal)
|
||||
button.setImage(UIImage(systemName: "checkmark.circle.fill"), for: .selected)
|
||||
button.imageView?.preferredSymbolConfiguration = UIImage.SymbolConfiguration(textStyle: .body)
|
||||
button.imageView?.tintColor = Asset.Colors.Label.secondary.color
|
||||
button.imageView?.contentMode = .scaleAspectFill
|
||||
return button
|
||||
}()
|
||||
lazy var stackView: UIStackView = {
|
||||
let view = UIStackView()
|
||||
view.axis = .vertical
|
||||
view.spacing = 10
|
||||
view.distribution = .equalSpacing
|
||||
return view
|
||||
}()
|
||||
|
||||
var selected: Bool = false {
|
||||
didSet {
|
||||
checkBox.isSelected = selected
|
||||
if selected {
|
||||
checkBox.imageView?.tintColor = Asset.Colors.brandBlue.color
|
||||
} else {
|
||||
checkBox.imageView?.tintColor = Asset.Colors.Label.secondary.color
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - Methods
|
||||
init(image: UIImage?, title: String) {
|
||||
super.init(frame: .zero)
|
||||
setupUI()
|
||||
|
||||
imageView.image = image
|
||||
titleLabel.text = title
|
||||
}
|
||||
|
||||
required init?(coder: NSCoder) {
|
||||
fatalError("init(coder:) has not been implemented")
|
||||
}
|
||||
|
||||
// MARK: - Private methods
|
||||
private func setupUI() {
|
||||
stackView.addArrangedSubview(imageView)
|
||||
stackView.addArrangedSubview(titleLabel)
|
||||
stackView.addArrangedSubview(checkBox)
|
||||
|
||||
addSubview(stackView)
|
||||
translatesAutoresizingMaskIntoConstraints = false
|
||||
stackView.translatesAutoresizingMaskIntoConstraints = false
|
||||
NSLayoutConstraint.activate([
|
||||
stackView.topAnchor.constraint(equalTo: self.topAnchor),
|
||||
stackView.leadingAnchor.constraint(equalTo: self.leadingAnchor),
|
||||
stackView.bottomAnchor.constraint(equalTo: self.bottomAnchor),
|
||||
stackView.trailingAnchor.constraint(equalTo: self.trailingAnchor),
|
||||
imageView.heightAnchor.constraint(equalTo: imageView.widthAnchor, multiplier: 218.0 / 100.0),
|
||||
])
|
||||
}
|
||||
}
|
||||
|
||||
class SettingsAppearanceTableViewCell: UITableViewCell {
|
||||
|
||||
var disposeBag = Set<AnyCancellable>()
|
||||
|
|
|
@ -165,7 +165,7 @@ final class StatusView: UIView {
|
|||
let label = UILabel()
|
||||
label.font = UIFontMetrics(forTextStyle: .body).scaledFont(for: .systemFont(ofSize: 12, weight: .regular))
|
||||
label.textColor = Asset.Colors.Label.secondary.color
|
||||
label.text = L10n.Common.Controls.Status.Poll.VoteCount.single(0)
|
||||
label.text = L10n.Plural.Count.vote(0)
|
||||
return label
|
||||
}()
|
||||
let pollStatusDotLabel: UILabel = {
|
||||
|
|
|
@ -51,7 +51,8 @@ extension ThreadViewController {
|
|||
|
||||
override func viewDidLoad() {
|
||||
super.viewDidLoad()
|
||||
|
||||
|
||||
view.backgroundColor = ThemeService.shared.currentTheme.value.secondarySystemBackgroundColor
|
||||
ThemeService.shared.currentTheme
|
||||
.receive(on: RunLoop.main)
|
||||
.sink { [weak self] theme in
|
||||
|
|
|
@ -17,7 +17,7 @@ extension Mastodon.Entity {
|
|||
/// # Reference
|
||||
/// [Document](https://docs.joinmastodon.org/entities/application/)
|
||||
public struct Application: Codable {
|
||||
|
||||
|
||||
public let name: String
|
||||
|
||||
public let website: String?
|
||||
|
@ -27,6 +27,15 @@ extension Mastodon.Entity {
|
|||
public let redirectURI: String? // undocumented
|
||||
public let clientID: String?
|
||||
public let clientSecret: String?
|
||||
|
||||
public init(name: String, website: String?, vapidKey: String?, redirectURI: String?, clientID: String?, clientSecret: String?) {
|
||||
self.name = name
|
||||
self.website = website
|
||||
self.vapidKey = vapidKey
|
||||
self.redirectURI = redirectURI
|
||||
self.clientID = clientID
|
||||
self.clientSecret = clientSecret
|
||||
}
|
||||
|
||||
enum CodingKeys: String, CodingKey {
|
||||
case name
|
||||
|
|
|
@ -17,10 +17,18 @@ extension Mastodon.Entity {
|
|||
/// # Reference
|
||||
/// [Document](https://docs.joinmastodon.org/entities/token/)
|
||||
public struct Token: Codable {
|
||||
|
||||
public let accessToken: String
|
||||
public let tokenType: String
|
||||
public let scope: String
|
||||
public let createdAt: Date
|
||||
|
||||
public init(accessToken: String, tokenType: String, scope: String, createdAt: Date) {
|
||||
self.accessToken = accessToken
|
||||
self.tokenType = tokenType
|
||||
self.scope = scope
|
||||
self.createdAt = createdAt
|
||||
}
|
||||
|
||||
enum CodingKeys: String, CodingKey {
|
||||
case accessToken = "access_token"
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
strings:
|
||||
inputs: Mastodon/Resources/en.lproj/Localizable.strings
|
||||
inputs:
|
||||
- Mastodon/Resources/en.lproj/Localizable.strings
|
||||
- Mastodon/Resources/en.lproj/Localizable.stringsdict
|
||||
outputs:
|
||||
- templateName: structured-swift5
|
||||
output: Mastodon/Generated/Strings.swift
|
||||
|
@ -7,4 +9,4 @@ xcassets:
|
|||
inputs: Mastodon/Resources/Assets.xcassets
|
||||
outputs:
|
||||
templateName: swift5
|
||||
output: Mastodon/Generated/Assets.swift
|
||||
output: Mastodon/Generated/Assets.swift
|
||||
|
|
Loading…
Reference in New Issue