diff --git a/Localization/app.json b/Localization/app.json index 1cf3a17b0..535630384 100644 --- a/Localization/app.json +++ b/Localization/app.json @@ -61,7 +61,10 @@ } }, "timeline": { - "load_more": "Load More" + "loader": { + "load_missing_posts": "Load missing posts", + "loading_missing_posts": "Loading missing posts..." + } } }, "countable": { diff --git a/Mastodon.xcodeproj/project.pbxproj b/Mastodon.xcodeproj/project.pbxproj index d2d581fd3..9dac11620 100644 --- a/Mastodon.xcodeproj/project.pbxproj +++ b/Mastodon.xcodeproj/project.pbxproj @@ -83,6 +83,7 @@ 2D939AB525EDD8A90076FA61 /* String.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2D939AB425EDD8A90076FA61 /* String.swift */; }; 2D939AC825EE14620076FA61 /* CropViewController in Frameworks */ = {isa = PBXBuildFile; productRef = 2D939AC725EE14620076FA61 /* CropViewController */; }; 2D939AE825EE1CF80076FA61 /* MastodonRegisterViewController+Avatar.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2D939AE725EE1CF80076FA61 /* MastodonRegisterViewController+Avatar.swift */; }; + 2DA504692601ADE7008F4E6C /* SawToothView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2DA504682601ADE7008F4E6C /* SawToothView.swift */; }; 2DA6054725F716A2006356F9 /* PlaybackState.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2DA6054625F716A2006356F9 /* PlaybackState.swift */; }; 2DA6055125F74407006356F9 /* AudioContainerViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2DA6055025F74407006356F9 /* AudioContainerViewModel.swift */; }; 2DA7D04425CA52B200804E11 /* TimelineLoaderTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2DA7D04325CA52B200804E11 /* TimelineLoaderTableViewCell.swift */; }; @@ -356,6 +357,7 @@ 2D927F1325C7EDD9004F19B8 /* Emoji.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Emoji.swift; sourceTree = ""; }; 2D939AB425EDD8A90076FA61 /* String.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = String.swift; sourceTree = ""; }; 2D939AE725EE1CF80076FA61 /* MastodonRegisterViewController+Avatar.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "MastodonRegisterViewController+Avatar.swift"; sourceTree = ""; }; + 2DA504682601ADE7008F4E6C /* SawToothView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SawToothView.swift; sourceTree = ""; }; 2DA6054625F716A2006356F9 /* PlaybackState.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PlaybackState.swift; sourceTree = ""; }; 2DA6055025F74407006356F9 /* AudioContainerViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AudioContainerViewModel.swift; sourceTree = ""; }; 2DA7D04325CA52B200804E11 /* TimelineLoaderTableViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TimelineLoaderTableViewCell.swift; sourceTree = ""; }; @@ -812,6 +814,7 @@ 2D7631A525C1532D00929FB9 /* View */ = { isa = PBXGroup; children = ( + 2DA504672601ADBA008F4E6C /* Decoration */, 2D42FF8325C82245004A627A /* Button */, 2D42FF7C25C82207004A627A /* ToolBar */, DB9D6C1325E4F97A0051B173 /* Container */, @@ -847,6 +850,14 @@ path = Item; sourceTree = ""; }; + 2DA504672601ADBA008F4E6C /* Decoration */ = { + isa = PBXGroup; + children = ( + 2DA504682601ADE7008F4E6C /* SawToothView.swift */, + ); + path = Decoration; + sourceTree = ""; + }; 2DF75BB725D1473400694EC8 /* Stack */ = { isa = PBXGroup; children = ( @@ -1738,6 +1749,7 @@ DB68A06325E905E000CFDF14 /* UIApplication.swift in Sources */, 2D8434FB25FF46B300EECE90 /* HomeTimelineNavigationBarView.swift in Sources */, DB45FAD725CA6C76005A8AC7 /* UIBarButtonItem.swift in Sources */, + 2DA504692601ADE7008F4E6C /* SawToothView.swift in Sources */, 2D8434F525FF465D00EECE90 /* HomeTimelineNavigationBarState.swift in Sources */, DBA0A10925FB3C2B0079C110 /* RoundedEdgesButton.swift in Sources */, DBABE3EC25ECAC4B00879EE5 /* WelcomeIllustrationView.swift in Sources */, diff --git a/Mastodon/Diffiable/Section/StatusSection.swift b/Mastodon/Diffiable/Section/StatusSection.swift index 11a8f1a0a..809e3b3cc 100644 --- a/Mastodon/Diffiable/Section/StatusSection.swift +++ b/Mastodon/Diffiable/Section/StatusSection.swift @@ -77,7 +77,7 @@ extension StatusSection { return cell case .bottomLoader: let cell = tableView.dequeueReusableCell(withIdentifier: String(describing: TimelineBottomLoaderTableViewCell.self), for: indexPath) as! TimelineBottomLoaderTableViewCell - cell.activityIndicatorView.startAnimating() + cell.startAnimating() return cell } } diff --git a/Mastodon/Generated/Assets.swift b/Mastodon/Generated/Assets.swift index 884a7b34e..2133c5aa3 100644 --- a/Mastodon/Generated/Assets.swift +++ b/Mastodon/Generated/Assets.swift @@ -22,9 +22,6 @@ internal typealias AssetImageTypeAlias = ImageAsset.Image // swiftlint:disable identifier_name line_length nesting type_body_length type_name internal enum Asset { internal static let accentColor = ColorAsset(name: "AccentColor") - 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") } diff --git a/Mastodon/Generated/Strings.swift b/Mastodon/Generated/Strings.swift index e9a9d0e0c..f4d3a8a56 100644 --- a/Mastodon/Generated/Strings.swift +++ b/Mastodon/Generated/Strings.swift @@ -124,8 +124,12 @@ internal enum L10n { } } internal enum Timeline { - /// Load More - internal static let loadMore = L10n.tr("Localizable", "Common.Controls.Timeline.LoadMore") + internal enum Loader { + /// Loading missing posts... + internal static let loadingMissingPosts = L10n.tr("Localizable", "Common.Controls.Timeline.Loader.LoadingMissingPosts") + /// Load missing posts + internal static let loadMissingPosts = L10n.tr("Localizable", "Common.Controls.Timeline.Loader.LoadMissingPosts") + } } } internal enum Countable { diff --git a/Mastodon/Resources/Assets.xcassets/Arrows/Contents.json b/Mastodon/Resources/Assets.xcassets/Arrows/Contents.json deleted file mode 100644 index 6e965652d..000000000 --- a/Mastodon/Resources/Assets.xcassets/Arrows/Contents.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "info" : { - "author" : "xcode", - "version" : 1 - }, - "properties" : { - "provides-namespace" : true - } -} 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 deleted file mode 100644 index c59347e9e..000000000 --- a/Mastodon/Resources/Assets.xcassets/Arrows/arrow.triangle.2.circlepath.imageset/Contents.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "images" : [ - { - "filename" : "arrow.triangle.2.circlepath.pdf", - "idiom" : "universal" - } - ], - "info" : { - "author" : "xcode", - "version" : 1 - } -} diff --git a/Mastodon/Resources/Assets.xcassets/Arrows/arrow.triangle.2.circlepath.imageset/arrow.triangle.2.circlepath.pdf b/Mastodon/Resources/Assets.xcassets/Arrows/arrow.triangle.2.circlepath.imageset/arrow.triangle.2.circlepath.pdf deleted file mode 100644 index b864ab380..000000000 --- a/Mastodon/Resources/Assets.xcassets/Arrows/arrow.triangle.2.circlepath.imageset/arrow.triangle.2.circlepath.pdf +++ /dev/null @@ -1,193 +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 4.000000 10.752930 cm -0.000000 0.000000 0.000000 scn -15.009519 2.109471 m -15.085540 1.562444 15.590621 1.180617 16.137648 1.256639 c -16.684677 1.332660 17.066502 1.837741 16.990480 2.384768 c -15.009519 2.109471 l -h --0.423099 4.631682 m --0.635487 4.121869 -0.394376 3.536408 0.115438 3.324021 c -0.625251 3.111633 1.210711 3.352744 1.423099 3.862558 c --0.423099 4.631682 l -h -1.000000 8.247120 m -1.000000 8.799404 0.552285 9.247120 0.000000 9.247120 c --0.552285 9.247120 -1.000000 8.799404 -1.000000 8.247120 c -1.000000 8.247120 l -h -0.000000 4.247120 m --1.000000 4.247120 l --1.000000 3.694835 -0.552285 3.247120 0.000000 3.247120 c -0.000000 4.247120 l -h -4.000000 3.247120 m -4.552285 3.247120 5.000000 3.694835 5.000000 4.247120 c -5.000000 4.799405 4.552285 5.247120 4.000000 5.247120 c -4.000000 3.247120 l -h -16.990480 2.384768 m -16.715729 4.361807 15.798570 6.193669 14.380284 7.598174 c -12.972991 6.177073 l -14.079566 5.081251 14.795152 3.651996 15.009519 2.109471 c -16.990480 2.384768 l -h -14.380284 7.598174 m -12.961998 9.002679 11.121269 9.901910 9.141643 10.157345 c -8.885699 8.173789 l -10.430243 7.974494 11.866417 7.272897 12.972991 6.177073 c -14.380284 7.598174 l -h -9.141643 10.157345 m -7.162015 10.412781 5.153316 10.010252 3.424967 9.011765 c -4.425436 7.279984 l -5.773929 8.059025 7.341156 8.373085 8.885699 8.173789 c -9.141643 10.157345 l -h -3.424967 9.011765 m -1.696617 8.013276 0.344502 6.474223 -0.423099 4.631682 c -1.423099 3.862558 l -2.021996 5.300145 3.076944 6.500945 4.425436 7.279984 c -3.424967 9.011765 l -h --1.000000 8.247120 m --1.000000 4.247120 l -1.000000 4.247120 l -1.000000 8.247120 l --1.000000 8.247120 l -h -0.000000 3.247120 m -4.000000 3.247120 l -4.000000 5.247120 l -0.000000 5.247120 l -0.000000 3.247120 l -h -f -n -Q -q -1.000000 0.000000 -0.000000 1.000000 4.000000 1.767822 cm -0.000000 0.000000 0.000000 scn -0.990481 9.369826 m -0.914460 9.916854 0.409379 10.298680 -0.137649 10.222659 c --0.684676 10.146638 -1.066502 9.641557 -0.990481 9.094529 c -0.990481 9.369826 l -h -16.423100 6.847616 m -16.635487 7.357429 16.394375 7.942889 15.884562 8.155277 c -15.374748 8.367664 14.789289 8.126554 14.576900 7.616740 c -16.423100 6.847616 l -h -15.000000 3.232178 m -15.000000 2.679893 15.447715 2.232178 16.000000 2.232178 c -16.552284 2.232178 17.000000 2.679893 17.000000 3.232178 c -15.000000 3.232178 l -h -16.000000 7.232178 m -17.000000 7.232178 l -17.000000 7.784462 16.552284 8.232178 16.000000 8.232178 c -16.000000 7.232178 l -h -12.000000 8.232178 m -11.447715 8.232178 11.000000 7.784462 11.000000 7.232178 c -11.000000 6.679893 11.447715 6.232178 12.000000 6.232178 c -12.000000 8.232178 l -h --0.990481 9.094529 m --0.715729 7.117491 0.201429 5.285628 1.619715 3.881123 c -3.027008 5.302223 l -1.920433 6.398046 1.204848 7.827302 0.990481 9.369826 c --0.990481 9.094529 l -h -1.619715 3.881123 m -3.038001 2.476617 4.878731 1.577388 6.858358 1.321952 c -7.114300 3.305508 l -5.569757 3.504804 4.133582 4.206400 3.027008 5.302223 c -1.619715 3.881123 l -h -6.858358 1.321952 m -8.837985 1.066517 10.846684 1.469046 12.575033 2.467534 c -11.574564 4.199314 l -10.226071 3.420273 8.658844 3.106212 7.114300 3.305508 c -6.858358 1.321952 l -h -12.575033 2.467534 m -14.303383 3.466022 15.655499 5.005074 16.423100 6.847616 c -14.576900 7.616740 l -13.978004 6.179152 12.923057 4.978354 11.574564 4.199314 c -12.575033 2.467534 l -h -17.000000 3.232178 m -17.000000 7.232178 l -15.000000 7.232178 l -15.000000 3.232178 l -17.000000 3.232178 l -h -16.000000 8.232178 m -12.000000 8.232178 l -12.000000 6.232178 l -16.000000 6.232178 l -16.000000 8.232178 l -h -f -n -Q - -endstream -endobj - -3 0 obj - 3597 -endobj - -4 0 obj - << /Annots [] - /Type /Page - /MediaBox [ 0.000000 0.000000 24.000000 24.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 -0000003687 00000 n -0000003710 00000 n -0000003883 00000 n -0000003957 00000 n -trailer -<< /ID [ (some) (id) ] - /Root 6 0 R - /Size 7 ->> -startxref -4016 -%%EOF \ No newline at end of file diff --git a/Mastodon/Resources/en.lproj/Localizable.strings b/Mastodon/Resources/en.lproj/Localizable.strings index 6289e2d76..e051aa9ec 100644 --- a/Mastodon/Resources/en.lproj/Localizable.strings +++ b/Mastodon/Resources/en.lproj/Localizable.strings @@ -35,7 +35,8 @@ "Common.Controls.Status.StatusContentWarning" = "content warning"; "Common.Controls.Status.UserReblogged" = "%@ reblogged"; "Common.Controls.Status.UserRepliedTo" = "Replied to %@"; -"Common.Controls.Timeline.LoadMore" = "Load More"; +"Common.Controls.Timeline.Loader.LoadMissingPosts" = "Load missing posts"; +"Common.Controls.Timeline.Loader.LoadingMissingPosts" = "Loading missing posts..."; "Common.Countable.Photo.Multiple" = "photos"; "Common.Countable.Photo.Single" = "photo"; "Scene.Compose.ComposeAction" = "Publish"; diff --git a/Mastodon/Scene/HomeTimeline/HomeTimelineViewController.swift b/Mastodon/Scene/HomeTimeline/HomeTimelineViewController.swift index 300e96bf8..6efdb76a3 100644 --- a/Mastodon/Scene/HomeTimeline/HomeTimelineViewController.swift +++ b/Mastodon/Scene/HomeTimeline/HomeTimelineViewController.swift @@ -276,15 +276,13 @@ extension HomeTimelineViewController: TimelineMiddleLoaderTableViewCellDelegate // make success state same as loading due to snapshot updating delay let isLoading = state is HomeTimelineViewModel.LoadMiddleState.Loading || state is HomeTimelineViewModel.LoadMiddleState.Success - cell.loadMoreButton.isHidden = isLoading if isLoading { - cell.activityIndicatorView.startAnimating() + cell.startAnimating() } else { - cell.activityIndicatorView.stopAnimating() + cell.stopAnimating() } } else { - cell.loadMoreButton.isHidden = false - cell.activityIndicatorView.stopAnimating() + cell.stopAnimating() } } .store(in: &cell.disposeBag) diff --git a/Mastodon/Scene/PublicTimeline/PublicTimelineViewController.swift b/Mastodon/Scene/PublicTimeline/PublicTimelineViewController.swift index abe46257c..8e954c053 100644 --- a/Mastodon/Scene/PublicTimeline/PublicTimelineViewController.swift +++ b/Mastodon/Scene/PublicTimeline/PublicTimelineViewController.swift @@ -173,15 +173,13 @@ extension PublicTimelineViewController: TimelineMiddleLoaderTableViewCellDelegat // make success state same as loading due to snapshot updating delay let isLoading = state is PublicTimelineViewModel.LoadMiddleState.Loading || state is PublicTimelineViewModel.LoadMiddleState.Success - cell.loadMoreButton.isHidden = isLoading if isLoading { - cell.activityIndicatorView.startAnimating() + cell.startAnimating() } else { - cell.activityIndicatorView.stopAnimating() + cell.stopAnimating() } } else { - cell.loadMoreButton.isHidden = false - cell.activityIndicatorView.stopAnimating() + cell.stopAnimating() } } .store(in: &cell.disposeBag) diff --git a/Mastodon/Scene/Share/View/Decoration/SawToothView.swift b/Mastodon/Scene/Share/View/Decoration/SawToothView.swift new file mode 100644 index 000000000..ef1c89cc0 --- /dev/null +++ b/Mastodon/Scene/Share/View/Decoration/SawToothView.swift @@ -0,0 +1,46 @@ +// +// SawToothView.swift +// Mastodon +// +// Created by sxiaojian on 2021/3/17. +// + +import Foundation +import UIKit + +final class SawToothView: UIView { + static let widthUint = 8 + + override init(frame: CGRect) { + super.init(frame: frame) + _init() + } + + required init?(coder: NSCoder) { + super.init(coder: coder) + _init() + } + + func _init() { + backgroundColor = Asset.Colors.Background.systemGroupedBackground.color + } + + override func draw(_ rect: CGRect) { + let bezierPath = UIBezierPath() + let bottomY = rect.height + let topY = 0 + let count = Int(ceil(rect.width / CGFloat(SawToothView.widthUint))) + bezierPath.move(to: CGPoint(x: 0, y: bottomY)) + for n in 0 ..< count { + bezierPath.addLine(to: CGPoint(x: CGFloat((Double(n) + 0.5) * Double(SawToothView.widthUint)), y: CGFloat(topY))) + bezierPath.addLine(to: CGPoint(x: CGFloat((Double(n) + 1) * Double(SawToothView.widthUint)), y: CGFloat(bottomY))) + } + bezierPath.addLine(to: CGPoint(x: 0, y: bottomY)) + bezierPath.close() + Asset.Colors.Background.secondaryGroupedSystemBackground.color.setFill() + bezierPath.fill() + bezierPath.lineWidth = 0 + bezierPath.stroke() + } + +} diff --git a/Mastodon/Scene/Share/View/TableviewCell/TimelineBottomLoaderTableViewCell.swift b/Mastodon/Scene/Share/View/TableviewCell/TimelineBottomLoaderTableViewCell.swift index 7fe4c0a77..8d3589fb1 100644 --- a/Mastodon/Scene/Share/View/TableviewCell/TimelineBottomLoaderTableViewCell.swift +++ b/Mastodon/Scene/Share/View/TableviewCell/TimelineBottomLoaderTableViewCell.swift @@ -11,10 +11,10 @@ import Combine final class TimelineBottomLoaderTableViewCell: TimelineLoaderTableViewCell { override func _init() { super._init() - backgroundColor = .clear - + activityIndicatorView.isHidden = false - activityIndicatorView.startAnimating() + + startAnimating() } } diff --git a/Mastodon/Scene/Share/View/TableviewCell/TimelineLoaderTableViewCell.swift b/Mastodon/Scene/Share/View/TableviewCell/TimelineLoaderTableViewCell.swift index 6aa195241..fe54380ed 100644 --- a/Mastodon/Scene/Share/View/TableviewCell/TimelineLoaderTableViewCell.swift +++ b/Mastodon/Scene/Share/View/TableviewCell/TimelineLoaderTableViewCell.swift @@ -10,22 +10,34 @@ import Combine class TimelineLoaderTableViewCell: UITableViewCell { - static let cellHeight: CGFloat = 44 + TimelineLoaderTableViewCell.extraTopPadding + TimelineLoaderTableViewCell.bottomPadding - static let extraTopPadding: CGFloat = 0 // the status cell already has 10pt bottom padding - static let bottomPadding: CGFloat = StatusTableViewCell.bottomPaddingHeight + TimelineLoaderTableViewCell.extraTopPadding // make balance + static let buttonHeight: CGFloat = 62 + static let cellHeight: CGFloat = TimelineLoaderTableViewCell.buttonHeight + 17 + static let extraTopPadding: CGFloat = 10 + static let labelFont = UIFontMetrics(forTextStyle: .body).scaledFont(for: .systemFont(ofSize: 17, weight: .medium)) var disposeBag = Set() + var stateBindDispose: AnyCancellable? + let loadMoreButton: UIButton = { - let button = UIButton(type: .system) - button.titleLabel?.font = .preferredFont(forTextStyle: .headline) - button.setTitle(L10n.Common.Controls.Timeline.loadMore, for: .normal) + let button = HighlightDimmableButton() + button.titleLabel?.font = TimelineLoaderTableViewCell.labelFont + button.backgroundColor = Asset.Colors.Background.secondaryGroupedSystemBackground.color + button.setTitleColor(Asset.Colors.Button.normal.color, for: .normal) + button.setTitle(L10n.Common.Controls.Timeline.Loader.loadMissingPosts, for: .normal) + button.setTitle("", for: .disabled) return button }() + let loadMoreLabel: UILabel = { + let label = UILabel() + label.font = TimelineLoaderTableViewCell.labelFont + return label + }() + let activityIndicatorView: UIActivityIndicatorView = { let activityIndicatorView = UIActivityIndicatorView(style: .medium) - activityIndicatorView.tintColor = .white + activityIndicatorView.tintColor = Asset.Colors.Label.secondary.color activityIndicatorView.hidesWhenStopped = true return activityIndicatorView }() @@ -45,28 +57,63 @@ class TimelineLoaderTableViewCell: UITableViewCell { _init() } + func startAnimating() { + activityIndicatorView.startAnimating() + self.loadMoreButton.isEnabled = false + self.loadMoreLabel.textColor = Asset.Colors.Label.secondary.color + self.loadMoreLabel.text = L10n.Common.Controls.Timeline.Loader.loadingMissingPosts + } + + func stopAnimating() { + activityIndicatorView.stopAnimating() + self.loadMoreButton.isEnabled = true + self.loadMoreLabel.textColor = Asset.Colors.buttonDefault.color + self.loadMoreLabel.text = "" + } + func _init() { selectionStyle = .none - backgroundColor = Asset.Colors.Background.secondarySystemBackground.color + backgroundColor = Asset.Colors.Background.systemGroupedBackground.color loadMoreButton.translatesAutoresizingMaskIntoConstraints = false contentView.addSubview(loadMoreButton) NSLayoutConstraint.activate([ - loadMoreButton.topAnchor.constraint(equalTo: contentView.topAnchor, constant: TimelineLoaderTableViewCell.extraTopPadding), - loadMoreButton.leadingAnchor.constraint(equalTo: contentView.readableContentGuide.leadingAnchor), - contentView.readableContentGuide.trailingAnchor.constraint(equalTo: loadMoreButton.trailingAnchor), - contentView.bottomAnchor.constraint(equalTo: loadMoreButton.bottomAnchor, constant: TimelineLoaderTableViewCell.bottomPadding), - loadMoreButton.heightAnchor.constraint(equalToConstant: 44).priority(.defaultHigh), + loadMoreButton.topAnchor.constraint(equalTo: contentView.topAnchor, constant: 7), + loadMoreButton.leadingAnchor.constraint(equalTo: contentView.leadingAnchor), + contentView.trailingAnchor.constraint(equalTo: loadMoreButton.trailingAnchor), + contentView.bottomAnchor.constraint(equalTo: loadMoreButton.bottomAnchor, constant: 14), + loadMoreButton.heightAnchor.constraint(equalToConstant: TimelineLoaderTableViewCell.buttonHeight).priority(.required - 1), ]) - activityIndicatorView.translatesAutoresizingMaskIntoConstraints = false - addSubview(activityIndicatorView) + // use stack view to alignlment content center + let stackView = UIStackView() + stackView.spacing = 4 + stackView.axis = .horizontal + stackView.alignment = .center + stackView.translatesAutoresizingMaskIntoConstraints = false + stackView.isUserInteractionEnabled = false + contentView.addSubview(stackView) NSLayoutConstraint.activate([ - activityIndicatorView.centerXAnchor.constraint(equalTo: loadMoreButton.centerXAnchor), - activityIndicatorView.centerYAnchor.constraint(equalTo: loadMoreButton.centerYAnchor), + stackView.topAnchor.constraint(equalTo: loadMoreButton.topAnchor), + stackView.leadingAnchor.constraint(equalTo: loadMoreButton.leadingAnchor), + stackView.trailingAnchor.constraint(equalTo: loadMoreButton.trailingAnchor), + stackView.bottomAnchor.constraint(equalTo: loadMoreButton.bottomAnchor), + ]) + let leftPaddingView = UIView() + leftPaddingView.translatesAutoresizingMaskIntoConstraints = false + stackView.addArrangedSubview(leftPaddingView) + stackView.addArrangedSubview(activityIndicatorView) + stackView.addArrangedSubview(loadMoreLabel) + let rightPaddingView = UIView() + rightPaddingView.translatesAutoresizingMaskIntoConstraints = false + stackView.addArrangedSubview(rightPaddingView) + NSLayoutConstraint.activate([ + leftPaddingView.widthAnchor.constraint(equalTo: rightPaddingView.widthAnchor, multiplier: 1.0), ]) + // default set hidden and let subclass override it loadMoreButton.isHidden = true + loadMoreLabel.isHidden = true activityIndicatorView.isHidden = true } diff --git a/Mastodon/Scene/Share/View/TableviewCell/TimelineMiddleLoaderTableViewCell.swift b/Mastodon/Scene/Share/View/TableviewCell/TimelineMiddleLoaderTableViewCell.swift index 16ab241f0..597420481 100644 --- a/Mastodon/Scene/Share/View/TableviewCell/TimelineMiddleLoaderTableViewCell.swift +++ b/Mastodon/Scene/Share/View/TableviewCell/TimelineMiddleLoaderTableViewCell.swift @@ -18,15 +18,29 @@ protocol TimelineMiddleLoaderTableViewCellDelegate: class { final class TimelineMiddleLoaderTableViewCell: TimelineLoaderTableViewCell { weak var delegate: TimelineMiddleLoaderTableViewCellDelegate? + let sawToothView: SawToothView = { + let sawToothView = SawToothView() + sawToothView.translatesAutoresizingMaskIntoConstraints = false + return sawToothView + }() + override func _init() { super._init() - backgroundColor = .clear - loadMoreButton.isHidden = false - loadMoreButton.setImage(Asset.Arrows.arrowTriangle2Circlepath.image.withRenderingMode(.alwaysTemplate), for: .normal) + loadMoreLabel.isHidden = false + activityIndicatorView.isHidden = false + loadMoreButton.setInsets(forContentPadding: .zero, imageTitlePadding: 4) loadMoreButton.addTarget(self, action: #selector(TimelineMiddleLoaderTableViewCell.loadMoreButtonDidPressed(_:)), for: .touchUpInside) + + contentView.addSubview(sawToothView) + NSLayoutConstraint.activate([ + sawToothView.leadingAnchor.constraint(equalTo: contentView.leadingAnchor), + sawToothView.trailingAnchor.constraint(equalTo: contentView.trailingAnchor), + sawToothView.bottomAnchor.constraint(equalTo: contentView.bottomAnchor), + sawToothView.heightAnchor.constraint(equalToConstant: 3), + ]) } }