diff --git a/CoreDataStack/CoreData.xcdatamodeld/CoreData.xcdatamodel/contents b/CoreDataStack/CoreData.xcdatamodeld/CoreData.xcdatamodel/contents index 0c42dfc6b..3fe5fe16e 100644 --- a/CoreDataStack/CoreData.xcdatamodeld/CoreData.xcdatamodel/contents +++ b/CoreDataStack/CoreData.xcdatamodeld/CoreData.xcdatamodel/contents @@ -1,5 +1,5 @@ - + @@ -7,6 +7,23 @@ + + + + + + + + + + + + + + + + + @@ -110,6 +127,7 @@ + @@ -127,6 +145,7 @@ - + + \ No newline at end of file diff --git a/CoreDataStack/Entity/Attachment.swift b/CoreDataStack/Entity/Attachment.swift new file mode 100644 index 000000000..f3071872f --- /dev/null +++ b/CoreDataStack/Entity/Attachment.swift @@ -0,0 +1,126 @@ +// +// Attachment.swift +// CoreDataStack +// +// Created by MainasuK Cirno on 2021-2-23. +// + +import CoreData +import Foundation + +public final class Attachment: NSManagedObject { + public typealias ID = String + + @NSManaged public private(set) var id: ID + @NSManaged public private(set) var domain: String + @NSManaged public private(set) var typeRaw: String + @NSManaged public private(set) var url: String + @NSManaged public private(set) var previewURL: String + + @NSManaged public private(set) var remoteURL: String? + @NSManaged public private(set) var metaData: Data? + @NSManaged public private(set) var textURL: String? + @NSManaged public private(set) var descriptionString: String? + @NSManaged public private(set) var blurhash: String? + + @NSManaged public private(set) var createdAt: Date + @NSManaged public private(set) var updatedAt: Date + @NSManaged public private(set) var index: NSNumber + + // many-to-one relastionship + @NSManaged public private(set) var toot: Toot? + +} + +public extension Attachment { + + override func awakeFromInsert() { + super.awakeFromInsert() + createdAt = Date() + } + + @discardableResult + static func insert( + into context: NSManagedObjectContext, + property: Property + ) -> Attachment { + let attachment: Attachment = context.insertObject() + + attachment.domain = property.domain + attachment.index = property.index + + attachment.id = property.id + attachment.typeRaw = property.typeRaw + attachment.url = property.url + attachment.previewURL = property.previewURL + + attachment.remoteURL = property.remoteURL + attachment.metaData = property.metaData + attachment.textURL = property.textURL + attachment.descriptionString = property.descriptionString + attachment.blurhash = property.blurhash + + attachment.updatedAt = property.networkDate + + return attachment + } + + func didUpdate(at networkDate: Date) { + self.updatedAt = networkDate + } + +} + +public extension Attachment { + struct Property { + public let domain: String + public let index: NSNumber + + public let id: ID + public let typeRaw: String + public let url: String + + public let previewURL: String + public let remoteURL: String? + public let metaData: Data? + public let textURL: String? + public let descriptionString: String? + public let blurhash: String? + + public let networkDate: Date + + public init( + domain: String, + index: Int, + id: Attachment.ID, + typeRaw: String, + url: String, + previewURL: String, + remoteURL: String?, + metaData: Data?, + textURL: String?, + descriptionString: String?, + blurhash: String?, + networkDate: Date + ) { + self.domain = domain + self.index = NSNumber(value: index) + self.id = id + self.typeRaw = typeRaw + self.url = url + self.previewURL = previewURL + self.remoteURL = remoteURL + self.metaData = metaData + self.textURL = textURL + self.descriptionString = descriptionString + self.blurhash = blurhash + self.networkDate = networkDate + } + } +} + +extension Attachment: Managed { + public static var defaultSortDescriptors: [NSSortDescriptor] { + return [NSSortDescriptor(keyPath: \Attachment.createdAt, ascending: false)] + } +} diff --git a/CoreDataStack/Entity/Toot.swift b/CoreDataStack/Entity/Toot.swift index 7bc3f2261..b37609a21 100644 --- a/CoreDataStack/Entity/Toot.swift +++ b/CoreDataStack/Entity/Toot.swift @@ -39,11 +39,13 @@ public final class Toot: NSManagedObject { // many-to-one relastionship @NSManaged public private(set) var author: MastodonUser @NSManaged public private(set) var reblog: Toot? + + // many-to-many relastionship @NSManaged public private(set) var favouritedBy: Set? @NSManaged public private(set) var rebloggedBy: Set? @NSManaged public private(set) var mutedBy: Set? @NSManaged public private(set) var bookmarkedBy: Set? - + // one-to-one relastionship @NSManaged public private(set) var pinnedBy: MastodonUser? @@ -53,6 +55,7 @@ public final class Toot: NSManagedObject { @NSManaged public private(set) var emojis: Set? @NSManaged public private(set) var tags: Set? @NSManaged public private(set) var homeTimelineIndexes: Set? + @NSManaged public private(set) var mediaAttachments: Set? @NSManaged public private(set) var updatedAt: Date @NSManaged public private(set) var deletedAt: Date? @@ -69,6 +72,7 @@ public extension Toot { mentions: [Mention]?, emojis: [Emoji]?, tags: [Tag]?, + mediaAttachments: [Attachment]?, favouritedBy: MastodonUser?, rebloggedBy: MastodonUser?, mutedBy: MastodonUser?, @@ -115,6 +119,9 @@ public extension Toot { if let tags = tags { toot.mutableSetValue(forKey: #keyPath(Toot.tags)).addObjects(from: tags) } + if let mediaAttachments = mediaAttachments { + toot.mutableSetValue(forKey: #keyPath(Toot.mediaAttachments)).addObjects(from: mediaAttachments) + } if let favouritedBy = favouritedBy { toot.mutableSetValue(forKey: #keyPath(Toot.favouritedBy)).add(favouritedBy) } diff --git a/Localization/StringsConvertor/input/en_US/app.json b/Localization/StringsConvertor/input/en_US/app.json index 0c3f16c7c..8fa054563 100644 --- a/Localization/StringsConvertor/input/en_US/app.json +++ b/Localization/StringsConvertor/input/en_US/app.json @@ -19,6 +19,11 @@ "preview": "Preview", "open_in_safari": "Open in Safari" }, + "status": { + "user_boosted": "%s boosted", + "content_warning": "content warning", + "show_post": "Show Post" + }, "timeline": { "load_more": "Load More" } @@ -75,4 +80,4 @@ "title": "Public" } } -} \ No newline at end of file +} diff --git a/Localization/StringsConvertor/output/en.lproj/Localizable.strings b/Localization/StringsConvertor/output/en.lproj/Localizable.strings index 707ef3cce..75dc3999b 100644 --- a/Localization/StringsConvertor/output/en.lproj/Localizable.strings +++ b/Localization/StringsConvertor/output/en.lproj/Localizable.strings @@ -13,6 +13,9 @@ "Common.Controls.Actions.SignIn" = "Sign in"; "Common.Controls.Actions.SignUp" = "Sign up"; "Common.Controls.Actions.TakePhoto" = "Take photo"; +"Common.Controls.Status.ContentWarning" = "content warning"; +"Common.Controls.Status.ShowPost" = "Show Post"; +"Common.Controls.Status.UserBoosted" = "%@ boosted"; "Common.Controls.Timeline.LoadMore" = "Load More"; "Common.Countable.Photo.Multiple" = "photos"; "Common.Countable.Photo.Single" = "photo"; diff --git a/Localization/app.json b/Localization/app.json index 0c3f16c7c..8fa054563 100644 --- a/Localization/app.json +++ b/Localization/app.json @@ -19,6 +19,11 @@ "preview": "Preview", "open_in_safari": "Open in Safari" }, + "status": { + "user_boosted": "%s boosted", + "content_warning": "content warning", + "show_post": "Show Post" + }, "timeline": { "load_more": "Load More" } @@ -75,4 +80,4 @@ "title": "Public" } } -} \ No newline at end of file +} diff --git a/Mastodon.xcodeproj/project.pbxproj b/Mastodon.xcodeproj/project.pbxproj index a67b28178..821dc8a60 100644 --- a/Mastodon.xcodeproj/project.pbxproj +++ b/Mastodon.xcodeproj/project.pbxproj @@ -13,7 +13,7 @@ 0FAA102725E1126A0017CCDE /* PickServerViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0FAA102625E1126A0017CCDE /* PickServerViewController.swift */; }; 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 */; }; - 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 */; }; 2D32EAAC25CB96DC00C9ED86 /* TimelineMiddleLoaderTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2D32EAAB25CB96DC00C9ED86 /* TimelineMiddleLoaderTableViewCell.swift */; }; 2D32EABA25CB9B0500C9ED86 /* UIView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2D32EAB925CB9B0500C9ED86 /* UIView.swift */; }; @@ -37,7 +37,6 @@ 2D46975E25C2A54100CF4AA9 /* NSLayoutConstraint.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2D46975D25C2A54100CF4AA9 /* NSLayoutConstraint.swift */; }; 2D46976425C2A71500CF4AA9 /* UIIamge.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2D46976325C2A71500CF4AA9 /* UIIamge.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 */; }; 2D5A3D3825CF8D9F002347D6 /* ScrollViewContainer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2D5A3D3725CF8D9F002347D6 /* ScrollViewContainer.swift */; }; 2D5A3D6225CFD9CB002347D6 /* HomeTimelineViewController+DebugAction.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2D5A3D6125CFD9CB002347D6 /* HomeTimelineViewController+DebugAction.swift */; }; @@ -50,8 +49,8 @@ 2D76316B25C14D4C00929FB9 /* PublicTimelineViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2D76316A25C14D4C00929FB9 /* PublicTimelineViewModel.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 */; }; - 2D76319F25C1521200929FB9 /* TimelineSection.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2D76319E25C1521200929FB9 /* TimelineSection.swift */; }; - 2D7631A825C1535600929FB9 /* TimelinePostTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2D7631A725C1535600929FB9 /* TimelinePostTableViewCell.swift */; }; + 2D76319F25C1521200929FB9 /* StatusSection.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2D76319E25C1521200929FB9 /* StatusSection.swift */; }; + 2D7631A825C1535600929FB9 /* StatusTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2D7631A725C1535600929FB9 /* StatusTableViewCell.swift */; }; 2D7631B325C159F700929FB9 /* Item.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2D7631B225C159F700929FB9 /* Item.swift */; }; 2D927F0225C7E4F2004F19B8 /* Mention.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2D927F0125C7E4F2004F19B8 /* Mention.swift */; }; 2D927F0825C7E9A8004F19B8 /* Tag.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2D927F0725C7E9A8004F19B8 /* Tag.swift */; }; @@ -78,6 +77,8 @@ DB0140CF25C42AEE00F9F3CF /* OSLog.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB0140CE25C42AEE00F9F3CF /* OSLog.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 */; }; + 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 */; }; DB2B3AE925E38850007045F9 /* UIViewPreview.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB2B3AE825E38850007045F9 /* UIViewPreview.swift */; }; DB3D0FF325BAA61700EAA174 /* AlamofireImage in Frameworks */ = {isa = PBXBuildFile; productRef = DB3D0FF225BAA61700EAA174 /* AlamofireImage */; }; @@ -102,6 +103,7 @@ DB5086AB25CC0BBB00C2C187 /* AvatarConfigurableView.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB5086AA25CC0BBB00C2C187 /* AvatarConfigurableView.swift */; }; DB5086B825CC0D6400C2C187 /* Kingfisher in Frameworks */ = {isa = PBXBuildFile; productRef = DB5086B725CC0D6400C2C187 /* Kingfisher */; }; DB5086BE25CC0D9900C2C187 /* SplashPreference.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB5086BD25CC0D9900C2C187 /* SplashPreference.swift */; }; + DB68586425E619B700F0A850 /* NSKeyValueObservation.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB68586325E619B700F0A850 /* NSKeyValueObservation.swift */; }; DB72601C25E36A2100235243 /* MastodonServerRulesViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB72601B25E36A2100235243 /* MastodonServerRulesViewController.swift */; }; DB72602725E36A6F00235243 /* MastodonServerRulesViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB72602625E36A6F00235243 /* MastodonServerRulesViewModel.swift */; }; DB89B9F725C10FD0008580ED /* CoreDataStack.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DB89B9EE25C10FD0008580ED /* CoreDataStack.framework */; }; @@ -133,6 +135,13 @@ DB98338725C945ED00AD9700 /* Strings.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB98338525C945ED00AD9700 /* Strings.swift */; }; DB98338825C945ED00AD9700 /* Assets.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB98338625C945ED00AD9700 /* Assets.swift */; }; DB98339C25C96DE600AD9700 /* APIService+Account.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB98339B25C96DE600AD9700 /* APIService+Account.swift */; }; + DB9D6BE925E4F5340051B173 /* SearchViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB9D6BE825E4F5340051B173 /* SearchViewController.swift */; }; + DB9D6BF825E4F5690051B173 /* NotificationViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB9D6BF725E4F5690051B173 /* NotificationViewController.swift */; }; + DB9D6BFF25E4F5940051B173 /* ProfileViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB9D6BFE25E4F5940051B173 /* ProfileViewController.swift */; }; + DB9D6C0E25E4F9780051B173 /* MosaicImageView.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB9D6C0D25E4F9780051B173 /* MosaicImageView.swift */; }; + DB9D6C2425E502C60051B173 /* MosaicImageViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB9D6C2225E502C60051B173 /* MosaicImageViewModel.swift */; }; + DB9D6C2E25E504AC0051B173 /* Attachment.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB9D6C2D25E504AC0051B173 /* Attachment.swift */; }; + DB9D6C3825E508BE0051B173 /* Attachment.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB9D6C3725E508BE0051B173 /* Attachment.swift */; }; DBD9149025DF6D8D00903DFD /* APIService+Onboarding.swift in Sources */ = {isa = PBXBuildFile; fileRef = DBD9148F25DF6D8D00903DFD /* APIService+Onboarding.swift */; }; DBE0821525CD382600FD6BBD /* MastodonRegisterViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = DBE0821425CD382600FD6BBD /* MastodonRegisterViewController.swift */; }; DBE0822425CD3F1E00FD6BBD /* MastodonRegisterViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = DBE0822325CD3F1E00FD6BBD /* MastodonRegisterViewModel.swift */; }; @@ -196,7 +205,7 @@ 0FAA101B25E10E760017CCDE /* UIFont.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UIFont.swift; sourceTree = ""; }; 0FAA102625E1126A0017CCDE /* PickServerViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PickServerViewController.swift; sourceTree = ""; }; 2D04F42425C255B9003F936F /* APIService+PublicTimeline.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "APIService+PublicTimeline.swift"; sourceTree = ""; }; - 2D152A8B25C295CC009AA50C /* TimelinePostView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TimelinePostView.swift; sourceTree = ""; }; + 2D152A8B25C295CC009AA50C /* StatusView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StatusView.swift; sourceTree = ""; }; 2D152A9125C2980C009AA50C /* UIFont.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UIFont.swift; sourceTree = ""; }; 2D32EAAB25CB96DC00C9ED86 /* TimelineMiddleLoaderTableViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TimelineMiddleLoaderTableViewCell.swift; sourceTree = ""; }; 2D32EAB925CB9B0500C9ED86 /* UIView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UIView.swift; sourceTree = ""; }; @@ -219,7 +228,6 @@ 2D46975D25C2A54100CF4AA9 /* NSLayoutConstraint.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NSLayoutConstraint.swift; sourceTree = ""; }; 2D46976325C2A71500CF4AA9 /* UIIamge.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UIIamge.swift; sourceTree = ""; }; 2D5A3D0225CF8742002347D6 /* ControlContainableScrollViews.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ControlContainableScrollViews.swift; sourceTree = ""; }; - 2D5A3D1025CF87AA002347D6 /* AvatarBarButtonItem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AvatarBarButtonItem.swift; sourceTree = ""; }; 2D5A3D2725CF8BC9002347D6 /* HomeTimelineViewModel+Diffable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "HomeTimelineViewModel+Diffable.swift"; sourceTree = ""; }; 2D5A3D3725CF8D9F002347D6 /* ScrollViewContainer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ScrollViewContainer.swift; sourceTree = ""; }; 2D5A3D6125CFD9CB002347D6 /* HomeTimelineViewController+DebugAction.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "HomeTimelineViewController+DebugAction.swift"; sourceTree = ""; }; @@ -231,8 +239,8 @@ 2D76316A25C14D4C00929FB9 /* PublicTimelineViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PublicTimelineViewModel.swift; sourceTree = ""; }; 2D76317C25C14DF400929FB9 /* PublicTimelineViewController+StatusProvider.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "PublicTimelineViewController+StatusProvider.swift"; sourceTree = ""; }; 2D76318225C14E8F00929FB9 /* PublicTimelineViewModel+Diffable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "PublicTimelineViewModel+Diffable.swift"; sourceTree = ""; }; - 2D76319E25C1521200929FB9 /* TimelineSection.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TimelineSection.swift; sourceTree = ""; }; - 2D7631A725C1535600929FB9 /* TimelinePostTableViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TimelinePostTableViewCell.swift; sourceTree = ""; }; + 2D76319E25C1521200929FB9 /* StatusSection.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StatusSection.swift; sourceTree = ""; }; + 2D7631A725C1535600929FB9 /* StatusTableViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StatusTableViewCell.swift; sourceTree = ""; }; 2D7631B225C159F700929FB9 /* Item.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Item.swift; sourceTree = ""; }; 2D927F0125C7E4F2004F19B8 /* Mention.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Mention.swift; sourceTree = ""; }; 2D927F0725C7E9A8004F19B8 /* Tag.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Tag.swift; sourceTree = ""; }; @@ -264,6 +272,8 @@ DB0140CE25C42AEE00F9F3CF /* OSLog.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = OSLog.swift; sourceTree = ""; }; DB084B5625CBC56C00F898ED /* Toot.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Toot.swift; sourceTree = ""; }; DB0AC6FB25CD02E600D75117 /* APIService+Instance.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "APIService+Instance.swift"; sourceTree = ""; }; + DB118A8125E4B6E600FAB162 /* Preview Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = "Preview Assets.xcassets"; sourceTree = ""; }; + DB118A8B25E4BFB500FAB162 /* HighlightDimmableButton.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HighlightDimmableButton.swift; sourceTree = ""; }; DB2B3ABD25E37E15007045F9 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/InfoPlist.strings; sourceTree = ""; }; DB2B3AE825E38850007045F9 /* UIViewPreview.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UIViewPreview.swift; sourceTree = ""; }; DB3D0FED25BAA42200EAA174 /* MastodonSDK */ = {isa = PBXFileReference; lastKnownFileType = folder; path = MastodonSDK; sourceTree = ""; }; @@ -293,6 +303,7 @@ DB5086A425CC0B7000C2C187 /* AvatarBarButtonItem.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AvatarBarButtonItem.swift; sourceTree = ""; }; DB5086AA25CC0BBB00C2C187 /* AvatarConfigurableView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AvatarConfigurableView.swift; sourceTree = ""; }; DB5086BD25CC0D9900C2C187 /* SplashPreference.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SplashPreference.swift; sourceTree = ""; }; + DB68586325E619B700F0A850 /* NSKeyValueObservation.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NSKeyValueObservation.swift; sourceTree = ""; }; DB72601B25E36A2100235243 /* MastodonServerRulesViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MastodonServerRulesViewController.swift; sourceTree = ""; }; DB72602625E36A6F00235243 /* MastodonServerRulesViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MastodonServerRulesViewModel.swift; sourceTree = ""; }; DB89B9EE25C10FD0008580ED /* CoreDataStack.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = CoreDataStack.framework; sourceTree = BUILT_PRODUCTS_DIR; }; @@ -326,6 +337,13 @@ DB98338525C945ED00AD9700 /* Strings.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Strings.swift; sourceTree = ""; }; DB98338625C945ED00AD9700 /* Assets.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Assets.swift; sourceTree = ""; }; DB98339B25C96DE600AD9700 /* APIService+Account.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "APIService+Account.swift"; sourceTree = ""; }; + DB9D6BE825E4F5340051B173 /* SearchViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SearchViewController.swift; sourceTree = ""; }; + DB9D6BF725E4F5690051B173 /* NotificationViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NotificationViewController.swift; sourceTree = ""; }; + DB9D6BFE25E4F5940051B173 /* ProfileViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ProfileViewController.swift; sourceTree = ""; }; + DB9D6C0D25E4F9780051B173 /* MosaicImageView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MosaicImageView.swift; sourceTree = ""; }; + DB9D6C2225E502C60051B173 /* MosaicImageViewModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MosaicImageViewModel.swift; sourceTree = ""; }; + DB9D6C2D25E504AC0051B173 /* Attachment.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Attachment.swift; sourceTree = ""; }; + DB9D6C3725E508BE0051B173 /* Attachment.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Attachment.swift; sourceTree = ""; }; DBD9148F25DF6D8D00903DFD /* APIService+Onboarding.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "APIService+Onboarding.swift"; sourceTree = ""; }; DBE0821425CD382600FD6BBD /* MastodonRegisterViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MastodonRegisterViewController.swift; sourceTree = ""; }; DBE0822325CD3F1E00FD6BBD /* MastodonRegisterViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MastodonRegisterViewModel.swift; sourceTree = ""; }; @@ -417,7 +435,7 @@ 2D152A8A25C295B8009AA50C /* Content */ = { isa = PBXGroup; children = ( - 2D152A8B25C295CC009AA50C /* TimelinePostView.swift */, + 2D152A8B25C295CC009AA50C /* StatusView.swift */, ); path = Content; sourceTree = ""; @@ -460,7 +478,7 @@ children = ( DB5086A425CC0B7000C2C187 /* AvatarBarButtonItem.swift */, 2D42FF8425C8224F004A627A /* HitTestExpandedButton.swift */, - 2D5A3D1025CF87AA002347D6 /* AvatarBarButtonItem.swift */, + DB118A8B25E4BFB500FAB162 /* HighlightDimmableButton.swift */, 0FAA101125E105390017CCDE /* PrimaryActionButton.swift */, ); path = Button; @@ -496,8 +514,8 @@ 2D69CFF225CA9E2200C3A1B2 /* Protocol */ = { isa = PBXGroup; children = ( - DB5086AA25CC0BBB00C2C187 /* AvatarConfigurableView.swift */, 2D38F1FC25CD47D900561493 /* StatusProvider */, + DB5086AA25CC0BBB00C2C187 /* AvatarConfigurableView.swift */, 2D69CFF325CA9E2200C3A1B2 /* LoadMoreConfigurableTableViewContainer.swift */, 2D38F1C525CD37F400561493 /* ContentOffsetAdjustableTimelineViewControllerDelegate.swift */, 2D38F20725CD491300561493 /* DisposeBagCollectable.swift */, @@ -531,7 +549,7 @@ 2D76319D25C151F600929FB9 /* Section */ = { isa = PBXGroup; children = ( - 2D76319E25C1521200929FB9 /* TimelineSection.swift */, + 2D76319E25C1521200929FB9 /* StatusSection.swift */, ); path = Section; sourceTree = ""; @@ -539,6 +557,7 @@ 2D7631A425C1532200929FB9 /* Share */ = { isa = PBXGroup; children = ( + DB9D6C2025E502C60051B173 /* ViewModel */, 2D7631A525C1532D00929FB9 /* View */, ); path = Share; @@ -549,6 +568,7 @@ children = ( 2D42FF8325C82245004A627A /* Button */, 2D42FF7C25C82207004A627A /* ToolBar */, + DB9D6C1325E4F97A0051B173 /* Container */, 2D152A8A25C295B8009AA50C /* Content */, 2D7631A625C1533800929FB9 /* TableviewCell */, ); @@ -558,7 +578,7 @@ 2D7631A625C1533800929FB9 /* TableviewCell */ = { isa = PBXGroup; children = ( - 2D7631A725C1535600929FB9 /* TimelinePostTableViewCell.swift */, + 2D7631A725C1535600929FB9 /* StatusTableViewCell.swift */, 2DA7D04325CA52B200804E11 /* TimelineLoaderTableViewCell.swift */, 2DA7D04925CA52CB00804E11 /* TimelineBottomLoaderTableViewCell.swift */, 2D32EAAB25CB96DC00C9ED86 /* TimelineMiddleLoaderTableViewCell.swift */, @@ -620,6 +640,7 @@ children = ( DB45FAE225CA7181005A8AC7 /* MastodonUser.swift */, DB084B5625CBC56C00F898ED /* Toot.swift */, + DB9D6C3725E508BE0051B173 /* Attachment.swift */, ); path = CoreDataStack; sourceTree = ""; @@ -639,6 +660,7 @@ isa = PBXGroup; children = ( DB427DDE25BAA00100D1B89D /* Assets.xcassets */, + DB118A8125E4B6E600FAB162 /* Preview Assets.xcassets */, DB3D100F25BAA75E00EAA174 /* Localizable.strings */, DB2B3ABE25E37E15007045F9 /* InfoPlist.strings */, ); @@ -807,6 +829,7 @@ 2D927F1325C7EDD9004F19B8 /* Emoji.swift */, DB45FAEC25CA7A9A005A8AC7 /* MastodonAuthentication.swift */, 2DA7D05625CA693F00804E11 /* Application.swift */, + DB9D6C2D25E504AC0051B173 /* Attachment.swift */, ); path = Entity; sourceTree = ""; @@ -850,13 +873,16 @@ DB8AF55525C1379F002E6C99 /* Scene */ = { isa = PBXGroup; children = ( - 0FAA102525E1125D0017CCDE /* PickServer */, - 0FAA0FDD25E0B5700017CCDE /* Welcome */, 2D7631A425C1532200929FB9 /* Share */, DB8AF54E25C13703002E6C99 /* MainTab */, + 0FAA0FDD25E0B5700017CCDE /* Welcome */, + 0FAA102525E1125D0017CCDE /* PickServer */, DB01409B25C40BB600F9F3CF /* Authentication */, 2D38F1D325CD463600561493 /* HomeTimeline */, 2D76316325C14BAC00929FB9 /* PublicTimeline */, + DB9D6BEE25E4F5370051B173 /* Search */, + DB9D6BFD25E4F57B0051B173 /* Notification */, + DB9D6C0825E4F5A60051B173 /* Profile */, ); path = Scene; sourceTree = ""; @@ -871,6 +897,7 @@ 2D46975D25C2A54100CF4AA9 /* NSLayoutConstraint.swift */, 2D46976325C2A71500CF4AA9 /* UIIamge.swift */, 2DF123A625C3B0210020F248 /* ActiveLabel.swift */, + DB68586325E619B700F0A850 /* NSKeyValueObservation.swift */, 2D42FF6A25C817D2004A627A /* MastodonContent.swift */, DB45FAB525CA5485005A8AC7 /* UIAlertController.swift */, 2D42FF8E25C8228A004A627A /* UIButton.swift */, @@ -899,6 +926,46 @@ path = Generated; sourceTree = ""; }; + DB9D6BEE25E4F5370051B173 /* Search */ = { + isa = PBXGroup; + children = ( + DB9D6BE825E4F5340051B173 /* SearchViewController.swift */, + ); + path = Search; + sourceTree = ""; + }; + DB9D6BFD25E4F57B0051B173 /* Notification */ = { + isa = PBXGroup; + children = ( + DB9D6BF725E4F5690051B173 /* NotificationViewController.swift */, + ); + path = Notification; + sourceTree = ""; + }; + DB9D6C0825E4F5A60051B173 /* Profile */ = { + isa = PBXGroup; + children = ( + DB9D6BFE25E4F5940051B173 /* ProfileViewController.swift */, + ); + path = Profile; + sourceTree = ""; + }; + DB9D6C1325E4F97A0051B173 /* Container */ = { + isa = PBXGroup; + children = ( + DB9D6C0D25E4F9780051B173 /* MosaicImageView.swift */, + ); + path = Container; + sourceTree = ""; + }; + DB9D6C2025E502C60051B173 /* ViewModel */ = { + isa = PBXGroup; + children = ( + DB9D6C2225E502C60051B173 /* MosaicImageViewModel.swift */, + ); + path = ViewModel; + sourceTree = ""; + }; DBE0821A25CD382900FD6BBD /* Register */ = { isa = PBXGroup; children = ( @@ -1097,6 +1164,7 @@ DB3D100D25BAA75E00EAA174 /* Localizable.strings in Resources */, DB427DDF25BAA00100D1B89D /* Assets.xcassets in Resources */, DB427DDD25BAA00100D1B89D /* Main.storyboard in Resources */, + DB118A8225E4B6E600FAB162 /* Preview Assets.xcassets in Resources */, DB2B3ABC25E37E15007045F9 /* InfoPlist.strings in Resources */, ); runOnlyForDeploymentPostprocessing = 0; @@ -1268,11 +1336,12 @@ DB72602725E36A6F00235243 /* MastodonServerRulesViewModel.swift in Sources */, 2D38F1F125CD477D00561493 /* HomeTimelineViewModel+LoadMiddleState.swift in Sources */, DB45FAD725CA6C76005A8AC7 /* UIBarButtonItem.swift in Sources */, - 2D152A8C25C295CC009AA50C /* TimelinePostView.swift in Sources */, + 2D152A8C25C295CC009AA50C /* StatusView.swift in Sources */, 2D42FF8525C8224F004A627A /* HitTestExpandedButton.swift in Sources */, DB72601C25E36A2100235243 /* MastodonServerRulesViewController.swift in Sources */, 2D42FF8F25C8228A004A627A /* UIButton.swift in Sources */, 0FAA102725E1126A0017CCDE /* PickServerViewController.swift in Sources */, + DB68586425E619B700F0A850 /* NSKeyValueObservation.swift in Sources */, 2D61335825C188A000CAE157 /* APIService+Persist+Timeline.swift in Sources */, DB45FAE325CA7181005A8AC7 /* MastodonUser.swift in Sources */, DB0AC6FC25CD02E600D75117 /* APIService+Instance.swift in Sources */, @@ -1282,6 +1351,7 @@ DB98338825C945ED00AD9700 /* Assets.swift in Sources */, 2DA7D04425CA52B200804E11 /* TimelineLoaderTableViewCell.swift in Sources */, DB8AF52F25C13561002E6C99 /* DocumentStore.swift in Sources */, + DB9D6C2425E502C60051B173 /* MosaicImageViewModel.swift in Sources */, 2D38F1EB25CD477000561493 /* HomeTimelineViewModel+LoadLatestState.swift in Sources */, DBD9149025DF6D8D00903DFD /* APIService+Onboarding.swift in Sources */, DB98337F25C9452D00AD9700 /* APIService+APIError.swift in Sources */, @@ -1303,18 +1373,22 @@ 2D42FF7E25C82218004A627A /* ActionToolBarContainer.swift in Sources */, DB0140A125C40C0600F9F3CF /* MastodonPinBasedAuthenticationViewController.swift in Sources */, DB8AF55025C13703002E6C99 /* MainTabBarController.swift in Sources */, + DB9D6BE925E4F5340051B173 /* SearchViewController.swift in Sources */, 2D38F1C625CD37F400561493 /* ContentOffsetAdjustableTimelineViewControllerDelegate.swift in Sources */, DB8AF54525C13647002E6C99 /* NeedsDependency.swift in Sources */, + DB9D6BF825E4F5690051B173 /* NotificationViewController.swift in Sources */, DB45FADD25CA6F6B005A8AC7 /* APIService+CoreData+MastodonUser.swift in Sources */, 2D32EABA25CB9B0500C9ED86 /* UIView.swift in Sources */, DB98334725C8056600AD9700 /* AuthenticationViewModel.swift in Sources */, 2D38F20825CD491300561493 /* DisposeBagCollectable.swift in Sources */, DB0140CF25C42AEE00F9F3CF /* OSLog.swift in Sources */, - 2D76319F25C1521200929FB9 /* TimelineSection.swift in Sources */, + 2D76319F25C1521200929FB9 /* StatusSection.swift in Sources */, + DB118A8C25E4BFB500FAB162 /* HighlightDimmableButton.swift in Sources */, DB084B5725CBC56C00F898ED /* Toot.swift in Sources */, DB0140A825C40C1500F9F3CF /* MastodonPinBasedAuthenticationViewModelNavigationDelegateShim.swift in Sources */, DB2B3AE925E38850007045F9 /* UIViewPreview.swift in Sources */, DB427DD625BAA00100D1B89D /* AppDelegate.swift in Sources */, + DB9D6C0E25E4F9780051B173 /* MosaicImageView.swift in Sources */, DB98338725C945ED00AD9700 /* Strings.swift in Sources */, DB45FAB625CA5485005A8AC7 /* UIAlertController.swift in Sources */, DBE0821525CD382600FD6BBD /* MastodonRegisterViewController.swift in Sources */, @@ -1329,10 +1403,11 @@ DB98339C25C96DE600AD9700 /* APIService+Account.swift in Sources */, 2D42FF6B25C817D2004A627A /* MastodonContent.swift in Sources */, 2DF75BA725D10E1000694EC8 /* APIService+Favorite.swift in Sources */, + DB9D6C3825E508BE0051B173 /* Attachment.swift in Sources */, DB8AF52E25C13561002E6C99 /* ViewStateStore.swift in Sources */, 2DA7D04A25CA52CB00804E11 /* TimelineBottomLoaderTableViewCell.swift in Sources */, 2D76318325C14E8F00929FB9 /* PublicTimelineViewModel+Diffable.swift in Sources */, - 2D7631A825C1535600929FB9 /* TimelinePostTableViewCell.swift in Sources */, + 2D7631A825C1535600929FB9 /* StatusTableViewCell.swift in Sources */, 2D76316525C14BD100929FB9 /* PublicTimelineViewController.swift in Sources */, 2D69CFF425CA9E2200C3A1B2 /* LoadMoreConfigurableTableViewContainer.swift in Sources */, DB01409625C40B6700F9F3CF /* AuthenticationViewController.swift in Sources */, @@ -1341,8 +1416,8 @@ DB0140AE25C40C7300F9F3CF /* MastodonPinBasedAuthenticationViewModel.swift in Sources */, 2D32EAAC25CB96DC00C9ED86 /* TimelineMiddleLoaderTableViewCell.swift in Sources */, 2D5A3D6225CFD9CB002347D6 /* HomeTimelineViewController+DebugAction.swift in Sources */, + DB9D6BFF25E4F5940051B173 /* ProfileViewController.swift in Sources */, 2D38F1FE25CD481700561493 /* StatusProvider.swift in Sources */, - 2D5A3D1125CF87AA002347D6 /* AvatarBarButtonItem.swift in Sources */, DB45FB0F25CA87D0005A8AC7 /* AuthenticationService.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; @@ -1372,6 +1447,7 @@ 2DF75BC725D1475D00694EC8 /* ManagedObjectContextObjectsDidChange.swift in Sources */, DB89BA1225C1105C008580ED /* CoreDataStack.swift in Sources */, DB89BA1C25C1107F008580ED /* NSManagedObjectContext.swift in Sources */, + DB9D6C2E25E504AC0051B173 /* Attachment.swift in Sources */, 2D927F0E25C7E9C9004F19B8 /* History.swift in Sources */, DB89BA3725C1145C008580ED /* CoreData.xcdatamodeld in Sources */, DB8AF52525C131D1002E6C99 /* MastodonUser.swift in Sources */, diff --git a/Mastodon/Coordinator/SceneCoordinator.swift b/Mastodon/Coordinator/SceneCoordinator.swift index 833e2a51a..c48c60d79 100644 --- a/Mastodon/Coordinator/SceneCoordinator.swift +++ b/Mastodon/Coordinator/SceneCoordinator.swift @@ -59,8 +59,9 @@ extension SceneCoordinator { DispatchQueue.main.async { var rootViewController: UIViewController if fetchResult.isEmpty { - let welcomeNaviVC = UINavigationController(rootViewController: WelcomeViewController()) - rootViewController = welcomeNaviVC + let welcomViewController = WelcomeViewController() + self.setupDependency(for: welcomViewController) + rootViewController = UINavigationController(rootViewController: welcomViewController) } else { rootViewController = MainTabBarController(context: self.appContext, coordinator: self) } diff --git a/Mastodon/Diffiable/Item/Item.swift b/Mastodon/Diffiable/Item/Item.swift index 8ee2f9a6c..2b34753b3 100644 --- a/Mastodon/Diffiable/Item/Item.swift +++ b/Mastodon/Diffiable/Item/Item.swift @@ -12,10 +12,11 @@ import MastodonSDK /// Note: update Equatable when change case enum Item { - case homeTimelineIndex(objectID: NSManagedObjectID, attribute: Attribute) + // timeline + case homeTimelineIndex(objectID: NSManagedObjectID, attribute: StatusTimelineAttribute) // normal list - case toot(objectID: NSManagedObjectID) + case toot(objectID: NSManagedObjectID, attribute: StatusTimelineAttribute) // loader case homeMiddleLoader(upperTimelineIndexAnchorObjectID: NSManagedObjectID) @@ -23,16 +24,31 @@ enum Item { case bottomLoader } -extension Item { - class Attribute: Hashable { - var separatorLineStyle: SeparatorLineStyle = .indent +protocol StatusContentWarningAttribute { + var isStatusTextSensitive: Bool { get set } +} - static func == (lhs: Item.Attribute, rhs: Item.Attribute) -> Bool { - return lhs.separatorLineStyle == rhs.separatorLineStyle +extension Item { + class StatusTimelineAttribute: Hashable, StatusContentWarningAttribute { + var separatorLineStyle: SeparatorLineStyle = .indent + var isStatusTextSensitive: Bool = false + + public init( + separatorLineStyle: Item.StatusTimelineAttribute.SeparatorLineStyle = .indent, + isStatusTextSensitive: Bool + ) { + self.separatorLineStyle = separatorLineStyle + self.isStatusTextSensitive = isStatusTextSensitive + } + + static func == (lhs: Item.StatusTimelineAttribute, rhs: Item.StatusTimelineAttribute) -> Bool { + return lhs.separatorLineStyle == rhs.separatorLineStyle && + lhs.isStatusTextSensitive == rhs.isStatusTextSensitive } func hash(into hasher: inout Hasher) { hasher.combine(separatorLineStyle) + hasher.combine(isStatusTextSensitive) } enum SeparatorLineStyle { @@ -48,7 +64,7 @@ extension Item: Equatable { switch (lhs, rhs) { case (.homeTimelineIndex(let objectIDLeft, _), .homeTimelineIndex(let objectIDRight, _)): return objectIDLeft == objectIDRight - case (.toot(let objectIDLeft), .toot(let objectIDRight)): + case (.toot(let objectIDLeft, _), .toot(let objectIDRight, _)): return objectIDLeft == objectIDRight case (.bottomLoader, .bottomLoader): return true @@ -67,7 +83,7 @@ extension Item: Hashable { switch self { case .homeTimelineIndex(let objectID, _): hasher.combine(objectID) - case .toot(let objectID): + case .toot(let objectID, _): hasher.combine(objectID) case .publicMiddleLoader(let upper): hasher.combine(String(describing: Item.publicMiddleLoader.self)) diff --git a/Mastodon/Diffiable/Section/StatusSection.swift b/Mastodon/Diffiable/Section/StatusSection.swift new file mode 100644 index 000000000..4cc19bdc3 --- /dev/null +++ b/Mastodon/Diffiable/Section/StatusSection.swift @@ -0,0 +1,199 @@ +// +// TimelineSection.swift +// Mastodon +// +// Created by sxiaojian on 2021/1/27. +// + +import Combine +import CoreData +import CoreDataStack +import os.log +import UIKit + +enum StatusSection: Equatable, Hashable { + case main +} + +extension StatusSection { + static func tableViewDiffableDataSource( + for tableView: UITableView, + dependency: NeedsDependency, + managedObjectContext: NSManagedObjectContext, + timestampUpdatePublisher: AnyPublisher, + timelinePostTableViewCellDelegate: StatusTableViewCellDelegate, + timelineMiddleLoaderTableViewCellDelegate: TimelineMiddleLoaderTableViewCellDelegate? + ) -> UITableViewDiffableDataSource { + UITableViewDiffableDataSource(tableView: tableView) { [weak timelinePostTableViewCellDelegate, weak timelineMiddleLoaderTableViewCellDelegate] tableView, indexPath, item -> UITableViewCell? in + guard let timelinePostTableViewCellDelegate = timelinePostTableViewCellDelegate else { return UITableViewCell() } + + switch item { + case .homeTimelineIndex(objectID: let objectID, let attribute): + let cell = tableView.dequeueReusableCell(withIdentifier: String(describing: StatusTableViewCell.self), for: indexPath) as! StatusTableViewCell + + // configure cell + managedObjectContext.performAndWait { + let timelineIndex = managedObjectContext.object(with: objectID) as! HomeTimelineIndex + StatusSection.configure(cell: cell, readableLayoutFrame: tableView.readableContentGuide.layoutFrame, timestampUpdatePublisher: timestampUpdatePublisher, toot: timelineIndex.toot, requestUserID: timelineIndex.userID, statusContentWarningAttribute: attribute) + } + cell.delegate = timelinePostTableViewCellDelegate + return cell + case .toot(let objectID, let attribute): + let cell = tableView.dequeueReusableCell(withIdentifier: String(describing: StatusTableViewCell.self), for: indexPath) as! StatusTableViewCell + let activeMastodonAuthenticationBox = dependency.context.authenticationService.activeMastodonAuthenticationBox.value + let requestUserID = activeMastodonAuthenticationBox?.userID ?? "" + // configure cell + managedObjectContext.performAndWait { + let toot = managedObjectContext.object(with: objectID) as! Toot + StatusSection.configure(cell: cell, readableLayoutFrame: tableView.readableContentGuide.layoutFrame, timestampUpdatePublisher: timestampUpdatePublisher, toot: toot, requestUserID: requestUserID, statusContentWarningAttribute: attribute) + } + cell.delegate = timelinePostTableViewCellDelegate + return cell + case .publicMiddleLoader(let upperTimelineTootID): + let cell = tableView.dequeueReusableCell(withIdentifier: String(describing: TimelineMiddleLoaderTableViewCell.self), for: indexPath) as! TimelineMiddleLoaderTableViewCell + cell.delegate = timelineMiddleLoaderTableViewCellDelegate + timelineMiddleLoaderTableViewCellDelegate?.configure(cell: cell, upperTimelineTootID: upperTimelineTootID, timelineIndexobjectID: nil) + return cell + case .homeMiddleLoader(let upperTimelineIndexObjectID): + let cell = tableView.dequeueReusableCell(withIdentifier: String(describing: TimelineMiddleLoaderTableViewCell.self), for: indexPath) as! TimelineMiddleLoaderTableViewCell + cell.delegate = timelineMiddleLoaderTableViewCellDelegate + timelineMiddleLoaderTableViewCellDelegate?.configure(cell: cell, upperTimelineTootID: nil, timelineIndexobjectID: upperTimelineIndexObjectID) + return cell + case .bottomLoader: + let cell = tableView.dequeueReusableCell(withIdentifier: String(describing: TimelineBottomLoaderTableViewCell.self), for: indexPath) as! TimelineBottomLoaderTableViewCell + cell.activityIndicatorView.startAnimating() + return cell + } + } + } + + static func configure( + cell: StatusTableViewCell, + readableLayoutFrame: CGRect?, + timestampUpdatePublisher: AnyPublisher, + toot: Toot, + requestUserID: String, + statusContentWarningAttribute: StatusContentWarningAttribute? + ) { + // set header + cell.statusView.headerContainerStackView.isHidden = toot.reblog == nil + cell.statusView.headerInfoLabel.text = { + let author = toot.author + let name = author.displayName.isEmpty ? author.username : author.displayName + return L10n.Common.Controls.Status.userBoosted(name) + }() + + // set name username avatar + cell.statusView.nameLabel.text = { + let author = (toot.reblog ?? toot).author + return author.displayName.isEmpty ? author.username : author.displayName + }() + cell.statusView.usernameLabel.text = "@" + (toot.reblog ?? toot).author.acct + cell.statusView.configure(with: AvatarConfigurableViewConfiguration(avatarImageURL: (toot.reblog ?? toot).author.avatarImageURL())) + + // set text + cell.statusView.activeTextLabel.config(content: (toot.reblog ?? toot).content) + + // set content warning + let isStatusTextSensitive = statusContentWarningAttribute?.isStatusTextSensitive ?? (toot.reblog ?? toot).sensitive + cell.statusView.updateContentWarningDisplay(isHidden: !isStatusTextSensitive) + cell.statusView.contentWarningTitle.text = (toot.reblog ?? toot).spoilerText.flatMap { spoilerText in + guard !spoilerText.isEmpty else { return nil } + return L10n.Common.Controls.Status.contentWarning + ": \(spoilerText)" + } ?? L10n.Common.Controls.Status.contentWarning + + // prepare media attachments + let mediaAttachments = Array((toot.reblog ?? toot).mediaAttachments ?? []).sorted { $0.index.compare($1.index) == .orderedAscending } + + // set image + let mosiacImageViewModel = MosaicImageViewModel(mediaAttachments: mediaAttachments) + let imageViewMaxSize: CGSize = { + let maxWidth: CGFloat = { + // use timelinePostView width as container width + // that width follows readable width and keep constant width after rotate + let containerFrame = readableLayoutFrame ?? cell.statusView.frame + var containerWidth = containerFrame.width + containerWidth -= 10 + containerWidth -= StatusView.avatarImageSize.width + return containerWidth + }() + let scale: CGFloat = { + switch mosiacImageViewModel.metas.count { + case 1: return 1.3 + default: return 0.7 + } + }() + return CGSize(width: maxWidth, height: maxWidth * scale) + }() + if mosiacImageViewModel.metas.count == 1 { + let meta = mosiacImageViewModel.metas[0] + let imageView = cell.statusView.mosaicImageView.setupImageView(aspectRatio: meta.size, maxSize: imageViewMaxSize) + imageView.af.setImage( + withURL: meta.url, + placeholderImage: UIImage.placeholder(color: .systemFill), + imageTransition: .crossDissolve(0.2) + ) + } else { + let imageViews = cell.statusView.mosaicImageView.setupImageViews(count: mosiacImageViewModel.metas.count, maxHeight: imageViewMaxSize.height) + for (i, imageView) in imageViews.enumerated() { + let meta = mosiacImageViewModel.metas[i] + imageView.af.setImage( + withURL: meta.url, + placeholderImage: UIImage.placeholder(color: .systemFill), + imageTransition: .crossDissolve(0.2) + ) + } + } + cell.statusView.mosaicImageView.isHidden = mosiacImageViewModel.metas.isEmpty + + // toolbar + let replyCountTitle: String = { + let count = (toot.reblog ?? toot).repliesCount?.intValue ?? 0 + return StatusSection.formattedNumberTitleForActionButton(count) + }() + cell.statusView.actionToolbarContainer.replyButton.setTitle(replyCountTitle, for: .normal) + + let isLike = (toot.reblog ?? toot).favouritedBy.flatMap { $0.contains(where: { $0.id == requestUserID }) } ?? false + let favoriteCountTitle: String = { + let count = (toot.reblog ?? toot).favouritesCount.intValue + return StatusSection.formattedNumberTitleForActionButton(count) + }() + cell.statusView.actionToolbarContainer.starButton.setTitle(favoriteCountTitle, for: .normal) + cell.statusView.actionToolbarContainer.isStarButtonHighlight = isLike + + // set date + let createdAt = (toot.reblog ?? toot).createdAt + cell.statusView.dateLabel.text = createdAt.shortTimeAgoSinceNow + timestampUpdatePublisher + .sink { _ in + cell.statusView.dateLabel.text = createdAt.shortTimeAgoSinceNow + } + .store(in: &cell.disposeBag) + + // observe model change + ManagedObjectObserver.observe(object: toot.reblog ?? toot) + .receive(on: DispatchQueue.main) + .sink { _ in + // do nothing + } receiveValue: { change in + guard case .update(let object) = change.changeType, + let newToot = object as? Toot else { return } + let targetToot = newToot.reblog ?? newToot + + let isLike = targetToot.favouritedBy.flatMap { $0.contains(where: { $0.id == requestUserID }) } ?? false + let favoriteCount = targetToot.favouritesCount.intValue + let favoriteCountTitle = StatusSection.formattedNumberTitleForActionButton(favoriteCount) + cell.statusView.actionToolbarContainer.starButton.setTitle(favoriteCountTitle, for: .normal) + 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) + } + .store(in: &cell.disposeBag) + } +} + +extension StatusSection { + private static func formattedNumberTitleForActionButton(_ number: Int?) -> String { + guard let number = number, number > 0 else { return "" } + return String(number) + } +} diff --git a/Mastodon/Diffiable/Section/TimelineSection.swift b/Mastodon/Diffiable/Section/TimelineSection.swift deleted file mode 100644 index c9adbd833..000000000 --- a/Mastodon/Diffiable/Section/TimelineSection.swift +++ /dev/null @@ -1,131 +0,0 @@ -// -// TimelineSection.swift -// Mastodon -// -// Created by sxiaojian on 2021/1/27. -// - -import Combine -import CoreData -import CoreDataStack -import os.log -import UIKit - -enum TimelineSection: Equatable, Hashable { - case main -} - -extension TimelineSection { - static func tableViewDiffableDataSource( - for tableView: UITableView, - dependency: NeedsDependency, - managedObjectContext: NSManagedObjectContext, - timestampUpdatePublisher: AnyPublisher, - timelinePostTableViewCellDelegate: TimelinePostTableViewCellDelegate, - timelineMiddleLoaderTableViewCellDelegate: TimelineMiddleLoaderTableViewCellDelegate? - ) -> UITableViewDiffableDataSource { - UITableViewDiffableDataSource(tableView: tableView) { [weak timelinePostTableViewCellDelegate, weak timelineMiddleLoaderTableViewCellDelegate] tableView, indexPath, item -> UITableViewCell? in - guard let timelinePostTableViewCellDelegate = timelinePostTableViewCellDelegate else { return UITableViewCell() } - - switch item { - case .homeTimelineIndex(objectID: let objectID, attribute: _): - let cell = tableView.dequeueReusableCell(withIdentifier: String(describing: TimelinePostTableViewCell.self), for: indexPath) as! TimelinePostTableViewCell - - // configure cell - managedObjectContext.performAndWait { - let timelineIndex = managedObjectContext.object(with: objectID) as! HomeTimelineIndex - TimelineSection.configure(cell: cell, timestampUpdatePublisher: timestampUpdatePublisher, toot: timelineIndex.toot, requestUserID: timelineIndex.userID) - } - cell.delegate = timelinePostTableViewCellDelegate - return cell - case .toot(let objectID): - let cell = tableView.dequeueReusableCell(withIdentifier: String(describing: TimelinePostTableViewCell.self), for: indexPath) as! TimelinePostTableViewCell - let activeMastodonAuthenticationBox = dependency.context.authenticationService.activeMastodonAuthenticationBox.value - let requestUserID = activeMastodonAuthenticationBox?.userID ?? "" - // configure cell - managedObjectContext.performAndWait { - let toot = managedObjectContext.object(with: objectID) as! Toot - TimelineSection.configure(cell: cell, timestampUpdatePublisher: timestampUpdatePublisher, toot: toot, requestUserID: requestUserID) - } - cell.delegate = timelinePostTableViewCellDelegate - return cell - case .publicMiddleLoader(let upperTimelineTootID): - let cell = tableView.dequeueReusableCell(withIdentifier: String(describing: TimelineMiddleLoaderTableViewCell.self), for: indexPath) as! TimelineMiddleLoaderTableViewCell - cell.delegate = timelineMiddleLoaderTableViewCellDelegate - timelineMiddleLoaderTableViewCellDelegate?.configure(cell: cell, upperTimelineTootID: upperTimelineTootID, timelineIndexobjectID: nil) - return cell - case .homeMiddleLoader(let upperTimelineIndexObjectID): - let cell = tableView.dequeueReusableCell(withIdentifier: String(describing: TimelineMiddleLoaderTableViewCell.self), for: indexPath) as! TimelineMiddleLoaderTableViewCell - cell.delegate = timelineMiddleLoaderTableViewCellDelegate - timelineMiddleLoaderTableViewCellDelegate?.configure(cell: cell, upperTimelineTootID: nil, timelineIndexobjectID: upperTimelineIndexObjectID) - return cell - case .bottomLoader: - let cell = tableView.dequeueReusableCell(withIdentifier: String(describing: TimelineBottomLoaderTableViewCell.self), for: indexPath) as! TimelineBottomLoaderTableViewCell - cell.activityIndicatorView.startAnimating() - return cell - } - } - } - - static func configure( - cell: TimelinePostTableViewCell, - timestampUpdatePublisher: AnyPublisher, - toot: Toot, - requestUserID: String - ) { - // set name username avatar - cell.timelinePostView.nameLabel.text = toot.author.displayName - cell.timelinePostView.usernameLabel.text = "@" + toot.author.username - cell.timelinePostView.avatarImageView.af.setImage( - withURL: URL(string: toot.author.avatar)!, - placeholderImage: UIImage.placeholder(color: .systemFill), - imageTransition: .crossDissolve(0.2) - ) - // set text - cell.timelinePostView.activeTextLabel.config(content: toot.content) - - // toolbar - let isLike = (toot.reblog ?? toot).favouritedBy.flatMap { $0.contains(where: { $0.id == requestUserID }) } ?? false - let favoriteCountTitle: String = { - let count = (toot.reblog ?? toot).favouritesCount.intValue - return TimelineSection.formattedNumberTitleForActionButton(count) - }() - cell.timelinePostView.actionToolbarContainer.starButton.setTitle(favoriteCountTitle, for: .normal) - cell.timelinePostView.actionToolbarContainer.isStarButtonHighlight = isLike - - // set date - let createdAt = (toot.reblog ?? toot).createdAt - cell.timelinePostView.dateLabel.text = createdAt.shortTimeAgoSinceNow - timestampUpdatePublisher - .sink { _ in - cell.timelinePostView.dateLabel.text = createdAt.shortTimeAgoSinceNow - } - .store(in: &cell.disposeBag) - - // observe model change - ManagedObjectObserver.observe(object: toot.reblog ?? toot) - .receive(on: DispatchQueue.main) - .sink { _ in - // do nothing - } receiveValue: { change in - guard case .update(let object) = change.changeType, - let newToot = object as? Toot else { return } - let targetToot = newToot.reblog ?? newToot - - let isLike = targetToot.favouritedBy.flatMap { $0.contains(where: { $0.id == requestUserID }) } ?? false - let favoriteCount = targetToot.favouritesCount.intValue - let favoriteCountTitle = TimelineSection.formattedNumberTitleForActionButton(favoriteCount) - cell.timelinePostView.actionToolbarContainer.starButton.setTitle(favoriteCountTitle, for: .normal) - cell.timelinePostView.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) - } - .store(in: &cell.disposeBag) - } -} - -extension TimelineSection { - private static func formattedNumberTitleForActionButton(_ number: Int?) -> String { - guard let number = number, number > 0 else { return "" } - return String(number) - } -} diff --git a/Mastodon/Extension/ActiveLabel.swift b/Mastodon/Extension/ActiveLabel.swift index 6e08d7268..9219701f5 100644 --- a/Mastodon/Extension/ActiveLabel.swift +++ b/Mastodon/Extension/ActiveLabel.swift @@ -22,18 +22,18 @@ extension ActiveLabel { switch style { case .default: -// urlMaximumLength = 30 font = .preferredFont(forTextStyle: .body) - textColor = .white + textColor = Asset.Colors.Label.primary.color case .timelineHeaderView: font = .preferredFont(forTextStyle: .footnote) textColor = .secondaryLabel } numberOfLines = 0 - mentionColor = UIColor.yellow - hashtagColor = UIColor.blue - URLColor = UIColor.red + lineSpacing = 5 + mentionColor = Asset.Colors.Label.highlight.color + 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." } @@ -41,16 +41,12 @@ extension ActiveLabel { extension ActiveLabel { func config(content: String) { + activeEntities.removeAll() if let parseResult = try? TootContent.parse(toot: content) { - activeEntities.removeAll() - numberOfLines = 0 - font = UIFont(name: "SFProText-Regular", size: 16) - textColor = .white - URLColor = .systemRed - mentionColor = .systemGreen - hashtagColor = .systemBlue text = parseResult.trimmed activeEntities = parseResult.activeEntities + } else { + text = "" } } } diff --git a/Mastodon/Extension/CoreDataStack/Attachment.swift b/Mastodon/Extension/CoreDataStack/Attachment.swift new file mode 100644 index 000000000..e17f9bfef --- /dev/null +++ b/Mastodon/Extension/CoreDataStack/Attachment.swift @@ -0,0 +1,23 @@ +// +// Attachment.swift +// Mastodon +// +// Created by MainasuK Cirno on 2021-2-23. +// + +import Foundation +import CoreDataStack +import MastodonSDK + +extension Attachment { + + var type: Mastodon.Entity.Attachment.AttachmentType { + return Mastodon.Entity.Attachment.AttachmentType(rawValue: typeRaw) ?? ._other(typeRaw) + } + + var meta: Mastodon.Entity.Attachment.Meta? { + let decoder = JSONDecoder() + return metaData.flatMap { try? decoder.decode(Mastodon.Entity.Attachment.Meta.self, from: $0) } + } + +} diff --git a/Mastodon/Extension/NSKeyValueObservation.swift b/Mastodon/Extension/NSKeyValueObservation.swift new file mode 100644 index 000000000..fa45364b3 --- /dev/null +++ b/Mastodon/Extension/NSKeyValueObservation.swift @@ -0,0 +1,14 @@ +// +// NSKeyValueObservation.swift +// Mastodon +// +// Created by Cirno MainasuK on 2021-2-24. +// + +import Foundation + +extension NSKeyValueObservation { + func store(in set: inout Set) { + set.insert(self) + } +} diff --git a/Mastodon/Extension/UIIamge.swift b/Mastodon/Extension/UIIamge.swift index 20069f7c7..4f4b350c3 100644 --- a/Mastodon/Extension/UIIamge.swift +++ b/Mastodon/Extension/UIIamge.swift @@ -40,3 +40,16 @@ extension UIImage { return UIColor(red: CGFloat(bitmap[0]) / 255, green: CGFloat(bitmap[1]) / 255, blue: CGFloat(bitmap[2]) / 255, alpha: CGFloat(bitmap[3]) / 255) } } + +extension UIImage { + func blur(radius: CGFloat) -> UIImage? { + guard let inputImage = CIImage(image: self) else { return nil } + let blurFilter = CIFilter.gaussianBlur() + blurFilter.inputImage = inputImage + blurFilter.radius = Float(radius) + guard let outputImage = blurFilter.outputImage else { return nil } + guard let cgImage = CIContext().createCGImage(outputImage, from: outputImage.extent) else { return nil } + let image = UIImage(cgImage: cgImage, scale: scale, orientation: imageOrientation) + return image + } +} diff --git a/Mastodon/Generated/Assets.swift b/Mastodon/Generated/Assets.swift index bbda2daa3..3fa09e446 100644 --- a/Mastodon/Generated/Assets.swift +++ b/Mastodon/Generated/Assets.swift @@ -25,14 +25,20 @@ internal enum Asset { internal enum Arrows { internal static let arrowTriangle2Circlepath = ImageAsset(name: "Arrows/arrow.triangle.2.circlepath") } + internal enum Asset { + internal static let mastodonTextLogo = ImageAsset(name: "Asset/mastodon.text.logo") + } internal enum Colors { internal enum 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 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 enum Button { + internal static let actionToolbar = ColorAsset(name: "Colors/Button/action.toolbar") internal static let highlight = ColorAsset(name: "Colors/Button/highlight") } internal enum Icon { @@ -40,7 +46,7 @@ internal enum Asset { internal static let plus = ColorAsset(name: "Colors/Icon/plus") } 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 secondary = ColorAsset(name: "Colors/Label/secondary") } @@ -61,21 +67,6 @@ internal enum Asset { internal static let lightWhite = ColorAsset(name: "Colors/lightWhite") internal static let systemOrange = ColorAsset(name: "Colors/system.orange") } - internal enum ToolBar { - internal static let bookmark = ImageAsset(name: "ToolBar/bookmark") - internal static let lock = ImageAsset(name: "ToolBar/lock") - internal static let more = ImageAsset(name: "ToolBar/more") - internal static let reply = ImageAsset(name: "ToolBar/reply") - internal static let retoot = ImageAsset(name: "ToolBar/retoot") - internal static let star = ImageAsset(name: "ToolBar/star") - } - internal enum TootTimeline { - internal static let global = ImageAsset(name: "TootTimeline/Global") - internal static let textlock = ImageAsset(name: "TootTimeline/Textlock") - internal static let email = ImageAsset(name: "TootTimeline/email") - internal static let lock = ImageAsset(name: "TootTimeline/lock") - internal static let unlock = ImageAsset(name: "TootTimeline/unlock") - } internal static let welcomeLogo = ImageAsset(name: "welcome.logo") } // swiftlint:enable identifier_name line_length nesting type_body_length type_name diff --git a/Mastodon/Generated/Strings.swift b/Mastodon/Generated/Strings.swift index 6042012d1..7b9d9eca5 100644 --- a/Mastodon/Generated/Strings.swift +++ b/Mastodon/Generated/Strings.swift @@ -11,13 +11,6 @@ import Foundation // swiftlint:disable nesting type_body_length type_name vertical_whitespace_opening_braces internal enum L10n { - internal enum Button { - /// Sign In - internal static let signIn = L10n.tr("Localizable", "Button.SignIn") - /// Sign Up - internal static let signUp = L10n.tr("Localizable", "Button.SignUp") - } - internal enum Common { internal enum Controls { internal enum Actions { @@ -52,6 +45,16 @@ internal enum L10n { /// Take photo internal static let takePhoto = L10n.tr("Localizable", "Common.Controls.Actions.TakePhoto") } + internal enum Status { + /// content warning + internal static let contentWarning = L10n.tr("Localizable", "Common.Controls.Status.ContentWarning") + /// Show Post + internal static let showPost = L10n.tr("Localizable", "Common.Controls.Status.ShowPost") + /// %@ boosted + internal static func userBoosted(_ p1: Any) -> String { + return L10n.tr("Localizable", "Common.Controls.Status.UserBoosted", String(describing: p1)) + } + } internal enum Timeline { /// Load More internal static let loadMore = L10n.tr("Localizable", "Common.Controls.Timeline.LoadMore") diff --git a/Mastodon/Info.plist b/Mastodon/Info.plist index 3455e6836..bc681a7d6 100644 --- a/Mastodon/Info.plist +++ b/Mastodon/Info.plist @@ -62,8 +62,6 @@ UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight - UIUserInterfaceStyle - Dark UIViewControllerBasedStatusBarAppearance diff --git a/Mastodon/Protocol/AvatarConfigurableView.swift b/Mastodon/Protocol/AvatarConfigurableView.swift index dfeb3e5bb..6c51d576c 100644 --- a/Mastodon/Protocol/AvatarConfigurableView.swift +++ b/Mastodon/Protocol/AvatarConfigurableView.swift @@ -10,28 +10,19 @@ import AlamofireImage import Kingfisher protocol AvatarConfigurableView { - static var configurableAvatarImageViewSize: CGSize { get } - static var configurableAvatarImageViewBadgeAppearanceStyle: AvatarConfigurableViewConfiguration.BadgeAppearanceStyle { get } + static var configurableAvatarImageSize: CGSize { get } + static var configurableAvatarImageCornerRadius: CGFloat { get } var configurableAvatarImageView: UIImageView? { get } var configurableAvatarButton: UIButton? { get } - var configurableVerifiedBadgeImageView: UIImageView? { get } - func configure(withConfigurationInput input: AvatarConfigurableViewConfiguration.Input) + func configure(with configuration: AvatarConfigurableViewConfiguration) func avatarConfigurableView(_ avatarConfigurableView: AvatarConfigurableView, didFinishConfiguration configuration: AvatarConfigurableViewConfiguration) } extension AvatarConfigurableView { - static var configurableAvatarImageViewBadgeAppearanceStyle: AvatarConfigurableViewConfiguration.BadgeAppearanceStyle { return .mini } - - 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 - + public func configure(with configuration: AvatarConfigurableViewConfiguration) { 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() }() @@ -51,12 +42,11 @@ extension AvatarConfigurableView { configurableAvatarButton?.layer.cornerCurve = .circular defer { - let configuration = AvatarConfigurableViewConfiguration(input: input) avatarConfigurableView(self, didFinishConfiguration: configuration) } // set placeholder if no asset - guard let avatarImageURL = input.avatarImageURL else { + guard let avatarImageURL = configuration.avatarImageURL else { configurableAvatarImageView?.image = placeholderImage configurableAvatarButton?.setImage(placeholderImage, for: .normal) return @@ -74,10 +64,10 @@ extension AvatarConfigurableView { ] ) avatarImageView.layer.masksToBounds = true - avatarImageView.layer.cornerRadius = cornerRadius + avatarImageView.layer.cornerRadius = Self.configurableAvatarImageCornerRadius avatarImageView.layer.cornerCurve = .circular default: - let filter = ScaledToSizeCircleFilter(size: Self.configurableAvatarImageViewSize) + let filter = ScaledToSizeWithRoundedCornersFilter(size: Self.configurableAvatarImageSize, radius: Self.configurableAvatarImageCornerRadius) avatarImageView.af.setImage( withURL: avatarImageURL, placeholderImage: placeholderImage, @@ -101,10 +91,10 @@ extension AvatarConfigurableView { ] ) avatarButton.layer.masksToBounds = true - avatarButton.layer.cornerRadius = cornerRadius - avatarButton.layer.cornerCurve = .circular + avatarButton.layer.cornerRadius = Self.configurableAvatarImageCornerRadius + avatarButton.layer.cornerCurve = .continuous default: - let filter = ScaledToSizeCircleFilter(size: Self.configurableAvatarImageViewSize) + let filter = ScaledToSizeWithRoundedCornersFilter(size: Self.configurableAvatarImageSize, radius: Self.configurableAvatarImageCornerRadius) avatarButton.af.setImage( for: .normal, url: avatarImageURL, @@ -122,25 +112,12 @@ extension AvatarConfigurableView { struct AvatarConfigurableViewConfiguration { - enum BadgeAppearanceStyle { - case mini - case normal - } + let avatarImageURL: URL? + let placeholderImage: UIImage? - struct Input { - let avatarImageURL: URL? - let placeholderImage: UIImage? - 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 - } + init(avatarImageURL: URL?, placeholderImage: UIImage? = nil) { + self.avatarImageURL = avatarImageURL + self.placeholderImage = placeholderImage } - let input: Input - } diff --git a/Mastodon/Protocol/StatusProvider/StatusProvider+TimelinePostTableViewCellDelegate.swift b/Mastodon/Protocol/StatusProvider/StatusProvider+TimelinePostTableViewCellDelegate.swift index 9b50071f7..9c6127b08 100644 --- a/Mastodon/Protocol/StatusProvider/StatusProvider+TimelinePostTableViewCellDelegate.swift +++ b/Mastodon/Protocol/StatusProvider/StatusProvider+TimelinePostTableViewCellDelegate.swift @@ -14,11 +14,32 @@ import MastodonSDK import ActiveLabel // 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) } + func statusTableViewCell(_ cell: StatusTableViewCell, statusView: StatusView, contentWarningActionButtonPressed button: UIButton) { + guard let diffableDataSource = self.tableViewDiffableDataSource else { return } + item(for: cell, indexPath: nil) + .receive(on: DispatchQueue.main) + .sink { [weak self] item in + guard let _ = self else { return } + guard let item = item else { return } + switch item { + case .homeTimelineIndex(_, let attribute): + attribute.isStatusTextSensitive = false + case .toot(_, let attribute): + attribute.isStatusTextSensitive = false + default: + return + } + var snapshot = diffableDataSource.snapshot() + snapshot.reloadItems([item]) + diffableDataSource.apply(snapshot) + } + .store(in: &cell.disposeBag) + } } diff --git a/Mastodon/Protocol/StatusProvider/StatusProvider.swift b/Mastodon/Protocol/StatusProvider/StatusProvider.swift index 667fc05ac..781ccc9f3 100644 --- a/Mastodon/Protocol/StatusProvider/StatusProvider.swift +++ b/Mastodon/Protocol/StatusProvider/StatusProvider.swift @@ -13,4 +13,7 @@ protocol StatusProvider: NeedsDependency & DisposeBagCollectable & UIViewControl func toot() -> Future func toot(for cell: UITableViewCell, indexPath: IndexPath?) -> Future func toot(for cell: UICollectionViewCell) -> Future + + var tableViewDiffableDataSource: UITableViewDiffableDataSource? { get } + func item(for cell: UITableViewCell, indexPath: IndexPath?) -> Future } diff --git a/Mastodon/Resources/Assets.xcassets/Arrows/arrow.triangle.2.circlepath.imageset/Contents.json b/Mastodon/Resources/Assets.xcassets/Arrows/arrow.triangle.2.circlepath.imageset/Contents.json index 0ee766f71..c59347e9e 100644 --- a/Mastodon/Resources/Assets.xcassets/Arrows/arrow.triangle.2.circlepath.imageset/Contents.json +++ b/Mastodon/Resources/Assets.xcassets/Arrows/arrow.triangle.2.circlepath.imageset/Contents.json @@ -2,16 +2,7 @@ "images" : [ { "filename" : "arrow.triangle.2.circlepath.pdf", - "idiom" : "universal", - "scale" : "1x" - }, - { - "idiom" : "universal", - "scale" : "2x" - }, - { - "idiom" : "universal", - "scale" : "3x" + "idiom" : "universal" } ], "info" : { diff --git a/Mastodon/Resources/Assets.xcassets/ToolBar/Contents.json b/Mastodon/Resources/Assets.xcassets/Asset/Contents.json similarity index 100% rename from Mastodon/Resources/Assets.xcassets/ToolBar/Contents.json rename to Mastodon/Resources/Assets.xcassets/Asset/Contents.json diff --git a/Mastodon/Resources/Assets.xcassets/Asset/mastodon.text.logo.imageset/Contents.json b/Mastodon/Resources/Assets.xcassets/Asset/mastodon.text.logo.imageset/Contents.json new file mode 100644 index 000000000..9083b4b4c --- /dev/null +++ b/Mastodon/Resources/Assets.xcassets/Asset/mastodon.text.logo.imageset/Contents.json @@ -0,0 +1,12 @@ +{ + "images" : [ + { + "filename" : "mastodon.title.logo.pdf", + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Mastodon/Resources/Assets.xcassets/Asset/mastodon.text.logo.imageset/mastodon.title.logo.pdf b/Mastodon/Resources/Assets.xcassets/Asset/mastodon.text.logo.imageset/mastodon.title.logo.pdf new file mode 100644 index 000000000..de17d847d --- /dev/null +++ b/Mastodon/Resources/Assets.xcassets/Asset/mastodon.text.logo.imageset/mastodon.title.logo.pdf @@ -0,0 +1,229 @@ +%PDF-1.7 + +1 0 obj + << >> +endobj + +2 0 obj + << /Length 3 0 R >> +stream +/DeviceRGB CS +/DeviceRGB cs +q +1.000000 0.000000 -0.000000 1.000000 2.000000 0.579529 cm +0.121569 0.137255 0.168627 scn +16.348507 7.298912 m +16.348507 0.110882 l +13.500799 0.110882 l +13.500799 7.087682 l +13.500799 8.558509 12.881892 9.304815 11.644079 9.304815 c +10.275755 9.304815 9.589746 8.419246 9.589746 6.668335 c +9.589746 2.849669 l +6.758763 2.849669 l +6.758763 6.668335 l +6.758763 8.419246 6.072753 9.304815 4.704429 9.304815 c +3.466616 9.304815 2.847710 8.558509 2.847710 7.087682 c +2.847710 0.110882 l +0.000000 0.110882 l +0.000000 7.298912 l +0.000000 8.767988 0.374029 9.935391 1.125391 10.799177 c +1.900289 11.662767 2.915007 12.105455 4.174410 12.105455 c +5.631816 12.105455 6.735424 11.545483 7.464808 10.425148 c +8.174352 9.235961 l +8.883701 10.425148 l +9.613279 11.545483 10.716693 12.105455 12.174294 12.105455 c +13.433697 12.105455 14.448222 11.662767 15.223120 10.799177 c +15.974483 9.935391 16.348507 8.767988 16.348507 7.298912 c +h +26.158895 3.725689 m +26.746487 4.346540 27.029490 5.128441 27.029490 6.071388 c +27.029490 7.014336 26.746487 7.796235 26.158895 8.394135 c +25.593088 9.015182 24.874598 9.313937 24.004005 9.313937 c +23.133219 9.313937 22.414919 9.015182 21.849112 8.394135 c +21.283110 7.796235 21.000111 7.014336 21.000111 6.071388 c +21.000111 5.128441 21.283110 4.346540 21.849112 3.725689 c +22.414919 3.127789 23.133219 2.828838 24.004005 2.828838 c +24.874598 2.828838 25.593088 3.127789 26.158895 3.725689 c +h +27.029490 11.820879 m +29.837523 11.820879 l +29.837523 0.321898 l +27.029490 0.321898 l +27.029490 1.678941 l +26.180681 0.551994 25.005110 -0.000004 23.481573 -0.000004 c +22.023193 -0.000004 20.782465 0.574944 19.737598 1.747989 c +18.714710 2.920838 18.192272 4.369687 18.192272 6.071388 c +18.192272 7.750138 18.714710 9.199181 19.737598 10.372030 c +20.782465 11.544880 22.023193 12.142780 23.481573 12.142780 c +25.005110 12.142780 26.180681 11.590782 27.029490 10.464029 c +27.029490 11.820879 l +h +39.284966 6.278339 m +40.111988 5.657488 40.525707 4.783587 40.503922 3.679787 c +40.503922 2.506742 40.090210 1.586940 39.241402 0.942943 c +38.392399 0.321896 37.369507 -0.000004 36.128777 -0.000004 c +33.886749 -0.000004 32.363014 0.919992 31.557581 2.736839 c +33.995674 4.185493 l +34.322048 3.196836 35.040340 2.690742 36.128777 2.690742 c +37.129879 2.690742 37.630730 3.012838 37.630730 3.679787 c +37.630730 4.162736 36.977592 4.599589 35.649918 4.944442 c +35.149075 5.082539 34.735561 5.220440 34.409187 5.335586 c +33.952106 5.519390 33.560379 5.726535 33.233810 5.979388 c +32.428375 6.600240 32.014854 7.428431 32.014854 8.486135 c +32.014854 9.613082 32.406590 10.509933 33.190239 11.153931 c +33.995674 11.820879 34.974995 12.142780 36.150566 12.142780 c +38.022457 12.142780 39.393890 11.337929 40.286072 9.705081 c +37.891945 8.325281 l +37.543591 9.106986 36.956001 9.497936 36.150566 9.497936 c +35.301563 9.497936 34.888054 9.176035 34.888054 8.555183 c +34.888054 8.072233 35.540989 7.635381 36.868858 7.290334 c +37.891941 7.060431 38.697178 6.715386 39.284966 6.278339 c +h +48.209846 8.969084 m +45.750168 8.969084 l +45.750168 4.185493 l +45.750168 3.610543 45.968018 3.265691 46.381531 3.104837 c +46.686317 2.989692 47.295685 2.966742 48.209846 3.012838 c +48.209846 0.321898 l +46.316364 0.091995 44.944931 0.275993 44.139496 0.897040 c +43.334255 1.494941 42.942337 2.598742 42.942337 4.185493 c +42.942337 8.969084 l +41.048660 8.969084 l +41.048660 11.820879 l +42.942337 11.820879 l +42.942337 14.143626 l +45.750168 15.040477 l +45.750168 11.820879 l +48.209846 11.820879 l +48.209846 8.969084 l +h +57.156685 3.794641 m +57.722687 4.392735 58.005493 5.151684 58.005493 6.071486 c +58.005493 6.991287 57.722687 7.750236 57.156685 8.348136 c +56.590683 8.946231 55.894169 9.244986 55.045166 9.244986 c +54.196358 9.244986 53.499847 8.946231 52.933846 8.348136 c +52.389629 7.727284 52.106628 6.968336 52.106628 6.071486 c +52.106628 5.174440 52.389629 4.415492 52.933846 3.794641 c +53.499847 3.196740 54.196358 2.897789 55.045166 2.897789 c +55.894169 2.897789 56.590683 3.196740 57.156685 3.794641 c +h +50.953033 1.747891 m +49.843010 2.920741 49.298790 4.346638 49.298790 6.071486 c +49.298790 7.773381 49.843010 9.199083 50.953033 10.371933 c +52.063057 11.544782 53.434490 12.142683 55.045166 12.142683 c +56.656036 12.142683 58.027279 11.544782 59.137497 10.371933 c +60.247715 9.199083 60.813522 7.750236 60.813522 6.071486 c +60.813522 4.369590 60.247715 2.920741 59.137497 1.747891 c +58.027279 0.574847 56.677818 0.000093 55.045166 0.000093 c +53.412708 0.000093 52.063057 0.574847 50.953033 1.747891 c +h +70.195557 3.725689 m +70.761559 4.346540 71.044373 5.128441 71.044373 6.071388 c +71.044373 7.014336 70.761559 7.796235 70.195557 8.394135 c +69.629745 9.015182 68.911255 9.313937 68.040665 9.313937 c +67.169876 9.313937 66.451584 9.015182 65.863991 8.394135 c +65.298180 7.796235 65.014984 7.014336 65.014984 6.071388 c +65.014984 5.128441 65.298180 4.346540 65.863991 3.725689 c +66.451584 3.127789 67.191658 2.828838 68.040665 2.828838 c +68.911255 2.828838 69.629745 3.127789 70.195557 3.725689 c +h +71.044373 16.420471 m +73.852386 16.420471 l +73.852386 0.321898 l +71.044373 0.321898 l +71.044373 1.678941 l +70.217346 0.551994 69.041771 -0.000004 67.518234 -0.000004 c +66.059853 -0.000004 64.797539 0.574944 63.752670 1.747989 c +62.729588 2.920838 62.207153 4.369687 62.207153 6.071388 c +62.207153 7.750138 62.729588 9.199181 63.752670 10.372030 c +64.797539 11.544880 66.059853 12.142780 67.518234 12.142780 c +69.041771 12.142780 70.217346 11.590782 71.044373 10.464029 c +71.044373 16.420471 l +h +83.713470 3.794641 m +84.279282 4.392735 84.562279 5.151684 84.562279 6.071486 c +84.562279 6.991287 84.279282 7.750236 83.713470 8.348136 c +83.147469 8.946231 82.450958 9.244986 81.601952 9.244986 c +80.753143 9.244986 80.056442 8.946231 79.490631 8.348136 c +78.946220 7.727284 78.663406 6.968336 78.663406 6.071486 c +78.663406 5.174440 78.946220 4.415492 79.490631 3.794641 c +80.056442 3.196740 80.753143 2.897789 81.601952 2.897789 c +82.450958 2.897789 83.147469 3.196740 83.713470 3.794641 c +h +77.509811 1.747891 m +76.399590 2.920741 75.855576 4.346638 75.855576 6.071486 c +75.855576 7.773381 76.399590 9.199083 77.509811 10.371933 c +78.620033 11.544782 79.991280 12.142683 81.601952 12.142683 c +83.212822 12.142683 84.584061 11.544782 85.694283 10.371933 c +86.804504 9.199083 87.370308 7.750236 87.370308 6.071486 c +87.370308 4.369590 86.804504 2.920741 85.694283 1.747891 c +84.584061 0.574847 83.234604 0.000093 81.601952 0.000093 c +79.969490 0.000093 78.620033 0.574847 77.509811 1.747891 c +h +99.516785 7.382295 m +99.516785 0.322052 l +96.708755 0.322052 l +96.708755 7.014297 l +96.708755 7.773245 96.512894 8.348194 96.121162 8.785046 c +95.751022 9.175996 95.228592 9.383141 94.553864 9.383141 c +92.964783 9.383141 92.159538 8.440193 92.159538 6.531347 c +92.159538 0.322052 l +89.351509 0.322052 l +89.351509 11.820840 l +92.159538 11.820840 l +92.159538 10.533039 l +92.834267 11.613889 93.900719 12.142740 95.402863 12.142740 c +96.600021 12.142740 97.579544 11.728840 98.341408 10.877892 c +99.124863 10.026944 99.516785 8.877046 99.516785 7.382295 c +h +f +n +Q + +endstream +endobj + +3 0 obj + 7081 +endobj + +4 0 obj + << /Annots [] + /Type /Page + /MediaBox [ 0.000000 0.000000 103.000000 17.000000 ] + /Resources 1 0 R + /Contents 2 0 R + /Parent 5 0 R + >> +endobj + +5 0 obj + << /Kids [ 4 0 R ] + /Count 1 + /Type /Pages + >> +endobj + +6 0 obj + << /Type /Catalog + /Pages 5 0 R + >> +endobj + +xref +0 7 +0000000000 65535 f +0000000010 00000 n +0000000034 00000 n +0000007171 00000 n +0000007194 00000 n +0000007368 00000 n +0000007442 00000 n +trailer +<< /ID [ (some) (id) ] + /Root 6 0 R + /Size 7 +>> +startxref +7501 +%%EOF \ No newline at end of file diff --git a/Mastodon/Resources/Assets.xcassets/Colors/Background/secondary.grouped.system.background.colorset/Contents.json b/Mastodon/Resources/Assets.xcassets/Colors/Background/secondary.grouped.system.background.colorset/Contents.json new file mode 100644 index 000000000..abe46b9aa --- /dev/null +++ b/Mastodon/Resources/Assets.xcassets/Colors/Background/secondary.grouped.system.background.colorset/Contents.json @@ -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 + } +} diff --git a/Mastodon/Resources/Assets.xcassets/Colors/Background/system.background.colorset/Contents.json b/Mastodon/Resources/Assets.xcassets/Colors/Background/system.background.colorset/Contents.json index 6bdafa8f2..b10e249b2 100644 --- a/Mastodon/Resources/Assets.xcassets/Colors/Background/system.background.colorset/Contents.json +++ b/Mastodon/Resources/Assets.xcassets/Colors/Background/system.background.colorset/Contents.json @@ -5,9 +5,27 @@ "color-space" : "srgb", "components" : { "alpha" : "1.000", - "blue" : "0x2B", - "green" : "0x24", - "red" : "0x20" + "blue" : "255", + "green" : "255", + "red" : "255" + } + }, + "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" diff --git a/Mastodon/Resources/Assets.xcassets/Colors/Background/system.grouped.background.colorset/Contents.json b/Mastodon/Resources/Assets.xcassets/Colors/Background/system.grouped.background.colorset/Contents.json new file mode 100644 index 000000000..edc0dce9a --- /dev/null +++ b/Mastodon/Resources/Assets.xcassets/Colors/Background/system.grouped.background.colorset/Contents.json @@ -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 + } +} diff --git a/Mastodon/Resources/Assets.xcassets/Colors/Button/action.toolbar.colorset/Contents.json b/Mastodon/Resources/Assets.xcassets/Colors/Button/action.toolbar.colorset/Contents.json new file mode 100644 index 000000000..8c938d914 --- /dev/null +++ b/Mastodon/Resources/Assets.xcassets/Colors/Button/action.toolbar.colorset/Contents.json @@ -0,0 +1,38 @@ +{ + "colors" : [ + { + "color" : { + "color-space" : "srgb", + "components" : { + "alpha" : "0.600", + "blue" : "0", + "green" : "0", + "red" : "0" + } + }, + "idiom" : "universal" + }, + { + "appearances" : [ + { + "appearance" : "luminosity", + "value" : "dark" + } + ], + "color" : { + "color-space" : "srgb", + "components" : { + "alpha" : "0.600", + "blue" : "1.000", + "green" : "1.000", + "red" : "1.000" + } + }, + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Mastodon/Resources/Assets.xcassets/Colors/Label/black.colorset/Contents.json b/Mastodon/Resources/Assets.xcassets/Colors/Label/highlight.colorset/Contents.json similarity index 74% rename from Mastodon/Resources/Assets.xcassets/Colors/Label/black.colorset/Contents.json rename to Mastodon/Resources/Assets.xcassets/Colors/Label/highlight.colorset/Contents.json index 95a50e5d3..2e1ce5f3a 100644 --- a/Mastodon/Resources/Assets.xcassets/Colors/Label/black.colorset/Contents.json +++ b/Mastodon/Resources/Assets.xcassets/Colors/Label/highlight.colorset/Contents.json @@ -5,9 +5,9 @@ "color-space" : "srgb", "components" : { "alpha" : "1.000", - "blue" : "0", - "green" : "0", - "red" : "0" + "blue" : "0.851", + "green" : "0.565", + "red" : "0.169" } }, "idiom" : "universal" diff --git a/Mastodon/Resources/Assets.xcassets/Colors/Label/primary.colorset/Contents.json b/Mastodon/Resources/Assets.xcassets/Colors/Label/primary.colorset/Contents.json index fafa47672..202a1c04e 100644 --- a/Mastodon/Resources/Assets.xcassets/Colors/Label/primary.colorset/Contents.json +++ b/Mastodon/Resources/Assets.xcassets/Colors/Label/primary.colorset/Contents.json @@ -5,9 +5,27 @@ "color-space" : "srgb", "components" : { "alpha" : "1.000", - "blue" : "0xFF", - "green" : "0xFF", - "red" : "0xFF" + "blue" : "0x00", + "green" : "0x00", + "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" diff --git a/Mastodon/Resources/Assets.xcassets/Colors/Label/secondary.colorset/Contents.json b/Mastodon/Resources/Assets.xcassets/Colors/Label/secondary.colorset/Contents.json index a47dfc697..70b1446d0 100644 --- a/Mastodon/Resources/Assets.xcassets/Colors/Label/secondary.colorset/Contents.json +++ b/Mastodon/Resources/Assets.xcassets/Colors/Label/secondary.colorset/Contents.json @@ -4,10 +4,28 @@ "color" : { "color-space" : "srgb", "components" : { - "alpha" : "1.000", - "blue" : "132", - "green" : "105", - "red" : "96" + "alpha" : "0.600", + "blue" : "0x43", + "green" : "0x3C", + "red" : "0x3C" + } + }, + "idiom" : "universal" + }, + { + "appearances" : [ + { + "appearance" : "luminosity", + "value" : "dark" + } + ], + "color" : { + "color-space" : "srgb", + "components" : { + "alpha" : "0.600", + "blue" : "0xF5", + "green" : "0xEB", + "red" : "0xEB" } }, "idiom" : "universal" diff --git a/Mastodon/Resources/Assets.xcassets/Colors/lightBrandBlue.colorset/Contents.json b/Mastodon/Resources/Assets.xcassets/Colors/lightBrandBlue.colorset/Contents.json index 2e1ce5f3a..d853a71aa 100644 --- a/Mastodon/Resources/Assets.xcassets/Colors/lightBrandBlue.colorset/Contents.json +++ b/Mastodon/Resources/Assets.xcassets/Colors/lightBrandBlue.colorset/Contents.json @@ -5,9 +5,9 @@ "color-space" : "srgb", "components" : { "alpha" : "1.000", - "blue" : "0.851", - "green" : "0.565", - "red" : "0.169" + "blue" : "217", + "green" : "144", + "red" : "43" } }, "idiom" : "universal" diff --git a/Mastodon/Resources/Assets.xcassets/ToolBar/bookmark.imageset/Contents.json b/Mastodon/Resources/Assets.xcassets/ToolBar/bookmark.imageset/Contents.json deleted file mode 100644 index 4a79584fa..000000000 --- a/Mastodon/Resources/Assets.xcassets/ToolBar/bookmark.imageset/Contents.json +++ /dev/null @@ -1,21 +0,0 @@ -{ - "images" : [ - { - "filename" : "bookmark.pdf", - "idiom" : "universal", - "scale" : "1x" - }, - { - "idiom" : "universal", - "scale" : "2x" - }, - { - "idiom" : "universal", - "scale" : "3x" - } - ], - "info" : { - "author" : "xcode", - "version" : 1 - } -} diff --git a/Mastodon/Resources/Assets.xcassets/ToolBar/bookmark.imageset/bookmark.pdf b/Mastodon/Resources/Assets.xcassets/ToolBar/bookmark.imageset/bookmark.pdf deleted file mode 100644 index 846a6e572..000000000 --- a/Mastodon/Resources/Assets.xcassets/ToolBar/bookmark.imageset/bookmark.pdf +++ /dev/null @@ -1,170 +0,0 @@ -%PDF-1.7 - -1 0 obj - << /Length 2 0 R >> -stream -1.063477 0 0.180664 -0.195801 0.882812 1.271484 d1 - -endstream -endobj - -2 0 obj - 51 -endobj - -3 0 obj - [ 1.063477 ] -endobj - -4 0 obj - << /Length 5 0 R >> -stream -/CIDInit /ProcSet findresource begin -12 dict begin -begincmap -/CIDSystemInfo -<< /Registry (FigmaPDF) - /Ordering (FigmaPDF) - /Supplement 0 ->> def -/CMapName /A-B-C def -/CMapType 2 def -1 begincodespacerange -<00> -endcodespacerange -1 beginbfchar -<00> -endbfchar -endcmap -CMapName currentdict /CMap defineresource pop -end -end -endstream -endobj - -5 0 obj - 336 -endobj - -6 0 obj - << /Subtype /Type3 - /CharProcs << /C0 1 0 R >> - /Encoding << /Type /Encoding - /Differences [ 0 /C0 ] - >> - /Widths 3 0 R - /FontBBox [ 0.000000 0.000000 0.000000 0.000000 ] - /FontMatrix [ 1.000000 0.000000 0.000000 1.000000 0.000000 0.000000 ] - /Type /Font - /ToUnicode 4 0 R - /FirstChar 0 - /LastChar 0 - /Resources << >> - >> -endobj - -7 0 obj - << /Font << /F1 6 0 R >> >> -endobj - -8 0 obj - << /Length 9 0 R >> -stream -/DeviceRGB CS -/DeviceRGB cs -q -1.000000 0.000000 -0.000000 1.000000 -6.382812 0.679688 cm -0.376471 0.411765 0.517647 scn -3.492188 2.453125 m -h -7.554688 -0.679688 m -8.007812 -0.679688 8.312500 -0.453125 8.945312 0.171875 c -11.937500 3.140625 l -11.968750 3.171875 12.031250 3.171875 12.070312 3.140625 c -15.054688 0.164062 l -15.695312 -0.453125 15.992188 -0.679688 16.453125 -0.679688 c -17.164062 -0.679688 17.617188 -0.179688 17.617188 0.601562 c -17.617188 14.289062 l -17.617188 15.898438 16.750000 16.773438 15.156250 16.773438 c -8.843750 16.773438 l -7.250000 16.773438 6.382812 15.898438 6.382812 14.289062 c -6.382812 0.601562 l -6.382812 -0.179688 6.835938 -0.679688 7.554688 -0.679688 c -h -8.382812 2.257812 m -8.281250 2.156250 8.164062 2.187500 8.164062 2.335938 c -8.164062 14.140625 l -8.164062 14.718750 8.437500 14.992188 9.023438 14.992188 c -14.976562 14.992188 l -15.562500 14.992188 15.843750 14.718750 15.843750 14.140625 c -15.843750 2.335938 l -15.843750 2.187500 15.726562 2.156250 15.617188 2.257812 c -12.601562 5.179688 l -12.203125 5.562500 11.796875 5.562500 11.398438 5.179688 c -8.382812 2.257812 l -h -f -n -Q -q -1.000000 0.000000 -0.000000 1.000000 -6.382812 0.679688 cm -BT -16.000000 0.000000 0.000000 16.000000 3.492188 2.453125 Tm -/F1 1.000000 Tf -[ (\000) ] TJ -ET -Q - -endstream -endobj - -9 0 obj - 1276 -endobj - -10 0 obj - << /Annots [] - /Type /Page - /MediaBox [ 0.000000 0.000000 11.234375 17.453125 ] - /Resources 7 0 R - /Contents 8 0 R - /Parent 11 0 R - >> -endobj - -11 0 obj - << /Kids [ 10 0 R ] - /Count 1 - /Type /Pages - >> -endobj - -12 0 obj - << /Type /Catalog - /Pages 11 0 R - >> -endobj - -xref -0 13 -0000000000 65535 f -0000000010 00000 n -0000000117 00000 n -0000000138 00000 n -0000000169 00000 n -0000000561 00000 n -0000000583 00000 n -0000000995 00000 n -0000001041 00000 n -0000002373 00000 n -0000002396 00000 n -0000002571 00000 n -0000002647 00000 n -trailer -<< /ID [ (some) (id) ] - /Root 12 0 R - /Size 13 ->> -startxref -2708 -%%EOF \ No newline at end of file diff --git a/Mastodon/Resources/Assets.xcassets/ToolBar/lock.imageset/Contents.json b/Mastodon/Resources/Assets.xcassets/ToolBar/lock.imageset/Contents.json deleted file mode 100644 index fe86d2855..000000000 --- a/Mastodon/Resources/Assets.xcassets/ToolBar/lock.imageset/Contents.json +++ /dev/null @@ -1,21 +0,0 @@ -{ - "images" : [ - { - "filename" : "lock.pdf", - "idiom" : "universal", - "scale" : "1x" - }, - { - "idiom" : "universal", - "scale" : "2x" - }, - { - "idiom" : "universal", - "scale" : "3x" - } - ], - "info" : { - "author" : "xcode", - "version" : 1 - } -} diff --git a/Mastodon/Resources/Assets.xcassets/ToolBar/lock.imageset/lock.pdf b/Mastodon/Resources/Assets.xcassets/ToolBar/lock.imageset/lock.pdf deleted file mode 100644 index 3aabb0bd0..000000000 --- a/Mastodon/Resources/Assets.xcassets/ToolBar/lock.imageset/lock.pdf +++ /dev/null @@ -1,174 +0,0 @@ -%PDF-1.7 - -1 0 obj - << /Length 2 0 R >> -stream -1.093750 0 0.197266 -0.131348 0.896484 1.184082 d1 - -endstream -endobj - -2 0 obj - 51 -endobj - -3 0 obj - [ 1.093750 ] -endobj - -4 0 obj - << /Length 5 0 R >> -stream -/CIDInit /ProcSet findresource begin -12 dict begin -begincmap -/CIDSystemInfo -<< /Registry (FigmaPDF) - /Ordering (FigmaPDF) - /Supplement 0 ->> def -/CMapName /A-B-C def -/CMapType 2 def -1 begincodespacerange -<00> -endcodespacerange -1 beginbfchar -<00> -endbfchar -endcmap -CMapName currentdict /CMap defineresource pop -end -end -endstream -endobj - -5 0 obj - 336 -endobj - -6 0 obj - << /Subtype /Type3 - /CharProcs << /C0 1 0 R >> - /Encoding << /Type /Encoding - /Differences [ 0 /C0 ] - >> - /Widths 3 0 R - /FontBBox [ 0.000000 0.000000 0.000000 0.000000 ] - /FontMatrix [ 1.000000 0.000000 0.000000 1.000000 0.000000 0.000000 ] - /Type /Font - /ToUnicode 4 0 R - /FirstChar 0 - /LastChar 0 - /Resources << >> - >> -endobj - -7 0 obj - << /Font << /F1 6 0 R >> >> -endobj - -8 0 obj - << /Length 9 0 R >> -stream -/DeviceRGB CS -/DeviceRGB cs -q -1.000000 0.000000 -0.000000 1.000000 -6.406250 1.312500 cm -0.266667 0.294118 0.364706 scn -3.250000 0.789062 m -h -8.257812 -1.312500 m -15.742188 -1.312500 l -16.984375 -1.312500 17.593750 -0.695312 17.593750 0.648438 c -17.593750 6.343750 l -17.593750 7.531250 17.101562 8.156250 16.117188 8.273438 c -16.117188 10.039062 l -16.117188 13.023438 14.101562 14.476562 12.000000 14.476562 c -9.898438 14.476562 7.882812 13.023438 7.882812 10.039062 c -7.882812 8.273438 l -6.890625 8.156250 6.406250 7.531250 6.406250 6.343750 c -6.406250 0.648438 l -6.406250 -0.695312 7.015625 -1.312500 8.257812 -1.312500 c -h -9.570312 10.171875 m -9.570312 11.882812 10.656250 12.843750 12.000000 12.843750 c -13.343750 12.843750 14.429688 11.882812 14.429688 10.171875 c -14.429688 8.296875 l -9.570312 8.296875 l -9.570312 10.171875 l -h -8.656250 0.289062 m -8.328125 0.289062 8.164062 0.445312 8.164062 0.843750 c -8.164062 6.148438 l -8.164062 6.546875 8.328125 6.687500 8.656250 6.687500 c -15.343750 6.687500 l -15.679688 6.687500 15.835938 6.546875 15.835938 6.148438 c -15.835938 0.843750 l -15.835938 0.445312 15.679688 0.289062 15.343750 0.289062 c -8.656250 0.289062 l -h -f -n -Q -q -1.000000 0.000000 -0.000000 1.000000 -6.406250 1.312500 cm -BT -16.000000 0.000000 0.000000 16.000000 3.250000 0.789062 Tm -/F1 1.000000 Tf -[ (\000) ] TJ -ET -Q - -endstream -endobj - -9 0 obj - 1332 -endobj - -10 0 obj - << /Annots [] - /Type /Page - /MediaBox [ 0.000000 0.000000 11.187500 15.789062 ] - /Resources 7 0 R - /Contents 8 0 R - /Parent 11 0 R - >> -endobj - -11 0 obj - << /Kids [ 10 0 R ] - /Count 1 - /Type /Pages - >> -endobj - -12 0 obj - << /Type /Catalog - /Pages 11 0 R - >> -endobj - -xref -0 13 -0000000000 65535 f -0000000010 00000 n -0000000117 00000 n -0000000138 00000 n -0000000169 00000 n -0000000561 00000 n -0000000583 00000 n -0000000995 00000 n -0000001041 00000 n -0000002429 00000 n -0000002452 00000 n -0000002627 00000 n -0000002703 00000 n -trailer -<< /ID [ (some) (id) ] - /Root 12 0 R - /Size 13 ->> -startxref -2764 -%%EOF \ No newline at end of file diff --git a/Mastodon/Resources/Assets.xcassets/ToolBar/more.imageset/Contents.json b/Mastodon/Resources/Assets.xcassets/ToolBar/more.imageset/Contents.json deleted file mode 100644 index d6d5bc04d..000000000 --- a/Mastodon/Resources/Assets.xcassets/ToolBar/more.imageset/Contents.json +++ /dev/null @@ -1,21 +0,0 @@ -{ - "images" : [ - { - "filename" : "more.pdf", - "idiom" : "universal", - "scale" : "1x" - }, - { - "idiom" : "universal", - "scale" : "2x" - }, - { - "idiom" : "universal", - "scale" : "3x" - } - ], - "info" : { - "author" : "xcode", - "version" : 1 - } -} diff --git a/Mastodon/Resources/Assets.xcassets/ToolBar/more.imageset/more.pdf b/Mastodon/Resources/Assets.xcassets/ToolBar/more.imageset/more.pdf deleted file mode 100644 index 93abdd80a..000000000 --- a/Mastodon/Resources/Assets.xcassets/ToolBar/more.imageset/more.pdf +++ /dev/null @@ -1,162 +0,0 @@ -%PDF-1.7 - -1 0 obj - << /Length 2 0 R >> -stream -1.124512 0 0.087402 0.243652 1.037109 0.304199 d1 - -endstream -endobj - -2 0 obj - 50 -endobj - -3 0 obj - [ 1.124512 ] -endobj - -4 0 obj - << /Length 5 0 R >> -stream -/CIDInit /ProcSet findresource begin -12 dict begin -begincmap -/CIDSystemInfo -<< /Registry (FigmaPDF) - /Ordering (FigmaPDF) - /Supplement 0 ->> def -/CMapName /A-B-C def -/CMapType 2 def -1 begincodespacerange -<00> -endcodespacerange -1 beginbfchar -<00> -endbfchar -endcmap -CMapName currentdict /CMap defineresource pop -end -end -endstream -endobj - -5 0 obj - 336 -endobj - -6 0 obj - << /Subtype /Type3 - /CharProcs << /C0 1 0 R >> - /Encoding << /Type /Encoding - /Differences [ 0 /C0 ] - >> - /Widths 3 0 R - /FontBBox [ 0.000000 0.000000 0.000000 0.000000 ] - /FontMatrix [ 1.000000 0.000000 0.000000 1.000000 0.000000 0.000000 ] - /Type /Font - /ToUnicode 4 0 R - /FirstChar 0 - /LastChar 0 - /Resources << >> - >> -endobj - -7 0 obj - << /Font << /F1 6 0 R >> >> -endobj - -8 0 obj - << /Length 9 0 R >> -stream -/DeviceRGB CS -/DeviceRGB cs -q -1.000000 0.000000 -0.000000 1.000000 -4.398438 7.632812 cm -0.376471 0.411765 0.517647 scn -3.000000 -11.531250 m -h -7.875000 -5.898438 m -7.875000 -4.921875 7.117188 -4.164062 6.132812 -4.164062 c -5.179688 -4.164062 4.398438 -4.937500 4.398438 -5.898438 c -4.398438 -6.835938 5.179688 -7.632812 6.132812 -7.632812 c -7.078125 -7.632812 7.875000 -6.835938 7.875000 -5.898438 c -h -13.726562 -5.898438 m -13.726562 -4.921875 12.968750 -4.164062 11.992188 -4.164062 c -11.039062 -4.164062 10.265625 -4.937500 10.265625 -5.898438 c -10.265625 -6.835938 11.039062 -7.632812 11.992188 -7.632812 c -12.937500 -7.632812 13.726562 -6.835938 13.726562 -5.898438 c -h -19.593750 -5.898438 m -19.593750 -4.921875 18.835938 -4.164062 17.859375 -4.164062 c -16.898438 -4.164062 16.117188 -4.937500 16.117188 -5.898438 c -16.117188 -6.835938 16.898438 -7.632812 17.859375 -7.632812 c -18.796875 -7.632812 19.593750 -6.835938 19.593750 -5.898438 c -h -f -n -Q -q -1.000000 0.000000 -0.000000 1.000000 -4.398438 7.632812 cm -BT -16.000000 0.000000 0.000000 16.000000 3.000000 -11.531250 Tm -/F1 1.000000 Tf -[ (\000) ] TJ -ET -Q - -endstream -endobj - -9 0 obj - 1113 -endobj - -10 0 obj - << /Annots [] - /Type /Page - /MediaBox [ 0.000000 0.000000 15.195312 3.468750 ] - /Resources 7 0 R - /Contents 8 0 R - /Parent 11 0 R - >> -endobj - -11 0 obj - << /Kids [ 10 0 R ] - /Count 1 - /Type /Pages - >> -endobj - -12 0 obj - << /Type /Catalog - /Pages 11 0 R - >> -endobj - -xref -0 13 -0000000000 65535 f -0000000010 00000 n -0000000116 00000 n -0000000137 00000 n -0000000168 00000 n -0000000560 00000 n -0000000582 00000 n -0000000994 00000 n -0000001040 00000 n -0000002209 00000 n -0000002232 00000 n -0000002406 00000 n -0000002482 00000 n -trailer -<< /ID [ (some) (id) ] - /Root 12 0 R - /Size 13 ->> -startxref -2543 -%%EOF \ No newline at end of file diff --git a/Mastodon/Resources/Assets.xcassets/ToolBar/reply.imageset/Contents.json b/Mastodon/Resources/Assets.xcassets/ToolBar/reply.imageset/Contents.json deleted file mode 100644 index 37b4fcb41..000000000 --- a/Mastodon/Resources/Assets.xcassets/ToolBar/reply.imageset/Contents.json +++ /dev/null @@ -1,21 +0,0 @@ -{ - "images" : [ - { - "filename" : "reply all.pdf", - "idiom" : "universal", - "scale" : "1x" - }, - { - "idiom" : "universal", - "scale" : "2x" - }, - { - "idiom" : "universal", - "scale" : "3x" - } - ], - "info" : { - "author" : "xcode", - "version" : 1 - } -} diff --git a/Mastodon/Resources/Assets.xcassets/ToolBar/reply.imageset/reply all.pdf b/Mastodon/Resources/Assets.xcassets/ToolBar/reply.imageset/reply all.pdf deleted file mode 100644 index a23ce8334..000000000 --- a/Mastodon/Resources/Assets.xcassets/ToolBar/reply.imageset/reply all.pdf +++ /dev/null @@ -1,206 +0,0 @@ -%PDF-1.7 - -1 0 obj - << /Length 2 0 R >> -stream -1.523438 0 0.076172 -0.107910 1.409668 0.996582 d1 - -endstream -endobj - -2 0 obj - 51 -endobj - -3 0 obj - [ 1.523438 ] -endobj - -4 0 obj - << /Length 5 0 R >> -stream -/CIDInit /ProcSet findresource begin -12 dict begin -begincmap -/CIDSystemInfo -<< /Registry (FigmaPDF) - /Ordering (FigmaPDF) - /Supplement 0 ->> def -/CMapName /A-B-C def -/CMapType 2 def -1 begincodespacerange -<00> -endcodespacerange -1 beginbfchar -<00> -endbfchar -endcmap -CMapName currentdict /CMap defineresource pop -end -end -endstream -endobj - -5 0 obj - 336 -endobj - -6 0 obj - << /Subtype /Type3 - /CharProcs << /C0 1 0 R >> - /Encoding << /Type /Encoding - /Differences [ 0 /C0 ] - >> - /Widths 3 0 R - /FontBBox [ 0.000000 0.000000 0.000000 0.000000 ] - /FontMatrix [ 1.000000 0.000000 0.000000 1.000000 0.000000 0.000000 ] - /Type /Font - /ToUnicode 4 0 R - /FirstChar 0 - /LastChar 0 - /Resources << >> - >> -endobj - -7 0 obj - << /Font << /F1 6 0 R >> >> -endobj - -8 0 obj - << /Length 9 0 R >> -stream -/DeviceRGB CS -/DeviceRGB cs -q -1.000000 0.000000 -0.000000 1.000000 -1.031250 2.000000 cm -0.376471 0.411765 0.517647 scn --0.187500 -0.273438 m -h -8.937500 -2.000000 m -9.601562 -2.000000 10.101562 -1.492188 10.101562 -0.828125 c -10.101562 0.390625 l -12.023438 -1.406250 l -12.460938 -1.812500 12.820312 -2.000000 13.281250 -2.000000 c -13.945312 -2.000000 14.445312 -1.492188 14.445312 -0.828125 c -14.445312 1.828125 l -14.617188 1.828125 l -17.335938 1.828125 18.953125 0.929688 20.062500 -1.140625 c -20.406250 -1.757812 20.804688 -1.929688 21.273438 -1.929688 c -21.921875 -1.929688 22.367188 -1.304688 22.367188 -0.078125 c -22.367188 5.515625 19.828125 8.867188 14.617188 8.867188 c -14.445312 8.867188 l -14.445312 11.531250 l -14.445312 12.195312 13.945312 12.726562 13.265625 12.726562 c -12.828125 12.726562 12.507812 12.546875 12.023438 12.101562 c -10.101562 10.320312 l -10.101562 11.531250 l -10.101562 12.195312 9.601562 12.726562 8.921875 12.726562 c -8.476562 12.726562 8.164062 12.546875 7.679688 12.101562 c -1.468750 6.335938 l -1.156250 6.039062 1.031250 5.687500 1.031250 5.367188 c -1.031250 5.054688 1.164062 4.687500 1.476562 4.390625 c -7.679688 -1.406250 l -8.109375 -1.812500 8.476562 -2.000000 8.937500 -2.000000 c -h -8.273438 0.343750 m -3.109375 5.218750 l -3.046875 5.281250 3.031250 5.320312 3.031250 5.367188 c -3.031250 5.414062 3.046875 5.453125 3.109375 5.507812 c -8.273438 10.429688 l -8.312500 10.460938 8.351562 10.484375 8.406250 10.484375 c -8.476562 10.484375 8.523438 10.437500 8.523438 10.359375 c -8.523438 8.851562 l -5.820312 6.335938 l -5.507812 6.039062 5.375000 5.687500 5.375000 5.367188 c -5.375000 5.054688 5.507812 4.687500 5.820312 4.390625 c -8.523438 1.867188 l -8.523438 0.414062 l -8.523438 0.335938 8.476562 0.281250 8.406250 0.281250 c -8.359375 0.281250 8.320312 0.296875 8.273438 0.343750 c -h -12.750000 0.281250 m -12.703125 0.281250 12.664062 0.296875 12.617188 0.343750 c -7.453125 5.218750 l -7.390625 5.281250 7.375000 5.320312 7.375000 5.367188 c -7.375000 5.414062 7.398438 5.453125 7.453125 5.507812 c -12.617188 10.429688 l -12.656250 10.460938 12.703125 10.484375 12.750000 10.484375 c -12.820312 10.484375 12.867188 10.437500 12.867188 10.359375 c -12.867188 7.523438 l -12.867188 7.351562 12.945312 7.273438 13.125000 7.273438 c -14.078125 7.273438 l -18.867188 7.273438 20.757812 4.257812 20.859375 0.492188 c -20.859375 0.445312 20.835938 0.421875 20.804688 0.421875 c -20.773438 0.421875 20.757812 0.445312 20.734375 0.492188 c -19.796875 2.437500 17.570312 3.453125 14.078125 3.453125 c -13.125000 3.453125 l -12.945312 3.453125 12.867188 3.375000 12.867188 3.195312 c -12.867188 0.414062 l -12.867188 0.335938 12.820312 0.281250 12.750000 0.281250 c -h -f -n -Q -q -1.000000 0.000000 -0.000000 1.000000 -1.031250 2.000000 cm -BT -16.000000 0.000000 0.000000 16.000000 -0.187500 -0.273438 Tm -/F1 1.000000 Tf -[ (\000) ] TJ -ET -Q - -endstream -endobj - -9 0 obj - 2842 -endobj - -10 0 obj - << /Annots [] - /Type /Page - /MediaBox [ 0.000000 0.000000 21.335938 14.726562 ] - /Resources 7 0 R - /Contents 8 0 R - /Parent 11 0 R - >> -endobj - -11 0 obj - << /Kids [ 10 0 R ] - /Count 1 - /Type /Pages - >> -endobj - -12 0 obj - << /Type /Catalog - /Pages 11 0 R - >> -endobj - -xref -0 13 -0000000000 65535 f -0000000010 00000 n -0000000117 00000 n -0000000138 00000 n -0000000169 00000 n -0000000561 00000 n -0000000583 00000 n -0000000995 00000 n -0000001041 00000 n -0000003939 00000 n -0000003962 00000 n -0000004137 00000 n -0000004213 00000 n -trailer -<< /ID [ (some) (id) ] - /Root 12 0 R - /Size 13 ->> -startxref -4274 -%%EOF \ No newline at end of file diff --git a/Mastodon/Resources/Assets.xcassets/ToolBar/retoot.imageset/Contents.json b/Mastodon/Resources/Assets.xcassets/ToolBar/retoot.imageset/Contents.json deleted file mode 100644 index 04488ee0a..000000000 --- a/Mastodon/Resources/Assets.xcassets/ToolBar/retoot.imageset/Contents.json +++ /dev/null @@ -1,21 +0,0 @@ -{ - "images" : [ - { - "filename" : "retoot.pdf", - "idiom" : "universal", - "scale" : "1x" - }, - { - "idiom" : "universal", - "scale" : "2x" - }, - { - "idiom" : "universal", - "scale" : "3x" - } - ], - "info" : { - "author" : "xcode", - "version" : 1 - } -} diff --git a/Mastodon/Resources/Assets.xcassets/ToolBar/retoot.imageset/retoot.pdf b/Mastodon/Resources/Assets.xcassets/ToolBar/retoot.imageset/retoot.pdf deleted file mode 100644 index 7cce18192..000000000 --- a/Mastodon/Resources/Assets.xcassets/ToolBar/retoot.imageset/retoot.pdf +++ /dev/null @@ -1,186 +0,0 @@ -%PDF-1.7 - -1 0 obj - << /Length 2 0 R >> -stream -1.503418 0 0.119141 -0.109863 1.384277 1.042480 d1 - -endstream -endobj - -2 0 obj - 51 -endobj - -3 0 obj - [ 1.503418 ] -endobj - -4 0 obj - << /Length 5 0 R >> -stream -/CIDInit /ProcSet findresource begin -12 dict begin -begincmap -/CIDSystemInfo -<< /Registry (FigmaPDF) - /Ordering (FigmaPDF) - /Supplement 0 ->> def -/CMapName /A-B-C def -/CMapType 2 def -1 begincodespacerange -<00> -endcodespacerange -1 beginbfchar -<00> -endbfchar -endcmap -CMapName currentdict /CMap defineresource pop -end -end -endstream -endobj - -5 0 obj - 336 -endobj - -6 0 obj - << /Subtype /Type3 - /CharProcs << /C0 1 0 R >> - /Encoding << /Type /Encoding - /Differences [ 0 /C0 ] - >> - /Widths 3 0 R - /FontBBox [ 0.000000 0.000000 0.000000 0.000000 ] - /FontMatrix [ 1.000000 0.000000 0.000000 1.000000 0.000000 0.000000 ] - /Type /Font - /ToUnicode 4 0 R - /FirstChar 0 - /LastChar 0 - /Resources << >> - >> -endobj - -7 0 obj - << /Font << /F1 6 0 R >> >> -endobj - -8 0 obj - << /Length 9 0 R >> -stream -/DeviceRGB CS -/DeviceRGB cs -q -1.000000 0.000000 -0.000000 1.000000 -1.967758 1.984375 cm -0.376471 0.411765 0.517647 scn --0.031250 -0.226562 m -h -16.234375 12.789062 m -10.367188 12.789062 l -9.789062 12.789062 9.414062 12.437500 9.414062 11.898438 c -9.421875 11.351562 9.789062 11.000000 10.367188 11.000000 c -16.070312 11.000000 l -16.750000 11.000000 17.109375 10.664062 17.109375 9.953125 c -17.109375 2.109375 l -16.062500 3.281250 l -15.531250 3.804688 l -15.156250 4.179688 14.625000 4.195312 14.257812 3.820312 c -13.882812 3.445312 13.890625 2.914062 14.265625 2.539062 c -16.968750 -0.156250 l -17.625000 -0.804688 18.382812 -0.804688 19.039062 -0.156250 c -21.742188 2.539062 l -22.117188 2.914062 22.117188 3.445312 21.750000 3.820312 c -21.382812 4.195312 20.851562 4.179688 20.476562 3.804688 c -19.945312 3.281250 l -18.898438 2.117188 l -18.898438 10.148438 l -18.898438 11.867188 17.968750 12.789062 16.234375 12.789062 c -h -2.242188 6.984375 m -2.609375 6.617188 3.140625 6.625000 3.515625 7.000000 c -4.046875 7.523438 l -5.093750 8.687500 l -5.093750 0.664062 l -5.093750 -1.062500 6.023438 -1.984375 7.757812 -1.984375 c -13.625000 -1.984375 l -14.203125 -1.984375 14.578125 -1.625000 14.578125 -1.085938 c -14.570312 -0.546875 14.203125 -0.195312 13.625000 -0.195312 c -7.921875 -0.195312 l -7.242188 -0.195312 6.882812 0.148438 6.882812 0.859375 c -6.882812 8.695312 l -7.929688 7.523438 l -8.460938 7.000000 l -8.835938 6.632812 9.367188 6.609375 9.734375 6.984375 c -10.109375 7.359375 10.101562 7.890625 9.726562 8.265625 c -7.023438 10.960938 l -6.367188 11.617188 5.609375 11.609375 4.953125 10.960938 c -2.250000 8.265625 l -1.875000 7.890625 1.875000 7.359375 2.242188 6.984375 c -h -f -n -Q -q -1.000000 0.000000 -0.000000 1.000000 -1.967758 1.984375 cm -BT -16.000000 0.000000 0.000000 16.000000 -0.031250 -0.226562 Tm -/F1 1.000000 Tf -[ (\000) ] TJ -ET -Q - -endstream -endobj - -9 0 obj - 1839 -endobj - -10 0 obj - << /Annots [] - /Type /Page - /MediaBox [ 0.000000 0.000000 20.056656 14.773438 ] - /Resources 7 0 R - /Contents 8 0 R - /Parent 11 0 R - >> -endobj - -11 0 obj - << /Kids [ 10 0 R ] - /Count 1 - /Type /Pages - >> -endobj - -12 0 obj - << /Type /Catalog - /Pages 11 0 R - >> -endobj - -xref -0 13 -0000000000 65535 f -0000000010 00000 n -0000000117 00000 n -0000000138 00000 n -0000000169 00000 n -0000000561 00000 n -0000000583 00000 n -0000000995 00000 n -0000001041 00000 n -0000002936 00000 n -0000002959 00000 n -0000003134 00000 n -0000003210 00000 n -trailer -<< /ID [ (some) (id) ] - /Root 12 0 R - /Size 13 ->> -startxref -3271 -%%EOF \ No newline at end of file diff --git a/Mastodon/Resources/Assets.xcassets/ToolBar/star.imageset/Contents.json b/Mastodon/Resources/Assets.xcassets/ToolBar/star.imageset/Contents.json deleted file mode 100644 index 80fb0f24a..000000000 --- a/Mastodon/Resources/Assets.xcassets/ToolBar/star.imageset/Contents.json +++ /dev/null @@ -1,21 +0,0 @@ -{ - "images" : [ - { - "filename" : "star.pdf", - "idiom" : "universal", - "scale" : "1x" - }, - { - "idiom" : "universal", - "scale" : "2x" - }, - { - "idiom" : "universal", - "scale" : "3x" - } - ], - "info" : { - "author" : "xcode", - "version" : 1 - } -} diff --git a/Mastodon/Resources/Assets.xcassets/ToolBar/star.imageset/star.pdf b/Mastodon/Resources/Assets.xcassets/ToolBar/star.imageset/star.pdf deleted file mode 100644 index b95a8f64e..000000000 --- a/Mastodon/Resources/Assets.xcassets/ToolBar/star.imageset/star.pdf +++ /dev/null @@ -1,193 +0,0 @@ -%PDF-1.7 - -1 0 obj - << /Length 2 0 R >> -stream -1.311523 0 0.092285 -0.149414 1.218750 1.164551 d1 - -endstream -endobj - -2 0 obj - 51 -endobj - -3 0 obj - [ 1.311523 ] -endobj - -4 0 obj - << /Length 5 0 R >> -stream -/CIDInit /ProcSet findresource begin -12 dict begin -begincmap -/CIDSystemInfo -<< /Registry (FigmaPDF) - /Ordering (FigmaPDF) - /Supplement 0 ->> def -/CMapName /A-B-C def -/CMapType 2 def -1 begincodespacerange -<00> -endcodespacerange -1 beginbfchar -<00> -endbfchar -endcmap -CMapName currentdict /CMap defineresource pop -end -end -endstream -endobj - -5 0 obj - 336 -endobj - -6 0 obj - << /Subtype /Type3 - /CharProcs << /C0 1 0 R >> - /Encoding << /Type /Encoding - /Differences [ 0 /C0 ] - >> - /Widths 3 0 R - /FontBBox [ 0.000000 0.000000 0.000000 0.000000 ] - /FontMatrix [ 1.000000 0.000000 0.000000 1.000000 0.000000 0.000000 ] - /Type /Font - /ToUnicode 4 0 R - /FirstChar 0 - /LastChar 0 - /Resources << >> - >> -endobj - -7 0 obj - << /Font << /F1 6 0 R >> >> -endobj - -8 0 obj - << /Length 9 0 R >> -stream -/DeviceRGB CS -/DeviceRGB cs -q -1.000000 0.000000 -0.000000 1.000000 -3.102768 0.104736 cm -0.376471 0.411765 0.517647 scn -1.507812 2.156250 m -h -6.515625 0.078125 m -6.929688 -0.234375 7.429688 -0.132812 8.000000 0.281250 c -12.000000 3.218750 l -16.000000 0.281250 l -16.570312 -0.132812 17.070312 -0.234375 17.484375 0.078125 c -17.890625 0.382812 17.968750 0.890625 17.750000 1.546875 c -16.164062 6.242188 l -20.203125 9.140625 l -20.765625 9.539062 21.007812 10.000000 20.843750 10.484375 c -20.679688 10.968750 20.226562 11.203125 19.531250 11.195312 c -14.585938 11.156250 l -13.078125 15.882812 l -12.867188 16.554688 12.507812 16.921875 12.000000 16.921875 c -11.492188 16.921875 11.140625 16.554688 10.921875 15.882812 c -9.414062 11.156250 l -4.468750 11.195312 l -3.773438 11.203125 3.320312 10.968750 3.156250 10.492188 c -2.984375 10.000000 3.234375 9.539062 3.796875 9.140625 c -7.835938 6.242188 l -6.250000 1.546875 l -6.031250 0.890625 6.109375 0.382812 6.515625 0.078125 c -h -8.117188 2.281250 m -8.109375 2.296875 8.109375 2.304688 8.117188 2.343750 c -9.531250 6.281250 l -9.695312 6.726562 9.664062 6.968750 9.234375 7.250000 c -5.773438 9.601562 l -5.742188 9.617188 5.726562 9.632812 5.734375 9.656250 c -5.742188 9.671875 5.757812 9.671875 5.796875 9.671875 c -9.976562 9.554688 l -10.453125 9.539062 10.671875 9.664062 10.804688 10.132812 c -11.960938 14.148438 l -11.968750 14.187500 11.984375 14.203125 12.000000 14.203125 c -12.015625 14.203125 12.031250 14.187500 12.039062 14.148438 c -13.203125 10.132812 l -13.328125 9.664062 13.546875 9.539062 14.023438 9.554688 c -18.203125 9.671875 l -18.242188 9.671875 18.265625 9.671875 18.273438 9.656250 c -18.273438 9.632812 18.265625 9.625000 18.234375 9.601562 c -14.765625 7.242188 l -14.343750 6.960938 14.304688 6.726562 14.468750 6.281250 c -15.882812 2.343750 l -15.890625 2.304688 15.890625 2.296875 15.882812 2.281250 c -15.867188 2.257812 15.851562 2.273438 15.820312 2.289062 c -12.515625 4.859375 l -12.132812 5.164062 11.867188 5.164062 11.484375 4.859375 c -8.179688 2.289062 l -8.148438 2.273438 8.132812 2.257812 8.117188 2.281250 c -h -f -n -Q -q -1.000000 0.000000 -0.000000 1.000000 -3.102768 0.104736 cm -BT -16.000000 0.000000 0.000000 16.000000 1.507812 2.156250 Tm -/F1 1.000000 Tf -[ (\000) ] TJ -ET -Q - -endstream -endobj - -9 0 obj - 2242 -endobj - -10 0 obj - << /Annots [] - /Type /Page - /MediaBox [ 0.000000 0.000000 17.791397 17.026611 ] - /Resources 7 0 R - /Contents 8 0 R - /Parent 11 0 R - >> -endobj - -11 0 obj - << /Kids [ 10 0 R ] - /Count 1 - /Type /Pages - >> -endobj - -12 0 obj - << /Type /Catalog - /Pages 11 0 R - >> -endobj - -xref -0 13 -0000000000 65535 f -0000000010 00000 n -0000000117 00000 n -0000000138 00000 n -0000000169 00000 n -0000000561 00000 n -0000000583 00000 n -0000000995 00000 n -0000001041 00000 n -0000003339 00000 n -0000003362 00000 n -0000003537 00000 n -0000003613 00000 n -trailer -<< /ID [ (some) (id) ] - /Root 12 0 R - /Size 13 ->> -startxref -3674 -%%EOF \ No newline at end of file diff --git a/Mastodon/Resources/Assets.xcassets/TootTimeline/Global.imageset/Contents.json b/Mastodon/Resources/Assets.xcassets/TootTimeline/Global.imageset/Contents.json deleted file mode 100644 index cc2565e2a..000000000 --- a/Mastodon/Resources/Assets.xcassets/TootTimeline/Global.imageset/Contents.json +++ /dev/null @@ -1,21 +0,0 @@ -{ - "images" : [ - { - "filename" : "globe-americas.pdf", - "idiom" : "universal", - "scale" : "1x" - }, - { - "idiom" : "universal", - "scale" : "2x" - }, - { - "idiom" : "universal", - "scale" : "3x" - } - ], - "info" : { - "author" : "xcode", - "version" : 1 - } -} diff --git a/Mastodon/Resources/Assets.xcassets/TootTimeline/Global.imageset/globe-americas.pdf b/Mastodon/Resources/Assets.xcassets/TootTimeline/Global.imageset/globe-americas.pdf deleted file mode 100644 index 623ec9691..000000000 --- a/Mastodon/Resources/Assets.xcassets/TootTimeline/Global.imageset/globe-americas.pdf +++ /dev/null @@ -1,140 +0,0 @@ -%PDF-1.7 - -1 0 obj - << >> -endobj - -2 0 obj - << /Length 3 0 R >> -stream -/DeviceRGB CS -/DeviceRGB cs -q -1.000000 0.000000 -0.000000 1.000000 1.333252 1.333252 cm -0.376471 0.411765 0.517647 scn -6.666667 13.333374 m -2.984678 13.333374 0.000000 10.348697 0.000000 6.666707 c -0.000000 2.984718 2.984678 0.000040 6.666667 0.000040 c -10.348656 0.000040 13.333334 2.984718 13.333334 6.666707 c -13.333334 10.348697 10.348656 13.333374 6.666667 13.333374 c -h -8.878764 3.720470 m -8.773925 3.616169 8.663979 3.506761 8.574732 3.417245 c -8.494355 3.336599 8.437634 3.237138 8.408871 3.129342 c -8.368279 2.977191 8.335485 2.823428 8.280645 2.675847 c -7.813172 1.416438 l -7.443280 1.335793 7.060484 1.290363 6.666667 1.290363 c -6.666667 2.026384 l -6.712097 2.365632 6.461290 3.001116 6.058333 3.404073 c -5.897043 3.565363 5.806452 3.784181 5.806452 4.012406 c -5.806452 4.872890 l -5.806452 5.185793 5.637903 5.473427 5.363978 5.624772 c -4.977688 5.838481 4.428226 6.137137 4.051882 6.326653 c -3.743279 6.482030 3.457796 6.679880 3.201075 6.911331 c -3.179570 6.930686 l -2.995985 7.096402 2.832988 7.283587 2.694086 7.488213 c -2.441936 7.858374 2.031183 8.467245 1.764247 8.862944 c -2.314516 10.086061 3.306183 11.068320 4.538441 11.601922 c -5.183871 11.279073 l -5.469893 11.136063 5.806452 11.343858 5.806452 11.663751 c -5.806452 11.967514 l -6.021236 12.002192 6.239785 12.024234 6.462097 12.032568 c -7.222850 11.271814 l -7.390861 11.103804 7.390861 10.831492 7.222850 10.663482 c -7.096774 10.537675 l -6.818818 10.259718 l -6.734946 10.175847 6.734946 10.039557 6.818818 9.955686 c -6.944893 9.829611 l -7.028764 9.745740 7.028764 9.609449 6.944893 9.525578 c -6.729839 9.310524 l -6.689461 9.270225 6.634737 9.247601 6.577688 9.247622 c -6.336021 9.247622 l -6.280107 9.247622 6.226344 9.225847 6.186021 9.186600 c -5.919355 8.927191 l -5.886667 8.895360 5.864938 8.853966 5.857304 8.808983 c -5.849670 8.764001 5.856525 8.717755 5.876882 8.676922 c -6.295968 7.838481 l -6.367474 7.695471 6.263441 7.527191 6.103764 7.527191 c -5.952151 7.527191 l -5.900269 7.527191 5.850269 7.546009 5.811290 7.579879 c -5.561828 7.796546 l -5.505376 7.845519 5.437150 7.878955 5.363858 7.893567 c -5.290566 7.908178 5.214734 7.903461 5.143817 7.879879 c -4.305914 7.600578 l -4.241943 7.579248 4.186307 7.538327 4.146889 7.483615 c -4.107471 7.428902 4.086270 7.363173 4.086290 7.295739 c -4.086290 7.173965 4.155107 7.062944 4.263978 7.008374 c -4.561828 6.859449 l -4.814785 6.732836 5.093817 6.666976 5.376613 6.666976 c -5.659409 6.666976 5.983871 5.933374 6.236828 5.806761 c -8.031183 5.806761 l -8.259409 5.806761 8.477958 5.716170 8.639517 5.554880 c -9.007526 5.186869 l -9.161268 5.033069 9.247619 4.824495 9.247581 4.607030 c -9.247526 4.442246 9.214915 4.279098 9.151622 4.126954 c -9.088329 3.974811 8.995601 3.836672 8.878764 3.720470 c -8.878764 3.720470 l -h -11.209678 6.176116 m -11.054032 6.215095 10.918280 6.310524 10.829302 6.444127 c -10.345968 7.169127 l -10.275246 7.275051 10.237501 7.399558 10.237501 7.526922 c -10.237501 7.654286 10.275246 7.778794 10.345968 7.884718 c -10.872581 8.674503 l -10.934946 8.767782 11.020431 8.843589 11.120968 8.893589 c -11.469893 9.068051 l -11.833333 8.344396 12.043011 7.530417 12.043011 6.666707 c -12.043011 6.433643 12.023118 6.205417 11.994086 5.980148 c -11.209678 6.176116 l -h -f -n -Q - -endstream -endobj - -3 0 obj - 3208 -endobj - -4 0 obj - << /Annots [] - /Type /Page - /MediaBox [ 0.000000 0.000000 16.000000 16.000000 ] - /Resources 1 0 R - /Contents 2 0 R - /Parent 5 0 R - >> -endobj - -5 0 obj - << /Kids [ 4 0 R ] - /Count 1 - /Type /Pages - >> -endobj - -6 0 obj - << /Type /Catalog - /Pages 5 0 R - >> -endobj - -xref -0 7 -0000000000 65535 f -0000000010 00000 n -0000000034 00000 n -0000003298 00000 n -0000003321 00000 n -0000003494 00000 n -0000003568 00000 n -trailer -<< /ID [ (some) (id) ] - /Root 6 0 R - /Size 7 ->> -startxref -3627 -%%EOF \ No newline at end of file diff --git a/Mastodon/Resources/Assets.xcassets/TootTimeline/Textlock.imageset/Contents.json b/Mastodon/Resources/Assets.xcassets/TootTimeline/Textlock.imageset/Contents.json deleted file mode 100644 index 05f0e9c97..000000000 --- a/Mastodon/Resources/Assets.xcassets/TootTimeline/Textlock.imageset/Contents.json +++ /dev/null @@ -1,21 +0,0 @@ -{ - "images" : [ - { - "filename" : "Textlock.pdf", - "idiom" : "universal", - "scale" : "1x" - }, - { - "idiom" : "universal", - "scale" : "2x" - }, - { - "idiom" : "universal", - "scale" : "3x" - } - ], - "info" : { - "author" : "xcode", - "version" : 1 - } -} diff --git a/Mastodon/Resources/Assets.xcassets/TootTimeline/Textlock.imageset/Textlock.pdf b/Mastodon/Resources/Assets.xcassets/TootTimeline/Textlock.imageset/Textlock.pdf deleted file mode 100644 index 0aba1b650..000000000 --- a/Mastodon/Resources/Assets.xcassets/TootTimeline/Textlock.imageset/Textlock.pdf +++ /dev/null @@ -1,174 +0,0 @@ -%PDF-1.7 - -1 0 obj - << /Length 2 0 R >> -stream -1.093750 0 0.197266 -0.131348 0.896484 1.184082 d1 - -endstream -endobj - -2 0 obj - 51 -endobj - -3 0 obj - [ 1.093750 ] -endobj - -4 0 obj - << /Length 5 0 R >> -stream -/CIDInit /ProcSet findresource begin -12 dict begin -begincmap -/CIDSystemInfo -<< /Registry (FigmaPDF) - /Ordering (FigmaPDF) - /Supplement 0 ->> def -/CMapName /A-B-C def -/CMapType 2 def -1 begincodespacerange -<00> -endcodespacerange -1 beginbfchar -<00> -endbfchar -endcmap -CMapName currentdict /CMap defineresource pop -end -end -endstream -endobj - -5 0 obj - 336 -endobj - -6 0 obj - << /Subtype /Type3 - /CharProcs << /C0 1 0 R >> - /Encoding << /Type /Encoding - /Differences [ 0 /C0 ] - >> - /Widths 3 0 R - /FontBBox [ 0.000000 0.000000 0.000000 0.000000 ] - /FontMatrix [ 1.000000 0.000000 0.000000 1.000000 0.000000 0.000000 ] - /Type /Font - /ToUnicode 4 0 R - /FirstChar 0 - /LastChar 0 - /Resources << >> - >> -endobj - -7 0 obj - << /Font << /F1 6 0 R >> >> -endobj - -8 0 obj - << /Length 9 0 R >> -stream -/DeviceRGB CS -/DeviceRGB cs -q -1.000000 0.000000 -0.000000 1.000000 -3.755859 1.167969 cm -0.376471 0.411765 0.517647 scn -0.796875 0.802246 m -h -5.491699 -1.167969 m -12.508301 -1.167969 l -13.672852 -1.167969 14.244141 -0.589355 14.244141 0.670410 c -14.244141 6.009766 l -14.244141 7.123047 13.782715 7.708984 12.859863 7.818848 c -12.859863 9.474121 l -12.859863 12.271973 10.970215 13.634277 9.000000 13.634277 c -7.029785 13.634277 5.140137 12.271973 5.140137 9.474121 c -5.140137 7.818848 l -4.209961 7.708984 3.755859 7.123047 3.755859 6.009766 c -3.755859 0.670410 l -3.755859 -0.589355 4.327148 -1.167969 5.491699 -1.167969 c -h -6.722168 9.598633 m -6.722168 11.202637 7.740234 12.103516 9.000000 12.103516 c -10.259766 12.103516 11.277832 11.202637 11.277832 9.598633 c -11.277832 7.840820 l -6.722168 7.840820 l -6.722168 9.598633 l -h -5.865234 0.333496 m -5.557617 0.333496 5.403809 0.479980 5.403809 0.853516 c -5.403809 5.826660 l -5.403809 6.200195 5.557617 6.332031 5.865234 6.332031 c -12.134766 6.332031 l -12.449707 6.332031 12.596191 6.200195 12.596191 5.826660 c -12.596191 0.853516 l -12.596191 0.479980 12.449707 0.333496 12.134766 0.333496 c -5.865234 0.333496 l -h -f -n -Q -q -1.000000 0.000000 -0.000000 1.000000 -3.755859 1.167969 cm -BT -15.000000 0.000000 0.000000 15.000000 0.796875 0.802246 Tm -/F1 1.000000 Tf -[ (\000) ] TJ -ET -Q - -endstream -endobj - -9 0 obj - 1324 -endobj - -10 0 obj - << /Annots [] - /Type /Page - /MediaBox [ 0.000000 0.000000 10.488281 14.802246 ] - /Resources 7 0 R - /Contents 8 0 R - /Parent 11 0 R - >> -endobj - -11 0 obj - << /Kids [ 10 0 R ] - /Count 1 - /Type /Pages - >> -endobj - -12 0 obj - << /Type /Catalog - /Pages 11 0 R - >> -endobj - -xref -0 13 -0000000000 65535 f -0000000010 00000 n -0000000117 00000 n -0000000138 00000 n -0000000169 00000 n -0000000561 00000 n -0000000583 00000 n -0000000995 00000 n -0000001041 00000 n -0000002421 00000 n -0000002444 00000 n -0000002619 00000 n -0000002695 00000 n -trailer -<< /ID [ (some) (id) ] - /Root 12 0 R - /Size 13 ->> -startxref -2756 -%%EOF \ No newline at end of file diff --git a/Mastodon/Resources/Assets.xcassets/TootTimeline/email.imageset/Contents.json b/Mastodon/Resources/Assets.xcassets/TootTimeline/email.imageset/Contents.json deleted file mode 100644 index 0604f1eff..000000000 --- a/Mastodon/Resources/Assets.xcassets/TootTimeline/email.imageset/Contents.json +++ /dev/null @@ -1,21 +0,0 @@ -{ - "images" : [ - { - "filename" : "icon_email.pdf", - "idiom" : "universal", - "scale" : "1x" - }, - { - "idiom" : "universal", - "scale" : "2x" - }, - { - "idiom" : "universal", - "scale" : "3x" - } - ], - "info" : { - "author" : "xcode", - "version" : 1 - } -} diff --git a/Mastodon/Resources/Assets.xcassets/TootTimeline/email.imageset/icon_email.pdf b/Mastodon/Resources/Assets.xcassets/TootTimeline/email.imageset/icon_email.pdf deleted file mode 100644 index 4114c2dcc..000000000 --- a/Mastodon/Resources/Assets.xcassets/TootTimeline/email.imageset/icon_email.pdf +++ /dev/null @@ -1,83 +0,0 @@ -%PDF-1.7 - -1 0 obj - << >> -endobj - -2 0 obj - << /Length 3 0 R >> -stream -/DeviceRGB CS -/DeviceRGB cs -q -1.000000 0.000000 -0.000000 1.000000 1.333252 2.666626 cm -0.376471 0.411765 0.517647 scn -12.000000 10.666687 m -1.333333 10.666687 l -0.600000 10.666687 0.006667 10.066687 0.006667 9.333354 c -0.000000 1.333354 l -0.000000 0.600021 0.600000 0.000021 1.333333 0.000021 c -12.000000 0.000021 l -12.733334 0.000021 13.333334 0.600021 13.333334 1.333354 c -13.333334 9.333354 l -13.333334 10.066687 12.733334 10.666687 12.000000 10.666687 c -h -12.000000 8.000021 m -6.666667 4.666687 l -1.333333 8.000021 l -1.333333 9.333354 l -6.666667 6.000021 l -12.000000 9.333354 l -12.000000 8.000021 l -h -f -n -Q - -endstream -endobj - -3 0 obj - 612 -endobj - -4 0 obj - << /Annots [] - /Type /Page - /MediaBox [ 0.000000 0.000000 16.000000 16.000000 ] - /Resources 1 0 R - /Contents 2 0 R - /Parent 5 0 R - >> -endobj - -5 0 obj - << /Kids [ 4 0 R ] - /Count 1 - /Type /Pages - >> -endobj - -6 0 obj - << /Type /Catalog - /Pages 5 0 R - >> -endobj - -xref -0 7 -0000000000 65535 f -0000000010 00000 n -0000000034 00000 n -0000000702 00000 n -0000000724 00000 n -0000000897 00000 n -0000000971 00000 n -trailer -<< /ID [ (some) (id) ] - /Root 6 0 R - /Size 7 ->> -startxref -1030 -%%EOF \ No newline at end of file diff --git a/Mastodon/Resources/Assets.xcassets/TootTimeline/lock.imageset/Contents.json b/Mastodon/Resources/Assets.xcassets/TootTimeline/lock.imageset/Contents.json deleted file mode 100644 index c83be324a..000000000 --- a/Mastodon/Resources/Assets.xcassets/TootTimeline/lock.imageset/Contents.json +++ /dev/null @@ -1,21 +0,0 @@ -{ - "images" : [ - { - "filename" : "Iconlock.pdf", - "idiom" : "universal", - "scale" : "1x" - }, - { - "idiom" : "universal", - "scale" : "2x" - }, - { - "idiom" : "universal", - "scale" : "3x" - } - ], - "info" : { - "author" : "xcode", - "version" : 1 - } -} diff --git a/Mastodon/Resources/Assets.xcassets/TootTimeline/lock.imageset/Iconlock.pdf b/Mastodon/Resources/Assets.xcassets/TootTimeline/lock.imageset/Iconlock.pdf deleted file mode 100644 index 235e9242a..000000000 --- a/Mastodon/Resources/Assets.xcassets/TootTimeline/lock.imageset/Iconlock.pdf +++ /dev/null @@ -1,87 +0,0 @@ -%PDF-1.7 - -1 0 obj - << >> -endobj - -2 0 obj - << /Length 3 0 R >> -stream -/DeviceRGB CS -/DeviceRGB cs -q -1.000000 0.000000 -0.000000 1.000000 2.000000 1.333252 cm -0.376471 0.411765 0.517647 scn -10.119047 7.500041 m -9.511904 7.500041 l -9.511904 9.375040 l -9.511904 11.557332 7.786607 13.333374 5.666667 13.333374 c -3.546726 13.333374 1.821428 11.557332 1.821428 9.375040 c -1.821428 7.500041 l -1.214286 7.500041 l -0.543899 7.500041 0.000000 6.940145 0.000000 6.250041 c -0.000000 1.250040 l -0.000000 0.559936 0.543899 0.000040 1.214286 0.000040 c -10.119047 0.000040 l -10.789433 0.000040 11.333333 0.559936 11.333333 1.250040 c -11.333333 6.250041 l -11.333333 6.940145 10.789433 7.500041 10.119047 7.500041 c -h -7.488095 7.500041 m -3.845238 7.500041 l -3.845238 9.375040 l -3.845238 10.408895 4.662351 11.250040 5.666667 11.250040 c -6.670982 11.250040 7.488095 10.408895 7.488095 9.375040 c -7.488095 7.500041 l -h -f -n -Q - -endstream -endobj - -3 0 obj - 836 -endobj - -4 0 obj - << /Annots [] - /Type /Page - /MediaBox [ 0.000000 0.000000 16.000000 16.000000 ] - /Resources 1 0 R - /Contents 2 0 R - /Parent 5 0 R - >> -endobj - -5 0 obj - << /Kids [ 4 0 R ] - /Count 1 - /Type /Pages - >> -endobj - -6 0 obj - << /Type /Catalog - /Pages 5 0 R - >> -endobj - -xref -0 7 -0000000000 65535 f -0000000010 00000 n -0000000034 00000 n -0000000926 00000 n -0000000948 00000 n -0000001121 00000 n -0000001195 00000 n -trailer -<< /ID [ (some) (id) ] - /Root 6 0 R - /Size 7 ->> -startxref -1254 -%%EOF \ No newline at end of file diff --git a/Mastodon/Resources/Assets.xcassets/TootTimeline/unlock.imageset/Contents.json b/Mastodon/Resources/Assets.xcassets/TootTimeline/unlock.imageset/Contents.json deleted file mode 100644 index 372e28767..000000000 --- a/Mastodon/Resources/Assets.xcassets/TootTimeline/unlock.imageset/Contents.json +++ /dev/null @@ -1,21 +0,0 @@ -{ - "images" : [ - { - "filename" : "Iconunlock.pdf", - "idiom" : "universal", - "scale" : "1x" - }, - { - "idiom" : "universal", - "scale" : "2x" - }, - { - "idiom" : "universal", - "scale" : "3x" - } - ], - "info" : { - "author" : "xcode", - "version" : 1 - } -} diff --git a/Mastodon/Resources/Assets.xcassets/TootTimeline/unlock.imageset/Iconunlock.pdf b/Mastodon/Resources/Assets.xcassets/TootTimeline/unlock.imageset/Iconunlock.pdf deleted file mode 100644 index 09d2143d5..000000000 --- a/Mastodon/Resources/Assets.xcassets/TootTimeline/unlock.imageset/Iconunlock.pdf +++ /dev/null @@ -1,87 +0,0 @@ -%PDF-1.7 - -1 0 obj - << >> -endobj - -2 0 obj - << /Length 3 0 R >> -stream -/DeviceRGB CS -/DeviceRGB cs -q -1.000000 0.000000 -0.000000 1.000000 2.000000 1.325439 cm -0.376471 0.411765 0.517647 scn -10.416220 6.674232 m -3.958164 6.674232 l -3.958164 9.359012 l -3.958164 10.390217 4.783649 11.246952 5.814855 11.257368 c -6.856477 11.267784 7.708003 10.421466 7.708003 9.382448 c -7.708003 8.965799 l -7.708003 8.619460 7.986637 8.340826 8.332976 8.340826 c -9.166274 8.340826 l -9.512613 8.340826 9.791247 8.619460 9.791247 8.965799 c -9.791247 9.382448 l -9.791247 11.569854 8.007469 13.348424 5.820063 13.340611 c -3.632657 13.332799 1.874920 11.530793 1.874920 9.343388 c -1.874920 6.674232 l -1.249946 6.674232 l -0.559872 6.674232 0.000000 6.114359 0.000000 5.424285 c -0.000000 1.257797 l -0.000000 0.567722 0.559872 0.007851 1.249946 0.007851 c -10.416220 0.007851 l -11.106295 0.007851 11.666166 0.567722 11.666166 1.257797 c -11.666166 5.424285 l -11.666166 6.114359 11.106295 6.674232 10.416220 6.674232 c -h -f -n -Q - -endstream -endobj - -3 0 obj - 926 -endobj - -4 0 obj - << /Annots [] - /Type /Page - /MediaBox [ 0.000000 0.000000 15.999268 16.000000 ] - /Resources 1 0 R - /Contents 2 0 R - /Parent 5 0 R - >> -endobj - -5 0 obj - << /Kids [ 4 0 R ] - /Count 1 - /Type /Pages - >> -endobj - -6 0 obj - << /Type /Catalog - /Pages 5 0 R - >> -endobj - -xref -0 7 -0000000000 65535 f -0000000010 00000 n -0000000034 00000 n -0000001016 00000 n -0000001038 00000 n -0000001211 00000 n -0000001285 00000 n -trailer -<< /ID [ (some) (id) ] - /Root 6 0 R - /Size 7 ->> -startxref -1344 -%%EOF \ No newline at end of file diff --git a/Mastodon/Resources/Assets.xcassets/TootTimeline/Contents.json b/Mastodon/Resources/Preview Assets.xcassets/Contents.json similarity index 52% rename from Mastodon/Resources/Assets.xcassets/TootTimeline/Contents.json rename to Mastodon/Resources/Preview Assets.xcassets/Contents.json index 6e965652d..73c00596a 100644 --- a/Mastodon/Resources/Assets.xcassets/TootTimeline/Contents.json +++ b/Mastodon/Resources/Preview Assets.xcassets/Contents.json @@ -2,8 +2,5 @@ "info" : { "author" : "xcode", "version" : 1 - }, - "properties" : { - "provides-namespace" : true } } diff --git a/Mastodon/Resources/Preview Assets.xcassets/bradley-dunn.imageset/Contents.json b/Mastodon/Resources/Preview Assets.xcassets/bradley-dunn.imageset/Contents.json new file mode 100644 index 000000000..9e42e6457 --- /dev/null +++ b/Mastodon/Resources/Preview Assets.xcassets/bradley-dunn.imageset/Contents.json @@ -0,0 +1,12 @@ +{ + "images" : [ + { + "filename" : "bradley-dunn-miqbDWtOG-o-unsplash.jpg", + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Mastodon/Resources/Preview Assets.xcassets/bradley-dunn.imageset/bradley-dunn-miqbDWtOG-o-unsplash.jpg b/Mastodon/Resources/Preview Assets.xcassets/bradley-dunn.imageset/bradley-dunn-miqbDWtOG-o-unsplash.jpg new file mode 100644 index 000000000..f0068b561 Binary files /dev/null and b/Mastodon/Resources/Preview Assets.xcassets/bradley-dunn.imageset/bradley-dunn-miqbDWtOG-o-unsplash.jpg differ diff --git a/Mastodon/Resources/Preview Assets.xcassets/lucas-ludwig.imageset/Contents.json b/Mastodon/Resources/Preview Assets.xcassets/lucas-ludwig.imageset/Contents.json new file mode 100644 index 000000000..343ab1207 --- /dev/null +++ b/Mastodon/Resources/Preview Assets.xcassets/lucas-ludwig.imageset/Contents.json @@ -0,0 +1,12 @@ +{ + "images" : [ + { + "filename" : "lucas-ludwig-8ARg12PU8nE-unsplash.jpg", + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Mastodon/Resources/Preview Assets.xcassets/lucas-ludwig.imageset/lucas-ludwig-8ARg12PU8nE-unsplash.jpg b/Mastodon/Resources/Preview Assets.xcassets/lucas-ludwig.imageset/lucas-ludwig-8ARg12PU8nE-unsplash.jpg new file mode 100644 index 000000000..05da9354c Binary files /dev/null and b/Mastodon/Resources/Preview Assets.xcassets/lucas-ludwig.imageset/lucas-ludwig-8ARg12PU8nE-unsplash.jpg differ diff --git a/Mastodon/Resources/Preview Assets.xcassets/markus-spiske.imageset/Contents.json b/Mastodon/Resources/Preview Assets.xcassets/markus-spiske.imageset/Contents.json new file mode 100644 index 000000000..45d5d122c --- /dev/null +++ b/Mastodon/Resources/Preview Assets.xcassets/markus-spiske.imageset/Contents.json @@ -0,0 +1,12 @@ +{ + "images" : [ + { + "filename" : "markus-spiske-45R3oFOJt2k-unsplash.jpg", + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Mastodon/Resources/Preview Assets.xcassets/markus-spiske.imageset/markus-spiske-45R3oFOJt2k-unsplash.jpg b/Mastodon/Resources/Preview Assets.xcassets/markus-spiske.imageset/markus-spiske-45R3oFOJt2k-unsplash.jpg new file mode 100644 index 000000000..9e0612e68 Binary files /dev/null and b/Mastodon/Resources/Preview Assets.xcassets/markus-spiske.imageset/markus-spiske-45R3oFOJt2k-unsplash.jpg differ diff --git a/Mastodon/Resources/Preview Assets.xcassets/mrdongok.imageset/Contents.json b/Mastodon/Resources/Preview Assets.xcassets/mrdongok.imageset/Contents.json new file mode 100644 index 000000000..75530a923 --- /dev/null +++ b/Mastodon/Resources/Preview Assets.xcassets/mrdongok.imageset/Contents.json @@ -0,0 +1,12 @@ +{ + "images" : [ + { + "filename" : "mrdongok-Z53ognhPjek-unsplash.jpg", + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Mastodon/Resources/Preview Assets.xcassets/mrdongok.imageset/mrdongok-Z53ognhPjek-unsplash.jpg b/Mastodon/Resources/Preview Assets.xcassets/mrdongok.imageset/mrdongok-Z53ognhPjek-unsplash.jpg new file mode 100644 index 000000000..4e507c8a0 Binary files /dev/null and b/Mastodon/Resources/Preview Assets.xcassets/mrdongok.imageset/mrdongok-Z53ognhPjek-unsplash.jpg differ diff --git a/Mastodon/Resources/Preview Assets.xcassets/tiraya-adam.imageset/Contents.json b/Mastodon/Resources/Preview Assets.xcassets/tiraya-adam.imageset/Contents.json new file mode 100644 index 000000000..54d7079e8 --- /dev/null +++ b/Mastodon/Resources/Preview Assets.xcassets/tiraya-adam.imageset/Contents.json @@ -0,0 +1,12 @@ +{ + "images" : [ + { + "filename" : "tiraya-adam-QfHEWqPelsc-unsplash.jpg", + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Mastodon/Resources/Preview Assets.xcassets/tiraya-adam.imageset/tiraya-adam-QfHEWqPelsc-unsplash.jpg b/Mastodon/Resources/Preview Assets.xcassets/tiraya-adam.imageset/tiraya-adam-QfHEWqPelsc-unsplash.jpg new file mode 100644 index 000000000..3670c92ae Binary files /dev/null and b/Mastodon/Resources/Preview Assets.xcassets/tiraya-adam.imageset/tiraya-adam-QfHEWqPelsc-unsplash.jpg differ diff --git a/Mastodon/Resources/en.lproj/Localizable.strings b/Mastodon/Resources/en.lproj/Localizable.strings index 9ef824361..75dc3999b 100644 --- a/Mastodon/Resources/en.lproj/Localizable.strings +++ b/Mastodon/Resources/en.lproj/Localizable.strings @@ -13,10 +13,10 @@ "Common.Controls.Actions.SignIn" = "Sign in"; "Common.Controls.Actions.SignUp" = "Sign up"; "Common.Controls.Actions.TakePhoto" = "Take photo"; +"Common.Controls.Status.ContentWarning" = "content warning"; +"Common.Controls.Status.ShowPost" = "Show Post"; +"Common.Controls.Status.UserBoosted" = "%@ boosted"; "Common.Controls.Timeline.LoadMore" = "Load More"; - -"Button.SignUp" = "Sign Up"; -"Button.SignIn" = "Sign In"; "Common.Countable.Photo.Multiple" = "photos"; "Common.Countable.Photo.Single" = "photo"; "Scene.HomeTimeline.Title" = "Home"; @@ -37,4 +37,4 @@ any server."; "Scene.ServerRules.Subtitle" = "These rules are set by the admins of %@."; "Scene.ServerRules.Title" = "Some ground rules."; "Scene.Welcome.Slogan" = "Social networking -back in your hands."; +back in your hands."; \ No newline at end of file diff --git a/Mastodon/Scene/Authentication/Register/MastodonRegisterViewController.swift b/Mastodon/Scene/Authentication/Register/MastodonRegisterViewController.swift index 98f876c3d..1ebb17bd5 100644 --- a/Mastodon/Scene/Authentication/Register/MastodonRegisterViewController.swift +++ b/Mastodon/Scene/Authentication/Register/MastodonRegisterViewController.swift @@ -39,7 +39,7 @@ final class MastodonRegisterViewController: UIViewController, NeedsDependency { let largeTitleLabel: UILabel = { let label = UILabel() 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 return label }() @@ -87,7 +87,7 @@ final class MastodonRegisterViewController: UIViewController, NeedsDependency { let domainLabel: UILabel = { let label = UILabel() label.font = .preferredFont(forTextStyle: .headline) - label.textColor = Asset.Colors.Label.black.color + label.textColor = .black return label }() diff --git a/Mastodon/Scene/Authentication/ServerRules/MastodonServerRulesViewController.swift b/Mastodon/Scene/Authentication/ServerRules/MastodonServerRulesViewController.swift index affd69d4d..826a8731a 100644 --- a/Mastodon/Scene/Authentication/ServerRules/MastodonServerRulesViewController.swift +++ b/Mastodon/Scene/Authentication/ServerRules/MastodonServerRulesViewController.swift @@ -35,7 +35,7 @@ final class MastodonServerRulesViewController: UIViewController, NeedsDependency let rulesLabel: UILabel = { let label = UILabel() label.font = .preferredFont(forTextStyle: .body) - label.textColor = Asset.Colors.Label.black.color + label.textColor = .black label.text = "Rules" label.numberOfLines = 0 return label diff --git a/Mastodon/Scene/HomeTimeline/HomeTimelineViewController+StatusProvider.swift b/Mastodon/Scene/HomeTimeline/HomeTimelineViewController+StatusProvider.swift index 4c4bda1da..697820072 100644 --- a/Mastodon/Scene/HomeTimeline/HomeTimelineViewController+StatusProvider.swift +++ b/Mastodon/Scene/HomeTimeline/HomeTimelineViewController+StatusProvider.swift @@ -12,7 +12,7 @@ import CoreDataStack // MARK: - StatusProvider extension HomeTimelineViewController: StatusProvider { - + func toot() -> Future { return Future { promise in promise(.success(nil)) } } @@ -47,4 +47,25 @@ extension HomeTimelineViewController: StatusProvider { return Future { promise in promise(.success(nil)) } } + var tableViewDiffableDataSource: UITableViewDiffableDataSource? { + return viewModel.diffableDataSource + } + + func item(for cell: UITableViewCell, indexPath: IndexPath?) -> Future { + return Future { promise in + guard let diffableDataSource = self.viewModel.diffableDataSource else { + assertionFailure() + promise(.success(nil)) + return + } + guard let indexPath = indexPath ?? self.tableView.indexPath(for: cell), + let item = diffableDataSource.itemIdentifier(for: indexPath) else { + promise(.success(nil)) + return + } + + promise(.success(item)) + } + } + } diff --git a/Mastodon/Scene/HomeTimeline/HomeTimelineViewController.swift b/Mastodon/Scene/HomeTimeline/HomeTimelineViewController.swift index cbd3fa9b9..153f46130 100644 --- a/Mastodon/Scene/HomeTimeline/HomeTimelineViewController.swift +++ b/Mastodon/Scene/HomeTimeline/HomeTimelineViewController.swift @@ -15,7 +15,7 @@ import GameplayKit import MastodonSDK import AlamofireImage -final class HomeTimelineViewController: UIViewController, NeedsDependency,TimelinePostTableViewCellDelegate { +final class HomeTimelineViewController: UIViewController, NeedsDependency { weak var context: AppContext! { willSet { precondition(!isViewLoaded) } } weak var coordinator: SceneCoordinator! { willSet { precondition(!isViewLoaded) } } @@ -23,11 +23,23 @@ final class HomeTimelineViewController: UIViewController, NeedsDependency,Timeli var disposeBag = Set() private(set) lazy var viewModel = HomeTimelineViewModel(context: context) - let avatarBarButtonItem = AvatarBarButtonItem() + let settingBarButtonItem: UIBarButtonItem = { + let barButtonItem = UIBarButtonItem() + barButtonItem.tintColor = Asset.Colors.Label.highlight.color + barButtonItem.image = UIImage(systemName: "gear")?.withRenderingMode(.alwaysTemplate) + return barButtonItem + }() + + let composeBarButtonItem: UIBarButtonItem = { + let barButtonItem = UIBarButtonItem() + barButtonItem.tintColor = Asset.Colors.Label.highlight.color + barButtonItem.image = UIImage(systemName: "square.and.pencil")?.withRenderingMode(.alwaysTemplate) + return barButtonItem + }() let tableView: UITableView = { 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(TimelineBottomLoaderTableViewCell.self, forCellReuseIdentifier: String(describing: TimelineBottomLoaderTableViewCell.self)) tableView.rowHeight = UITableView.automaticDimension @@ -39,10 +51,10 @@ final class HomeTimelineViewController: UIViewController, NeedsDependency,Timeli let refreshControl = UIRefreshControl() - deinit { os_log(.info, log: .debug, "%{public}s[%{public}ld], %{public}s:", ((#file as NSString).lastPathComponent), #line, #function) } + } extension HomeTimelineViewController { @@ -51,9 +63,18 @@ extension HomeTimelineViewController { super.viewDidLoad() title = L10n.Scene.HomeTimeline.title - view.backgroundColor = Asset.Colors.Background.systemBackground.color - navigationItem.leftBarButtonItem = avatarBarButtonItem - avatarBarButtonItem.avatarButton.addTarget(self, action: #selector(HomeTimelineViewController.avatarButtonPressed(_:)), for: .touchUpInside) + view.backgroundColor = Asset.Colors.Background.systemGroupedBackground.color + navigationItem.titleView = { + let imageView = UIImageView(image: Asset.Asset.mastodonTextLogo.image.withRenderingMode(.alwaysTemplate)) + imageView.tintColor = Asset.Colors.Label.primary.color + return imageView + }() + navigationItem.leftBarButtonItem = settingBarButtonItem + settingBarButtonItem.target = self + settingBarButtonItem.action = #selector(HomeTimelineViewController.settingBarButtonItemPressed(_:)) + navigationItem.rightBarButtonItem = composeBarButtonItem + composeBarButtonItem.target = self + composeBarButtonItem.action = #selector(HomeTimelineViewController.composeBarButtonItemPressed(_:)) tableView.refreshControl = refreshControl refreshControl.addTarget(self, action: #selector(HomeTimelineViewController.refreshControlValueChanged(_:)), for: .valueChanged) @@ -92,27 +113,9 @@ extension HomeTimelineViewController { .store(in: &disposeBag) #if DEBUG - avatarBarButtonItem.avatarButton.menu = debugMenu - avatarBarButtonItem.avatarButton.showsMenuAsPrimaryAction = true + // long press to trigger debug menu + settingBarButtonItem.menu = debugMenu #endif - - Publishers.CombineLatest( - context.authenticationService.activeMastodonAuthentication.eraseToAnyPublisher(), - viewModel.viewDidAppear.eraseToAnyPublisher() - ) - .receive(on: DispatchQueue.main) - .sink { [weak self] activeMastodonAuthentication, _ in - guard let self = self else { return } - guard let user = activeMastodonAuthentication?.user, - let avatarImageURL = user.avatarImageURL() else { - let input = AvatarConfigurableViewConfiguration.Input(avatarImageURL: nil) - self.avatarBarButtonItem.configure(withConfigurationInput: input) - return - } - let input = AvatarConfigurableViewConfiguration.Input(avatarImageURL: avatarImageURL) - self.avatarBarButtonItem.configure(withConfigurationInput: input) - } - .store(in: &disposeBag) } @@ -149,7 +152,12 @@ extension HomeTimelineViewController { extension HomeTimelineViewController { - @objc private func avatarButtonPressed(_ sender: UIButton) { + @objc private func settingBarButtonItemPressed(_ sender: UIBarButtonItem) { + os_log(.info, log: .debug, "%{public}s[%{public}ld], %{public}s", ((#file as NSString).lastPathComponent), #line, #function) + + } + + @objc private func composeBarButtonItemPressed(_ sender: UIBarButtonItem) { os_log(.info, log: .debug, "%{public}s[%{public}ld], %{public}s", ((#file as NSString).lastPathComponent), #line, #function) } @@ -198,6 +206,14 @@ extension HomeTimelineViewController: UITableViewDelegate { return ceil(frame.height) } + + func tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath) { + if let cell = cell as? StatusTableViewCell { + DispatchQueue.main.async { + cell.statusView.drawContentWarningImageView() + } + } + } } // MARK: - ContentOffsetAdjustableTimelineViewControllerDelegate @@ -297,3 +313,6 @@ extension HomeTimelineViewController: ScrollViewContainer { } } + +// MARK: - StatusTableViewCellDelegate +extension HomeTimelineViewController: StatusTableViewCellDelegate { } diff --git a/Mastodon/Scene/HomeTimeline/HomeTimelineViewModel+Diffable.swift b/Mastodon/Scene/HomeTimeline/HomeTimelineViewModel+Diffable.swift index 5a63fe26a..0091f06bf 100644 --- a/Mastodon/Scene/HomeTimeline/HomeTimelineViewModel+Diffable.swift +++ b/Mastodon/Scene/HomeTimeline/HomeTimelineViewModel+Diffable.swift @@ -15,7 +15,7 @@ extension HomeTimelineViewModel { func setupDiffableDataSource( for tableView: UITableView, dependency: NeedsDependency, - timelinePostTableViewCellDelegate: TimelinePostTableViewCellDelegate, + timelinePostTableViewCellDelegate: StatusTableViewCellDelegate, timelineMiddleLoaderTableViewCellDelegate: TimelineMiddleLoaderTableViewCellDelegate ) { let timestampUpdatePublisher = Timer.publish(every: 1.0, on: .main, in: .common) @@ -23,7 +23,7 @@ extension HomeTimelineViewModel { .share() .eraseToAnyPublisher() - diffableDataSource = TimelineSection.tableViewDiffableDataSource( + diffableDataSource = StatusSection.tableViewDiffableDataSource( for: tableView, dependency: dependency, managedObjectContext: fetchedResultsController.managedObjectContext, @@ -73,7 +73,7 @@ extension HomeTimelineViewModel: NSFetchedResultsControllerDelegate { // that's will be the most fastest fetch because of upstream just update and no modify needs consider - var oldSnapshotAttributeDict: [NSManagedObjectID : Item.Attribute] = [:] + var oldSnapshotAttributeDict: [NSManagedObjectID : Item.StatusTimelineAttribute] = [:] for item in oldSnapshot.itemIdentifiers { guard case let .homeTimelineIndex(objectID, attribute) = item else { continue } @@ -83,7 +83,7 @@ extension HomeTimelineViewModel: NSFetchedResultsControllerDelegate { var newTimelineItems: [Item] = [] for (i, timelineIndex) in timelineIndexes.enumerated() { - let attribute = oldSnapshotAttributeDict[timelineIndex.objectID] ?? Item.Attribute() + let attribute = oldSnapshotAttributeDict[timelineIndex.objectID] ?? Item.StatusTimelineAttribute(isStatusTextSensitive: timelineIndex.toot.sensitive) // append new item into snapshot newTimelineItems.append(.homeTimelineIndex(objectID: timelineIndex.objectID, attribute: attribute)) @@ -103,7 +103,7 @@ extension HomeTimelineViewModel: NSFetchedResultsControllerDelegate { } } // end for - var newSnapshot = NSDiffableDataSourceSnapshot() + var newSnapshot = NSDiffableDataSourceSnapshot() newSnapshot.appendSections([.main]) newSnapshot.appendItems(newTimelineItems, toSection: .main) @@ -142,8 +142,8 @@ extension HomeTimelineViewModel: NSFetchedResultsControllerDelegate { private func calculateReloadSnapshotDifference( navigationBar: UINavigationBar, tableView: UITableView, - oldSnapshot: NSDiffableDataSourceSnapshot, - newSnapshot: NSDiffableDataSourceSnapshot + oldSnapshot: NSDiffableDataSourceSnapshot, + newSnapshot: NSDiffableDataSourceSnapshot ) -> Difference? { guard oldSnapshot.numberOfItems != 0 else { return nil } diff --git a/Mastodon/Scene/HomeTimeline/HomeTimelineViewModel.swift b/Mastodon/Scene/HomeTimeline/HomeTimelineViewModel.swift index 5ccfca2fd..dd5ee97b1 100644 --- a/Mastodon/Scene/HomeTimeline/HomeTimelineViewModel.swift +++ b/Mastodon/Scene/HomeTimeline/HomeTimelineViewModel.swift @@ -63,7 +63,7 @@ final class HomeTimelineViewModel: NSObject { lazy var loadOldestStateMachinePublisher = CurrentValueSubject(nil) // middle loader let loadMiddleSateMachineList = CurrentValueSubject<[NSManagedObjectID: GKStateMachine], Never>([:]) // TimelineIndex.objectID : middle loading state machine - var diffableDataSource: UITableViewDiffableDataSource? + var diffableDataSource: UITableViewDiffableDataSource? var cellFrameCache = NSCache() diff --git a/Mastodon/Scene/MainTab/MainTabBarController.swift b/Mastodon/Scene/MainTab/MainTabBarController.swift index cc39cd9fc..c946ffefe 100644 --- a/Mastodon/Scene/MainTab/MainTabBarController.swift +++ b/Mastodon/Scene/MainTab/MainTabBarController.swift @@ -19,19 +19,25 @@ class MainTabBarController: UITabBarController { enum Tab: Int, CaseIterable { case home - case publicTimeline + case search + case notification + case me var title: String { switch self { - case .home: return "Home" - case .publicTimeline : return "Public" + case .home: return "Home" + case .search: return "Search" + case .notification: return "Notification" + case .me: return "Me" } } var image: UIImage { switch self { - case .home: return UIImage(systemName: "house")! - case .publicTimeline: return UIImage(systemName: "flame")! + case .home: return UIImage(systemName: "house.fill")! + case .search: return UIImage(systemName: "magnifyingglass")! + case .notification: return UIImage(systemName: "bell.fill")! + case .me: return UIImage(systemName: "person.fill")! } } @@ -43,9 +49,18 @@ class MainTabBarController: UITabBarController { _viewController.context = context _viewController.coordinator = coordinator viewController = _viewController - case .publicTimeline: - let _viewController = PublicTimelineViewController() - _viewController.viewModel = PublicTimelineViewModel(context: context) + case .search: + let _viewController = SearchViewController() + _viewController.context = context + _viewController.coordinator = coordinator + viewController = _viewController + case .notification: + let _viewController = NotificationViewController() + _viewController.context = context + _viewController.coordinator = coordinator + viewController = _viewController + case .me: + let _viewController = ProfileViewController() _viewController.context = context _viewController.coordinator = coordinator viewController = _viewController diff --git a/Mastodon/Scene/Notification/NotificationViewController.swift b/Mastodon/Scene/Notification/NotificationViewController.swift new file mode 100644 index 000000000..f8b3ba815 --- /dev/null +++ b/Mastodon/Scene/Notification/NotificationViewController.swift @@ -0,0 +1,24 @@ +// +// NotificationViewController.swift +// Mastodon +// +// Created by MainasuK Cirno on 2021-2-23. +// + +import UIKit + +final class NotificationViewController: UIViewController, NeedsDependency { + + weak var context: AppContext! { willSet { precondition(!isViewLoaded) } } + weak var coordinator: SceneCoordinator! { willSet { precondition(!isViewLoaded) } } + +} + +extension NotificationViewController { + + override func viewDidLoad() { + super.viewDidLoad() + + } + +} diff --git a/Mastodon/Scene/PickServer/PickServerViewController.swift b/Mastodon/Scene/PickServer/PickServerViewController.swift index 97cfd395c..b05fe745c 100644 --- a/Mastodon/Scene/PickServer/PickServerViewController.swift +++ b/Mastodon/Scene/PickServer/PickServerViewController.swift @@ -11,7 +11,7 @@ class PickServerViewController: UIViewController { let titleLabel: UILabel = { let label = UILabel() label.font = .boldSystemFont(ofSize: 34) - label.textColor = Asset.Colors.Label.black.color + label.textColor = Asset.Colors.Label.primary.color label.text = L10n.Scene.ServerPicker.title label.adjustsFontForContentSizeCategory = true label.translatesAutoresizingMaskIntoConstraints = false diff --git a/Mastodon/Scene/Profile/ProfileViewController.swift b/Mastodon/Scene/Profile/ProfileViewController.swift new file mode 100644 index 000000000..b3c46a42d --- /dev/null +++ b/Mastodon/Scene/Profile/ProfileViewController.swift @@ -0,0 +1,24 @@ +// +// ProfileViewController.swift +// Mastodon +// +// Created by MainasuK Cirno on 2021-2-23. +// + +import UIKit + +final class ProfileViewController: UIViewController, NeedsDependency { + + weak var context: AppContext! { willSet { precondition(!isViewLoaded) } } + weak var coordinator: SceneCoordinator! { willSet { precondition(!isViewLoaded) } } + +} + +extension ProfileViewController { + + override func viewDidLoad() { + super.viewDidLoad() + + } + +} diff --git a/Mastodon/Scene/PublicTimeline/PublicTimelineViewController+StatusProvider.swift b/Mastodon/Scene/PublicTimeline/PublicTimelineViewController+StatusProvider.swift index 889e9c6f5..6d83e79af 100644 --- a/Mastodon/Scene/PublicTimeline/PublicTimelineViewController+StatusProvider.swift +++ b/Mastodon/Scene/PublicTimeline/PublicTimelineViewController+StatusProvider.swift @@ -32,7 +32,7 @@ extension PublicTimelineViewController: StatusProvider { } switch item { - case .toot(let objectID): + case .toot(let objectID, _): let managedObjectContext = self.viewModel.fetchedResultsController.managedObjectContext managedObjectContext.perform { let toot = managedObjectContext.object(with: objectID) as? Toot @@ -48,4 +48,25 @@ extension PublicTimelineViewController: StatusProvider { return Future { promise in promise(.success(nil)) } } + var tableViewDiffableDataSource: UITableViewDiffableDataSource? { + return viewModel.diffableDataSource + } + + func item(for cell: UITableViewCell, indexPath: IndexPath?) -> Future { + return Future { promise in + guard let diffableDataSource = self.viewModel.diffableDataSource else { + assertionFailure() + promise(.success(nil)) + return + } + guard let indexPath = indexPath ?? self.tableView.indexPath(for: cell), + let item = diffableDataSource.itemIdentifier(for: indexPath) else { + promise(.success(nil)) + return + } + + promise(.success(item)) + } + } + } diff --git a/Mastodon/Scene/PublicTimeline/PublicTimelineViewController.swift b/Mastodon/Scene/PublicTimeline/PublicTimelineViewController.swift index fd72a18c1..62993bfb5 100644 --- a/Mastodon/Scene/PublicTimeline/PublicTimelineViewController.swift +++ b/Mastodon/Scene/PublicTimeline/PublicTimelineViewController.swift @@ -13,7 +13,7 @@ import GameplayKit import os.log import UIKit -final class PublicTimelineViewController: UIViewController, NeedsDependency, TimelinePostTableViewCellDelegate { +final class PublicTimelineViewController: UIViewController, NeedsDependency, StatusTableViewCellDelegate { weak var context: AppContext! { willSet { precondition(!isViewLoaded) } } weak var coordinator: SceneCoordinator! { willSet { precondition(!isViewLoaded) } } @@ -24,7 +24,7 @@ final class PublicTimelineViewController: UIViewController, NeedsDependency, Tim lazy var 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(TimelineBottomLoaderTableViewCell.self, forCellReuseIdentifier: String(describing: TimelineBottomLoaderTableViewCell.self)) tableView.rowHeight = UITableView.automaticDimension @@ -42,7 +42,7 @@ extension PublicTimelineViewController { override func viewDidLoad() { super.viewDidLoad() - view.backgroundColor = Asset.Colors.Background.systemBackground.color + view.backgroundColor = Asset.Colors.Background.systemGroupedBackground.color tableView.refreshControl = refreshControl refreshControl.addTarget(self, action: #selector(PublicTimelineViewController.refreshControlValueChanged(_:)), for: .valueChanged) diff --git a/Mastodon/Scene/PublicTimeline/PublicTimelineViewModel+Diffable.swift b/Mastodon/Scene/PublicTimeline/PublicTimelineViewModel+Diffable.swift index b3e8b27f6..26638578f 100644 --- a/Mastodon/Scene/PublicTimeline/PublicTimelineViewModel+Diffable.swift +++ b/Mastodon/Scene/PublicTimeline/PublicTimelineViewModel+Diffable.swift @@ -14,7 +14,7 @@ extension PublicTimelineViewModel { func setupDiffableDataSource( for tableView: UITableView, dependency: NeedsDependency, - timelinePostTableViewCellDelegate: TimelinePostTableViewCellDelegate, + timelinePostTableViewCellDelegate: StatusTableViewCellDelegate, timelineMiddleLoaderTableViewCellDelegate: TimelineMiddleLoaderTableViewCellDelegate ) { let timestampUpdatePublisher = Timer.publish(every: 1.0, on: .main, in: .common) @@ -22,7 +22,7 @@ extension PublicTimelineViewModel { .share() .eraseToAnyPublisher() - diffableDataSource = TimelineSection.tableViewDiffableDataSource( + diffableDataSource = StatusSection.tableViewDiffableDataSource( for: tableView, dependency: dependency, managedObjectContext: fetchedResultsController.managedObjectContext, @@ -50,11 +50,18 @@ extension PublicTimelineViewModel: NSFetchedResultsControllerDelegate { return indexes.firstIndex(of: toot.id).map { index in (index, toot) } } .sorted { $0.0 < $1.0 } + var oldSnapshotAttributeDict: [NSManagedObjectID: Item.StatusTimelineAttribute] = [:] + for item in self.items.value { + guard case let .toot(objectID, attribute) = item else { continue } + oldSnapshotAttributeDict[objectID] = attribute + } + var items = [Item]() - for tuple in indexTootTuples { - items.append(Item.toot(objectID: tuple.1.objectID)) - if tootIDsWhichHasGap.contains(tuple.1.id) { - items.append(Item.publicMiddleLoader(tootID: tuple.1.id)) + for (_, toot) in indexTootTuples { + let attribute = oldSnapshotAttributeDict[toot.objectID] ?? Item.StatusTimelineAttribute(isStatusTextSensitive: toot.sensitive) + items.append(Item.toot(objectID: toot.objectID, attribute: attribute)) + if tootIDsWhichHasGap.contains(toot.id) { + items.append(Item.publicMiddleLoader(tootID: toot.id)) } } diff --git a/Mastodon/Scene/PublicTimeline/PublicTimelineViewModel.swift b/Mastodon/Scene/PublicTimeline/PublicTimelineViewModel.swift index 42590a919..d7d6448a5 100644 --- a/Mastodon/Scene/PublicTimeline/PublicTimelineViewModel.swift +++ b/Mastodon/Scene/PublicTimeline/PublicTimelineViewModel.swift @@ -33,7 +33,7 @@ class PublicTimelineViewModel: NSObject { // var tootIDsWhichHasGap = [String]() // output - var diffableDataSource: UITableViewDiffableDataSource? + var diffableDataSource: UITableViewDiffableDataSource? lazy var stateMachine: GKStateMachine = { let stateMachine = GKStateMachine(states: [ @@ -82,7 +82,7 @@ class PublicTimelineViewModel: NSObject { let oldSnapshot = diffableDataSource.snapshot() os_log("%{public}s[%{public}ld], %{public}s: items did change", (#file as NSString).lastPathComponent, #line, #function) - var snapshot = NSDiffableDataSourceSnapshot() + var snapshot = NSDiffableDataSourceSnapshot() snapshot.appendSections([.main]) snapshot.appendItems(items) if let currentState = self.stateMachine.currentState { @@ -140,8 +140,8 @@ class PublicTimelineViewModel: NSObject { private func calculateReloadSnapshotDifference( navigationBar: UINavigationBar, tableView: UITableView, - oldSnapshot: NSDiffableDataSourceSnapshot, - newSnapshot: NSDiffableDataSourceSnapshot + oldSnapshot: NSDiffableDataSourceSnapshot, + newSnapshot: NSDiffableDataSourceSnapshot ) -> Difference? { guard oldSnapshot.numberOfItems != 0 else { return nil } diff --git a/Mastodon/Scene/Search/SearchViewController.swift b/Mastodon/Scene/Search/SearchViewController.swift new file mode 100644 index 000000000..084e7b231 --- /dev/null +++ b/Mastodon/Scene/Search/SearchViewController.swift @@ -0,0 +1,24 @@ +// +// SearchViewController.swift +// Mastodon +// +// Created by MainasuK Cirno on 2021-2-23. +// + +import UIKit + +final class SearchViewController: UIViewController, NeedsDependency { + + weak var context: AppContext! { willSet { precondition(!isViewLoaded) } } + weak var coordinator: SceneCoordinator! { willSet { precondition(!isViewLoaded) } } + +} + +extension SearchViewController { + + override func viewDidLoad() { + super.viewDidLoad() + + } + +} diff --git a/Mastodon/Scene/Share/View/Button/AvatarBarButtonItem.swift b/Mastodon/Scene/Share/View/Button/AvatarBarButtonItem.swift index f117c2120..254403bde 100644 --- a/Mastodon/Scene/Share/View/Button/AvatarBarButtonItem.swift +++ b/Mastodon/Scene/Share/View/Button/AvatarBarButtonItem.swift @@ -42,7 +42,8 @@ extension AvatarBarButtonItem { } 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 configurableAvatarButton: UIButton? { return avatarButton } var configurableVerifiedBadgeImageView: UIImageView? { return nil } diff --git a/Mastodon/Scene/Share/View/Button/HighlightDimmableButton.swift b/Mastodon/Scene/Share/View/Button/HighlightDimmableButton.swift new file mode 100644 index 000000000..3eb916f26 --- /dev/null +++ b/Mastodon/Scene/Share/View/Button/HighlightDimmableButton.swift @@ -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 + } +} diff --git a/Mastodon/Scene/Share/View/Container/MosaicImageView.swift b/Mastodon/Scene/Share/View/Container/MosaicImageView.swift new file mode 100644 index 000000000..5f8c877db --- /dev/null +++ b/Mastodon/Scene/Share/View/Container/MosaicImageView.swift @@ -0,0 +1,284 @@ +// +// MosaicImageView.swift +// Mastodon +// +// Created by Cirno MainasuK on 2021-2-23. +// + +import os.log +import func AVFoundation.AVMakeRect +import UIKit + +protocol MosaicImageViewPresentable: class { + var mosaicImageView: MosaicImageView { get } +} + +protocol MosaicImageViewDelegate: class { + func mosaicImageView(_ mosaicImageView: MosaicImageView, didTapImageView imageView: UIImageView, atIndex index: Int) +} + +final class MosaicImageView: UIView { + + static let cornerRadius: CGFloat = 4 + + weak var delegate: MosaicImageViewDelegate? + + let container = UIStackView() + var imageViews = [UIImageView]() { + didSet { + imageViews.forEach { imageView in + imageView.isUserInteractionEnabled = true + let tapGesture = UITapGestureRecognizer.singleTapGestureRecognizer + tapGesture.addTarget(self, action: #selector(MosaicImageView.photoTapGestureRecognizerHandler(_:))) + imageView.addGestureRecognizer(tapGesture) + } + } + } + + private var containerHeightLayoutConstraint: NSLayoutConstraint! + + override init(frame: CGRect) { + super.init(frame: frame) + _init() + } + + required init?(coder: NSCoder) { + super.init(coder: coder) + _init() + } + +} + +extension MosaicImageView { + + private func _init() { + container.translatesAutoresizingMaskIntoConstraints = false + addSubview(container) + containerHeightLayoutConstraint = container.heightAnchor.constraint(equalToConstant: 162).priority(.required - 1) + NSLayoutConstraint.activate([ + container.topAnchor.constraint(equalTo: topAnchor), + container.leadingAnchor.constraint(equalTo: leadingAnchor), + trailingAnchor.constraint(equalTo: container.trailingAnchor), + bottomAnchor.constraint(equalTo: container.bottomAnchor), + containerHeightLayoutConstraint + ]) + + container.axis = .horizontal + container.distribution = .fillEqually + } + +} + +extension MosaicImageView { + + func reset() { + container.arrangedSubviews.forEach { subview in + container.removeArrangedSubview(subview) + subview.removeFromSuperview() + } + container.subviews.forEach { subview in + subview.removeFromSuperview() + } + imageViews = [] + + container.spacing = 1 + } + + func setupImageView(aspectRatio: CGSize, maxSize: CGSize) -> UIImageView { + reset() + + let contentView = UIView() + contentView.translatesAutoresizingMaskIntoConstraints = false + container.addArrangedSubview(contentView) + + let rect = AVMakeRect( + aspectRatio: aspectRatio, + insideRect: CGRect(origin: .zero, size: maxSize) + ) + + let imageView = UIImageView() + imageViews.append(imageView) + imageView.layer.masksToBounds = true + imageView.layer.cornerRadius = MosaicImageView.cornerRadius + imageView.contentMode = .scaleAspectFill + + imageView.translatesAutoresizingMaskIntoConstraints = false + contentView.addSubview(imageView) + NSLayoutConstraint.activate([ + imageView.topAnchor.constraint(equalTo: contentView.topAnchor), + imageView.leadingAnchor.constraint(equalTo: contentView.leadingAnchor), + imageView.bottomAnchor.constraint(equalTo: contentView.bottomAnchor), + imageView.widthAnchor.constraint(equalToConstant: floor(rect.width)).priority(.required - 1), + ]) + containerHeightLayoutConstraint.constant = floor(rect.height) + containerHeightLayoutConstraint.isActive = true + + return imageView + } + + func setupImageViews(count: Int, maxHeight: CGFloat) -> [UIImageView] { + reset() + guard count > 1 else { + return [] + } + + containerHeightLayoutConstraint.constant = maxHeight + containerHeightLayoutConstraint.isActive = true + + let contentLeftStackView = UIStackView() + let contentRightStackView = UIStackView() + [contentLeftStackView, contentRightStackView].forEach { stackView in + stackView.axis = .vertical + stackView.distribution = .fillEqually + stackView.spacing = 1 + } + container.addArrangedSubview(contentLeftStackView) + container.addArrangedSubview(contentRightStackView) + + var imageViews: [UIImageView] = [] + for _ in 0..() + var observations = Set() + + let statusView = StatusView() + + override func prepareForReuse() { + super.prepareForReuse() + statusView.cleanUpContentWarning() + 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.delegate = self + statusView.actionToolbarContainer.delegate = self + bottomPaddingView.backgroundColor = Asset.Colors.Background.systemGroupedBackground.color + } + +} + +// MARK: - StatusViewDelegate +extension StatusTableViewCell: StatusViewDelegate { + func statusView(_ statusView: StatusView, contentWarningActionButtonPressed button: UIButton) { + delegate?.statusTableViewCell(self, statusView: statusView, contentWarningActionButtonPressed: button) + } +} + +// 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) { + + } +} diff --git a/Mastodon/Scene/Share/View/TableviewCell/TimelinePostTableViewCell.swift b/Mastodon/Scene/Share/View/TableviewCell/TimelinePostTableViewCell.swift deleted file mode 100644 index 9a513dd79..000000000 --- a/Mastodon/Scene/Share/View/TableviewCell/TimelinePostTableViewCell.swift +++ /dev/null @@ -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() - var observations = Set() - - 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) { - - } -} diff --git a/Mastodon/Scene/Share/View/ToolBar/ActionToolBarContainer.swift b/Mastodon/Scene/Share/View/ToolBar/ActionToolBarContainer.swift index 4be522b41..02f60d518 100644 --- a/Mastodon/Scene/Share/View/ToolBar/ActionToolBarContainer.swift +++ b/Mastodon/Scene/Share/View/ToolBar/ActionToolBarContainer.swift @@ -12,9 +12,7 @@ protocol ActionToolbarContainerDelegate: class { func actionToolbarContainer(_ actionToolbarContainer: ActionToolbarContainer, replayButtonDidPressed sender: UIButton) func actionToolbarContainer(_ actionToolbarContainer: ActionToolbarContainer, retootButtonDidPressed sender: UIButton) func actionToolbarContainer(_ actionToolbarContainer: ActionToolbarContainer, starButtonDidPressed sender: UIButton) - func actionToolbarContainer(_ actionToolbarContainer: ActionToolbarContainer, bookmarkButtonDidPressed sender: UIButton) func actionToolbarContainer(_ actionToolbarContainer: ActionToolbarContainer, moreButtonDidPressed sender: UIButton) - } @@ -23,7 +21,6 @@ final class ActionToolbarContainer: UIView { let replyButton = HitTestExpandedButton() let retootButton = HitTestExpandedButton() let starButton = HitTestExpandedButton() - let bookmartButton = HitTestExpandedButton() let moreButton = HitTestExpandedButton() var isStarButtonHighlight: Bool = false { @@ -62,7 +59,6 @@ extension ActionToolbarContainer { replyButton.addTarget(self, action: #selector(ActionToolbarContainer.replyButtonDidPressed(_:)), for: .touchUpInside) retootButton.addTarget(self, action: #selector(ActionToolbarContainer.retootButtonDidPressed(_:)), 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) } @@ -93,25 +89,29 @@ extension ActionToolbarContainer { subview.removeFromSuperview() } - let buttons = [replyButton, retootButton, starButton,bookmartButton, moreButton] + let buttons = [replyButton, retootButton, starButton, moreButton] buttons.forEach { button in - button.tintColor = Asset.Colors.Label.secondary.color + button.tintColor = Asset.Colors.Button.actionToolbar.color button.titleLabel?.font = .monospacedDigitSystemFont(ofSize: 12, weight: .regular) button.setTitle("", for: .normal) button.setTitleColor(.secondaryLabel, for: .normal) 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 { case .inline: buttons.forEach { button in button.contentHorizontalAlignment = .leading } - replyButton.setImage(Asset.ToolBar.reply.image.withRenderingMode(.alwaysTemplate), for: .normal) - retootButton.setImage(Asset.ToolBar.retoot.image.withRenderingMode(.alwaysTemplate), for: .normal) - starButton.setImage(Asset.ToolBar.star.image.withRenderingMode(.alwaysTemplate), for: .normal) - bookmartButton.setImage(Asset.ToolBar.bookmark.image.withRenderingMode(.alwaysTemplate), for: .normal) - moreButton.setImage(Asset.ToolBar.more.image.withRenderingMode(.alwaysTemplate), for: .normal) + replyButton.setImage(replyImage, for: .normal) + retootButton.setImage(reblogImage, for: .normal) + starButton.setImage(starImage, for: .normal) + moreButton.setImage(moreImage, for: .normal) container.axis = .horizontal container.distribution = .fill @@ -119,22 +119,18 @@ extension ActionToolbarContainer { replyButton.translatesAutoresizingMaskIntoConstraints = false retootButton.translatesAutoresizingMaskIntoConstraints = false starButton.translatesAutoresizingMaskIntoConstraints = false - bookmartButton.translatesAutoresizingMaskIntoConstraints = false moreButton.translatesAutoresizingMaskIntoConstraints = false container.addArrangedSubview(replyButton) container.addArrangedSubview(retootButton) container.addArrangedSubview(starButton) - container.addArrangedSubview(bookmartButton) container.addArrangedSubview(moreButton) 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: starButton.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: starButton.widthAnchor).priority(.defaultHigh), - replyButton.widthAnchor.constraint(equalTo: bookmartButton.widthAnchor).priority(.defaultHigh), ]) moreButton.setContentHuggingPriority(.defaultHigh, for: .horizontal) moreButton.setContentCompressionResistancePriority(.defaultHigh, for: .horizontal) @@ -143,10 +139,9 @@ extension ActionToolbarContainer { buttons.forEach { button in button.contentHorizontalAlignment = .center } - replyButton.setImage(Asset.ToolBar.reply.image.withRenderingMode(.alwaysTemplate), for: .normal) - retootButton.setImage(Asset.ToolBar.retoot.image.withRenderingMode(.alwaysTemplate), for: .normal) - starButton.setImage(Asset.ToolBar.bookmark.image.withRenderingMode(.alwaysTemplate), for: .normal) - bookmartButton.setImage(Asset.ToolBar.bookmark.image.withRenderingMode(.alwaysTemplate), for: .normal) + replyButton.setImage(replyImage, for: .normal) + retootButton.setImage(reblogImage, for: .normal) + starButton.setImage(starImage, for: .normal) container.axis = .horizontal container.spacing = 8 @@ -155,7 +150,6 @@ extension ActionToolbarContainer { container.addArrangedSubview(replyButton) container.addArrangedSubview(retootButton) container.addArrangedSubview(starButton) - container.addArrangedSubview(bookmartButton) } } @@ -165,7 +159,7 @@ extension ActionToolbarContainer { } 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 : Asset.Colors.Button.actionToolbar.color starButton.tintColor = tintColor starButton.setTitleColor(tintColor, for: .normal) starButton.setTitleColor(tintColor, for: .highlighted) @@ -193,9 +187,23 @@ extension ActionToolbarContainer { os_log("%{public}s[%{public}ld], %{public}s", ((#file as NSString).lastPathComponent), #line, #function) 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 diff --git a/Mastodon/Scene/Share/ViewModel/MosaicImageViewModel.swift b/Mastodon/Scene/Share/ViewModel/MosaicImageViewModel.swift new file mode 100644 index 000000000..aa9d79c73 --- /dev/null +++ b/Mastodon/Scene/Share/ViewModel/MosaicImageViewModel.swift @@ -0,0 +1,36 @@ +// +// MosaicImageViewModel.swift +// Mastodon +// +// Created by Cirno MainasuK on 2021-2-23. +// + +import UIKit +import CoreDataStack + +struct MosaicImageViewModel { + + let metas: [MosaicMeta] + + init(mediaAttachments: [Attachment]) { + var metas: [MosaicMeta] = [] + for element in mediaAttachments where element.type == .image { + // Display original on the iPad/Mac + let urlString = UIDevice.current.userInterfaceIdiom == .phone ? element.previewURL : element.url + guard let meta = element.meta, + let width = meta.original?.width, + let height = meta.original?.height, + let url = URL(string: urlString) else { + continue + } + metas.append(MosaicMeta(url: url, size: CGSize(width: width, height: height))) + } + self.metas = metas + } + +} + +struct MosaicMeta { + let url: URL + let size: CGSize +} diff --git a/Mastodon/Scene/Welcome/WelcomeViewController.swift b/Mastodon/Scene/Welcome/WelcomeViewController.swift index f8a7136b9..99aa89f92 100644 --- a/Mastodon/Scene/Welcome/WelcomeViewController.swift +++ b/Mastodon/Scene/Welcome/WelcomeViewController.swift @@ -5,9 +5,18 @@ // Created by 高原 on 2021/2/20. // +import os.log import UIKit -final class WelcomeViewController: UIViewController { +final class WelcomeViewController: UIViewController, NeedsDependency { + + weak var context: AppContext! { willSet { precondition(!isViewLoaded) } } + weak var coordinator: SceneCoordinator! { willSet { precondition(!isViewLoaded) } } + + #if DEBUG + let authenticationViewController = AuthenticationViewController() + #endif + let logoImageView: UIImageView = { let imageView = UIImageView(image: Asset.welcomeLogo.image) imageView.translatesAutoresizingMaskIntoConstraints = false @@ -17,7 +26,7 @@ final class WelcomeViewController: UIViewController { let sloganLabel: UILabel = { let label = UILabel() label.font = UIFontMetrics(forTextStyle: .largeTitle).scaledFont(for: UIFont.boldSystemFont(ofSize: 34)) - label.textColor = Asset.Colors.Label.black.color + label.textColor = Asset.Colors.Label.primary.color label.text = L10n.Scene.Welcome.slogan label.adjustsFontForContentSizeCategory = true label.translatesAutoresizingMaskIntoConstraints = false @@ -27,16 +36,17 @@ final class WelcomeViewController: UIViewController { let signUpButton: PrimaryActionButton = { let button = PrimaryActionButton(type: .system) - button.setTitle(L10n.Button.signUp, for: .normal) + button.titleLabel?.font = UIFontMetrics(forTextStyle: .headline).scaledFont(for: .systemFont(ofSize: 17, weight: .semibold)) + button.setTitle(L10n.Common.Controls.Actions.signUp, for: .normal) button.translatesAutoresizingMaskIntoConstraints = false return button }() let signInButton: UIButton = { let button = UIButton(type: .system) - button.setTitle(L10n.Button.signIn, for: .normal) + button.titleLabel?.font = UIFontMetrics(forTextStyle: .headline).scaledFont(for: .systemFont(ofSize: 15, weight: .semibold)) + button.setTitle(L10n.Common.Controls.Actions.signIn, for: .normal) button.setTitleColor(Asset.Colors.lightBrandBlue.color, for: .normal) - button.titleLabel?.font = .preferredFont(forTextStyle: .subheadline) button.setInsets(forContentPadding: UIEdgeInsets(top: 12, left: 0, bottom: 12, right: 0), imageTitlePadding: 0) button.translatesAutoresizingMaskIntoConstraints = false return button @@ -45,13 +55,10 @@ final class WelcomeViewController: UIViewController { extension WelcomeViewController { - override var preferredStatusBarStyle: UIStatusBarStyle { - return .darkContent - } - override func viewDidLoad() { super.viewDidLoad() + overrideUserInterfaceStyle = .light view.backgroundColor = Asset.Colors.Background.onboardingBackground.color view.addSubview(logoImageView) @@ -80,10 +87,35 @@ extension WelcomeViewController { view.readableContentGuide.trailingAnchor.constraint(equalTo: signUpButton.trailingAnchor, constant: 12), signInButton.topAnchor.constraint(equalTo: signUpButton.bottomAnchor, constant: 5) ]) + + signInButton.addTarget(self, action: #selector(WelcomeViewController.signInButtonPressed(_:)), for: .touchUpInside) + signUpButton.addTarget(self, action: #selector(WelcomeViewController.signUpButtonPressed(_:)), for: .touchUpInside) } override func viewWillAppear(_ animated: Bool) { super.viewWillAppear(animated) navigationController?.setNavigationBarHidden(true, animated: false) } + +} + +extension WelcomeViewController { + + @objc private func signInButtonPressed(_ sender: UIButton) { + os_log(.info, log: .debug, "%{public}s[%{public}ld], %{public}s", ((#file as NSString).lastPathComponent), #line, #function) + + #if DEBUG + authenticationViewController.context = context + authenticationViewController.coordinator = coordinator + authenticationViewController.viewModel = AuthenticationViewModel(context: context, coordinator: coordinator, isAuthenticationExist: true) + authenticationViewController.viewModel.domain.value = "pawoo.net" + let _ = authenticationViewController.view // trigger view load + authenticationViewController.signInButton.sendActions(for: .touchUpInside) + #endif + } + + @objc private func signUpButtonPressed(_ sender: UIButton) { + os_log(.info, log: .debug, "%{public}s[%{public}ld], %{public}s", ((#file as NSString).lastPathComponent), #line, #function) + } + } diff --git a/Mastodon/Service/APIService/CoreData/APIService+CoreData+Toot.swift b/Mastodon/Service/APIService/CoreData/APIService+CoreData+Toot.swift index d4385d115..bbf814e66 100644 --- a/Mastodon/Service/APIService/CoreData/APIService+CoreData+Toot.swift +++ b/Mastodon/Service/APIService/CoreData/APIService+CoreData+Toot.swift @@ -58,11 +58,24 @@ extension APIService.CoreData { Emoji.insert(into: managedObjectContext, property: Emoji.Property(shortcode: emoji.shortcode, url: emoji.url, staticURL: emoji.staticURL, visibleInPicker: emoji.visibleInPicker, category: emoji.category)) } let tags = entity.tags?.compactMap { tag -> Tag in - let histories = tag.history?.compactMap({ (history) -> History in + let histories = tag.history?.compactMap { history -> History in History.insert(into: managedObjectContext, property: History.Property(day: history.day, uses: history.uses, accounts: history.accounts)) - }) + } return Tag.insert(into: managedObjectContext, property: Tag.Property(name: tag.name, url: tag.url, histories: histories)) } + let mediaAttachments: [Attachment]? = { + let encoder = JSONEncoder() + var attachments: [Attachment] = [] + for (index, attachment) in (entity.mediaAttachments ?? []).enumerated() { + let metaData = attachment.meta.flatMap { meta in + try? encoder.encode(meta) + } + let property = Attachment.Property(domain: domain, index: index, id: attachment.id, typeRaw: attachment.type.rawValue, url: attachment.url, previewURL: attachment.previewURL, remoteURL: attachment.remoteURL, metaData: metaData, textURL: attachment.textURL, descriptionString: attachment.description, blurhash: attachment.blurhash, networkDate: networkDate) + attachments.append(Attachment.insert(into: managedObjectContext, property: property)) + } + guard !attachments.isEmpty else { return nil } + return attachments + }() let tootProperty = Toot.Property(entity: entity, domain: domain, networkDate: networkDate) let toot = Toot.insert( into: managedObjectContext, @@ -73,6 +86,7 @@ extension APIService.CoreData { mentions: metions, emojis: emojis, tags: tags, + mediaAttachments: mediaAttachments, favouritedBy: (entity.favourited ?? false) ? requestMastodonUser : nil, rebloggedBy: (entity.reblogged ?? false) ? requestMastodonUser : nil, mutedBy: (entity.muted ?? false) ? requestMastodonUser : nil, diff --git a/MastodonSDK/Sources/MastodonSDK/Entity/Mastodon+Entity+Attachment.swift b/MastodonSDK/Sources/MastodonSDK/Entity/Mastodon+Entity+Attachment.swift index 9c1a34106..2a09ccfc8 100644 --- a/MastodonSDK/Sources/MastodonSDK/Entity/Mastodon+Entity+Attachment.swift +++ b/MastodonSDK/Sources/MastodonSDK/Entity/Mastodon+Entity+Attachment.swift @@ -47,6 +47,7 @@ extension Mastodon.Entity { } extension Mastodon.Entity.Attachment { + public typealias AttachmentType = Type public enum `Type`: RawRepresentable, Codable { case unknown case image diff --git a/MastodonSDK/Sources/MastodonSDK/Entity/Mastodon+Entity+Status.swift b/MastodonSDK/Sources/MastodonSDK/Entity/Mastodon+Entity+Status.swift index 4b820b235..31a8806a7 100644 --- a/MastodonSDK/Sources/MastodonSDK/Entity/Mastodon+Entity+Status.swift +++ b/MastodonSDK/Sources/MastodonSDK/Entity/Mastodon+Entity+Status.swift @@ -14,7 +14,7 @@ extension Mastodon.Entity { /// - Since: 0.1.0 /// - Version: 3.3.0 /// # Last Update - /// 2021/1/28 + /// 2021/2/23 /// # Reference /// [Document](https://docs.joinmastodon.org/entities/status/) public class Status: Codable { @@ -31,7 +31,7 @@ extension Mastodon.Entity { public let visibility: Visibility? public let sensitive: Bool? public let spoilerText: String? - public let mediaAttachments: [Attachment] + public let mediaAttachments: [Attachment]? public let application: Application? // Rendering