feat: update status cell UI
This commit is contained in:
parent
0ffc0019a4
commit
40a524434f
|
@ -19,6 +19,9 @@
|
||||||
"preview": "Preview",
|
"preview": "Preview",
|
||||||
"open_in_safari": "Open in Safari"
|
"open_in_safari": "Open in Safari"
|
||||||
},
|
},
|
||||||
|
"status": {
|
||||||
|
"userBoosted": "%s boosted"
|
||||||
|
},
|
||||||
"timeline": {
|
"timeline": {
|
||||||
"load_more": "Load More"
|
"load_more": "Load More"
|
||||||
}
|
}
|
||||||
|
@ -75,4 +78,4 @@
|
||||||
"title": "Public"
|
"title": "Public"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,6 +13,7 @@
|
||||||
"Common.Controls.Actions.SignIn" = "Sign in";
|
"Common.Controls.Actions.SignIn" = "Sign in";
|
||||||
"Common.Controls.Actions.SignUp" = "Sign up";
|
"Common.Controls.Actions.SignUp" = "Sign up";
|
||||||
"Common.Controls.Actions.TakePhoto" = "Take photo";
|
"Common.Controls.Actions.TakePhoto" = "Take photo";
|
||||||
|
"Common.Controls.Status.Userboosted" = "%@ boosted";
|
||||||
"Common.Controls.Timeline.LoadMore" = "Load More";
|
"Common.Controls.Timeline.LoadMore" = "Load More";
|
||||||
"Common.Countable.Photo.Multiple" = "photos";
|
"Common.Countable.Photo.Multiple" = "photos";
|
||||||
"Common.Countable.Photo.Single" = "photo";
|
"Common.Countable.Photo.Single" = "photo";
|
||||||
|
|
|
@ -19,6 +19,9 @@
|
||||||
"preview": "Preview",
|
"preview": "Preview",
|
||||||
"open_in_safari": "Open in Safari"
|
"open_in_safari": "Open in Safari"
|
||||||
},
|
},
|
||||||
|
"status": {
|
||||||
|
"userBoosted": "%s boosted"
|
||||||
|
},
|
||||||
"timeline": {
|
"timeline": {
|
||||||
"load_more": "Load More"
|
"load_more": "Load More"
|
||||||
}
|
}
|
||||||
|
@ -75,4 +78,4 @@
|
||||||
"title": "Public"
|
"title": "Public"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,7 +9,7 @@
|
||||||
/* Begin PBXBuildFile section */
|
/* Begin PBXBuildFile section */
|
||||||
18BC7629F65E6DB12CB8416D /* Pods_Mastodon_MastodonUITests.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 3C030226D3C73DCC23D67452 /* Pods_Mastodon_MastodonUITests.framework */; };
|
18BC7629F65E6DB12CB8416D /* Pods_Mastodon_MastodonUITests.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 3C030226D3C73DCC23D67452 /* Pods_Mastodon_MastodonUITests.framework */; };
|
||||||
2D04F42525C255B9003F936F /* APIService+PublicTimeline.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2D04F42425C255B9003F936F /* APIService+PublicTimeline.swift */; };
|
2D04F42525C255B9003F936F /* APIService+PublicTimeline.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2D04F42425C255B9003F936F /* APIService+PublicTimeline.swift */; };
|
||||||
2D152A8C25C295CC009AA50C /* TimelinePostView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2D152A8B25C295CC009AA50C /* TimelinePostView.swift */; };
|
2D152A8C25C295CC009AA50C /* StatusView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2D152A8B25C295CC009AA50C /* StatusView.swift */; };
|
||||||
2D152A9225C2980C009AA50C /* UIFont.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2D152A9125C2980C009AA50C /* UIFont.swift */; };
|
2D152A9225C2980C009AA50C /* UIFont.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2D152A9125C2980C009AA50C /* UIFont.swift */; };
|
||||||
2D32EAAC25CB96DC00C9ED86 /* TimelineMiddleLoaderTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2D32EAAB25CB96DC00C9ED86 /* TimelineMiddleLoaderTableViewCell.swift */; };
|
2D32EAAC25CB96DC00C9ED86 /* TimelineMiddleLoaderTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2D32EAAB25CB96DC00C9ED86 /* TimelineMiddleLoaderTableViewCell.swift */; };
|
||||||
2D32EABA25CB9B0500C9ED86 /* UIView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2D32EAB925CB9B0500C9ED86 /* UIView.swift */; };
|
2D32EABA25CB9B0500C9ED86 /* UIView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2D32EAB925CB9B0500C9ED86 /* UIView.swift */; };
|
||||||
|
@ -33,7 +33,6 @@
|
||||||
2D46975E25C2A54100CF4AA9 /* NSLayoutConstraint.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2D46975D25C2A54100CF4AA9 /* NSLayoutConstraint.swift */; };
|
2D46975E25C2A54100CF4AA9 /* NSLayoutConstraint.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2D46975D25C2A54100CF4AA9 /* NSLayoutConstraint.swift */; };
|
||||||
2D46976425C2A71500CF4AA9 /* UIIamge.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2D46976325C2A71500CF4AA9 /* UIIamge.swift */; };
|
2D46976425C2A71500CF4AA9 /* UIIamge.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2D46976325C2A71500CF4AA9 /* UIIamge.swift */; };
|
||||||
2D5A3D0325CF8742002347D6 /* ControlContainableScrollViews.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2D5A3D0225CF8742002347D6 /* ControlContainableScrollViews.swift */; };
|
2D5A3D0325CF8742002347D6 /* ControlContainableScrollViews.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2D5A3D0225CF8742002347D6 /* ControlContainableScrollViews.swift */; };
|
||||||
2D5A3D1125CF87AA002347D6 /* AvatarBarButtonItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2D5A3D1025CF87AA002347D6 /* AvatarBarButtonItem.swift */; };
|
|
||||||
2D5A3D2825CF8BC9002347D6 /* HomeTimelineViewModel+Diffable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2D5A3D2725CF8BC9002347D6 /* HomeTimelineViewModel+Diffable.swift */; };
|
2D5A3D2825CF8BC9002347D6 /* HomeTimelineViewModel+Diffable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2D5A3D2725CF8BC9002347D6 /* HomeTimelineViewModel+Diffable.swift */; };
|
||||||
2D5A3D3825CF8D9F002347D6 /* ScrollViewContainer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2D5A3D3725CF8D9F002347D6 /* ScrollViewContainer.swift */; };
|
2D5A3D3825CF8D9F002347D6 /* ScrollViewContainer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2D5A3D3725CF8D9F002347D6 /* ScrollViewContainer.swift */; };
|
||||||
2D5A3D6225CFD9CB002347D6 /* HomeTimelineViewController+DebugAction.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2D5A3D6125CFD9CB002347D6 /* HomeTimelineViewController+DebugAction.swift */; };
|
2D5A3D6225CFD9CB002347D6 /* HomeTimelineViewController+DebugAction.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2D5A3D6125CFD9CB002347D6 /* HomeTimelineViewController+DebugAction.swift */; };
|
||||||
|
@ -47,7 +46,7 @@
|
||||||
2D76317D25C14DF500929FB9 /* PublicTimelineViewController+StatusProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2D76317C25C14DF400929FB9 /* PublicTimelineViewController+StatusProvider.swift */; };
|
2D76317D25C14DF500929FB9 /* PublicTimelineViewController+StatusProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2D76317C25C14DF400929FB9 /* PublicTimelineViewController+StatusProvider.swift */; };
|
||||||
2D76318325C14E8F00929FB9 /* PublicTimelineViewModel+Diffable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2D76318225C14E8F00929FB9 /* PublicTimelineViewModel+Diffable.swift */; };
|
2D76318325C14E8F00929FB9 /* PublicTimelineViewModel+Diffable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2D76318225C14E8F00929FB9 /* PublicTimelineViewModel+Diffable.swift */; };
|
||||||
2D76319F25C1521200929FB9 /* TimelineSection.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2D76319E25C1521200929FB9 /* TimelineSection.swift */; };
|
2D76319F25C1521200929FB9 /* TimelineSection.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2D76319E25C1521200929FB9 /* TimelineSection.swift */; };
|
||||||
2D7631A825C1535600929FB9 /* TimelinePostTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2D7631A725C1535600929FB9 /* TimelinePostTableViewCell.swift */; };
|
2D7631A825C1535600929FB9 /* StatusTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2D7631A725C1535600929FB9 /* StatusTableViewCell.swift */; };
|
||||||
2D7631B325C159F700929FB9 /* Item.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2D7631B225C159F700929FB9 /* Item.swift */; };
|
2D7631B325C159F700929FB9 /* Item.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2D7631B225C159F700929FB9 /* Item.swift */; };
|
||||||
2D927F0225C7E4F2004F19B8 /* Mention.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2D927F0125C7E4F2004F19B8 /* Mention.swift */; };
|
2D927F0225C7E4F2004F19B8 /* Mention.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2D927F0125C7E4F2004F19B8 /* Mention.swift */; };
|
||||||
2D927F0825C7E9A8004F19B8 /* Tag.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2D927F0725C7E9A8004F19B8 /* Tag.swift */; };
|
2D927F0825C7E9A8004F19B8 /* Tag.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2D927F0725C7E9A8004F19B8 /* Tag.swift */; };
|
||||||
|
@ -74,6 +73,8 @@
|
||||||
DB0140CF25C42AEE00F9F3CF /* OSLog.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB0140CE25C42AEE00F9F3CF /* OSLog.swift */; };
|
DB0140CF25C42AEE00F9F3CF /* OSLog.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB0140CE25C42AEE00F9F3CF /* OSLog.swift */; };
|
||||||
DB084B5725CBC56C00F898ED /* Toot.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB084B5625CBC56C00F898ED /* Toot.swift */; };
|
DB084B5725CBC56C00F898ED /* Toot.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB084B5625CBC56C00F898ED /* Toot.swift */; };
|
||||||
DB0AC6FC25CD02E600D75117 /* APIService+Instance.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB0AC6FB25CD02E600D75117 /* APIService+Instance.swift */; };
|
DB0AC6FC25CD02E600D75117 /* APIService+Instance.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB0AC6FB25CD02E600D75117 /* APIService+Instance.swift */; };
|
||||||
|
DB118A8225E4B6E600FAB162 /* Preview Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = DB118A8125E4B6E600FAB162 /* Preview Assets.xcassets */; };
|
||||||
|
DB118A8C25E4BFB500FAB162 /* HighlightDimmableButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB118A8B25E4BFB500FAB162 /* HighlightDimmableButton.swift */; };
|
||||||
DB2B3ABC25E37E15007045F9 /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = DB2B3ABE25E37E15007045F9 /* InfoPlist.strings */; };
|
DB2B3ABC25E37E15007045F9 /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = DB2B3ABE25E37E15007045F9 /* InfoPlist.strings */; };
|
||||||
DB2B3AE925E38850007045F9 /* UIViewPreview.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB2B3AE825E38850007045F9 /* UIViewPreview.swift */; };
|
DB2B3AE925E38850007045F9 /* UIViewPreview.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB2B3AE825E38850007045F9 /* UIViewPreview.swift */; };
|
||||||
DB3D0FF325BAA61700EAA174 /* AlamofireImage in Frameworks */ = {isa = PBXBuildFile; productRef = DB3D0FF225BAA61700EAA174 /* AlamofireImage */; };
|
DB3D0FF325BAA61700EAA174 /* AlamofireImage in Frameworks */ = {isa = PBXBuildFile; productRef = DB3D0FF225BAA61700EAA174 /* AlamofireImage */; };
|
||||||
|
@ -188,7 +189,7 @@
|
||||||
|
|
||||||
/* Begin PBXFileReference section */
|
/* Begin PBXFileReference section */
|
||||||
2D04F42425C255B9003F936F /* APIService+PublicTimeline.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "APIService+PublicTimeline.swift"; sourceTree = "<group>"; };
|
2D04F42425C255B9003F936F /* APIService+PublicTimeline.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "APIService+PublicTimeline.swift"; sourceTree = "<group>"; };
|
||||||
2D152A8B25C295CC009AA50C /* TimelinePostView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TimelinePostView.swift; sourceTree = "<group>"; };
|
2D152A8B25C295CC009AA50C /* StatusView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StatusView.swift; sourceTree = "<group>"; };
|
||||||
2D152A9125C2980C009AA50C /* UIFont.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UIFont.swift; sourceTree = "<group>"; };
|
2D152A9125C2980C009AA50C /* UIFont.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UIFont.swift; sourceTree = "<group>"; };
|
||||||
2D32EAAB25CB96DC00C9ED86 /* TimelineMiddleLoaderTableViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TimelineMiddleLoaderTableViewCell.swift; sourceTree = "<group>"; };
|
2D32EAAB25CB96DC00C9ED86 /* TimelineMiddleLoaderTableViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TimelineMiddleLoaderTableViewCell.swift; sourceTree = "<group>"; };
|
||||||
2D32EAB925CB9B0500C9ED86 /* UIView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UIView.swift; sourceTree = "<group>"; };
|
2D32EAB925CB9B0500C9ED86 /* UIView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UIView.swift; sourceTree = "<group>"; };
|
||||||
|
@ -211,7 +212,6 @@
|
||||||
2D46975D25C2A54100CF4AA9 /* NSLayoutConstraint.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NSLayoutConstraint.swift; sourceTree = "<group>"; };
|
2D46975D25C2A54100CF4AA9 /* NSLayoutConstraint.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NSLayoutConstraint.swift; sourceTree = "<group>"; };
|
||||||
2D46976325C2A71500CF4AA9 /* UIIamge.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UIIamge.swift; sourceTree = "<group>"; };
|
2D46976325C2A71500CF4AA9 /* UIIamge.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UIIamge.swift; sourceTree = "<group>"; };
|
||||||
2D5A3D0225CF8742002347D6 /* ControlContainableScrollViews.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ControlContainableScrollViews.swift; sourceTree = "<group>"; };
|
2D5A3D0225CF8742002347D6 /* ControlContainableScrollViews.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ControlContainableScrollViews.swift; sourceTree = "<group>"; };
|
||||||
2D5A3D1025CF87AA002347D6 /* AvatarBarButtonItem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AvatarBarButtonItem.swift; sourceTree = "<group>"; };
|
|
||||||
2D5A3D2725CF8BC9002347D6 /* HomeTimelineViewModel+Diffable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "HomeTimelineViewModel+Diffable.swift"; sourceTree = "<group>"; };
|
2D5A3D2725CF8BC9002347D6 /* HomeTimelineViewModel+Diffable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "HomeTimelineViewModel+Diffable.swift"; sourceTree = "<group>"; };
|
||||||
2D5A3D3725CF8D9F002347D6 /* ScrollViewContainer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ScrollViewContainer.swift; sourceTree = "<group>"; };
|
2D5A3D3725CF8D9F002347D6 /* ScrollViewContainer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ScrollViewContainer.swift; sourceTree = "<group>"; };
|
||||||
2D5A3D6125CFD9CB002347D6 /* HomeTimelineViewController+DebugAction.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "HomeTimelineViewController+DebugAction.swift"; sourceTree = "<group>"; };
|
2D5A3D6125CFD9CB002347D6 /* HomeTimelineViewController+DebugAction.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "HomeTimelineViewController+DebugAction.swift"; sourceTree = "<group>"; };
|
||||||
|
@ -224,7 +224,7 @@
|
||||||
2D76317C25C14DF400929FB9 /* PublicTimelineViewController+StatusProvider.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "PublicTimelineViewController+StatusProvider.swift"; sourceTree = "<group>"; };
|
2D76317C25C14DF400929FB9 /* PublicTimelineViewController+StatusProvider.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "PublicTimelineViewController+StatusProvider.swift"; sourceTree = "<group>"; };
|
||||||
2D76318225C14E8F00929FB9 /* PublicTimelineViewModel+Diffable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "PublicTimelineViewModel+Diffable.swift"; sourceTree = "<group>"; };
|
2D76318225C14E8F00929FB9 /* PublicTimelineViewModel+Diffable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "PublicTimelineViewModel+Diffable.swift"; sourceTree = "<group>"; };
|
||||||
2D76319E25C1521200929FB9 /* TimelineSection.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TimelineSection.swift; sourceTree = "<group>"; };
|
2D76319E25C1521200929FB9 /* TimelineSection.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TimelineSection.swift; sourceTree = "<group>"; };
|
||||||
2D7631A725C1535600929FB9 /* TimelinePostTableViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TimelinePostTableViewCell.swift; sourceTree = "<group>"; };
|
2D7631A725C1535600929FB9 /* StatusTableViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StatusTableViewCell.swift; sourceTree = "<group>"; };
|
||||||
2D7631B225C159F700929FB9 /* Item.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Item.swift; sourceTree = "<group>"; };
|
2D7631B225C159F700929FB9 /* Item.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Item.swift; sourceTree = "<group>"; };
|
||||||
2D927F0125C7E4F2004F19B8 /* Mention.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Mention.swift; sourceTree = "<group>"; };
|
2D927F0125C7E4F2004F19B8 /* Mention.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Mention.swift; sourceTree = "<group>"; };
|
||||||
2D927F0725C7E9A8004F19B8 /* Tag.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Tag.swift; sourceTree = "<group>"; };
|
2D927F0725C7E9A8004F19B8 /* Tag.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Tag.swift; sourceTree = "<group>"; };
|
||||||
|
@ -256,6 +256,8 @@
|
||||||
DB0140CE25C42AEE00F9F3CF /* OSLog.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = OSLog.swift; sourceTree = "<group>"; };
|
DB0140CE25C42AEE00F9F3CF /* OSLog.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = OSLog.swift; sourceTree = "<group>"; };
|
||||||
DB084B5625CBC56C00F898ED /* Toot.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Toot.swift; sourceTree = "<group>"; };
|
DB084B5625CBC56C00F898ED /* Toot.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Toot.swift; sourceTree = "<group>"; };
|
||||||
DB0AC6FB25CD02E600D75117 /* APIService+Instance.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "APIService+Instance.swift"; sourceTree = "<group>"; };
|
DB0AC6FB25CD02E600D75117 /* APIService+Instance.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "APIService+Instance.swift"; sourceTree = "<group>"; };
|
||||||
|
DB118A8125E4B6E600FAB162 /* Preview Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = "Preview Assets.xcassets"; sourceTree = "<group>"; };
|
||||||
|
DB118A8B25E4BFB500FAB162 /* HighlightDimmableButton.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HighlightDimmableButton.swift; sourceTree = "<group>"; };
|
||||||
DB2B3ABD25E37E15007045F9 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/InfoPlist.strings; sourceTree = "<group>"; };
|
DB2B3ABD25E37E15007045F9 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/InfoPlist.strings; sourceTree = "<group>"; };
|
||||||
DB2B3AE825E38850007045F9 /* UIViewPreview.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UIViewPreview.swift; sourceTree = "<group>"; };
|
DB2B3AE825E38850007045F9 /* UIViewPreview.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UIViewPreview.swift; sourceTree = "<group>"; };
|
||||||
DB3D0FED25BAA42200EAA174 /* MastodonSDK */ = {isa = PBXFileReference; lastKnownFileType = folder; path = MastodonSDK; sourceTree = "<group>"; };
|
DB3D0FED25BAA42200EAA174 /* MastodonSDK */ = {isa = PBXFileReference; lastKnownFileType = folder; path = MastodonSDK; sourceTree = "<group>"; };
|
||||||
|
@ -393,7 +395,7 @@
|
||||||
2D152A8A25C295B8009AA50C /* Content */ = {
|
2D152A8A25C295B8009AA50C /* Content */ = {
|
||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
2D152A8B25C295CC009AA50C /* TimelinePostView.swift */,
|
2D152A8B25C295CC009AA50C /* StatusView.swift */,
|
||||||
);
|
);
|
||||||
path = Content;
|
path = Content;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
|
@ -436,7 +438,7 @@
|
||||||
children = (
|
children = (
|
||||||
DB5086A425CC0B7000C2C187 /* AvatarBarButtonItem.swift */,
|
DB5086A425CC0B7000C2C187 /* AvatarBarButtonItem.swift */,
|
||||||
2D42FF8425C8224F004A627A /* HitTestExpandedButton.swift */,
|
2D42FF8425C8224F004A627A /* HitTestExpandedButton.swift */,
|
||||||
2D5A3D1025CF87AA002347D6 /* AvatarBarButtonItem.swift */,
|
DB118A8B25E4BFB500FAB162 /* HighlightDimmableButton.swift */,
|
||||||
);
|
);
|
||||||
path = Button;
|
path = Button;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
|
@ -533,7 +535,7 @@
|
||||||
2D7631A625C1533800929FB9 /* TableviewCell */ = {
|
2D7631A625C1533800929FB9 /* TableviewCell */ = {
|
||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
2D7631A725C1535600929FB9 /* TimelinePostTableViewCell.swift */,
|
2D7631A725C1535600929FB9 /* StatusTableViewCell.swift */,
|
||||||
2DA7D04325CA52B200804E11 /* TimelineLoaderTableViewCell.swift */,
|
2DA7D04325CA52B200804E11 /* TimelineLoaderTableViewCell.swift */,
|
||||||
2DA7D04925CA52CB00804E11 /* TimelineBottomLoaderTableViewCell.swift */,
|
2DA7D04925CA52CB00804E11 /* TimelineBottomLoaderTableViewCell.swift */,
|
||||||
2D32EAAB25CB96DC00C9ED86 /* TimelineMiddleLoaderTableViewCell.swift */,
|
2D32EAAB25CB96DC00C9ED86 /* TimelineMiddleLoaderTableViewCell.swift */,
|
||||||
|
@ -614,6 +616,7 @@
|
||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
DB427DDE25BAA00100D1B89D /* Assets.xcassets */,
|
DB427DDE25BAA00100D1B89D /* Assets.xcassets */,
|
||||||
|
DB118A8125E4B6E600FAB162 /* Preview Assets.xcassets */,
|
||||||
DB3D100F25BAA75E00EAA174 /* Localizable.strings */,
|
DB3D100F25BAA75E00EAA174 /* Localizable.strings */,
|
||||||
DB2B3ABE25E37E15007045F9 /* InfoPlist.strings */,
|
DB2B3ABE25E37E15007045F9 /* InfoPlist.strings */,
|
||||||
);
|
);
|
||||||
|
@ -1069,6 +1072,7 @@
|
||||||
DB3D100D25BAA75E00EAA174 /* Localizable.strings in Resources */,
|
DB3D100D25BAA75E00EAA174 /* Localizable.strings in Resources */,
|
||||||
DB427DDF25BAA00100D1B89D /* Assets.xcassets in Resources */,
|
DB427DDF25BAA00100D1B89D /* Assets.xcassets in Resources */,
|
||||||
DB427DDD25BAA00100D1B89D /* Main.storyboard in Resources */,
|
DB427DDD25BAA00100D1B89D /* Main.storyboard in Resources */,
|
||||||
|
DB118A8225E4B6E600FAB162 /* Preview Assets.xcassets in Resources */,
|
||||||
DB2B3ABC25E37E15007045F9 /* InfoPlist.strings in Resources */,
|
DB2B3ABC25E37E15007045F9 /* InfoPlist.strings in Resources */,
|
||||||
);
|
);
|
||||||
runOnlyForDeploymentPostprocessing = 0;
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
|
@ -1238,7 +1242,7 @@
|
||||||
DB72602725E36A6F00235243 /* MastodonServerRulesViewModel.swift in Sources */,
|
DB72602725E36A6F00235243 /* MastodonServerRulesViewModel.swift in Sources */,
|
||||||
2D38F1F125CD477D00561493 /* HomeTimelineViewModel+LoadMiddleState.swift in Sources */,
|
2D38F1F125CD477D00561493 /* HomeTimelineViewModel+LoadMiddleState.swift in Sources */,
|
||||||
DB45FAD725CA6C76005A8AC7 /* UIBarButtonItem.swift in Sources */,
|
DB45FAD725CA6C76005A8AC7 /* UIBarButtonItem.swift in Sources */,
|
||||||
2D152A8C25C295CC009AA50C /* TimelinePostView.swift in Sources */,
|
2D152A8C25C295CC009AA50C /* StatusView.swift in Sources */,
|
||||||
2D42FF8525C8224F004A627A /* HitTestExpandedButton.swift in Sources */,
|
2D42FF8525C8224F004A627A /* HitTestExpandedButton.swift in Sources */,
|
||||||
DB72601C25E36A2100235243 /* MastodonServerRulesViewController.swift in Sources */,
|
DB72601C25E36A2100235243 /* MastodonServerRulesViewController.swift in Sources */,
|
||||||
2D42FF8F25C8228A004A627A /* UIButton.swift in Sources */,
|
2D42FF8F25C8228A004A627A /* UIButton.swift in Sources */,
|
||||||
|
@ -1279,6 +1283,7 @@
|
||||||
2D38F20825CD491300561493 /* DisposeBagCollectable.swift in Sources */,
|
2D38F20825CD491300561493 /* DisposeBagCollectable.swift in Sources */,
|
||||||
DB0140CF25C42AEE00F9F3CF /* OSLog.swift in Sources */,
|
DB0140CF25C42AEE00F9F3CF /* OSLog.swift in Sources */,
|
||||||
2D76319F25C1521200929FB9 /* TimelineSection.swift in Sources */,
|
2D76319F25C1521200929FB9 /* TimelineSection.swift in Sources */,
|
||||||
|
DB118A8C25E4BFB500FAB162 /* HighlightDimmableButton.swift in Sources */,
|
||||||
DB084B5725CBC56C00F898ED /* Toot.swift in Sources */,
|
DB084B5725CBC56C00F898ED /* Toot.swift in Sources */,
|
||||||
DB0140A825C40C1500F9F3CF /* MastodonPinBasedAuthenticationViewModelNavigationDelegateShim.swift in Sources */,
|
DB0140A825C40C1500F9F3CF /* MastodonPinBasedAuthenticationViewModelNavigationDelegateShim.swift in Sources */,
|
||||||
DB2B3AE925E38850007045F9 /* UIViewPreview.swift in Sources */,
|
DB2B3AE925E38850007045F9 /* UIViewPreview.swift in Sources */,
|
||||||
|
@ -1300,7 +1305,7 @@
|
||||||
DB8AF52E25C13561002E6C99 /* ViewStateStore.swift in Sources */,
|
DB8AF52E25C13561002E6C99 /* ViewStateStore.swift in Sources */,
|
||||||
2DA7D04A25CA52CB00804E11 /* TimelineBottomLoaderTableViewCell.swift in Sources */,
|
2DA7D04A25CA52CB00804E11 /* TimelineBottomLoaderTableViewCell.swift in Sources */,
|
||||||
2D76318325C14E8F00929FB9 /* PublicTimelineViewModel+Diffable.swift in Sources */,
|
2D76318325C14E8F00929FB9 /* PublicTimelineViewModel+Diffable.swift in Sources */,
|
||||||
2D7631A825C1535600929FB9 /* TimelinePostTableViewCell.swift in Sources */,
|
2D7631A825C1535600929FB9 /* StatusTableViewCell.swift in Sources */,
|
||||||
2D76316525C14BD100929FB9 /* PublicTimelineViewController.swift in Sources */,
|
2D76316525C14BD100929FB9 /* PublicTimelineViewController.swift in Sources */,
|
||||||
2D69CFF425CA9E2200C3A1B2 /* LoadMoreConfigurableTableViewContainer.swift in Sources */,
|
2D69CFF425CA9E2200C3A1B2 /* LoadMoreConfigurableTableViewContainer.swift in Sources */,
|
||||||
DB01409625C40B6700F9F3CF /* AuthenticationViewController.swift in Sources */,
|
DB01409625C40B6700F9F3CF /* AuthenticationViewController.swift in Sources */,
|
||||||
|
@ -1310,7 +1315,6 @@
|
||||||
2D32EAAC25CB96DC00C9ED86 /* TimelineMiddleLoaderTableViewCell.swift in Sources */,
|
2D32EAAC25CB96DC00C9ED86 /* TimelineMiddleLoaderTableViewCell.swift in Sources */,
|
||||||
2D5A3D6225CFD9CB002347D6 /* HomeTimelineViewController+DebugAction.swift in Sources */,
|
2D5A3D6225CFD9CB002347D6 /* HomeTimelineViewController+DebugAction.swift in Sources */,
|
||||||
2D38F1FE25CD481700561493 /* StatusProvider.swift in Sources */,
|
2D38F1FE25CD481700561493 /* StatusProvider.swift in Sources */,
|
||||||
2D5A3D1125CF87AA002347D6 /* AvatarBarButtonItem.swift in Sources */,
|
|
||||||
DB45FB0F25CA87D0005A8AC7 /* AuthenticationService.swift in Sources */,
|
DB45FB0F25CA87D0005A8AC7 /* AuthenticationService.swift in Sources */,
|
||||||
);
|
);
|
||||||
runOnlyForDeploymentPostprocessing = 0;
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
|
|
|
@ -21,7 +21,7 @@ extension TimelineSection {
|
||||||
dependency: NeedsDependency,
|
dependency: NeedsDependency,
|
||||||
managedObjectContext: NSManagedObjectContext,
|
managedObjectContext: NSManagedObjectContext,
|
||||||
timestampUpdatePublisher: AnyPublisher<Date, Never>,
|
timestampUpdatePublisher: AnyPublisher<Date, Never>,
|
||||||
timelinePostTableViewCellDelegate: TimelinePostTableViewCellDelegate,
|
timelinePostTableViewCellDelegate: StatusTableViewCellDelegate,
|
||||||
timelineMiddleLoaderTableViewCellDelegate: TimelineMiddleLoaderTableViewCellDelegate?
|
timelineMiddleLoaderTableViewCellDelegate: TimelineMiddleLoaderTableViewCellDelegate?
|
||||||
) -> UITableViewDiffableDataSource<TimelineSection, Item> {
|
) -> UITableViewDiffableDataSource<TimelineSection, Item> {
|
||||||
UITableViewDiffableDataSource(tableView: tableView) { [weak timelinePostTableViewCellDelegate, weak timelineMiddleLoaderTableViewCellDelegate] tableView, indexPath, item -> UITableViewCell? in
|
UITableViewDiffableDataSource(tableView: tableView) { [weak timelinePostTableViewCellDelegate, weak timelineMiddleLoaderTableViewCellDelegate] tableView, indexPath, item -> UITableViewCell? in
|
||||||
|
@ -29,7 +29,7 @@ extension TimelineSection {
|
||||||
|
|
||||||
switch item {
|
switch item {
|
||||||
case .homeTimelineIndex(objectID: let objectID, attribute: _):
|
case .homeTimelineIndex(objectID: let objectID, attribute: _):
|
||||||
let cell = tableView.dequeueReusableCell(withIdentifier: String(describing: TimelinePostTableViewCell.self), for: indexPath) as! TimelinePostTableViewCell
|
let cell = tableView.dequeueReusableCell(withIdentifier: String(describing: StatusTableViewCell.self), for: indexPath) as! StatusTableViewCell
|
||||||
|
|
||||||
// configure cell
|
// configure cell
|
||||||
managedObjectContext.performAndWait {
|
managedObjectContext.performAndWait {
|
||||||
|
@ -39,7 +39,7 @@ extension TimelineSection {
|
||||||
cell.delegate = timelinePostTableViewCellDelegate
|
cell.delegate = timelinePostTableViewCellDelegate
|
||||||
return cell
|
return cell
|
||||||
case .toot(let objectID):
|
case .toot(let objectID):
|
||||||
let cell = tableView.dequeueReusableCell(withIdentifier: String(describing: TimelinePostTableViewCell.self), for: indexPath) as! TimelinePostTableViewCell
|
let cell = tableView.dequeueReusableCell(withIdentifier: String(describing: StatusTableViewCell.self), for: indexPath) as! StatusTableViewCell
|
||||||
let activeMastodonAuthenticationBox = dependency.context.authenticationService.activeMastodonAuthenticationBox.value
|
let activeMastodonAuthenticationBox = dependency.context.authenticationService.activeMastodonAuthenticationBox.value
|
||||||
let requestUserID = activeMastodonAuthenticationBox?.userID ?? ""
|
let requestUserID = activeMastodonAuthenticationBox?.userID ?? ""
|
||||||
// configure cell
|
// configure cell
|
||||||
|
@ -68,21 +68,22 @@ extension TimelineSection {
|
||||||
}
|
}
|
||||||
|
|
||||||
static func configure(
|
static func configure(
|
||||||
cell: TimelinePostTableViewCell,
|
cell: StatusTableViewCell,
|
||||||
timestampUpdatePublisher: AnyPublisher<Date, Never>,
|
timestampUpdatePublisher: AnyPublisher<Date, Never>,
|
||||||
toot: Toot,
|
toot: Toot,
|
||||||
requestUserID: String
|
requestUserID: String
|
||||||
) {
|
) {
|
||||||
|
// set header
|
||||||
|
cell.statusView.headerContainerStackView.isHidden = toot.reblog == nil
|
||||||
|
cell.statusView.headerInfoLabel.text = L10n.Common.Controls.Status.userboosted(toot.author.displayName)
|
||||||
|
|
||||||
// set name username avatar
|
// set name username avatar
|
||||||
cell.timelinePostView.nameLabel.text = toot.author.displayName
|
cell.statusView.nameLabel.text = toot.author.displayName
|
||||||
cell.timelinePostView.usernameLabel.text = "@" + toot.author.username
|
cell.statusView.usernameLabel.text = "@" + toot.author.username
|
||||||
cell.timelinePostView.avatarImageView.af.setImage(
|
cell.statusView.configure(with: AvatarConfigurableViewConfiguration(avatarImageURL: toot.author.avatarImageURL()))
|
||||||
withURL: URL(string: toot.author.avatar)!,
|
|
||||||
placeholderImage: UIImage.placeholder(color: .systemFill),
|
|
||||||
imageTransition: .crossDissolve(0.2)
|
|
||||||
)
|
|
||||||
// set text
|
// set text
|
||||||
cell.timelinePostView.activeTextLabel.config(content: toot.content)
|
cell.statusView.activeTextLabel.config(content: (toot.reblog ?? toot).content)
|
||||||
|
|
||||||
// toolbar
|
// toolbar
|
||||||
let isLike = (toot.reblog ?? toot).favouritedBy.flatMap { $0.contains(where: { $0.id == requestUserID }) } ?? false
|
let isLike = (toot.reblog ?? toot).favouritedBy.flatMap { $0.contains(where: { $0.id == requestUserID }) } ?? false
|
||||||
|
@ -90,15 +91,15 @@ extension TimelineSection {
|
||||||
let count = (toot.reblog ?? toot).favouritesCount.intValue
|
let count = (toot.reblog ?? toot).favouritesCount.intValue
|
||||||
return TimelineSection.formattedNumberTitleForActionButton(count)
|
return TimelineSection.formattedNumberTitleForActionButton(count)
|
||||||
}()
|
}()
|
||||||
cell.timelinePostView.actionToolbarContainer.starButton.setTitle(favoriteCountTitle, for: .normal)
|
cell.statusView.actionToolbarContainer.starButton.setTitle(favoriteCountTitle, for: .normal)
|
||||||
cell.timelinePostView.actionToolbarContainer.isStarButtonHighlight = isLike
|
cell.statusView.actionToolbarContainer.isStarButtonHighlight = isLike
|
||||||
|
|
||||||
// set date
|
// set date
|
||||||
let createdAt = (toot.reblog ?? toot).createdAt
|
let createdAt = (toot.reblog ?? toot).createdAt
|
||||||
cell.timelinePostView.dateLabel.text = createdAt.shortTimeAgoSinceNow
|
cell.statusView.dateLabel.text = createdAt.shortTimeAgoSinceNow
|
||||||
timestampUpdatePublisher
|
timestampUpdatePublisher
|
||||||
.sink { _ in
|
.sink { _ in
|
||||||
cell.timelinePostView.dateLabel.text = createdAt.shortTimeAgoSinceNow
|
cell.statusView.dateLabel.text = createdAt.shortTimeAgoSinceNow
|
||||||
}
|
}
|
||||||
.store(in: &cell.disposeBag)
|
.store(in: &cell.disposeBag)
|
||||||
|
|
||||||
|
@ -115,8 +116,8 @@ extension TimelineSection {
|
||||||
let isLike = targetToot.favouritedBy.flatMap { $0.contains(where: { $0.id == requestUserID }) } ?? false
|
let isLike = targetToot.favouritedBy.flatMap { $0.contains(where: { $0.id == requestUserID }) } ?? false
|
||||||
let favoriteCount = targetToot.favouritesCount.intValue
|
let favoriteCount = targetToot.favouritesCount.intValue
|
||||||
let favoriteCountTitle = TimelineSection.formattedNumberTitleForActionButton(favoriteCount)
|
let favoriteCountTitle = TimelineSection.formattedNumberTitleForActionButton(favoriteCount)
|
||||||
cell.timelinePostView.actionToolbarContainer.starButton.setTitle(favoriteCountTitle, for: .normal)
|
cell.statusView.actionToolbarContainer.starButton.setTitle(favoriteCountTitle, for: .normal)
|
||||||
cell.timelinePostView.actionToolbarContainer.isStarButtonHighlight = isLike
|
cell.statusView.actionToolbarContainer.isStarButtonHighlight = isLike
|
||||||
os_log("%{public}s[%{public}ld], %{public}s: like count label for toot %s did update: %ld", (#file as NSString).lastPathComponent, #line, #function, targetToot.id, favoriteCount)
|
os_log("%{public}s[%{public}ld], %{public}s: like count label for toot %s did update: %ld", (#file as NSString).lastPathComponent, #line, #function, targetToot.id, favoriteCount)
|
||||||
}
|
}
|
||||||
.store(in: &cell.disposeBag)
|
.store(in: &cell.disposeBag)
|
||||||
|
|
|
@ -22,18 +22,18 @@ extension ActiveLabel {
|
||||||
|
|
||||||
switch style {
|
switch style {
|
||||||
case .default:
|
case .default:
|
||||||
// urlMaximumLength = 30
|
|
||||||
font = .preferredFont(forTextStyle: .body)
|
font = .preferredFont(forTextStyle: .body)
|
||||||
textColor = .white
|
textColor = Asset.Colors.Label.primary.color
|
||||||
case .timelineHeaderView:
|
case .timelineHeaderView:
|
||||||
font = .preferredFont(forTextStyle: .footnote)
|
font = .preferredFont(forTextStyle: .footnote)
|
||||||
textColor = .secondaryLabel
|
textColor = .secondaryLabel
|
||||||
}
|
}
|
||||||
|
|
||||||
numberOfLines = 0
|
numberOfLines = 0
|
||||||
mentionColor = UIColor.yellow
|
lineSpacing = 5
|
||||||
hashtagColor = UIColor.blue
|
mentionColor = Asset.Colors.Label.highlight.color
|
||||||
URLColor = UIColor.red
|
hashtagColor = Asset.Colors.Label.highlight.color
|
||||||
|
URLColor = Asset.Colors.Label.highlight.color
|
||||||
text = "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua."
|
text = "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua."
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -43,12 +43,6 @@ extension ActiveLabel {
|
||||||
func config(content: String) {
|
func config(content: String) {
|
||||||
if let parseResult = try? TootContent.parse(toot: content) {
|
if let parseResult = try? TootContent.parse(toot: content) {
|
||||||
activeEntities.removeAll()
|
activeEntities.removeAll()
|
||||||
numberOfLines = 0
|
|
||||||
font = UIFont(name: "SFProText-Regular", size: 16)
|
|
||||||
textColor = .white
|
|
||||||
URLColor = .systemRed
|
|
||||||
mentionColor = .systemGreen
|
|
||||||
hashtagColor = .systemBlue
|
|
||||||
text = parseResult.trimmed
|
text = parseResult.trimmed
|
||||||
activeEntities = parseResult.activeEntities
|
activeEntities = parseResult.activeEntities
|
||||||
}
|
}
|
||||||
|
|
|
@ -28,8 +28,10 @@ internal enum Asset {
|
||||||
internal enum Colors {
|
internal enum Colors {
|
||||||
internal enum Background {
|
internal enum Background {
|
||||||
internal static let onboardingBackground = ColorAsset(name: "Colors/Background/onboarding.background")
|
internal static let onboardingBackground = ColorAsset(name: "Colors/Background/onboarding.background")
|
||||||
|
internal static let secondaryGroupedSystemBackground = ColorAsset(name: "Colors/Background/secondary.grouped.system.background")
|
||||||
internal static let secondarySystemBackground = ColorAsset(name: "Colors/Background/secondary.system.background")
|
internal static let secondarySystemBackground = ColorAsset(name: "Colors/Background/secondary.system.background")
|
||||||
internal static let systemBackground = ColorAsset(name: "Colors/Background/system.background")
|
internal static let systemBackground = ColorAsset(name: "Colors/Background/system.background")
|
||||||
|
internal static let systemGroupedBackground = ColorAsset(name: "Colors/Background/system.grouped.background")
|
||||||
internal static let tertiarySystemBackground = ColorAsset(name: "Colors/Background/tertiary.system.background")
|
internal static let tertiarySystemBackground = ColorAsset(name: "Colors/Background/tertiary.system.background")
|
||||||
}
|
}
|
||||||
internal enum Button {
|
internal enum Button {
|
||||||
|
@ -40,7 +42,7 @@ internal enum Asset {
|
||||||
internal static let plus = ColorAsset(name: "Colors/Icon/plus")
|
internal static let plus = ColorAsset(name: "Colors/Icon/plus")
|
||||||
}
|
}
|
||||||
internal enum Label {
|
internal enum Label {
|
||||||
internal static let black = ColorAsset(name: "Colors/Label/black")
|
internal static let highlight = ColorAsset(name: "Colors/Label/highlight")
|
||||||
internal static let primary = ColorAsset(name: "Colors/Label/primary")
|
internal static let primary = ColorAsset(name: "Colors/Label/primary")
|
||||||
internal static let secondary = ColorAsset(name: "Colors/Label/secondary")
|
internal static let secondary = ColorAsset(name: "Colors/Label/secondary")
|
||||||
}
|
}
|
||||||
|
|
|
@ -45,6 +45,12 @@ internal enum L10n {
|
||||||
/// Take photo
|
/// Take photo
|
||||||
internal static let takePhoto = L10n.tr("Localizable", "Common.Controls.Actions.TakePhoto")
|
internal static let takePhoto = L10n.tr("Localizable", "Common.Controls.Actions.TakePhoto")
|
||||||
}
|
}
|
||||||
|
internal enum Status {
|
||||||
|
/// %@ boosted
|
||||||
|
internal static func userboosted(_ p1: Any) -> String {
|
||||||
|
return L10n.tr("Localizable", "Common.Controls.Status.Userboosted", String(describing: p1))
|
||||||
|
}
|
||||||
|
}
|
||||||
internal enum Timeline {
|
internal enum Timeline {
|
||||||
/// Load More
|
/// Load More
|
||||||
internal static let loadMore = L10n.tr("Localizable", "Common.Controls.Timeline.LoadMore")
|
internal static let loadMore = L10n.tr("Localizable", "Common.Controls.Timeline.LoadMore")
|
||||||
|
|
|
@ -10,28 +10,19 @@ import AlamofireImage
|
||||||
import Kingfisher
|
import Kingfisher
|
||||||
|
|
||||||
protocol AvatarConfigurableView {
|
protocol AvatarConfigurableView {
|
||||||
static var configurableAvatarImageViewSize: CGSize { get }
|
static var configurableAvatarImageSize: CGSize { get }
|
||||||
static var configurableAvatarImageViewBadgeAppearanceStyle: AvatarConfigurableViewConfiguration.BadgeAppearanceStyle { get }
|
static var configurableAvatarImageCornerRadius: CGFloat { get }
|
||||||
var configurableAvatarImageView: UIImageView? { get }
|
var configurableAvatarImageView: UIImageView? { get }
|
||||||
var configurableAvatarButton: UIButton? { get }
|
var configurableAvatarButton: UIButton? { get }
|
||||||
var configurableVerifiedBadgeImageView: UIImageView? { get }
|
func configure(with configuration: AvatarConfigurableViewConfiguration)
|
||||||
func configure(withConfigurationInput input: AvatarConfigurableViewConfiguration.Input)
|
|
||||||
func avatarConfigurableView(_ avatarConfigurableView: AvatarConfigurableView, didFinishConfiguration configuration: AvatarConfigurableViewConfiguration)
|
func avatarConfigurableView(_ avatarConfigurableView: AvatarConfigurableView, didFinishConfiguration configuration: AvatarConfigurableViewConfiguration)
|
||||||
}
|
}
|
||||||
|
|
||||||
extension AvatarConfigurableView {
|
extension AvatarConfigurableView {
|
||||||
|
|
||||||
static var configurableAvatarImageViewBadgeAppearanceStyle: AvatarConfigurableViewConfiguration.BadgeAppearanceStyle { return .mini }
|
public func configure(with configuration: AvatarConfigurableViewConfiguration) {
|
||||||
|
|
||||||
public func configure(withConfigurationInput input: AvatarConfigurableViewConfiguration.Input) {
|
|
||||||
// TODO: set badge
|
|
||||||
configurableVerifiedBadgeImageView?.isHidden = true
|
|
||||||
|
|
||||||
let cornerRadius = Self.configurableAvatarImageViewSize.width * 0.5
|
|
||||||
// let scale = (configurableAvatarImageView ?? configurableAvatarButton)?.window?.screen.scale ?? UIScreen.main.scale
|
|
||||||
|
|
||||||
let placeholderImage: UIImage = {
|
let placeholderImage: UIImage = {
|
||||||
let placeholderImage = input.placeholderImage ?? UIImage.placeholder(size: Self.configurableAvatarImageViewSize, color: .systemFill)
|
let placeholderImage = configuration.placeholderImage ?? UIImage.placeholder(size: Self.configurableAvatarImageSize, color: .systemFill)
|
||||||
return placeholderImage.af.imageRoundedIntoCircle()
|
return placeholderImage.af.imageRoundedIntoCircle()
|
||||||
}()
|
}()
|
||||||
|
|
||||||
|
@ -51,12 +42,11 @@ extension AvatarConfigurableView {
|
||||||
configurableAvatarButton?.layer.cornerCurve = .circular
|
configurableAvatarButton?.layer.cornerCurve = .circular
|
||||||
|
|
||||||
defer {
|
defer {
|
||||||
let configuration = AvatarConfigurableViewConfiguration(input: input)
|
|
||||||
avatarConfigurableView(self, didFinishConfiguration: configuration)
|
avatarConfigurableView(self, didFinishConfiguration: configuration)
|
||||||
}
|
}
|
||||||
|
|
||||||
// set placeholder if no asset
|
// set placeholder if no asset
|
||||||
guard let avatarImageURL = input.avatarImageURL else {
|
guard let avatarImageURL = configuration.avatarImageURL else {
|
||||||
configurableAvatarImageView?.image = placeholderImage
|
configurableAvatarImageView?.image = placeholderImage
|
||||||
configurableAvatarButton?.setImage(placeholderImage, for: .normal)
|
configurableAvatarButton?.setImage(placeholderImage, for: .normal)
|
||||||
return
|
return
|
||||||
|
@ -74,10 +64,10 @@ extension AvatarConfigurableView {
|
||||||
]
|
]
|
||||||
)
|
)
|
||||||
avatarImageView.layer.masksToBounds = true
|
avatarImageView.layer.masksToBounds = true
|
||||||
avatarImageView.layer.cornerRadius = cornerRadius
|
avatarImageView.layer.cornerRadius = Self.configurableAvatarImageCornerRadius
|
||||||
avatarImageView.layer.cornerCurve = .circular
|
avatarImageView.layer.cornerCurve = .circular
|
||||||
default:
|
default:
|
||||||
let filter = ScaledToSizeCircleFilter(size: Self.configurableAvatarImageViewSize)
|
let filter = ScaledToSizeWithRoundedCornersFilter(size: Self.configurableAvatarImageSize, radius: Self.configurableAvatarImageCornerRadius)
|
||||||
avatarImageView.af.setImage(
|
avatarImageView.af.setImage(
|
||||||
withURL: avatarImageURL,
|
withURL: avatarImageURL,
|
||||||
placeholderImage: placeholderImage,
|
placeholderImage: placeholderImage,
|
||||||
|
@ -101,10 +91,10 @@ extension AvatarConfigurableView {
|
||||||
]
|
]
|
||||||
)
|
)
|
||||||
avatarButton.layer.masksToBounds = true
|
avatarButton.layer.masksToBounds = true
|
||||||
avatarButton.layer.cornerRadius = cornerRadius
|
avatarButton.layer.cornerRadius = Self.configurableAvatarImageCornerRadius
|
||||||
avatarButton.layer.cornerCurve = .circular
|
avatarButton.layer.cornerCurve = .continuous
|
||||||
default:
|
default:
|
||||||
let filter = ScaledToSizeCircleFilter(size: Self.configurableAvatarImageViewSize)
|
let filter = ScaledToSizeWithRoundedCornersFilter(size: Self.configurableAvatarImageSize, radius: Self.configurableAvatarImageCornerRadius)
|
||||||
avatarButton.af.setImage(
|
avatarButton.af.setImage(
|
||||||
for: .normal,
|
for: .normal,
|
||||||
url: avatarImageURL,
|
url: avatarImageURL,
|
||||||
|
@ -122,25 +112,12 @@ extension AvatarConfigurableView {
|
||||||
|
|
||||||
struct AvatarConfigurableViewConfiguration {
|
struct AvatarConfigurableViewConfiguration {
|
||||||
|
|
||||||
enum BadgeAppearanceStyle {
|
let avatarImageURL: URL?
|
||||||
case mini
|
let placeholderImage: UIImage?
|
||||||
case normal
|
|
||||||
}
|
|
||||||
|
|
||||||
struct Input {
|
init(avatarImageURL: URL?, placeholderImage: UIImage? = nil) {
|
||||||
let avatarImageURL: URL?
|
self.avatarImageURL = avatarImageURL
|
||||||
let placeholderImage: UIImage?
|
self.placeholderImage = placeholderImage
|
||||||
let blocked: Bool
|
|
||||||
let verified: Bool
|
|
||||||
|
|
||||||
init(avatarImageURL: URL?, placeholderImage: UIImage? = nil, blocked: Bool = false, verified: Bool = false) {
|
|
||||||
self.avatarImageURL = avatarImageURL
|
|
||||||
self.placeholderImage = placeholderImage
|
|
||||||
self.blocked = blocked
|
|
||||||
self.verified = verified
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let input: Input
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,9 +14,9 @@ import MastodonSDK
|
||||||
import ActiveLabel
|
import ActiveLabel
|
||||||
|
|
||||||
// MARK: - ActionToolbarContainerDelegate
|
// MARK: - ActionToolbarContainerDelegate
|
||||||
extension TimelinePostTableViewCellDelegate where Self: StatusProvider {
|
extension StatusTableViewCellDelegate where Self: StatusProvider {
|
||||||
|
|
||||||
func timelinePostTableViewCell(_ cell: TimelinePostTableViewCell, actionToolbarContainer: ActionToolbarContainer, likeButtonDidPressed sender: UIButton) {
|
func statusTableViewCell(_ cell: StatusTableViewCell, actionToolbarContainer: ActionToolbarContainer, likeButtonDidPressed sender: UIButton) {
|
||||||
StatusProviderFacade.responseToStatusLikeAction(provider: self, cell: cell)
|
StatusProviderFacade.responseToStatusLikeAction(provider: self, cell: cell)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,38 @@
|
||||||
|
{
|
||||||
|
"colors" : [
|
||||||
|
{
|
||||||
|
"color" : {
|
||||||
|
"color-space" : "srgb",
|
||||||
|
"components" : {
|
||||||
|
"alpha" : "1.000",
|
||||||
|
"blue" : "255",
|
||||||
|
"green" : "255",
|
||||||
|
"red" : "255"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"idiom" : "universal"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"appearances" : [
|
||||||
|
{
|
||||||
|
"appearance" : "luminosity",
|
||||||
|
"value" : "dark"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"color" : {
|
||||||
|
"color-space" : "srgb",
|
||||||
|
"components" : {
|
||||||
|
"alpha" : "1.000",
|
||||||
|
"blue" : "0x37",
|
||||||
|
"green" : "0x2D",
|
||||||
|
"red" : "0x29"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"idiom" : "universal"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"info" : {
|
||||||
|
"author" : "xcode",
|
||||||
|
"version" : 1
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,38 @@
|
||||||
|
{
|
||||||
|
"colors" : [
|
||||||
|
{
|
||||||
|
"color" : {
|
||||||
|
"color-space" : "srgb",
|
||||||
|
"components" : {
|
||||||
|
"alpha" : "1.000",
|
||||||
|
"blue" : "232",
|
||||||
|
"green" : "225",
|
||||||
|
"red" : "217"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"idiom" : "universal"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"appearances" : [
|
||||||
|
{
|
||||||
|
"appearance" : "luminosity",
|
||||||
|
"value" : "dark"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"color" : {
|
||||||
|
"color-space" : "srgb",
|
||||||
|
"components" : {
|
||||||
|
"alpha" : "1.000",
|
||||||
|
"blue" : "0.169",
|
||||||
|
"green" : "0.141",
|
||||||
|
"red" : "0.125"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"idiom" : "universal"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"info" : {
|
||||||
|
"author" : "xcode",
|
||||||
|
"version" : 1
|
||||||
|
}
|
||||||
|
}
|
|
@ -5,9 +5,9 @@
|
||||||
"color-space" : "srgb",
|
"color-space" : "srgb",
|
||||||
"components" : {
|
"components" : {
|
||||||
"alpha" : "1.000",
|
"alpha" : "1.000",
|
||||||
"blue" : "0",
|
"blue" : "0.851",
|
||||||
"green" : "0",
|
"green" : "0.565",
|
||||||
"red" : "0"
|
"red" : "0.169"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"idiom" : "universal"
|
"idiom" : "universal"
|
|
@ -5,9 +5,27 @@
|
||||||
"color-space" : "srgb",
|
"color-space" : "srgb",
|
||||||
"components" : {
|
"components" : {
|
||||||
"alpha" : "1.000",
|
"alpha" : "1.000",
|
||||||
"blue" : "0xFF",
|
"blue" : "0x00",
|
||||||
"green" : "0xFF",
|
"green" : "0x00",
|
||||||
"red" : "0xFF"
|
"red" : "0x00"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"idiom" : "universal"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"appearances" : [
|
||||||
|
{
|
||||||
|
"appearance" : "luminosity",
|
||||||
|
"value" : "dark"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"color" : {
|
||||||
|
"color-space" : "srgb",
|
||||||
|
"components" : {
|
||||||
|
"alpha" : "1.000",
|
||||||
|
"blue" : "1.000",
|
||||||
|
"green" : "1.000",
|
||||||
|
"red" : "1.000"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"idiom" : "universal"
|
"idiom" : "universal"
|
||||||
|
|
|
@ -4,10 +4,28 @@
|
||||||
"color" : {
|
"color" : {
|
||||||
"color-space" : "srgb",
|
"color-space" : "srgb",
|
||||||
"components" : {
|
"components" : {
|
||||||
"alpha" : "1.000",
|
"alpha" : "0.600",
|
||||||
"blue" : "132",
|
"blue" : "0x43",
|
||||||
"green" : "105",
|
"green" : "0x3C",
|
||||||
"red" : "96"
|
"red" : "0x3C"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"idiom" : "universal"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"appearances" : [
|
||||||
|
{
|
||||||
|
"appearance" : "luminosity",
|
||||||
|
"value" : "dark"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"color" : {
|
||||||
|
"color-space" : "srgb",
|
||||||
|
"components" : {
|
||||||
|
"alpha" : "0.600",
|
||||||
|
"blue" : "0x43",
|
||||||
|
"green" : "0x3C",
|
||||||
|
"red" : "0x3C"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"idiom" : "universal"
|
"idiom" : "universal"
|
||||||
|
|
|
@ -5,9 +5,9 @@
|
||||||
"color-space" : "srgb",
|
"color-space" : "srgb",
|
||||||
"components" : {
|
"components" : {
|
||||||
"alpha" : "1.000",
|
"alpha" : "1.000",
|
||||||
"blue" : "0.851",
|
"blue" : "217",
|
||||||
"green" : "0.565",
|
"green" : "144",
|
||||||
"red" : "0.169"
|
"red" : "43"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"idiom" : "universal"
|
"idiom" : "universal"
|
||||||
|
|
|
@ -0,0 +1,6 @@
|
||||||
|
{
|
||||||
|
"info" : {
|
||||||
|
"author" : "xcode",
|
||||||
|
"version" : 1
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,12 @@
|
||||||
|
{
|
||||||
|
"images" : [
|
||||||
|
{
|
||||||
|
"filename" : "tiraya-adam-QfHEWqPelsc-unsplash.jpg",
|
||||||
|
"idiom" : "universal"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"info" : {
|
||||||
|
"author" : "xcode",
|
||||||
|
"version" : 1
|
||||||
|
}
|
||||||
|
}
|
Binary file not shown.
After Width: | Height: | Size: 89 KiB |
|
@ -13,6 +13,7 @@
|
||||||
"Common.Controls.Actions.SignIn" = "Sign in";
|
"Common.Controls.Actions.SignIn" = "Sign in";
|
||||||
"Common.Controls.Actions.SignUp" = "Sign up";
|
"Common.Controls.Actions.SignUp" = "Sign up";
|
||||||
"Common.Controls.Actions.TakePhoto" = "Take photo";
|
"Common.Controls.Actions.TakePhoto" = "Take photo";
|
||||||
|
"Common.Controls.Status.Userboosted" = "%@ boosted";
|
||||||
"Common.Controls.Timeline.LoadMore" = "Load More";
|
"Common.Controls.Timeline.LoadMore" = "Load More";
|
||||||
"Common.Countable.Photo.Multiple" = "photos";
|
"Common.Countable.Photo.Multiple" = "photos";
|
||||||
"Common.Countable.Photo.Single" = "photo";
|
"Common.Countable.Photo.Single" = "photo";
|
||||||
|
|
|
@ -39,7 +39,7 @@ final class MastodonRegisterViewController: UIViewController, NeedsDependency {
|
||||||
let largeTitleLabel: UILabel = {
|
let largeTitleLabel: UILabel = {
|
||||||
let label = UILabel()
|
let label = UILabel()
|
||||||
label.font = UIFontMetrics(forTextStyle: .largeTitle).scaledFont(for: UIFont.boldSystemFont(ofSize: 34))
|
label.font = UIFontMetrics(forTextStyle: .largeTitle).scaledFont(for: UIFont.boldSystemFont(ofSize: 34))
|
||||||
label.textColor = Asset.Colors.Label.black.color
|
label.textColor = .black
|
||||||
label.text = L10n.Scene.Register.title
|
label.text = L10n.Scene.Register.title
|
||||||
return label
|
return label
|
||||||
}()
|
}()
|
||||||
|
@ -87,7 +87,7 @@ final class MastodonRegisterViewController: UIViewController, NeedsDependency {
|
||||||
let domainLabel: UILabel = {
|
let domainLabel: UILabel = {
|
||||||
let label = UILabel()
|
let label = UILabel()
|
||||||
label.font = .preferredFont(forTextStyle: .headline)
|
label.font = .preferredFont(forTextStyle: .headline)
|
||||||
label.textColor = Asset.Colors.Label.black.color
|
label.textColor = .black
|
||||||
return label
|
return label
|
||||||
}()
|
}()
|
||||||
|
|
||||||
|
|
|
@ -35,7 +35,7 @@ final class MastodonServerRulesViewController: UIViewController, NeedsDependency
|
||||||
let rulesLabel: UILabel = {
|
let rulesLabel: UILabel = {
|
||||||
let label = UILabel()
|
let label = UILabel()
|
||||||
label.font = .preferredFont(forTextStyle: .body)
|
label.font = .preferredFont(forTextStyle: .body)
|
||||||
label.textColor = Asset.Colors.Label.black.color
|
label.textColor = .black
|
||||||
label.text = "Rules"
|
label.text = "Rules"
|
||||||
label.numberOfLines = 0
|
label.numberOfLines = 0
|
||||||
return label
|
return label
|
||||||
|
|
|
@ -15,7 +15,7 @@ import GameplayKit
|
||||||
import MastodonSDK
|
import MastodonSDK
|
||||||
import AlamofireImage
|
import AlamofireImage
|
||||||
|
|
||||||
final class HomeTimelineViewController: UIViewController, NeedsDependency,TimelinePostTableViewCellDelegate {
|
final class HomeTimelineViewController: UIViewController, NeedsDependency,StatusTableViewCellDelegate {
|
||||||
|
|
||||||
weak var context: AppContext! { willSet { precondition(!isViewLoaded) } }
|
weak var context: AppContext! { willSet { precondition(!isViewLoaded) } }
|
||||||
weak var coordinator: SceneCoordinator! { willSet { precondition(!isViewLoaded) } }
|
weak var coordinator: SceneCoordinator! { willSet { precondition(!isViewLoaded) } }
|
||||||
|
@ -27,7 +27,7 @@ final class HomeTimelineViewController: UIViewController, NeedsDependency,Timeli
|
||||||
|
|
||||||
let tableView: UITableView = {
|
let tableView: UITableView = {
|
||||||
let tableView = ControlContainableTableView()
|
let tableView = ControlContainableTableView()
|
||||||
tableView.register(TimelinePostTableViewCell.self, forCellReuseIdentifier: String(describing: TimelinePostTableViewCell.self))
|
tableView.register(StatusTableViewCell.self, forCellReuseIdentifier: String(describing: StatusTableViewCell.self))
|
||||||
tableView.register(TimelineMiddleLoaderTableViewCell.self, forCellReuseIdentifier: String(describing: TimelineMiddleLoaderTableViewCell.self))
|
tableView.register(TimelineMiddleLoaderTableViewCell.self, forCellReuseIdentifier: String(describing: TimelineMiddleLoaderTableViewCell.self))
|
||||||
tableView.register(TimelineBottomLoaderTableViewCell.self, forCellReuseIdentifier: String(describing: TimelineBottomLoaderTableViewCell.self))
|
tableView.register(TimelineBottomLoaderTableViewCell.self, forCellReuseIdentifier: String(describing: TimelineBottomLoaderTableViewCell.self))
|
||||||
tableView.rowHeight = UITableView.automaticDimension
|
tableView.rowHeight = UITableView.automaticDimension
|
||||||
|
@ -51,7 +51,7 @@ extension HomeTimelineViewController {
|
||||||
super.viewDidLoad()
|
super.viewDidLoad()
|
||||||
|
|
||||||
title = L10n.Scene.HomeTimeline.title
|
title = L10n.Scene.HomeTimeline.title
|
||||||
view.backgroundColor = Asset.Colors.Background.systemBackground.color
|
view.backgroundColor = Asset.Colors.Background.systemGroupedBackground.color
|
||||||
navigationItem.leftBarButtonItem = avatarBarButtonItem
|
navigationItem.leftBarButtonItem = avatarBarButtonItem
|
||||||
avatarBarButtonItem.avatarButton.addTarget(self, action: #selector(HomeTimelineViewController.avatarButtonPressed(_:)), for: .touchUpInside)
|
avatarBarButtonItem.avatarButton.addTarget(self, action: #selector(HomeTimelineViewController.avatarButtonPressed(_:)), for: .touchUpInside)
|
||||||
|
|
||||||
|
@ -105,12 +105,10 @@ extension HomeTimelineViewController {
|
||||||
guard let self = self else { return }
|
guard let self = self else { return }
|
||||||
guard let user = activeMastodonAuthentication?.user,
|
guard let user = activeMastodonAuthentication?.user,
|
||||||
let avatarImageURL = user.avatarImageURL() else {
|
let avatarImageURL = user.avatarImageURL() else {
|
||||||
let input = AvatarConfigurableViewConfiguration.Input(avatarImageURL: nil)
|
self.avatarBarButtonItem.configure(with: AvatarConfigurableViewConfiguration(avatarImageURL: nil))
|
||||||
self.avatarBarButtonItem.configure(withConfigurationInput: input)
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
let input = AvatarConfigurableViewConfiguration.Input(avatarImageURL: avatarImageURL)
|
self.avatarBarButtonItem.configure(with: AvatarConfigurableViewConfiguration(avatarImageURL: avatarImageURL))
|
||||||
self.avatarBarButtonItem.configure(withConfigurationInput: input)
|
|
||||||
}
|
}
|
||||||
.store(in: &disposeBag)
|
.store(in: &disposeBag)
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,7 +15,7 @@ extension HomeTimelineViewModel {
|
||||||
func setupDiffableDataSource(
|
func setupDiffableDataSource(
|
||||||
for tableView: UITableView,
|
for tableView: UITableView,
|
||||||
dependency: NeedsDependency,
|
dependency: NeedsDependency,
|
||||||
timelinePostTableViewCellDelegate: TimelinePostTableViewCellDelegate,
|
timelinePostTableViewCellDelegate: StatusTableViewCellDelegate,
|
||||||
timelineMiddleLoaderTableViewCellDelegate: TimelineMiddleLoaderTableViewCellDelegate
|
timelineMiddleLoaderTableViewCellDelegate: TimelineMiddleLoaderTableViewCellDelegate
|
||||||
) {
|
) {
|
||||||
let timestampUpdatePublisher = Timer.publish(every: 1.0, on: .main, in: .common)
|
let timestampUpdatePublisher = Timer.publish(every: 1.0, on: .main, in: .common)
|
||||||
|
|
|
@ -13,7 +13,7 @@ import GameplayKit
|
||||||
import os.log
|
import os.log
|
||||||
import UIKit
|
import UIKit
|
||||||
|
|
||||||
final class PublicTimelineViewController: UIViewController, NeedsDependency, TimelinePostTableViewCellDelegate {
|
final class PublicTimelineViewController: UIViewController, NeedsDependency, StatusTableViewCellDelegate {
|
||||||
weak var context: AppContext! { willSet { precondition(!isViewLoaded) } }
|
weak var context: AppContext! { willSet { precondition(!isViewLoaded) } }
|
||||||
weak var coordinator: SceneCoordinator! { willSet { precondition(!isViewLoaded) } }
|
weak var coordinator: SceneCoordinator! { willSet { precondition(!isViewLoaded) } }
|
||||||
|
|
||||||
|
@ -24,7 +24,7 @@ final class PublicTimelineViewController: UIViewController, NeedsDependency, Tim
|
||||||
|
|
||||||
lazy var tableView: UITableView = {
|
lazy var tableView: UITableView = {
|
||||||
let tableView = UITableView()
|
let tableView = UITableView()
|
||||||
tableView.register(TimelinePostTableViewCell.self, forCellReuseIdentifier: String(describing: TimelinePostTableViewCell.self))
|
tableView.register(StatusTableViewCell.self, forCellReuseIdentifier: String(describing: StatusTableViewCell.self))
|
||||||
tableView.register(TimelineMiddleLoaderTableViewCell.self, forCellReuseIdentifier: String(describing: TimelineMiddleLoaderTableViewCell.self))
|
tableView.register(TimelineMiddleLoaderTableViewCell.self, forCellReuseIdentifier: String(describing: TimelineMiddleLoaderTableViewCell.self))
|
||||||
tableView.register(TimelineBottomLoaderTableViewCell.self, forCellReuseIdentifier: String(describing: TimelineBottomLoaderTableViewCell.self))
|
tableView.register(TimelineBottomLoaderTableViewCell.self, forCellReuseIdentifier: String(describing: TimelineBottomLoaderTableViewCell.self))
|
||||||
tableView.rowHeight = UITableView.automaticDimension
|
tableView.rowHeight = UITableView.automaticDimension
|
||||||
|
@ -42,7 +42,7 @@ extension PublicTimelineViewController {
|
||||||
override func viewDidLoad() {
|
override func viewDidLoad() {
|
||||||
super.viewDidLoad()
|
super.viewDidLoad()
|
||||||
|
|
||||||
view.backgroundColor = Asset.Colors.Background.systemBackground.color
|
view.backgroundColor = Asset.Colors.Background.systemGroupedBackground.color
|
||||||
|
|
||||||
tableView.refreshControl = refreshControl
|
tableView.refreshControl = refreshControl
|
||||||
refreshControl.addTarget(self, action: #selector(PublicTimelineViewController.refreshControlValueChanged(_:)), for: .valueChanged)
|
refreshControl.addTarget(self, action: #selector(PublicTimelineViewController.refreshControlValueChanged(_:)), for: .valueChanged)
|
||||||
|
|
|
@ -14,7 +14,7 @@ extension PublicTimelineViewModel {
|
||||||
func setupDiffableDataSource(
|
func setupDiffableDataSource(
|
||||||
for tableView: UITableView,
|
for tableView: UITableView,
|
||||||
dependency: NeedsDependency,
|
dependency: NeedsDependency,
|
||||||
timelinePostTableViewCellDelegate: TimelinePostTableViewCellDelegate,
|
timelinePostTableViewCellDelegate: StatusTableViewCellDelegate,
|
||||||
timelineMiddleLoaderTableViewCellDelegate: TimelineMiddleLoaderTableViewCellDelegate
|
timelineMiddleLoaderTableViewCellDelegate: TimelineMiddleLoaderTableViewCellDelegate
|
||||||
) {
|
) {
|
||||||
let timestampUpdatePublisher = Timer.publish(every: 1.0, on: .main, in: .common)
|
let timestampUpdatePublisher = Timer.publish(every: 1.0, on: .main, in: .common)
|
||||||
|
|
|
@ -42,7 +42,8 @@ extension AvatarBarButtonItem {
|
||||||
}
|
}
|
||||||
|
|
||||||
extension AvatarBarButtonItem: AvatarConfigurableView {
|
extension AvatarBarButtonItem: AvatarConfigurableView {
|
||||||
static var configurableAvatarImageViewSize: CGSize { return avatarButtonSize }
|
static var configurableAvatarImageSize: CGSize { return avatarButtonSize }
|
||||||
|
static var configurableAvatarImageCornerRadius: CGFloat { return 4 }
|
||||||
var configurableAvatarImageView: UIImageView? { return nil }
|
var configurableAvatarImageView: UIImageView? { return nil }
|
||||||
var configurableAvatarButton: UIButton? { return avatarButton }
|
var configurableAvatarButton: UIButton? { return avatarButton }
|
||||||
var configurableVerifiedBadgeImageView: UIImageView? { return nil }
|
var configurableVerifiedBadgeImageView: UIImageView? { return nil }
|
||||||
|
|
|
@ -0,0 +1,35 @@
|
||||||
|
//
|
||||||
|
// HighlightDimmableButton.swift
|
||||||
|
// Mastodon
|
||||||
|
//
|
||||||
|
// Created by MainasuK Cirno on 2021-2-23.
|
||||||
|
//
|
||||||
|
|
||||||
|
import UIKit
|
||||||
|
|
||||||
|
final class HighlightDimmableButton: UIButton {
|
||||||
|
|
||||||
|
override init(frame: CGRect) {
|
||||||
|
super.init(frame: frame)
|
||||||
|
_init()
|
||||||
|
}
|
||||||
|
|
||||||
|
required init?(coder: NSCoder) {
|
||||||
|
super.init(coder: coder)
|
||||||
|
_init()
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
override var isHighlighted: Bool {
|
||||||
|
didSet {
|
||||||
|
alpha = isHighlighted ? 0.6 : 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
extension HighlightDimmableButton {
|
||||||
|
private func _init() {
|
||||||
|
adjustsImageWhenHighlighted = false
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,257 @@
|
||||||
|
//
|
||||||
|
// StatusView.swift
|
||||||
|
// Mastodon
|
||||||
|
//
|
||||||
|
// Created by sxiaojian on 2021/1/28.
|
||||||
|
//
|
||||||
|
|
||||||
|
import UIKit
|
||||||
|
import AVKit
|
||||||
|
import ActiveLabel
|
||||||
|
import AlamofireImage
|
||||||
|
|
||||||
|
final class StatusView: UIView {
|
||||||
|
|
||||||
|
static let avatarImageSize = CGSize(width: 42, height: 42)
|
||||||
|
static let avatarImageCornerRadius: CGFloat = 4
|
||||||
|
|
||||||
|
let headerContainerStackView = UIStackView()
|
||||||
|
|
||||||
|
let headerIconLabel: UILabel = {
|
||||||
|
let label = UILabel()
|
||||||
|
let attributedString = NSMutableAttributedString()
|
||||||
|
let imageTextAttachment = NSTextAttachment()
|
||||||
|
let font = UIFont.systemFont(ofSize: 13, weight: .medium)
|
||||||
|
let configuration = UIImage.SymbolConfiguration(font: font)
|
||||||
|
imageTextAttachment.image = UIImage(systemName: "arrow.2.squarepath", withConfiguration: configuration)?.withTintColor(Asset.Colors.Label.secondary.color)
|
||||||
|
let imageAttribute = NSAttributedString(attachment: imageTextAttachment)
|
||||||
|
attributedString.append(imageAttribute)
|
||||||
|
label.attributedText = attributedString
|
||||||
|
return label
|
||||||
|
}()
|
||||||
|
|
||||||
|
let headerInfoLabel: UILabel = {
|
||||||
|
let label = UILabel()
|
||||||
|
label.font = UIFontMetrics(forTextStyle: .footnote).scaledFont(for: .systemFont(ofSize: 13, weight: .medium))
|
||||||
|
label.textColor = Asset.Colors.Label.secondary.color
|
||||||
|
label.text = "Bob boosted"
|
||||||
|
return label
|
||||||
|
}()
|
||||||
|
|
||||||
|
let avatarView = UIView()
|
||||||
|
let avatarButton: UIButton = {
|
||||||
|
let button = HighlightDimmableButton(type: .custom)
|
||||||
|
let placeholderImage = UIImage.placeholder(size: avatarImageSize, color: .systemFill)
|
||||||
|
.af.imageRounded(withCornerRadius: StatusView.avatarImageCornerRadius, divideRadiusByImageScale: true)
|
||||||
|
button.setImage(placeholderImage, for: .normal)
|
||||||
|
return button
|
||||||
|
}()
|
||||||
|
|
||||||
|
let visibilityImageView: UIImageView = {
|
||||||
|
let imageView = UIImageView(image: Asset.TootTimeline.global.image.withRenderingMode(.alwaysTemplate))
|
||||||
|
imageView.tintColor = Asset.Colors.Label.secondary.color
|
||||||
|
return imageView
|
||||||
|
}()
|
||||||
|
|
||||||
|
let lockImageView: UIImageView = {
|
||||||
|
let imageview = UIImageView(image: Asset.TootTimeline.textlock.image.withRenderingMode(.alwaysTemplate))
|
||||||
|
imageview.tintColor = Asset.Colors.Label.secondary.color
|
||||||
|
imageview.isHidden = true
|
||||||
|
return imageview
|
||||||
|
}()
|
||||||
|
|
||||||
|
let nameLabel: UILabel = {
|
||||||
|
let label = UILabel()
|
||||||
|
label.font = .systemFont(ofSize: 17, weight: .semibold)
|
||||||
|
label.textColor = Asset.Colors.Label.primary.color
|
||||||
|
label.text = "Alice"
|
||||||
|
return label
|
||||||
|
}()
|
||||||
|
|
||||||
|
let usernameLabel: UILabel = {
|
||||||
|
let label = UILabel()
|
||||||
|
label.font = .systemFont(ofSize: 15, weight: .regular)
|
||||||
|
label.textColor = Asset.Colors.Label.secondary.color
|
||||||
|
label.text = "@alice"
|
||||||
|
return label
|
||||||
|
}()
|
||||||
|
|
||||||
|
let dateLabel: UILabel = {
|
||||||
|
let label = UILabel()
|
||||||
|
label.font = .systemFont(ofSize: 13, weight: .regular)
|
||||||
|
label.textColor = Asset.Colors.Label.secondary.color
|
||||||
|
label.text = "1d"
|
||||||
|
return label
|
||||||
|
}()
|
||||||
|
|
||||||
|
let statusContainerStackView = UIStackView()
|
||||||
|
|
||||||
|
let actionToolbarContainer: ActionToolbarContainer = {
|
||||||
|
let actionToolbarContainer = ActionToolbarContainer()
|
||||||
|
actionToolbarContainer.configure(for: .inline)
|
||||||
|
return actionToolbarContainer
|
||||||
|
}()
|
||||||
|
|
||||||
|
|
||||||
|
let activeTextLabel = ActiveLabel(style: .default)
|
||||||
|
|
||||||
|
override init(frame: CGRect) {
|
||||||
|
super.init(frame: frame)
|
||||||
|
_init()
|
||||||
|
}
|
||||||
|
|
||||||
|
required init?(coder: NSCoder) {
|
||||||
|
super.init(coder: coder)
|
||||||
|
_init()
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
extension StatusView {
|
||||||
|
|
||||||
|
func _init() {
|
||||||
|
// container: [retoot | author | status | action toolbar]
|
||||||
|
let containerStackView = UIStackView()
|
||||||
|
containerStackView.axis = .vertical
|
||||||
|
containerStackView.spacing = 10
|
||||||
|
containerStackView.translatesAutoresizingMaskIntoConstraints = false
|
||||||
|
addSubview(containerStackView)
|
||||||
|
NSLayoutConstraint.activate([
|
||||||
|
containerStackView.topAnchor.constraint(equalTo: topAnchor),
|
||||||
|
containerStackView.leadingAnchor.constraint(equalTo: leadingAnchor),
|
||||||
|
trailingAnchor.constraint(equalTo: containerStackView.trailingAnchor),
|
||||||
|
bottomAnchor.constraint(equalTo: containerStackView.bottomAnchor),
|
||||||
|
])
|
||||||
|
|
||||||
|
// header container: [icon | info]
|
||||||
|
containerStackView.addArrangedSubview(headerContainerStackView)
|
||||||
|
headerContainerStackView.spacing = 4
|
||||||
|
headerContainerStackView.addArrangedSubview(headerIconLabel)
|
||||||
|
headerContainerStackView.addArrangedSubview(headerInfoLabel)
|
||||||
|
headerIconLabel.setContentHuggingPriority(.defaultHigh, for: .horizontal)
|
||||||
|
|
||||||
|
// author container: [avatar | author meta container]
|
||||||
|
let authorContainerStackView = UIStackView()
|
||||||
|
containerStackView.addArrangedSubview(authorContainerStackView)
|
||||||
|
authorContainerStackView.axis = .horizontal
|
||||||
|
authorContainerStackView.spacing = 5
|
||||||
|
|
||||||
|
// avatar
|
||||||
|
avatarView.translatesAutoresizingMaskIntoConstraints = false
|
||||||
|
authorContainerStackView.addArrangedSubview(avatarView)
|
||||||
|
NSLayoutConstraint.activate([
|
||||||
|
avatarView.widthAnchor.constraint(equalToConstant: StatusView.avatarImageSize.width).priority(.required - 1),
|
||||||
|
avatarView.heightAnchor.constraint(equalToConstant: StatusView.avatarImageSize.height).priority(.required - 1),
|
||||||
|
])
|
||||||
|
avatarButton.translatesAutoresizingMaskIntoConstraints = false
|
||||||
|
avatarView.addSubview(avatarButton)
|
||||||
|
NSLayoutConstraint.activate([
|
||||||
|
avatarButton.topAnchor.constraint(equalTo: avatarView.topAnchor),
|
||||||
|
avatarButton.leadingAnchor.constraint(equalTo: avatarView.leadingAnchor),
|
||||||
|
avatarButton.trailingAnchor.constraint(equalTo: avatarView.trailingAnchor),
|
||||||
|
avatarButton.bottomAnchor.constraint(equalTo: avatarView.bottomAnchor),
|
||||||
|
])
|
||||||
|
|
||||||
|
// author meta container: [title container | subtitle container]
|
||||||
|
let authorMetaContainerStackView = UIStackView()
|
||||||
|
authorContainerStackView.addArrangedSubview(authorMetaContainerStackView)
|
||||||
|
authorMetaContainerStackView.axis = .vertical
|
||||||
|
authorMetaContainerStackView.spacing = 4
|
||||||
|
|
||||||
|
// title container: [display name | "·" | date]
|
||||||
|
let titleContainerStackView = UIStackView()
|
||||||
|
authorMetaContainerStackView.addArrangedSubview(titleContainerStackView)
|
||||||
|
titleContainerStackView.axis = .horizontal
|
||||||
|
titleContainerStackView.spacing = 4
|
||||||
|
nameLabel.translatesAutoresizingMaskIntoConstraints = false
|
||||||
|
titleContainerStackView.addArrangedSubview(nameLabel)
|
||||||
|
NSLayoutConstraint.activate([
|
||||||
|
nameLabel.heightAnchor.constraint(equalToConstant: 22).priority(.defaultHigh),
|
||||||
|
])
|
||||||
|
titleContainerStackView.alignment = .firstBaseline
|
||||||
|
let dotLabel: UILabel = {
|
||||||
|
let label = UILabel()
|
||||||
|
label.textColor = Asset.Colors.Label.secondary.color
|
||||||
|
label.font = .systemFont(ofSize: 17)
|
||||||
|
label.text = "·"
|
||||||
|
return label
|
||||||
|
}()
|
||||||
|
titleContainerStackView.addArrangedSubview(dotLabel)
|
||||||
|
titleContainerStackView.addArrangedSubview(dateLabel)
|
||||||
|
nameLabel.setContentHuggingPriority(.defaultHigh + 1, for: .horizontal)
|
||||||
|
dotLabel.setContentHuggingPriority(.defaultHigh + 2, for: .horizontal)
|
||||||
|
dotLabel.setContentCompressionResistancePriority(.required - 2, for: .horizontal)
|
||||||
|
dateLabel.setContentHuggingPriority(.defaultHigh, for: .horizontal)
|
||||||
|
dateLabel.setContentCompressionResistancePriority(.required - 1, for: .horizontal)
|
||||||
|
|
||||||
|
// subtitle container: [username]
|
||||||
|
let subtitleContainerStackView = UIStackView()
|
||||||
|
authorMetaContainerStackView.addArrangedSubview(subtitleContainerStackView)
|
||||||
|
subtitleContainerStackView.axis = .horizontal
|
||||||
|
subtitleContainerStackView.addArrangedSubview(usernameLabel)
|
||||||
|
|
||||||
|
// status container: [status | image / video | audio]
|
||||||
|
containerStackView.addArrangedSubview(statusContainerStackView)
|
||||||
|
statusContainerStackView.axis = .vertical
|
||||||
|
statusContainerStackView.spacing = 10
|
||||||
|
statusContainerStackView.addArrangedSubview(activeTextLabel)
|
||||||
|
activeTextLabel.setContentCompressionResistancePriority(.required - 2, for: .vertical)
|
||||||
|
|
||||||
|
// action toolbar container
|
||||||
|
containerStackView.addArrangedSubview(actionToolbarContainer)
|
||||||
|
actionToolbarContainer.setContentCompressionResistancePriority(.defaultLow, for: .vertical)
|
||||||
|
|
||||||
|
headerContainerStackView.isHidden = true
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
extension StatusView: AvatarConfigurableView {
|
||||||
|
static var configurableAvatarImageSize: CGSize { return Self.avatarImageSize }
|
||||||
|
static var configurableAvatarImageCornerRadius: CGFloat { return 4 }
|
||||||
|
var configurableAvatarImageView: UIImageView? { return nil }
|
||||||
|
var configurableAvatarButton: UIButton? { return avatarButton }
|
||||||
|
var configurableVerifiedBadgeImageView: UIImageView? { nil }
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#if canImport(SwiftUI) && DEBUG
|
||||||
|
import SwiftUI
|
||||||
|
|
||||||
|
struct StatusView_Previews: PreviewProvider {
|
||||||
|
|
||||||
|
static let avatarFlora = UIImage(named: "tiraya-adam-QfHEWqPelsc-unsplash")
|
||||||
|
|
||||||
|
static var previews: some View {
|
||||||
|
Group {
|
||||||
|
UIViewPreview(width: 375) {
|
||||||
|
let statusView = StatusView()
|
||||||
|
statusView.configure(
|
||||||
|
with: AvatarConfigurableViewConfiguration(
|
||||||
|
avatarImageURL: nil,
|
||||||
|
placeholderImage: avatarFlora
|
||||||
|
)
|
||||||
|
)
|
||||||
|
return statusView
|
||||||
|
}
|
||||||
|
.previewLayout(.fixed(width: 375, height: 200))
|
||||||
|
UIViewPreview(width: 375) {
|
||||||
|
let statusView = StatusView()
|
||||||
|
statusView.configure(
|
||||||
|
with: AvatarConfigurableViewConfiguration(
|
||||||
|
avatarImageURL: nil,
|
||||||
|
placeholderImage: avatarFlora
|
||||||
|
)
|
||||||
|
)
|
||||||
|
statusView.headerContainerStackView.isHidden = false
|
||||||
|
return statusView
|
||||||
|
}
|
||||||
|
.previewLayout(.fixed(width: 375, height: 200))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
|
@ -1,163 +0,0 @@
|
||||||
//
|
|
||||||
// TimelinePostView.swift
|
|
||||||
// Mastodon
|
|
||||||
//
|
|
||||||
// Created by sxiaojian on 2021/1/28.
|
|
||||||
//
|
|
||||||
|
|
||||||
import UIKit
|
|
||||||
import AVKit
|
|
||||||
import ActiveLabel
|
|
||||||
|
|
||||||
final class TimelinePostView: UIView {
|
|
||||||
|
|
||||||
static let avatarImageViewSize = CGSize(width: 44, height: 44)
|
|
||||||
|
|
||||||
let avatarImageView: UIImageView = {
|
|
||||||
let imageView = UIImageView()
|
|
||||||
imageView.layer.masksToBounds = true
|
|
||||||
imageView.layer.cornerRadius = avatarImageViewSize.width/2
|
|
||||||
imageView.layer.cornerCurve = .continuous
|
|
||||||
imageView.contentMode = .scaleAspectFill
|
|
||||||
return imageView
|
|
||||||
}()
|
|
||||||
|
|
||||||
let visibilityImageView: UIImageView = {
|
|
||||||
let imageView = UIImageView(image: Asset.TootTimeline.global.image.withRenderingMode(.alwaysTemplate))
|
|
||||||
imageView.tintColor = Asset.Colors.Label.secondary.color
|
|
||||||
return imageView
|
|
||||||
}()
|
|
||||||
|
|
||||||
let lockImageView: UIImageView = {
|
|
||||||
let imageview = UIImageView(image: Asset.TootTimeline.textlock.image.withRenderingMode(.alwaysTemplate))
|
|
||||||
imageview.tintColor = Asset.Colors.Label.secondary.color
|
|
||||||
imageview.isHidden = true
|
|
||||||
return imageview
|
|
||||||
}()
|
|
||||||
|
|
||||||
let nameLabel: UILabel = {
|
|
||||||
let label = UILabel()
|
|
||||||
label.font = UIFont(name: "Roboto-Medium", size: 14)
|
|
||||||
label.textColor = Asset.Colors.Label.primary.color
|
|
||||||
|
|
||||||
label.text = "Alice"
|
|
||||||
return label
|
|
||||||
}()
|
|
||||||
|
|
||||||
let usernameLabel: UILabel = {
|
|
||||||
let label = UILabel()
|
|
||||||
label.textColor = Asset.Colors.Label.secondary.color
|
|
||||||
label.font = UIFont(name: "Roboto-Regular", size: 14)
|
|
||||||
label.text = "@alice"
|
|
||||||
return label
|
|
||||||
}()
|
|
||||||
|
|
||||||
let dateLabel: UILabel = {
|
|
||||||
let label = UILabel()
|
|
||||||
label.font = UIFont(name: "Roboto-Regular", size: 14)
|
|
||||||
label.textAlignment = UIApplication.shared.userInterfaceLayoutDirection == .rightToLeft ? .left : .right
|
|
||||||
label.textColor = Asset.Colors.Label.secondary.color
|
|
||||||
label.text = "1d"
|
|
||||||
return label
|
|
||||||
}()
|
|
||||||
|
|
||||||
let actionToolbarContainer: ActionToolbarContainer = {
|
|
||||||
let actionToolbarContainer = ActionToolbarContainer()
|
|
||||||
actionToolbarContainer.configure(for: .inline)
|
|
||||||
return actionToolbarContainer
|
|
||||||
}()
|
|
||||||
|
|
||||||
let mainContainerStackView = UIStackView()
|
|
||||||
|
|
||||||
let activeTextLabel = ActiveLabel(style: .default)
|
|
||||||
|
|
||||||
override init(frame: CGRect) {
|
|
||||||
super.init(frame: frame)
|
|
||||||
_init()
|
|
||||||
}
|
|
||||||
|
|
||||||
required init?(coder: NSCoder) {
|
|
||||||
super.init(coder: coder)
|
|
||||||
_init()
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
extension TimelinePostView {
|
|
||||||
|
|
||||||
func _init() {
|
|
||||||
// container: [retoot | post]
|
|
||||||
let containerStackView = UIStackView()
|
|
||||||
containerStackView.axis = .vertical
|
|
||||||
containerStackView.spacing = 8
|
|
||||||
//containerStackView.alignment = .top
|
|
||||||
containerStackView.translatesAutoresizingMaskIntoConstraints = false
|
|
||||||
addSubview(containerStackView)
|
|
||||||
NSLayoutConstraint.activate([
|
|
||||||
containerStackView.topAnchor.constraint(equalTo: topAnchor),
|
|
||||||
containerStackView.leadingAnchor.constraint(equalTo: leadingAnchor),
|
|
||||||
trailingAnchor.constraint(equalTo: containerStackView.trailingAnchor),
|
|
||||||
bottomAnchor.constraint(equalTo: containerStackView.bottomAnchor),
|
|
||||||
])
|
|
||||||
|
|
||||||
// post container: [user avatar | toot container]
|
|
||||||
let postContainerStackView = UIStackView()
|
|
||||||
containerStackView.addArrangedSubview(postContainerStackView)
|
|
||||||
postContainerStackView.axis = .horizontal
|
|
||||||
postContainerStackView.spacing = 10
|
|
||||||
postContainerStackView.alignment = .top
|
|
||||||
|
|
||||||
// user avatar
|
|
||||||
avatarImageView.translatesAutoresizingMaskIntoConstraints = false
|
|
||||||
postContainerStackView.addArrangedSubview(avatarImageView)
|
|
||||||
NSLayoutConstraint.activate([
|
|
||||||
avatarImageView.widthAnchor.constraint(equalToConstant: TimelinePostView.avatarImageViewSize.width).priority(.required - 1),
|
|
||||||
avatarImageView.heightAnchor.constraint(equalToConstant: TimelinePostView.avatarImageViewSize.height).priority(.required - 1),
|
|
||||||
])
|
|
||||||
|
|
||||||
// toot container: [user meta container | main container | action toolbar]
|
|
||||||
let tootContainerStackView = UIStackView()
|
|
||||||
postContainerStackView.addArrangedSubview(tootContainerStackView)
|
|
||||||
tootContainerStackView.axis = .vertical
|
|
||||||
tootContainerStackView.spacing = 2
|
|
||||||
|
|
||||||
// user meta container: [name | lock | username | visiablity | date ]
|
|
||||||
let userMetaContainerStackView = UIStackView()
|
|
||||||
tootContainerStackView.addArrangedSubview(userMetaContainerStackView)
|
|
||||||
userMetaContainerStackView.axis = .horizontal
|
|
||||||
userMetaContainerStackView.alignment = .center
|
|
||||||
userMetaContainerStackView.spacing = 6
|
|
||||||
userMetaContainerStackView.addArrangedSubview(nameLabel)
|
|
||||||
userMetaContainerStackView.addArrangedSubview(lockImageView)
|
|
||||||
userMetaContainerStackView.addArrangedSubview(usernameLabel)
|
|
||||||
userMetaContainerStackView.addArrangedSubview(visibilityImageView)
|
|
||||||
userMetaContainerStackView.addArrangedSubview(dateLabel)
|
|
||||||
nameLabel.setContentHuggingPriority(.defaultHigh + 10, for: .horizontal)
|
|
||||||
nameLabel.setContentCompressionResistancePriority(.defaultHigh, for: .horizontal)
|
|
||||||
lockImageView.setContentCompressionResistancePriority(.defaultHigh + 1, for: .horizontal)
|
|
||||||
lockImageView.setContentHuggingPriority(.defaultHigh + 1, for: .horizontal)
|
|
||||||
usernameLabel.setContentHuggingPriority(.defaultHigh - 3, for: .horizontal)
|
|
||||||
usernameLabel.setContentCompressionResistancePriority(.defaultHigh - 1, for: .horizontal)
|
|
||||||
visibilityImageView.setContentCompressionResistancePriority(.defaultHigh + 1, for: .horizontal)
|
|
||||||
visibilityImageView.setContentHuggingPriority(.defaultHigh + 1, for: .horizontal)
|
|
||||||
dateLabel.setContentHuggingPriority(.defaultHigh, for: .horizontal)
|
|
||||||
dateLabel.setContentCompressionResistancePriority(.required - 2, for: .horizontal)
|
|
||||||
|
|
||||||
// main container: [text | image / video | quote | geo]
|
|
||||||
tootContainerStackView.addArrangedSubview(mainContainerStackView)
|
|
||||||
mainContainerStackView.axis = .vertical
|
|
||||||
mainContainerStackView.spacing = 8
|
|
||||||
activeTextLabel.translatesAutoresizingMaskIntoConstraints = false
|
|
||||||
mainContainerStackView.addArrangedSubview(activeTextLabel)
|
|
||||||
|
|
||||||
activeTextLabel.setContentCompressionResistancePriority(.required - 2, for: .vertical)
|
|
||||||
|
|
||||||
// action toolbar
|
|
||||||
actionToolbarContainer.translatesAutoresizingMaskIntoConstraints = false
|
|
||||||
tootContainerStackView.addArrangedSubview(actionToolbarContainer)
|
|
||||||
actionToolbarContainer.setContentCompressionResistancePriority(.defaultLow, for: .vertical)
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
|
@ -0,0 +1,93 @@
|
||||||
|
//
|
||||||
|
// StatusTableViewCell.swift
|
||||||
|
// Mastodon
|
||||||
|
//
|
||||||
|
// Created by sxiaojian on 2021/1/27.
|
||||||
|
//
|
||||||
|
|
||||||
|
import os.log
|
||||||
|
import UIKit
|
||||||
|
import AVKit
|
||||||
|
import Combine
|
||||||
|
|
||||||
|
|
||||||
|
protocol StatusTableViewCellDelegate: class {
|
||||||
|
func statusTableViewCell(_ cell: StatusTableViewCell, actionToolbarContainer: ActionToolbarContainer, likeButtonDidPressed sender: UIButton)
|
||||||
|
}
|
||||||
|
|
||||||
|
final class StatusTableViewCell: UITableViewCell {
|
||||||
|
|
||||||
|
|
||||||
|
weak var delegate: StatusTableViewCellDelegate?
|
||||||
|
|
||||||
|
var disposeBag = Set<AnyCancellable>()
|
||||||
|
var observations = Set<NSKeyValueObservation>()
|
||||||
|
|
||||||
|
let statusView = StatusView()
|
||||||
|
|
||||||
|
override func prepareForReuse() {
|
||||||
|
super.prepareForReuse()
|
||||||
|
disposeBag.removeAll()
|
||||||
|
observations.removeAll()
|
||||||
|
}
|
||||||
|
|
||||||
|
override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
|
||||||
|
super.init(style: style, reuseIdentifier: reuseIdentifier)
|
||||||
|
_init()
|
||||||
|
}
|
||||||
|
|
||||||
|
required init?(coder: NSCoder) {
|
||||||
|
super.init(coder: coder)
|
||||||
|
_init()
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
extension StatusTableViewCell {
|
||||||
|
|
||||||
|
private func _init() {
|
||||||
|
selectionStyle = .none
|
||||||
|
backgroundColor = Asset.Colors.Background.secondaryGroupedSystemBackground.color
|
||||||
|
|
||||||
|
statusView.translatesAutoresizingMaskIntoConstraints = false
|
||||||
|
contentView.addSubview(statusView)
|
||||||
|
NSLayoutConstraint.activate([
|
||||||
|
statusView.topAnchor.constraint(equalTo: contentView.topAnchor, constant: 20),
|
||||||
|
statusView.leadingAnchor.constraint(equalTo: contentView.readableContentGuide.leadingAnchor),
|
||||||
|
contentView.readableContentGuide.trailingAnchor.constraint(equalTo: statusView.trailingAnchor),
|
||||||
|
])
|
||||||
|
|
||||||
|
let bottomPaddingView = UIView()
|
||||||
|
bottomPaddingView.translatesAutoresizingMaskIntoConstraints = false
|
||||||
|
contentView.addSubview(bottomPaddingView)
|
||||||
|
NSLayoutConstraint.activate([
|
||||||
|
bottomPaddingView.topAnchor.constraint(equalTo: statusView.bottomAnchor, constant: 10),
|
||||||
|
bottomPaddingView.leadingAnchor.constraint(equalTo: contentView.leadingAnchor),
|
||||||
|
bottomPaddingView.trailingAnchor.constraint(equalTo: contentView.trailingAnchor),
|
||||||
|
bottomPaddingView.bottomAnchor.constraint(equalTo: contentView.bottomAnchor),
|
||||||
|
bottomPaddingView.heightAnchor.constraint(equalToConstant: 10).priority(.defaultHigh),
|
||||||
|
])
|
||||||
|
|
||||||
|
statusView.actionToolbarContainer.delegate = self
|
||||||
|
bottomPaddingView.backgroundColor = Asset.Colors.Background.systemGroupedBackground.color
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
// MARK: - ActionToolbarContainerDelegate
|
||||||
|
extension StatusTableViewCell: ActionToolbarContainerDelegate {
|
||||||
|
func actionToolbarContainer(_ actionToolbarContainer: ActionToolbarContainer, replayButtonDidPressed sender: UIButton) {
|
||||||
|
|
||||||
|
}
|
||||||
|
func actionToolbarContainer(_ actionToolbarContainer: ActionToolbarContainer, retootButtonDidPressed sender: UIButton) {
|
||||||
|
|
||||||
|
}
|
||||||
|
func actionToolbarContainer(_ actionToolbarContainer: ActionToolbarContainer, starButtonDidPressed sender: UIButton) {
|
||||||
|
delegate?.statusTableViewCell(self, actionToolbarContainer: actionToolbarContainer, likeButtonDidPressed: sender)
|
||||||
|
}
|
||||||
|
func actionToolbarContainer(_ actionToolbarContainer: ActionToolbarContainer, bookmarkButtonDidPressed sender: UIButton) {
|
||||||
|
|
||||||
|
}
|
||||||
|
func actionToolbarContainer(_ actionToolbarContainer: ActionToolbarContainer, moreButtonDidPressed sender: UIButton) {
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,86 +0,0 @@
|
||||||
//
|
|
||||||
// TimelinePostTableViewCell.swift
|
|
||||||
// Mastodon
|
|
||||||
//
|
|
||||||
// Created by sxiaojian on 2021/1/27.
|
|
||||||
//
|
|
||||||
|
|
||||||
import os.log
|
|
||||||
import UIKit
|
|
||||||
import AVKit
|
|
||||||
import Combine
|
|
||||||
|
|
||||||
|
|
||||||
protocol TimelinePostTableViewCellDelegate: class {
|
|
||||||
func timelinePostTableViewCell(_ cell: TimelinePostTableViewCell, actionToolbarContainer: ActionToolbarContainer, likeButtonDidPressed sender: UIButton)
|
|
||||||
}
|
|
||||||
|
|
||||||
final class TimelinePostTableViewCell: UITableViewCell {
|
|
||||||
|
|
||||||
static let verticalMargin: CGFloat = 16 // without retoot indicator
|
|
||||||
static let verticalMarginAlt: CGFloat = 8 // with retoot indicator
|
|
||||||
|
|
||||||
weak var delegate: TimelinePostTableViewCellDelegate?
|
|
||||||
|
|
||||||
var disposeBag = Set<AnyCancellable>()
|
|
||||||
var observations = Set<NSKeyValueObservation>()
|
|
||||||
|
|
||||||
let timelinePostView = TimelinePostView()
|
|
||||||
|
|
||||||
var timelinePostViewTopLayoutConstraint: NSLayoutConstraint!
|
|
||||||
|
|
||||||
override func prepareForReuse() {
|
|
||||||
super.prepareForReuse()
|
|
||||||
disposeBag.removeAll()
|
|
||||||
observations.removeAll()
|
|
||||||
}
|
|
||||||
|
|
||||||
override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
|
|
||||||
super.init(style: style, reuseIdentifier: reuseIdentifier)
|
|
||||||
_init()
|
|
||||||
}
|
|
||||||
|
|
||||||
required init?(coder: NSCoder) {
|
|
||||||
super.init(coder: coder)
|
|
||||||
_init()
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
extension TimelinePostTableViewCell {
|
|
||||||
|
|
||||||
private func _init() {
|
|
||||||
self.backgroundColor = Asset.Colors.Background.secondarySystemBackground.color
|
|
||||||
self.selectionStyle = .none
|
|
||||||
timelinePostView.translatesAutoresizingMaskIntoConstraints = false
|
|
||||||
timelinePostViewTopLayoutConstraint = timelinePostView.topAnchor.constraint(equalTo: contentView.topAnchor, constant: TimelinePostTableViewCell.verticalMargin)
|
|
||||||
contentView.addSubview(timelinePostView)
|
|
||||||
NSLayoutConstraint.activate([
|
|
||||||
timelinePostViewTopLayoutConstraint,
|
|
||||||
timelinePostView.leadingAnchor.constraint(equalTo: contentView.readableContentGuide.leadingAnchor),
|
|
||||||
contentView.readableContentGuide.trailingAnchor.constraint(equalTo: timelinePostView.trailingAnchor),
|
|
||||||
contentView.bottomAnchor.constraint(equalTo: timelinePostView.bottomAnchor), // use action toolbar margin
|
|
||||||
])
|
|
||||||
|
|
||||||
timelinePostView.actionToolbarContainer.delegate = self
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
// MARK: - ActionToolbarContainerDelegate
|
|
||||||
extension TimelinePostTableViewCell: ActionToolbarContainerDelegate {
|
|
||||||
func actionToolbarContainer(_ actionToolbarContainer: ActionToolbarContainer, replayButtonDidPressed sender: UIButton) {
|
|
||||||
|
|
||||||
}
|
|
||||||
func actionToolbarContainer(_ actionToolbarContainer: ActionToolbarContainer, retootButtonDidPressed sender: UIButton) {
|
|
||||||
|
|
||||||
}
|
|
||||||
func actionToolbarContainer(_ actionToolbarContainer: ActionToolbarContainer, starButtonDidPressed sender: UIButton) {
|
|
||||||
delegate?.timelinePostTableViewCell(self, actionToolbarContainer: actionToolbarContainer, likeButtonDidPressed: sender)
|
|
||||||
}
|
|
||||||
func actionToolbarContainer(_ actionToolbarContainer: ActionToolbarContainer, bookmarkButtonDidPressed sender: UIButton) {
|
|
||||||
|
|
||||||
}
|
|
||||||
func actionToolbarContainer(_ actionToolbarContainer: ActionToolbarContainer, moreButtonDidPressed sender: UIButton) {
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -12,7 +12,6 @@ protocol ActionToolbarContainerDelegate: class {
|
||||||
func actionToolbarContainer(_ actionToolbarContainer: ActionToolbarContainer, replayButtonDidPressed sender: UIButton)
|
func actionToolbarContainer(_ actionToolbarContainer: ActionToolbarContainer, replayButtonDidPressed sender: UIButton)
|
||||||
func actionToolbarContainer(_ actionToolbarContainer: ActionToolbarContainer, retootButtonDidPressed sender: UIButton)
|
func actionToolbarContainer(_ actionToolbarContainer: ActionToolbarContainer, retootButtonDidPressed sender: UIButton)
|
||||||
func actionToolbarContainer(_ actionToolbarContainer: ActionToolbarContainer, starButtonDidPressed sender: UIButton)
|
func actionToolbarContainer(_ actionToolbarContainer: ActionToolbarContainer, starButtonDidPressed sender: UIButton)
|
||||||
func actionToolbarContainer(_ actionToolbarContainer: ActionToolbarContainer, bookmarkButtonDidPressed sender: UIButton)
|
|
||||||
func actionToolbarContainer(_ actionToolbarContainer: ActionToolbarContainer, moreButtonDidPressed sender: UIButton)
|
func actionToolbarContainer(_ actionToolbarContainer: ActionToolbarContainer, moreButtonDidPressed sender: UIButton)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -23,7 +22,6 @@ final class ActionToolbarContainer: UIView {
|
||||||
let replyButton = HitTestExpandedButton()
|
let replyButton = HitTestExpandedButton()
|
||||||
let retootButton = HitTestExpandedButton()
|
let retootButton = HitTestExpandedButton()
|
||||||
let starButton = HitTestExpandedButton()
|
let starButton = HitTestExpandedButton()
|
||||||
let bookmartButton = HitTestExpandedButton()
|
|
||||||
let moreButton = HitTestExpandedButton()
|
let moreButton = HitTestExpandedButton()
|
||||||
|
|
||||||
var isStarButtonHighlight: Bool = false {
|
var isStarButtonHighlight: Bool = false {
|
||||||
|
@ -62,7 +60,6 @@ extension ActionToolbarContainer {
|
||||||
replyButton.addTarget(self, action: #selector(ActionToolbarContainer.replyButtonDidPressed(_:)), for: .touchUpInside)
|
replyButton.addTarget(self, action: #selector(ActionToolbarContainer.replyButtonDidPressed(_:)), for: .touchUpInside)
|
||||||
retootButton.addTarget(self, action: #selector(ActionToolbarContainer.retootButtonDidPressed(_:)), for: .touchUpInside)
|
retootButton.addTarget(self, action: #selector(ActionToolbarContainer.retootButtonDidPressed(_:)), for: .touchUpInside)
|
||||||
starButton.addTarget(self, action: #selector(ActionToolbarContainer.starButtonDidPressed(_:)), for: .touchUpInside)
|
starButton.addTarget(self, action: #selector(ActionToolbarContainer.starButtonDidPressed(_:)), for: .touchUpInside)
|
||||||
bookmartButton.addTarget(self, action: #selector(ActionToolbarContainer.bookmarkButtonDidPressed(_:)), for: .touchUpInside)
|
|
||||||
moreButton.addTarget(self, action: #selector(ActionToolbarContainer.moreButtonDidPressed(_:)), for: .touchUpInside)
|
moreButton.addTarget(self, action: #selector(ActionToolbarContainer.moreButtonDidPressed(_:)), for: .touchUpInside)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -93,25 +90,29 @@ extension ActionToolbarContainer {
|
||||||
subview.removeFromSuperview()
|
subview.removeFromSuperview()
|
||||||
}
|
}
|
||||||
|
|
||||||
let buttons = [replyButton, retootButton, starButton,bookmartButton, moreButton]
|
let buttons = [replyButton, retootButton, starButton, moreButton]
|
||||||
buttons.forEach { button in
|
buttons.forEach { button in
|
||||||
button.tintColor = Asset.Colors.Label.secondary.color
|
button.tintColor = UIColor.black.withAlphaComponent(0.6)
|
||||||
button.titleLabel?.font = .monospacedDigitSystemFont(ofSize: 12, weight: .regular)
|
button.titleLabel?.font = .monospacedDigitSystemFont(ofSize: 12, weight: .regular)
|
||||||
button.setTitle("", for: .normal)
|
button.setTitle("", for: .normal)
|
||||||
button.setTitleColor(.secondaryLabel, for: .normal)
|
button.setTitleColor(.secondaryLabel, for: .normal)
|
||||||
button.setInsets(forContentPadding: .zero, imageTitlePadding: style.buttonTitleImagePadding)
|
button.setInsets(forContentPadding: .zero, imageTitlePadding: style.buttonTitleImagePadding)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let replyImage = UIImage(systemName: "arrowshape.turn.up.left.fill", withConfiguration: UIImage.SymbolConfiguration(pointSize: 17, weight: .ultraLight))!.withRenderingMode(.alwaysTemplate)
|
||||||
|
let reblogImage = UIImage(systemName: "arrow.2.squarepath", withConfiguration: UIImage.SymbolConfiguration(pointSize: 17, weight: .bold))!.withRenderingMode(.alwaysTemplate)
|
||||||
|
let starImage = UIImage(systemName: "star.fill", withConfiguration: UIImage.SymbolConfiguration(pointSize: 17, weight: .bold))!.withRenderingMode(.alwaysTemplate)
|
||||||
|
let moreImage = UIImage(systemName: "ellipsis", withConfiguration: UIImage.SymbolConfiguration(pointSize: 17, weight: .bold))!.withRenderingMode(.alwaysTemplate)
|
||||||
|
|
||||||
switch style {
|
switch style {
|
||||||
case .inline:
|
case .inline:
|
||||||
buttons.forEach { button in
|
buttons.forEach { button in
|
||||||
button.contentHorizontalAlignment = .leading
|
button.contentHorizontalAlignment = .leading
|
||||||
}
|
}
|
||||||
replyButton.setImage(Asset.ToolBar.reply.image.withRenderingMode(.alwaysTemplate), for: .normal)
|
replyButton.setImage(replyImage, for: .normal)
|
||||||
retootButton.setImage(Asset.ToolBar.retoot.image.withRenderingMode(.alwaysTemplate), for: .normal)
|
retootButton.setImage(reblogImage, for: .normal)
|
||||||
starButton.setImage(Asset.ToolBar.star.image.withRenderingMode(.alwaysTemplate), for: .normal)
|
starButton.setImage(starImage, for: .normal)
|
||||||
bookmartButton.setImage(Asset.ToolBar.bookmark.image.withRenderingMode(.alwaysTemplate), for: .normal)
|
moreButton.setImage(moreImage, for: .normal)
|
||||||
moreButton.setImage(Asset.ToolBar.more.image.withRenderingMode(.alwaysTemplate), for: .normal)
|
|
||||||
|
|
||||||
container.axis = .horizontal
|
container.axis = .horizontal
|
||||||
container.distribution = .fill
|
container.distribution = .fill
|
||||||
|
@ -119,22 +120,18 @@ extension ActionToolbarContainer {
|
||||||
replyButton.translatesAutoresizingMaskIntoConstraints = false
|
replyButton.translatesAutoresizingMaskIntoConstraints = false
|
||||||
retootButton.translatesAutoresizingMaskIntoConstraints = false
|
retootButton.translatesAutoresizingMaskIntoConstraints = false
|
||||||
starButton.translatesAutoresizingMaskIntoConstraints = false
|
starButton.translatesAutoresizingMaskIntoConstraints = false
|
||||||
bookmartButton.translatesAutoresizingMaskIntoConstraints = false
|
|
||||||
moreButton.translatesAutoresizingMaskIntoConstraints = false
|
moreButton.translatesAutoresizingMaskIntoConstraints = false
|
||||||
container.addArrangedSubview(replyButton)
|
container.addArrangedSubview(replyButton)
|
||||||
container.addArrangedSubview(retootButton)
|
container.addArrangedSubview(retootButton)
|
||||||
container.addArrangedSubview(starButton)
|
container.addArrangedSubview(starButton)
|
||||||
container.addArrangedSubview(bookmartButton)
|
|
||||||
container.addArrangedSubview(moreButton)
|
container.addArrangedSubview(moreButton)
|
||||||
NSLayoutConstraint.activate([
|
NSLayoutConstraint.activate([
|
||||||
replyButton.heightAnchor.constraint(equalToConstant: 40).priority(.defaultHigh),
|
replyButton.heightAnchor.constraint(equalToConstant: 44).priority(.defaultHigh),
|
||||||
replyButton.heightAnchor.constraint(equalTo: retootButton.heightAnchor).priority(.defaultHigh),
|
replyButton.heightAnchor.constraint(equalTo: retootButton.heightAnchor).priority(.defaultHigh),
|
||||||
replyButton.heightAnchor.constraint(equalTo: starButton.heightAnchor).priority(.defaultHigh),
|
replyButton.heightAnchor.constraint(equalTo: starButton.heightAnchor).priority(.defaultHigh),
|
||||||
replyButton.heightAnchor.constraint(equalTo: moreButton.heightAnchor).priority(.defaultHigh),
|
replyButton.heightAnchor.constraint(equalTo: moreButton.heightAnchor).priority(.defaultHigh),
|
||||||
replyButton.heightAnchor.constraint(equalTo: bookmartButton.heightAnchor).priority(.defaultHigh),
|
|
||||||
replyButton.widthAnchor.constraint(equalTo: retootButton.widthAnchor).priority(.defaultHigh),
|
replyButton.widthAnchor.constraint(equalTo: retootButton.widthAnchor).priority(.defaultHigh),
|
||||||
replyButton.widthAnchor.constraint(equalTo: starButton.widthAnchor).priority(.defaultHigh),
|
replyButton.widthAnchor.constraint(equalTo: starButton.widthAnchor).priority(.defaultHigh),
|
||||||
replyButton.widthAnchor.constraint(equalTo: bookmartButton.widthAnchor).priority(.defaultHigh),
|
|
||||||
])
|
])
|
||||||
moreButton.setContentHuggingPriority(.defaultHigh, for: .horizontal)
|
moreButton.setContentHuggingPriority(.defaultHigh, for: .horizontal)
|
||||||
moreButton.setContentCompressionResistancePriority(.defaultHigh, for: .horizontal)
|
moreButton.setContentCompressionResistancePriority(.defaultHigh, for: .horizontal)
|
||||||
|
@ -143,10 +140,9 @@ extension ActionToolbarContainer {
|
||||||
buttons.forEach { button in
|
buttons.forEach { button in
|
||||||
button.contentHorizontalAlignment = .center
|
button.contentHorizontalAlignment = .center
|
||||||
}
|
}
|
||||||
replyButton.setImage(Asset.ToolBar.reply.image.withRenderingMode(.alwaysTemplate), for: .normal)
|
replyButton.setImage(replyImage, for: .normal)
|
||||||
retootButton.setImage(Asset.ToolBar.retoot.image.withRenderingMode(.alwaysTemplate), for: .normal)
|
retootButton.setImage(reblogImage, for: .normal)
|
||||||
starButton.setImage(Asset.ToolBar.bookmark.image.withRenderingMode(.alwaysTemplate), for: .normal)
|
starButton.setImage(starImage, for: .normal)
|
||||||
bookmartButton.setImage(Asset.ToolBar.bookmark.image.withRenderingMode(.alwaysTemplate), for: .normal)
|
|
||||||
|
|
||||||
container.axis = .horizontal
|
container.axis = .horizontal
|
||||||
container.spacing = 8
|
container.spacing = 8
|
||||||
|
@ -155,7 +151,6 @@ extension ActionToolbarContainer {
|
||||||
container.addArrangedSubview(replyButton)
|
container.addArrangedSubview(replyButton)
|
||||||
container.addArrangedSubview(retootButton)
|
container.addArrangedSubview(retootButton)
|
||||||
container.addArrangedSubview(starButton)
|
container.addArrangedSubview(starButton)
|
||||||
container.addArrangedSubview(bookmartButton)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -165,7 +160,7 @@ extension ActionToolbarContainer {
|
||||||
}
|
}
|
||||||
|
|
||||||
private func isStarButtonHighlightStateDidChange(to isHighlight: Bool) {
|
private func isStarButtonHighlightStateDidChange(to isHighlight: Bool) {
|
||||||
let tintColor = isHighlight ? Asset.Colors.systemOrange.color : Asset.Colors.Label.secondary.color
|
let tintColor = isHighlight ? Asset.Colors.systemOrange.color : UIColor.black.withAlphaComponent(0.6)
|
||||||
starButton.tintColor = tintColor
|
starButton.tintColor = tintColor
|
||||||
starButton.setTitleColor(tintColor, for: .normal)
|
starButton.setTitleColor(tintColor, for: .normal)
|
||||||
starButton.setTitleColor(tintColor, for: .highlighted)
|
starButton.setTitleColor(tintColor, for: .highlighted)
|
||||||
|
@ -193,9 +188,23 @@ extension ActionToolbarContainer {
|
||||||
os_log("%{public}s[%{public}ld], %{public}s", ((#file as NSString).lastPathComponent), #line, #function)
|
os_log("%{public}s[%{public}ld], %{public}s", ((#file as NSString).lastPathComponent), #line, #function)
|
||||||
delegate?.actionToolbarContainer(self, moreButtonDidPressed: sender)
|
delegate?.actionToolbarContainer(self, moreButtonDidPressed: sender)
|
||||||
}
|
}
|
||||||
@objc private func bookmarkButtonDidPressed(_ sender: UIButton) {
|
|
||||||
os_log("%{public}s[%{public}ld], %{public}s", ((#file as NSString).lastPathComponent), #line, #function)
|
|
||||||
delegate?.actionToolbarContainer(self, bookmarkButtonDidPressed: sender)
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if DEBUG
|
||||||
|
import SwiftUI
|
||||||
|
|
||||||
|
struct ActionToolbarContainer_Previews: PreviewProvider {
|
||||||
|
static var previews: some View {
|
||||||
|
Group {
|
||||||
|
UIViewPreview(width: 300) {
|
||||||
|
let toolbar = ActionToolbarContainer()
|
||||||
|
toolbar.configure(for: .inline)
|
||||||
|
return toolbar
|
||||||
|
}
|
||||||
|
.previewLayout(.fixed(width: 300, height: 44))
|
||||||
|
.previewDisplayName("Inline")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
Loading…
Reference in New Issue