forked from zelo72/mastodon-ios
Merge branch 'release/0.7.4'
This commit is contained in:
commit
e364e9edf1
|
@ -121,9 +121,8 @@
|
|||
"user_replied_to": "Replied to %s",
|
||||
"show_post": "Show Post",
|
||||
"show_user_profile": "Show user profile",
|
||||
"content_warning": "content warning",
|
||||
"content_warning_text": "cw: %s",
|
||||
"media_content_warning": "Tap to reveal that may be sensitive",
|
||||
"content_warning": "Content Warning",
|
||||
"media_content_warning": "Tap anywhere to reveal",
|
||||
"poll": {
|
||||
"vote": "Vote",
|
||||
"vote_count": {
|
||||
|
|
|
@ -192,6 +192,7 @@
|
|||
DB040ED126538E3D00BEE9D8 /* Trie.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB040ED026538E3C00BEE9D8 /* Trie.swift */; };
|
||||
DB084B5725CBC56C00F898ED /* Status.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB084B5625CBC56C00F898ED /* Status.swift */; };
|
||||
DB0AC6FC25CD02E600D75117 /* APIService+Instance.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB0AC6FB25CD02E600D75117 /* APIService+Instance.swift */; };
|
||||
DB0E2D2E26833FF700865C3C /* NukeFLAnimatedImagePlugin in Frameworks */ = {isa = PBXBuildFile; productRef = DB0E2D2D26833FF700865C3C /* NukeFLAnimatedImagePlugin */; };
|
||||
DB0F8150264D1E2500F2A12B /* PickServerLoaderTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB0F814F264D1E2500F2A12B /* PickServerLoaderTableViewCell.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 */; };
|
||||
|
@ -489,6 +490,7 @@
|
|||
DBE54ABF2636C889004E7C0B /* UserDefaults.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB6D1B23263684C600ACB481 /* UserDefaults.swift */; };
|
||||
DBE54AC62636C89F004E7C0B /* NotificationPreference.swift in Sources */ = {isa = PBXBuildFile; fileRef = DBE54AC52636C89F004E7C0B /* NotificationPreference.swift */; };
|
||||
DBE54ACC2636C8FD004E7C0B /* NotificationPreference.swift in Sources */ = {isa = PBXBuildFile; fileRef = DBE54AC52636C89F004E7C0B /* NotificationPreference.swift */; };
|
||||
DBF7A0FC26830C33004176A2 /* FPSIndicator in Frameworks */ = {isa = PBXBuildFile; productRef = DBF7A0FB26830C33004176A2 /* FPSIndicator */; };
|
||||
DBF8AE16263293E400C9C23C /* NotificationService.swift in Sources */ = {isa = PBXBuildFile; fileRef = DBF8AE15263293E400C9C23C /* NotificationService.swift */; };
|
||||
DBF8AE1A263293E400C9C23C /* NotificationService.appex in Embed App Extensions */ = {isa = PBXBuildFile; fileRef = DBF8AE13263293E400C9C23C /* NotificationService.appex */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; };
|
||||
DBF96326262EC0A6001D8D25 /* AuthenticationServices.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DBF96325262EC0A6001D8D25 /* AuthenticationServices.framework */; };
|
||||
|
@ -1126,6 +1128,7 @@
|
|||
DB5086B825CC0D6400C2C187 /* Kingfisher in Frameworks */,
|
||||
DBF96326262EC0A6001D8D25 /* AuthenticationServices.framework in Frameworks */,
|
||||
DBAC6483267D0B21007FE9FD /* DifferenceKit in Frameworks */,
|
||||
DB0E2D2E26833FF700865C3C /* NukeFLAnimatedImagePlugin in Frameworks */,
|
||||
2D61336925C18A4F00CAE157 /* AlamofireNetworkActivityIndicator in Frameworks */,
|
||||
DBAC64A1267E6D02007FE9FD /* Fuzi in Frameworks */,
|
||||
DB3D0FF325BAA61700EAA174 /* AlamofireImage in Frameworks */,
|
||||
|
@ -1133,6 +1136,7 @@
|
|||
2D5981BA25E4D7F8000FB903 /* ThirdPartyMailer in Frameworks */,
|
||||
87FFDA5D898A5C42ADCB35E7 /* Pods_Mastodon.framework in Frameworks */,
|
||||
DB6804C82637CE2F00430867 /* AppShared.framework in Frameworks */,
|
||||
DBF7A0FC26830C33004176A2 /* FPSIndicator in Frameworks */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
|
@ -2644,6 +2648,8 @@
|
|||
DBAC6482267D0B21007FE9FD /* DifferenceKit */,
|
||||
DBAC649D267DFE43007FE9FD /* DiffableDataSources */,
|
||||
DBAC64A0267E6D02007FE9FD /* Fuzi */,
|
||||
DBF7A0FB26830C33004176A2 /* FPSIndicator */,
|
||||
DB0E2D2D26833FF700865C3C /* NukeFLAnimatedImagePlugin */,
|
||||
);
|
||||
productName = Mastodon;
|
||||
productReference = DB427DD225BAA00100D1B89D /* Mastodon.app */;
|
||||
|
@ -2835,6 +2841,8 @@
|
|||
DBAC6481267D0B21007FE9FD /* XCRemoteSwiftPackageReference "DifferenceKit" */,
|
||||
DBAC649C267DFE43007FE9FD /* XCRemoteSwiftPackageReference "DiffableDataSources" */,
|
||||
DBAC649F267E6D01007FE9FD /* XCRemoteSwiftPackageReference "Fuzi" */,
|
||||
DBF7A0FA26830C33004176A2 /* XCRemoteSwiftPackageReference "FPSIndicator" */,
|
||||
DB0E2D2C26833FF600865C3C /* XCRemoteSwiftPackageReference "Nuke-FLAnimatedImage-Plugin" */,
|
||||
);
|
||||
productRefGroup = DB427DD325BAA00100D1B89D /* Products */;
|
||||
projectDirPath = "";
|
||||
|
@ -3788,7 +3796,7 @@
|
|||
CLANG_ENABLE_MODULES = YES;
|
||||
CODE_SIGN_ENTITLEMENTS = Mastodon/Mastodon.entitlements;
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
CURRENT_PROJECT_VERSION = 18;
|
||||
CURRENT_PROJECT_VERSION = 20;
|
||||
DEVELOPMENT_ASSET_PATHS = "Mastodon/Resources/Preview\\ Assets.xcassets";
|
||||
DEVELOPMENT_TEAM = 5Z4GVSS33P;
|
||||
INFOPLIST_FILE = Mastodon/Info.plist;
|
||||
|
@ -3796,7 +3804,7 @@
|
|||
"$(inherited)",
|
||||
"@executable_path/Frameworks",
|
||||
);
|
||||
MARKETING_VERSION = 0.7.2;
|
||||
MARKETING_VERSION = 0.7.4;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = org.joinmastodon.app;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
PROVISIONING_PROFILE_SPECIFIER = "";
|
||||
|
@ -3815,7 +3823,7 @@
|
|||
CLANG_ENABLE_MODULES = YES;
|
||||
CODE_SIGN_ENTITLEMENTS = Mastodon/Mastodon.entitlements;
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
CURRENT_PROJECT_VERSION = 18;
|
||||
CURRENT_PROJECT_VERSION = 20;
|
||||
DEVELOPMENT_ASSET_PATHS = "Mastodon/Resources/Preview\\ Assets.xcassets";
|
||||
DEVELOPMENT_TEAM = 5Z4GVSS33P;
|
||||
INFOPLIST_FILE = Mastodon/Info.plist;
|
||||
|
@ -3823,7 +3831,7 @@
|
|||
"$(inherited)",
|
||||
"@executable_path/Frameworks",
|
||||
);
|
||||
MARKETING_VERSION = 0.7.2;
|
||||
MARKETING_VERSION = 0.7.4;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = org.joinmastodon.app;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
PROVISIONING_PROFILE_SPECIFIER = "";
|
||||
|
@ -4143,7 +4151,7 @@
|
|||
CLANG_ENABLE_MODULES = YES;
|
||||
CODE_SIGN_ENTITLEMENTS = Mastodon/Mastodon.entitlements;
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
CURRENT_PROJECT_VERSION = 18;
|
||||
CURRENT_PROJECT_VERSION = 20;
|
||||
DEVELOPMENT_ASSET_PATHS = "Mastodon/Resources/Preview\\ Assets.xcassets";
|
||||
DEVELOPMENT_TEAM = 5Z4GVSS33P;
|
||||
INFOPLIST_FILE = Mastodon/Info.plist;
|
||||
|
@ -4151,7 +4159,7 @@
|
|||
"$(inherited)",
|
||||
"@executable_path/Frameworks",
|
||||
);
|
||||
MARKETING_VERSION = 0.7.2;
|
||||
MARKETING_VERSION = 0.7.4;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = org.joinmastodon.app;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
PROVISIONING_PROFILE_SPECIFIER = "";
|
||||
|
@ -4257,7 +4265,7 @@
|
|||
buildSettings = {
|
||||
CODE_SIGN_ENTITLEMENTS = NotificationService/NotificationService.entitlements;
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
CURRENT_PROJECT_VERSION = 18;
|
||||
CURRENT_PROJECT_VERSION = 20;
|
||||
DEVELOPMENT_TEAM = 5Z4GVSS33P;
|
||||
INFOPLIST_FILE = NotificationService/Info.plist;
|
||||
LD_RUNPATH_SEARCH_PATHS = (
|
||||
|
@ -4265,7 +4273,7 @@
|
|||
"@executable_path/Frameworks",
|
||||
"@executable_path/../../Frameworks",
|
||||
);
|
||||
MARKETING_VERSION = 0.7.2;
|
||||
MARKETING_VERSION = 0.7.4;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = org.joinmastodon.app.NotificationService;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SKIP_INSTALL = YES;
|
||||
|
@ -4376,7 +4384,7 @@
|
|||
CLANG_ENABLE_MODULES = YES;
|
||||
CODE_SIGN_ENTITLEMENTS = Mastodon/Mastodon.entitlements;
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
CURRENT_PROJECT_VERSION = 18;
|
||||
CURRENT_PROJECT_VERSION = 20;
|
||||
DEVELOPMENT_ASSET_PATHS = "Mastodon/Resources/Preview\\ Assets.xcassets";
|
||||
DEVELOPMENT_TEAM = 5Z4GVSS33P;
|
||||
INFOPLIST_FILE = Mastodon/Info.plist;
|
||||
|
@ -4384,7 +4392,7 @@
|
|||
"$(inherited)",
|
||||
"@executable_path/Frameworks",
|
||||
);
|
||||
MARKETING_VERSION = 0.7.2;
|
||||
MARKETING_VERSION = 0.7.4;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = org.joinmastodon.app;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
PROVISIONING_PROFILE_SPECIFIER = "";
|
||||
|
@ -4490,7 +4498,7 @@
|
|||
buildSettings = {
|
||||
CODE_SIGN_ENTITLEMENTS = NotificationService/NotificationService.entitlements;
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
CURRENT_PROJECT_VERSION = 18;
|
||||
CURRENT_PROJECT_VERSION = 20;
|
||||
DEVELOPMENT_TEAM = 5Z4GVSS33P;
|
||||
INFOPLIST_FILE = NotificationService/Info.plist;
|
||||
LD_RUNPATH_SEARCH_PATHS = (
|
||||
|
@ -4498,7 +4506,7 @@
|
|||
"@executable_path/Frameworks",
|
||||
"@executable_path/../../Frameworks",
|
||||
);
|
||||
MARKETING_VERSION = 0.7.2;
|
||||
MARKETING_VERSION = 0.7.4;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = org.joinmastodon.app.NotificationService;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SKIP_INSTALL = YES;
|
||||
|
@ -4544,7 +4552,7 @@
|
|||
buildSettings = {
|
||||
CODE_SIGN_ENTITLEMENTS = NotificationService/NotificationService.entitlements;
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
CURRENT_PROJECT_VERSION = 18;
|
||||
CURRENT_PROJECT_VERSION = 20;
|
||||
DEVELOPMENT_TEAM = 5Z4GVSS33P;
|
||||
INFOPLIST_FILE = NotificationService/Info.plist;
|
||||
LD_RUNPATH_SEARCH_PATHS = (
|
||||
|
@ -4552,7 +4560,7 @@
|
|||
"@executable_path/Frameworks",
|
||||
"@executable_path/../../Frameworks",
|
||||
);
|
||||
MARKETING_VERSION = 0.7.2;
|
||||
MARKETING_VERSION = 0.7.4;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = org.joinmastodon.app.NotificationService;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SKIP_INSTALL = YES;
|
||||
|
@ -4567,7 +4575,7 @@
|
|||
buildSettings = {
|
||||
CODE_SIGN_ENTITLEMENTS = NotificationService/NotificationService.entitlements;
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
CURRENT_PROJECT_VERSION = 18;
|
||||
CURRENT_PROJECT_VERSION = 20;
|
||||
DEVELOPMENT_TEAM = 5Z4GVSS33P;
|
||||
INFOPLIST_FILE = NotificationService/Info.plist;
|
||||
LD_RUNPATH_SEARCH_PATHS = (
|
||||
|
@ -4575,7 +4583,7 @@
|
|||
"@executable_path/Frameworks",
|
||||
"@executable_path/../../Frameworks",
|
||||
);
|
||||
MARKETING_VERSION = 0.7.2;
|
||||
MARKETING_VERSION = 0.7.4;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = org.joinmastodon.app.NotificationService;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SKIP_INSTALL = YES;
|
||||
|
@ -4718,6 +4726,14 @@
|
|||
minimumVersion = 0.1.1;
|
||||
};
|
||||
};
|
||||
DB0E2D2C26833FF600865C3C /* XCRemoteSwiftPackageReference "Nuke-FLAnimatedImage-Plugin" */ = {
|
||||
isa = XCRemoteSwiftPackageReference;
|
||||
repositoryURL = "https://github.com/kean/Nuke-FLAnimatedImage-Plugin.git";
|
||||
requirement = {
|
||||
kind = upToNextMajorVersion;
|
||||
minimumVersion = 8.0.0;
|
||||
};
|
||||
};
|
||||
DB3D0FF125BAA61700EAA174 /* XCRemoteSwiftPackageReference "AlamofireImage" */ = {
|
||||
isa = XCRemoteSwiftPackageReference;
|
||||
repositoryURL = "https://github.com/Alamofire/AlamofireImage.git";
|
||||
|
@ -4798,6 +4814,14 @@
|
|||
minimumVersion = 2.11.0;
|
||||
};
|
||||
};
|
||||
DBF7A0FA26830C33004176A2 /* XCRemoteSwiftPackageReference "FPSIndicator" */ = {
|
||||
isa = XCRemoteSwiftPackageReference;
|
||||
repositoryURL = "https://github.com/MainasuK/FPSIndicator.git";
|
||||
requirement = {
|
||||
kind = upToNextMajorVersion;
|
||||
minimumVersion = 1.0.0;
|
||||
};
|
||||
};
|
||||
/* End XCRemoteSwiftPackageReference section */
|
||||
|
||||
/* Begin XCSwiftPackageProductDependency section */
|
||||
|
@ -4835,6 +4859,11 @@
|
|||
package = DB0140BB25C40D7500F9F3CF /* XCRemoteSwiftPackageReference "CommonOSLog" */;
|
||||
productName = CommonOSLog;
|
||||
};
|
||||
DB0E2D2D26833FF700865C3C /* NukeFLAnimatedImagePlugin */ = {
|
||||
isa = XCSwiftPackageProductDependency;
|
||||
package = DB0E2D2C26833FF600865C3C /* XCRemoteSwiftPackageReference "Nuke-FLAnimatedImage-Plugin" */;
|
||||
productName = NukeFLAnimatedImagePlugin;
|
||||
};
|
||||
DB3D0FF225BAA61700EAA174 /* AlamofireImage */ = {
|
||||
isa = XCSwiftPackageProductDependency;
|
||||
package = DB3D0FF125BAA61700EAA174 /* XCRemoteSwiftPackageReference "AlamofireImage" */;
|
||||
|
@ -4890,6 +4919,11 @@
|
|||
package = DBB525062611EAC0002F1F29 /* XCRemoteSwiftPackageReference "Tabman" */;
|
||||
productName = Tabman;
|
||||
};
|
||||
DBF7A0FB26830C33004176A2 /* FPSIndicator */ = {
|
||||
isa = XCSwiftPackageProductDependency;
|
||||
package = DBF7A0FA26830C33004176A2 /* XCRemoteSwiftPackageReference "FPSIndicator" */;
|
||||
productName = FPSIndicator;
|
||||
};
|
||||
/* End XCSwiftPackageProductDependency section */
|
||||
|
||||
/* Begin XCVersionGroup section */
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
<key>AppShared.xcscheme_^#shared#^_</key>
|
||||
<dict>
|
||||
<key>orderHint</key>
|
||||
<integer>14</integer>
|
||||
<integer>26</integer>
|
||||
</dict>
|
||||
<key>CoreDataStack.xcscheme_^#shared#^_</key>
|
||||
<dict>
|
||||
|
@ -17,7 +17,7 @@
|
|||
<key>Mastodon - ASDK.xcscheme_^#shared#^_</key>
|
||||
<dict>
|
||||
<key>orderHint</key>
|
||||
<integer>3</integer>
|
||||
<integer>1</integer>
|
||||
</dict>
|
||||
<key>Mastodon - RTL.xcscheme_^#shared#^_</key>
|
||||
<dict>
|
||||
|
@ -32,12 +32,12 @@
|
|||
<key>Mastodon.xcscheme_^#shared#^_</key>
|
||||
<dict>
|
||||
<key>orderHint</key>
|
||||
<integer>2</integer>
|
||||
<integer>0</integer>
|
||||
</dict>
|
||||
<key>NotificationService.xcscheme_^#shared#^_</key>
|
||||
<dict>
|
||||
<key>orderHint</key>
|
||||
<integer>22</integer>
|
||||
<integer>2</integer>
|
||||
</dict>
|
||||
</dict>
|
||||
<key>SuppressBuildableAutocreation</key>
|
||||
|
|
|
@ -64,6 +64,24 @@
|
|||
"version": "1.2.0"
|
||||
}
|
||||
},
|
||||
{
|
||||
"package": "FLAnimatedImage",
|
||||
"repositoryURL": "https://github.com/Flipboard/FLAnimatedImage",
|
||||
"state": {
|
||||
"branch": null,
|
||||
"revision": "e7f9fd4681ae41bf6f3056db08af4f401d61da52",
|
||||
"version": "1.0.16"
|
||||
}
|
||||
},
|
||||
{
|
||||
"package": "FPSIndicator",
|
||||
"repositoryURL": "https://github.com/MainasuK/FPSIndicator.git",
|
||||
"state": {
|
||||
"branch": null,
|
||||
"revision": "b2a002d689c400485f2ba41f9e71e15f7b99764a",
|
||||
"version": "1.0.1"
|
||||
}
|
||||
},
|
||||
{
|
||||
"package": "Fuzi",
|
||||
"repositoryURL": "https://github.com/cezheng/Fuzi.git",
|
||||
|
@ -100,6 +118,15 @@
|
|||
"version": "10.3.0"
|
||||
}
|
||||
},
|
||||
{
|
||||
"package": "NukeFLAnimatedImagePlugin",
|
||||
"repositoryURL": "https://github.com/kean/Nuke-FLAnimatedImage-Plugin.git",
|
||||
"state": {
|
||||
"branch": null,
|
||||
"revision": "b59c346a7d536336db3b0f12c72c6e53ee709e16",
|
||||
"version": "8.0.0"
|
||||
}
|
||||
},
|
||||
{
|
||||
"package": "Pageboy",
|
||||
"repositoryURL": "https://github.com/uias/Pageboy",
|
||||
|
|
|
@ -41,8 +41,14 @@ enum Item {
|
|||
extension Item {
|
||||
class StatusAttribute {
|
||||
var isSeparatorLineHidden: Bool
|
||||
|
||||
|
||||
/// is media loaded or not
|
||||
let isImageLoaded = CurrentValueSubject<Bool, Never>(false)
|
||||
|
||||
/// flag for current sensitive content reveal state
|
||||
///
|
||||
/// - true: displaying sensitive content
|
||||
/// - false: displaying content warning overlay
|
||||
let isRevealing = CurrentValueSubject<Bool, Never>(false)
|
||||
|
||||
init(isSeparatorLineHidden: Bool = false) {
|
||||
|
|
|
@ -52,9 +52,9 @@ extension NotificationSection {
|
|||
let frame = CGRect(x: 0, y: 0, width: tableView.readableContentGuide.layoutFrame.width - NotificationStatusTableViewCell.statusPadding.left - NotificationStatusTableViewCell.statusPadding.right, height: tableView.readableContentGuide.layoutFrame.height)
|
||||
StatusSection.configure(
|
||||
cell: cell,
|
||||
tableView: tableView,
|
||||
dependency: dependency,
|
||||
readableLayoutFrame: frame,
|
||||
timestampUpdatePublisher: timestampUpdatePublisher,
|
||||
status: status,
|
||||
requestUserID: requestUserID,
|
||||
statusItemAttribute: attribute
|
||||
|
|
|
@ -41,9 +41,9 @@ extension ReportSection {
|
|||
let status = managedObjectContext.object(with: objectID) as! Status
|
||||
StatusSection.configure(
|
||||
cell: cell,
|
||||
tableView: tableView,
|
||||
dependency: dependency,
|
||||
readableLayoutFrame: tableView.readableContentGuide.layoutFrame,
|
||||
timestampUpdatePublisher: timestampUpdatePublisher,
|
||||
status: status,
|
||||
requestUserID: requestUserID,
|
||||
statusItemAttribute: attribute
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -29,9 +29,6 @@ extension ActiveLabel {
|
|||
hashtagColor = Asset.Colors.brandBlue.color
|
||||
URLColor = Asset.Colors.brandBlue.color
|
||||
emojiPlaceholderColor = .systemFill
|
||||
#if DEBUG
|
||||
text = "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua."
|
||||
#endif
|
||||
|
||||
accessibilityContainerType = .semanticGroup
|
||||
|
||||
|
|
|
@ -22,7 +22,7 @@ extension UIView {
|
|||
|
||||
}
|
||||
|
||||
// MARK: - Convinience view appearance modification method
|
||||
// MARK: - Convenience view appearance modification method
|
||||
extension UIView {
|
||||
@discardableResult
|
||||
func applyCornerRadius(radius: CGFloat) -> Self {
|
||||
|
|
|
@ -58,6 +58,9 @@ internal enum Asset {
|
|||
internal static let disabled = ColorAsset(name: "Colors/Button/disabled")
|
||||
internal static let inactive = ColorAsset(name: "Colors/Button/inactive")
|
||||
}
|
||||
internal enum ContentWarningOverlay {
|
||||
internal static let background = ColorAsset(name: "Colors/ContentWarningOverlay/background")
|
||||
}
|
||||
internal enum Icon {
|
||||
internal static let plus = ColorAsset(name: "Colors/Icon/plus")
|
||||
}
|
||||
|
|
|
@ -254,13 +254,9 @@ internal enum L10n {
|
|||
}
|
||||
}
|
||||
internal enum Status {
|
||||
/// content warning
|
||||
/// Content Warning
|
||||
internal static let contentWarning = L10n.tr("Localizable", "Common.Controls.Status.ContentWarning")
|
||||
/// cw: %@
|
||||
internal static func contentWarningText(_ p1: Any) -> String {
|
||||
return L10n.tr("Localizable", "Common.Controls.Status.ContentWarningText", String(describing: p1))
|
||||
}
|
||||
/// Tap to reveal that may be sensitive
|
||||
/// Tap anywhere to reveal
|
||||
internal static let mediaContentWarning = L10n.tr("Localizable", "Common.Controls.Status.MediaContentWarning")
|
||||
/// Show Post
|
||||
internal static let showPost = L10n.tr("Localizable", "Common.Controls.Status.ShowPost")
|
||||
|
|
|
@ -7,7 +7,8 @@
|
|||
|
||||
import UIKit
|
||||
import AlamofireImage
|
||||
import Kingfisher
|
||||
import FLAnimatedImage
|
||||
import Nuke
|
||||
|
||||
protocol AvatarConfigurableView {
|
||||
static var configurableAvatarImageSize: CGSize { get }
|
||||
|
@ -31,13 +32,7 @@ extension AvatarConfigurableView {
|
|||
}
|
||||
return placeholderImage
|
||||
}()
|
||||
|
||||
// cancel previous task
|
||||
configurableAvatarImageView?.af.cancelImageRequest()
|
||||
configurableAvatarImageView?.kf.cancelDownloadTask()
|
||||
configurableAvatarButton?.af.cancelImageRequest(for: .normal)
|
||||
configurableAvatarButton?.kf.cancelImageDownloadTask()
|
||||
|
||||
|
||||
// reset layer attributes
|
||||
configurableAvatarImageView?.layer.masksToBounds = false
|
||||
configurableAvatarImageView?.layer.cornerRadius = 0
|
||||
|
@ -55,85 +50,50 @@ extension AvatarConfigurableView {
|
|||
avatarConfigurableView(self, didFinishConfiguration: configuration)
|
||||
}
|
||||
|
||||
let filter = ScaledToSizeWithRoundedCornersFilter(
|
||||
size: Self.configurableAvatarImageSize,
|
||||
radius: configuration.keepImageCorner ? 0 : Self.configurableAvatarImageCornerRadius
|
||||
)
|
||||
|
||||
// set placeholder if no asset
|
||||
guard let avatarImageURL = configuration.avatarImageURL else {
|
||||
configurableAvatarImageView?.image = placeholderImage
|
||||
configurableAvatarImageView?.layer.masksToBounds = true
|
||||
configurableAvatarImageView?.layer.cornerRadius = Self.configurableAvatarImageCornerRadius
|
||||
configurableAvatarImageView?.layer.cornerCurve = Self.configurableAvatarImageCornerRadius < Self.configurableAvatarImageSize.width * 0.5 ? .continuous :.circular
|
||||
|
||||
configurableAvatarButton?.setImage(placeholderImage, for: .normal)
|
||||
configurableAvatarButton?.layer.masksToBounds = true
|
||||
configurableAvatarButton?.layer.cornerRadius = Self.configurableAvatarImageCornerRadius
|
||||
configurableAvatarButton?.layer.cornerCurve = Self.configurableAvatarImageCornerRadius < Self.configurableAvatarImageSize.width * 0.5 ? .continuous :.circular
|
||||
guard let imageDisplayingView: ImageDisplayingView = configurableAvatarImageView ?? configurableAvatarButton?.imageView else {
|
||||
return
|
||||
}
|
||||
|
||||
if let avatarImageView = configurableAvatarImageView {
|
||||
// set avatar (GIF using Kingfisher)
|
||||
switch avatarImageURL.pathExtension {
|
||||
case "gif":
|
||||
avatarImageView.kf.setImage(
|
||||
with: avatarImageURL,
|
||||
placeholder: placeholderImage,
|
||||
options: [
|
||||
.transition(.fade(0.2))
|
||||
]
|
||||
)
|
||||
avatarImageView.layer.masksToBounds = true
|
||||
avatarImageView.layer.cornerRadius = Self.configurableAvatarImageCornerRadius
|
||||
avatarImageView.layer.cornerCurve = Self.configurableAvatarImageCornerRadius < Self.configurableAvatarImageSize.width * 0.5 ? .continuous :.circular
|
||||
|
||||
default:
|
||||
avatarImageView.af.setImage(
|
||||
withURL: avatarImageURL,
|
||||
placeholderImage: placeholderImage,
|
||||
filter: filter,
|
||||
imageTransition: .crossDissolve(0.3),
|
||||
runImageTransitionIfCached: false,
|
||||
completion: nil
|
||||
)
|
||||
|
||||
if Self.configurableAvatarImageCornerRadius > 0, configuration.keepImageCorner {
|
||||
configurableAvatarImageView?.layer.masksToBounds = true
|
||||
configurableAvatarImageView?.layer.cornerRadius = Self.configurableAvatarImageCornerRadius
|
||||
configurableAvatarImageView?.layer.cornerCurve = Self.configurableAvatarImageCornerRadius < Self.configurableAvatarImageSize.width * 0.5 ? .continuous :.circular
|
||||
}
|
||||
// set corner radius (due to GIF won't crop)
|
||||
imageDisplayingView.layer.masksToBounds = true
|
||||
imageDisplayingView.layer.cornerRadius = Self.configurableAvatarImageCornerRadius
|
||||
imageDisplayingView.layer.cornerCurve = Self.configurableAvatarImageCornerRadius < Self.configurableAvatarImageSize.width * 0.5 ? .continuous :.circular
|
||||
|
||||
// set border
|
||||
configureLayerBorder(view: imageDisplayingView, configuration: configuration)
|
||||
|
||||
|
||||
// set image
|
||||
let url = configuration.avatarImageURL
|
||||
let processors: [ImageProcessing] = [
|
||||
ImageProcessors.Resize(
|
||||
size: Self.configurableAvatarImageSize,
|
||||
unit: .points,
|
||||
contentMode: .aspectFill,
|
||||
crop: false
|
||||
),
|
||||
ImageProcessors.RoundedCorners(
|
||||
radius: Self.configurableAvatarImageCornerRadius
|
||||
)
|
||||
]
|
||||
|
||||
let request = ImageRequest(url: url, processors: processors)
|
||||
let options = ImageLoadingOptions(
|
||||
placeholder: placeholderImage,
|
||||
transition: .fadeIn(duration: 0.2)
|
||||
)
|
||||
|
||||
Nuke.loadImage(
|
||||
with: request,
|
||||
options: options,
|
||||
into: imageDisplayingView
|
||||
) { result in
|
||||
switch result {
|
||||
case .failure:
|
||||
break
|
||||
case .success:
|
||||
break
|
||||
}
|
||||
|
||||
configureLayerBorder(view: avatarImageView, configuration: configuration)
|
||||
}
|
||||
|
||||
if let avatarButton = configurableAvatarButton {
|
||||
switch avatarImageURL.pathExtension {
|
||||
case "gif":
|
||||
avatarButton.kf.setImage(
|
||||
with: avatarImageURL,
|
||||
for: .normal,
|
||||
placeholder: placeholderImage,
|
||||
options: [
|
||||
.transition(.fade(0.2))
|
||||
]
|
||||
)
|
||||
avatarButton.layer.masksToBounds = true
|
||||
avatarButton.layer.cornerRadius = Self.configurableAvatarImageCornerRadius
|
||||
avatarButton.layer.cornerCurve = Self.configurableAvatarImageCornerRadius < Self.configurableAvatarImageSize.width * 0.5 ? .continuous : .circular
|
||||
default:
|
||||
avatarButton.af.setImage(
|
||||
for: .normal,
|
||||
url: avatarImageURL,
|
||||
placeholderImage: placeholderImage,
|
||||
filter: filter,
|
||||
completion: nil
|
||||
)
|
||||
}
|
||||
|
||||
configureLayerBorder(view: avatarButton, configuration: configuration)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -20,7 +20,7 @@ extension StatusTableViewCellDelegate where Self: StatusProvider {
|
|||
StatusProviderFacade.coordinateToStatusAuthorProfileScene(for: .secondary, provider: self, cell: cell)
|
||||
}
|
||||
|
||||
func statusTableViewCell(_ cell: StatusTableViewCell, statusView: StatusView, avatarButtonDidPressed button: UIButton) {
|
||||
func statusTableViewCell(_ cell: StatusTableViewCell, statusView: StatusView, avatarImageViewDidPressed imageView: UIImageView) {
|
||||
StatusProviderFacade.coordinateToStatusAuthorProfileScene(for: .primary, provider: self, cell: cell)
|
||||
}
|
||||
|
||||
|
|
|
@ -66,6 +66,7 @@ extension StatusTableViewCellDelegate where Self: StatusProvider {
|
|||
.store(in: &disposeBag)
|
||||
|
||||
status(for: cell, indexPath: indexPath)
|
||||
.receive(on: RunLoop.main)
|
||||
.sink { [weak self] status in
|
||||
guard let self = self else { return }
|
||||
let status = status?.reblog ?? status
|
||||
|
|
|
@ -541,8 +541,9 @@ extension StatusProviderFacade {
|
|||
.compactMap { [weak dependency] status -> AnyPublisher<Status?, Never>? in
|
||||
guard let dependency = dependency else { return nil }
|
||||
guard let _status = status else { return nil }
|
||||
return dependency.context.managedObjectContext.performChanges {
|
||||
guard let status = dependency.context.managedObjectContext.object(with: _status.objectID) as? Status else { return }
|
||||
let managedObjectContext = dependency.context.backgroundManagedObjectContext
|
||||
return managedObjectContext.performChanges {
|
||||
guard let status = managedObjectContext.object(with: _status.objectID) as? Status else { return }
|
||||
let appStartUpTimestamp = dependency.context.documentStore.appStartUpTimestamp
|
||||
let isRevealing: Bool = {
|
||||
if dependency.context.documentStore.defaultRevealStatusDict[status.id] == true {
|
||||
|
@ -560,7 +561,11 @@ extension StatusProviderFacade {
|
|||
// toggle reveal
|
||||
dependency.context.documentStore.defaultRevealStatusDict[status.id] = false
|
||||
status.update(isReveal: !isRevealing)
|
||||
status.reblog?.update(isReveal: !isRevealing)
|
||||
|
||||
if let reblog = status.reblog {
|
||||
dependency.context.documentStore.defaultRevealStatusDict[reblog.id] = false
|
||||
reblog.update(isReveal: !isRevealing)
|
||||
}
|
||||
|
||||
// pause video playback if isRevealing before toggle
|
||||
if isRevealing, let attachment = (status.reblog ?? status).mediaAttachments?.first,
|
||||
|
|
|
@ -0,0 +1,9 @@
|
|||
{
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
},
|
||||
"properties" : {
|
||||
"provides-namespace" : true
|
||||
}
|
||||
}
|
|
@ -0,0 +1,38 @@
|
|||
{
|
||||
"colors" : [
|
||||
{
|
||||
"color" : {
|
||||
"color-space" : "srgb",
|
||||
"components" : {
|
||||
"alpha" : "1.000",
|
||||
"blue" : "235",
|
||||
"green" : "229",
|
||||
"red" : "221"
|
||||
}
|
||||
},
|
||||
"idiom" : "universal"
|
||||
},
|
||||
{
|
||||
"appearances" : [
|
||||
{
|
||||
"appearance" : "luminosity",
|
||||
"value" : "dark"
|
||||
}
|
||||
],
|
||||
"color" : {
|
||||
"color-space" : "srgb",
|
||||
"components" : {
|
||||
"alpha" : "1.000",
|
||||
"blue" : "0.922",
|
||||
"green" : "0.898",
|
||||
"red" : "0.867"
|
||||
}
|
||||
},
|
||||
"idiom" : "universal"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
}
|
||||
}
|
|
@ -94,9 +94,8 @@ Please check your internet connection.";
|
|||
"Common.Controls.Status.Actions.Reply" = "Reply";
|
||||
"Common.Controls.Status.Actions.Unfavorite" = "Unfavorite";
|
||||
"Common.Controls.Status.Actions.Unreblog" = "Unreblog";
|
||||
"Common.Controls.Status.ContentWarning" = "content warning";
|
||||
"Common.Controls.Status.ContentWarningText" = "cw: %@";
|
||||
"Common.Controls.Status.MediaContentWarning" = "Tap to reveal that may be sensitive";
|
||||
"Common.Controls.Status.ContentWarning" = "Content Warning";
|
||||
"Common.Controls.Status.MediaContentWarning" = "Tap anywhere to reveal";
|
||||
"Common.Controls.Status.Poll.Closed" = "Closed";
|
||||
"Common.Controls.Status.Poll.TimeLeft" = "%@ left";
|
||||
"Common.Controls.Status.Poll.Vote" = "Vote";
|
||||
|
|
|
@ -94,9 +94,8 @@ Please check your internet connection.";
|
|||
"Common.Controls.Status.Actions.Reply" = "Reply";
|
||||
"Common.Controls.Status.Actions.Unfavorite" = "Unfavorite";
|
||||
"Common.Controls.Status.Actions.Unreblog" = "Unreblog";
|
||||
"Common.Controls.Status.ContentWarning" = "content warning";
|
||||
"Common.Controls.Status.ContentWarningText" = "cw: %@";
|
||||
"Common.Controls.Status.MediaContentWarning" = "Tap to reveal that may be sensitive";
|
||||
"Common.Controls.Status.ContentWarning" = "Content Warning";
|
||||
"Common.Controls.Status.MediaContentWarning" = "Tap anywhere to reveal";
|
||||
"Common.Controls.Status.Poll.Closed" = "Closed";
|
||||
"Common.Controls.Status.Poll.TimeLeft" = "%@ left";
|
||||
"Common.Controls.Status.Poll.Vote" = "Vote";
|
||||
|
|
|
@ -10,10 +10,6 @@ import UIKit
|
|||
import Combine
|
||||
import SafariServices
|
||||
|
||||
#if DEBUG
|
||||
import GDPerformanceView_Swift
|
||||
#endif
|
||||
|
||||
class MainTabBarController: UITabBarController {
|
||||
|
||||
var disposeBag = Set<AnyCancellable>()
|
||||
|
@ -189,15 +185,7 @@ extension MainTabBarController {
|
|||
}
|
||||
.store(in: &disposeBag)
|
||||
}
|
||||
|
||||
override func viewDidAppear(_ animated: Bool) {
|
||||
super.viewDidAppear(animated)
|
||||
|
||||
#if DEBUG
|
||||
PerformanceMonitor.shared().start()
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
extension MainTabBarController {
|
||||
|
|
|
@ -104,16 +104,7 @@ final class NotificationStatusTableViewCell: UITableViewCell, StatusCell {
|
|||
super.init(coder: coder)
|
||||
configure()
|
||||
}
|
||||
|
||||
override func layoutSubviews() {
|
||||
super.layoutSubviews()
|
||||
|
||||
// precondition: app is active
|
||||
guard UIApplication.shared.applicationState == .active else { return }
|
||||
DispatchQueue.main.async {
|
||||
self.statusView.drawContentWarningImageView()
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
extension NotificationStatusTableViewCell {
|
||||
|
@ -231,32 +222,17 @@ extension NotificationStatusTableViewCell {
|
|||
statusBorder.layer.borderColor = Asset.Colors.Border.notification.color.cgColor
|
||||
actionImageBackground.layer.borderColor = Asset.Colors.Background.systemBackground.color.cgColor
|
||||
}
|
||||
|
||||
override func setHighlighted(_ highlighted: Bool, animated: Bool) {
|
||||
super.setHighlighted(highlighted, animated: animated)
|
||||
|
||||
resetContentOverlayBlurImageBackgroundColor(selected: highlighted)
|
||||
}
|
||||
|
||||
override func setSelected(_ selected: Bool, animated: Bool) {
|
||||
super.setSelected(selected, animated: animated)
|
||||
|
||||
resetContentOverlayBlurImageBackgroundColor(selected: selected)
|
||||
}
|
||||
|
||||
private func resetContentOverlayBlurImageBackgroundColor(selected: Bool) {
|
||||
let imageViewBackgroundColor: UIColor? = selected ? selectedBackgroundView?.backgroundColor : backgroundColor
|
||||
statusView.contentWarningOverlayView.blurContentImageView.backgroundColor = imageViewBackgroundColor
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// MARK: - StatusViewDelegate
|
||||
extension NotificationStatusTableViewCell: StatusViewDelegate {
|
||||
|
||||
func statusView(_ statusView: StatusView, headerInfoLabelDidPressed label: UILabel) {
|
||||
// do nothing
|
||||
}
|
||||
|
||||
func statusView(_ statusView: StatusView, avatarButtonDidPressed button: UIButton) {
|
||||
|
||||
func statusView(_ statusView: StatusView, avatarImageViewDidPressed imageView: UIImageView) {
|
||||
// do nothing
|
||||
}
|
||||
|
||||
|
|
|
@ -36,6 +36,7 @@ final class WelcomeViewController: UIViewController, NeedsDependency {
|
|||
|
||||
private(set) lazy var signUpButton: PrimaryActionButton = {
|
||||
let button = PrimaryActionButton()
|
||||
button.adjustsBackgroundImageWhenUserInterfaceStyleChanges = false
|
||||
button.setTitle(L10n.Common.Controls.Actions.signUp, for: .normal)
|
||||
let backgroundImageColor: UIColor = traitCollection.userInterfaceIdiom == .phone ? .white : Asset.Colors.brandBlue.color
|
||||
let backgroundImageHighlightedColor: UIColor = traitCollection.userInterfaceIdiom == .phone ? UIColor(white: 0.8, alpha: 1.0) : Asset.Colors.brandBlueDarken20.color
|
||||
|
|
|
@ -9,6 +9,7 @@ import os.log
|
|||
import UIKit
|
||||
import ActiveLabel
|
||||
import TwitterTextEditor
|
||||
import FLAnimatedImage
|
||||
|
||||
protocol ProfileHeaderViewDelegate: AnyObject {
|
||||
func profileHeaderView(_ profileHeaderView: ProfileHeaderView, avatarImageViewDidPressed imageView: UIImageView)
|
||||
|
@ -66,7 +67,7 @@ final class ProfileHeaderView: UIView {
|
|||
}()
|
||||
|
||||
let avatarImageView: UIImageView = {
|
||||
let imageView = UIImageView()
|
||||
let imageView = FLAnimatedImageView()
|
||||
let placeholderImage = UIImage
|
||||
.placeholder(size: ProfileHeaderView.avatarImageViewSize, color: Asset.Colors.Background.systemGroupedBackground.color)
|
||||
.af.imageRounded(withCornerRadius: ProfileHeaderView.avatarImageViewCornerRadius, divideRadiusByImageScale: false)
|
||||
|
|
|
@ -19,7 +19,6 @@ final class ReportedStatusTableViewCell: UITableViewCell, StatusCell {
|
|||
|
||||
weak var dependency: ReportViewController?
|
||||
var disposeBag = Set<AnyCancellable>()
|
||||
var pollCountdownSubscription: AnyCancellable?
|
||||
var observations = Set<NSKeyValueObservation>()
|
||||
|
||||
let statusView = StatusView()
|
||||
|
@ -62,16 +61,6 @@ final class ReportedStatusTableViewCell: UITableViewCell, StatusCell {
|
|||
_init()
|
||||
}
|
||||
|
||||
override func layoutSubviews() {
|
||||
super.layoutSubviews()
|
||||
|
||||
// precondition: app is active
|
||||
guard UIApplication.shared.applicationState == .active else { return }
|
||||
DispatchQueue.main.async {
|
||||
self.statusView.drawContentWarningImageView()
|
||||
}
|
||||
}
|
||||
|
||||
override func setHighlighted(_ highlighted: Bool, animated: Bool) {
|
||||
super.setHighlighted(highlighted, animated: animated)
|
||||
if highlighted {
|
||||
|
@ -134,7 +123,6 @@ extension ReportedStatusTableViewCell {
|
|||
statusView.delegate = self
|
||||
statusView.statusMosaicImageViewContainer.delegate = self
|
||||
statusView.actionToolbarContainer.isHidden = true
|
||||
statusView.contentWarningOverlayView.blurContentImageView.backgroundColor = backgroundColor
|
||||
}
|
||||
|
||||
override func traitCollectionDidChange(_ previousTraitCollection: UITraitCollection?) {
|
||||
|
@ -188,12 +176,13 @@ extension ReportedStatusTableViewCell: MosaicImageViewContainerDelegate {
|
|||
}
|
||||
|
||||
extension ReportedStatusTableViewCell: StatusViewDelegate {
|
||||
|
||||
func statusView(_ statusView: StatusView, headerInfoLabelDidPressed label: UILabel) {
|
||||
}
|
||||
|
||||
func statusView(_ statusView: StatusView, avatarButtonDidPressed button: UIButton) {
|
||||
|
||||
func statusView(_ statusView: StatusView, avatarImageViewDidPressed imageView: UIImageView) {
|
||||
}
|
||||
|
||||
|
||||
func statusView(_ statusView: StatusView, revealContentWarningButtonDidPressed button: UIButton) {
|
||||
guard let dependency = self.dependency else { return }
|
||||
StatusProviderFacade.responseToStatusContentWarningRevealAction(dependency: dependency, cell: self)
|
||||
|
|
|
@ -20,6 +20,8 @@ class PrimaryActionButton: UIButton {
|
|||
}()
|
||||
|
||||
private var originalButtonTitle: String?
|
||||
|
||||
var adjustsBackgroundImageWhenUserInterfaceStyleChanges = true
|
||||
|
||||
override init(frame: CGRect) {
|
||||
super.init(frame: frame)
|
||||
|
@ -51,7 +53,9 @@ extension PrimaryActionButton {
|
|||
override func traitCollectionDidChange(_ previousTraitCollection: UITraitCollection?) {
|
||||
super.traitCollectionDidChange(previousTraitCollection)
|
||||
|
||||
setupBackgroundAppearance()
|
||||
if adjustsBackgroundImageWhenUserInterfaceStyleChanges {
|
||||
setupBackgroundAppearance()
|
||||
}
|
||||
}
|
||||
|
||||
func showLoading() {
|
||||
|
|
|
@ -42,7 +42,7 @@ final class MosaicImageViewContainer: UIView {
|
|||
|
||||
let contentWarningOverlayView: ContentWarningOverlayView = {
|
||||
let contentWarningOverlayView = ContentWarningOverlayView()
|
||||
contentWarningOverlayView.configure(style: .visualEffectView)
|
||||
contentWarningOverlayView.configure(style: .media)
|
||||
return contentWarningOverlayView
|
||||
}()
|
||||
|
||||
|
@ -103,10 +103,20 @@ extension MosaicImageViewContainer {
|
|||
imageViews.forEach { imageView in
|
||||
imageView.constraints.forEach { imageView.removeConstraint($0) }
|
||||
imageView.removeFromSuperview()
|
||||
imageView.layer.maskedCorners = [
|
||||
.layerMinXMinYCorner, .layerMaxXMinYCorner,
|
||||
.layerMinXMaxYCorner, .layerMaxXMaxYCorner
|
||||
]
|
||||
imageView.image = nil
|
||||
}
|
||||
blurhashOverlayImageViews.forEach { imageView in
|
||||
imageView.constraints.forEach { imageView.removeConstraint($0) }
|
||||
imageView.removeFromSuperview()
|
||||
imageView.layer.maskedCorners = [
|
||||
.layerMinXMinYCorner, .layerMaxXMinYCorner,
|
||||
.layerMinXMaxYCorner, .layerMaxXMaxYCorner
|
||||
]
|
||||
imageView.image = nil
|
||||
}
|
||||
|
||||
contentWarningOverlayView.removeFromSuperview()
|
||||
|
|
|
@ -29,19 +29,22 @@ class ContentWarningOverlayView: UIView {
|
|||
label.isAccessibilityElement = false
|
||||
return label
|
||||
}()
|
||||
|
||||
let blurContentImageView: UIImageView = {
|
||||
let imageView = UIImageView()
|
||||
imageView.layer.masksToBounds = false
|
||||
return imageView
|
||||
|
||||
// for status style overlay
|
||||
let contentOverlayView: UIView = {
|
||||
let view = UIView()
|
||||
view.backgroundColor = Asset.Colors.ContentWarningOverlay.background.color
|
||||
view.applyCornerRadius(radius: ContentWarningOverlayView.cornerRadius)
|
||||
return view
|
||||
}()
|
||||
let blurContentWarningTitleLabel: UILabel = {
|
||||
let label = UILabel()
|
||||
label.font = UIFontMetrics(forTextStyle: .body).scaledFont(for: .systemFont(ofSize: 17), maximumPointSize: 23)
|
||||
label.font = UIFontMetrics(forTextStyle: .body).scaledFont(for: .systemFont(ofSize: 17, weight: .semibold), maximumPointSize: 23)
|
||||
label.text = L10n.Common.Controls.Status.mediaContentWarning
|
||||
label.textColor = Asset.Colors.Label.primary.color
|
||||
label.textAlignment = .center
|
||||
label.isAccessibilityElement = false
|
||||
label.numberOfLines = 2
|
||||
return label
|
||||
}()
|
||||
let blurContentWarningLabel: UILabel = {
|
||||
|
@ -50,8 +53,8 @@ class ContentWarningOverlayView: UIView {
|
|||
label.text = L10n.Common.Controls.Status.mediaContentWarning
|
||||
label.textColor = Asset.Colors.Label.secondary.color
|
||||
label.textAlignment = .center
|
||||
label.layer.setupShadow()
|
||||
label.isAccessibilityElement = false
|
||||
label.numberOfLines = 2
|
||||
return label
|
||||
}()
|
||||
|
||||
|
@ -108,13 +111,13 @@ extension ContentWarningOverlayView {
|
|||
])
|
||||
|
||||
// blur image style
|
||||
blurContentImageView.translatesAutoresizingMaskIntoConstraints = false
|
||||
addSubview(blurContentImageView)
|
||||
contentOverlayView.translatesAutoresizingMaskIntoConstraints = false
|
||||
addSubview(contentOverlayView)
|
||||
NSLayoutConstraint.activate([
|
||||
blurContentImageView.topAnchor.constraint(equalTo: topAnchor),
|
||||
blurContentImageView.leadingAnchor.constraint(equalTo: leadingAnchor),
|
||||
blurContentImageView.trailingAnchor.constraint(equalTo: trailingAnchor),
|
||||
blurContentImageView.bottomAnchor.constraint(equalTo: bottomAnchor),
|
||||
contentOverlayView.topAnchor.constraint(equalTo: topAnchor),
|
||||
contentOverlayView.leadingAnchor.constraint(equalTo: leadingAnchor),
|
||||
contentOverlayView.trailingAnchor.constraint(equalTo: trailingAnchor),
|
||||
contentOverlayView.bottomAnchor.constraint(equalTo: bottomAnchor),
|
||||
])
|
||||
|
||||
let blurContentWarningLabelContainer = UIStackView()
|
||||
|
@ -123,7 +126,7 @@ extension ContentWarningOverlayView {
|
|||
blurContentWarningLabelContainer.alignment = .center
|
||||
|
||||
blurContentWarningLabelContainer.translatesAutoresizingMaskIntoConstraints = false
|
||||
blurContentImageView.addSubview(blurContentWarningLabelContainer)
|
||||
contentOverlayView.addSubview(blurContentWarningLabelContainer)
|
||||
NSLayoutConstraint.activate([
|
||||
blurContentWarningLabelContainer.topAnchor.constraint(equalTo: topAnchor),
|
||||
blurContentWarningLabelContainer.leadingAnchor.constraint(equalTo: leadingAnchor),
|
||||
|
@ -143,42 +146,43 @@ extension ContentWarningOverlayView {
|
|||
topPaddingView.heightAnchor.constraint(equalTo: bottomPaddingView.heightAnchor, multiplier: 1.0).priority(.defaultHigh),
|
||||
])
|
||||
blurContentWarningTitleLabel.setContentHuggingPriority(.defaultHigh + 2, for: .vertical)
|
||||
blurContentWarningTitleLabel.setContentCompressionResistancePriority(.defaultHigh + 1, for: .vertical)
|
||||
blurContentWarningLabel.setContentHuggingPriority(.defaultHigh + 1, for: .vertical)
|
||||
|
||||
tapGestureRecognizer.addTarget(self, action: #selector(ContentWarningOverlayView.tapGestureRecognizerHandler(_:)))
|
||||
addGestureRecognizer(tapGestureRecognizer)
|
||||
|
||||
configure(style: .visualEffectView)
|
||||
configure(style: .media)
|
||||
}
|
||||
}
|
||||
|
||||
extension ContentWarningOverlayView {
|
||||
|
||||
enum Style {
|
||||
case visualEffectView
|
||||
case blurContentImageView
|
||||
case media // visualEffectView for media
|
||||
case contentWarning // overlay for post
|
||||
}
|
||||
|
||||
func configure(style: Style) {
|
||||
switch style {
|
||||
case .visualEffectView:
|
||||
case .media:
|
||||
blurVisualEffectView.isHidden = false
|
||||
vibrancyVisualEffectView.isHidden = false
|
||||
blurContentImageView.isHidden = true
|
||||
case .blurContentImageView:
|
||||
contentOverlayView.isHidden = true
|
||||
case .contentWarning:
|
||||
blurVisualEffectView.isHidden = true
|
||||
vibrancyVisualEffectView.isHidden = true
|
||||
blurContentImageView.isHidden = false
|
||||
contentOverlayView.isHidden = false
|
||||
}
|
||||
}
|
||||
|
||||
func update(isRevealing: Bool, style: Style) {
|
||||
switch style {
|
||||
case .visualEffectView:
|
||||
case .media:
|
||||
blurVisualEffectView.effect = isRevealing ? nil : ContentWarningOverlayView.blurVisualEffect
|
||||
vibrancyVisualEffectView.alpha = isRevealing ? 0 : 1
|
||||
isUserInteractionEnabled = !isRevealing
|
||||
case .blurContentImageView:
|
||||
case .contentWarning:
|
||||
assertionFailure("not handle here")
|
||||
break
|
||||
}
|
||||
|
|
|
@ -7,13 +7,18 @@
|
|||
|
||||
import os.log
|
||||
import UIKit
|
||||
import Combine
|
||||
import AVKit
|
||||
import ActiveLabel
|
||||
import AlamofireImage
|
||||
import FLAnimatedImage
|
||||
|
||||
// TODO:
|
||||
// import LinkPresentation
|
||||
|
||||
protocol StatusViewDelegate: AnyObject {
|
||||
func statusView(_ statusView: StatusView, headerInfoLabelDidPressed label: UILabel)
|
||||
func statusView(_ statusView: StatusView, avatarButtonDidPressed button: UIButton)
|
||||
func statusView(_ statusView: StatusView, avatarImageViewDidPressed imageView: UIImageView)
|
||||
func statusView(_ statusView: StatusView, revealContentWarningButtonDidPressed button: UIButton)
|
||||
func statusView(_ statusView: StatusView, contentWarningOverlayViewDidPressed contentWarningOverlayView: ContentWarningOverlayView)
|
||||
func statusView(_ statusView: StatusView, playerContainerView: PlayerContainerView, contentWarningOverlayViewDidPressed contentWarningOverlayView: ContentWarningOverlayView)
|
||||
|
@ -24,6 +29,7 @@ protocol StatusViewDelegate: AnyObject {
|
|||
final class StatusView: UIView {
|
||||
|
||||
var statusPollTableViewHeightObservation: NSKeyValueObservation?
|
||||
var pollCountdownSubscription: AnyCancellable?
|
||||
|
||||
static let avatarImageSize = CGSize(width: 42, height: 42)
|
||||
static let avatarImageCornerRadius: CGFloat = 4
|
||||
|
@ -32,9 +38,9 @@ final class StatusView: UIView {
|
|||
static let containerStackViewSpacing: CGFloat = 10
|
||||
|
||||
weak var delegate: StatusViewDelegate?
|
||||
private var needsDrawContentOverlay = false
|
||||
|
||||
var pollTableViewDataSource: UITableViewDiffableDataSource<PollSection, PollItem>?
|
||||
var pollTableViewHeightLaoutConstraint: NSLayoutConstraint!
|
||||
var pollTableViewHeightLayoutConstraint: NSLayoutConstraint!
|
||||
|
||||
let containerStackView = UIStackView()
|
||||
let headerContainerView = UIView()
|
||||
|
@ -82,18 +88,11 @@ final class StatusView: UIView {
|
|||
view.accessibilityLabel = L10n.Common.Controls.Status.showUserProfile
|
||||
return view
|
||||
}()
|
||||
let avatarButton: UIButton = {
|
||||
let button = HighlightDimmableButton(type: .custom)
|
||||
let placeholderImage = UIImage.placeholder(size: avatarImageSize, color: .systemFill)
|
||||
.af.imageRounded(withCornerRadius: StatusView.avatarImageCornerRadius, divideRadiusByImageScale: true)
|
||||
button.setImage(placeholderImage, for: .normal)
|
||||
return button
|
||||
}()
|
||||
let avatarImageView: UIImageView = FLAnimatedImageView()
|
||||
let avatarStackedContainerButton: AvatarStackContainerButton = AvatarStackContainerButton()
|
||||
|
||||
let nameLabel: ActiveLabel = {
|
||||
let label = ActiveLabel(style: .statusName)
|
||||
label.text = "Alice"
|
||||
return label
|
||||
}()
|
||||
|
||||
|
@ -185,8 +184,8 @@ final class StatusView: UIView {
|
|||
// do not use visual effect view due to we blur text only without background
|
||||
let contentWarningOverlayView: ContentWarningOverlayView = {
|
||||
let contentWarningOverlayView = ContentWarningOverlayView()
|
||||
contentWarningOverlayView.layer.masksToBounds = false
|
||||
contentWarningOverlayView.configure(style: .blurContentImageView)
|
||||
contentWarningOverlayView.configure(style: .contentWarning)
|
||||
contentWarningOverlayView.layer.masksToBounds = true
|
||||
return contentWarningOverlayView
|
||||
}()
|
||||
|
||||
|
@ -207,7 +206,10 @@ final class StatusView: UIView {
|
|||
private let headerInfoLabelTapGestureRecognizer = UITapGestureRecognizer.singleTapGestureRecognizer
|
||||
|
||||
var isRevealing = true
|
||||
|
||||
|
||||
// TODO:
|
||||
// let linkPreview = LPLinkView()
|
||||
|
||||
override init(frame: CGRect) {
|
||||
super.init(frame: frame)
|
||||
_init()
|
||||
|
@ -218,15 +220,6 @@ final class StatusView: UIView {
|
|||
_init()
|
||||
}
|
||||
|
||||
override func traitCollectionDidChange(_ previousTraitCollection: UITraitCollection?) {
|
||||
super.traitCollectionDidChange(previousTraitCollection)
|
||||
|
||||
// update blur image when interface style changed
|
||||
if previousTraitCollection?.userInterfaceStyle != traitCollection.userInterfaceStyle {
|
||||
drawContentWarningImageView()
|
||||
}
|
||||
}
|
||||
|
||||
deinit {
|
||||
statusPollTableViewHeightObservation = nil
|
||||
}
|
||||
|
@ -249,6 +242,7 @@ extension StatusView {
|
|||
bottomAnchor.constraint(equalTo: containerStackView.bottomAnchor),
|
||||
])
|
||||
containerStackView.setContentHuggingPriority(.required - 1, for: .vertical)
|
||||
containerStackView.setContentCompressionResistancePriority(.required - 1, for: .vertical)
|
||||
|
||||
// header container: [icon | info]
|
||||
let headerContainerStackView = UIStackView()
|
||||
|
@ -281,13 +275,13 @@ extension StatusView {
|
|||
avatarView.widthAnchor.constraint(equalToConstant: StatusView.avatarImageSize.width).priority(.required - 1),
|
||||
avatarView.heightAnchor.constraint(equalToConstant: StatusView.avatarImageSize.height).priority(.required - 1),
|
||||
])
|
||||
avatarButton.translatesAutoresizingMaskIntoConstraints = false
|
||||
avatarView.addSubview(avatarButton)
|
||||
avatarImageView.translatesAutoresizingMaskIntoConstraints = false
|
||||
avatarView.addSubview(avatarImageView)
|
||||
NSLayoutConstraint.activate([
|
||||
avatarButton.topAnchor.constraint(equalTo: avatarView.topAnchor),
|
||||
avatarButton.leadingAnchor.constraint(equalTo: avatarView.leadingAnchor),
|
||||
avatarButton.trailingAnchor.constraint(equalTo: avatarView.trailingAnchor),
|
||||
avatarButton.bottomAnchor.constraint(equalTo: avatarView.bottomAnchor),
|
||||
avatarImageView.topAnchor.constraint(equalTo: avatarView.topAnchor),
|
||||
avatarImageView.leadingAnchor.constraint(equalTo: avatarView.leadingAnchor),
|
||||
avatarImageView.trailingAnchor.constraint(equalTo: avatarView.trailingAnchor),
|
||||
avatarImageView.bottomAnchor.constraint(equalTo: avatarView.bottomAnchor),
|
||||
])
|
||||
avatarStackedContainerButton.translatesAutoresizingMaskIntoConstraints = false
|
||||
avatarView.addSubview(avatarStackedContainerButton)
|
||||
|
@ -355,18 +349,25 @@ extension StatusView {
|
|||
contentWarningOverlayView.translatesAutoresizingMaskIntoConstraints = false
|
||||
containerStackView.addSubview(contentWarningOverlayView)
|
||||
NSLayoutConstraint.activate([
|
||||
statusContainerStackView.topAnchor.constraint(equalTo: contentWarningOverlayView.topAnchor, constant: StatusView.contentWarningBlurRadius).priority(.defaultHigh),
|
||||
statusContainerStackView.leftAnchor.constraint(equalTo: contentWarningOverlayView.leftAnchor, constant: StatusView.contentWarningBlurRadius).priority(.defaultHigh),
|
||||
contentWarningOverlayView.rightAnchor.constraint(equalTo: statusContainerStackView.rightAnchor, constant: StatusView.contentWarningBlurRadius).priority(.defaultHigh),
|
||||
// only layout to top and left & right then draw image to fit size
|
||||
statusContainerStackView.topAnchor.constraint(equalTo: contentWarningOverlayView.topAnchor).priority(.defaultHigh + 10),
|
||||
statusContainerStackView.leftAnchor.constraint(equalTo: contentWarningOverlayView.leftAnchor).priority(.defaultHigh),
|
||||
contentWarningOverlayView.rightAnchor.constraint(equalTo: statusContainerStackView.rightAnchor).priority(.defaultHigh),
|
||||
contentWarningOverlayView.bottomAnchor.constraint(equalTo: statusContainerStackView.bottomAnchor).priority(.defaultHigh),
|
||||
])
|
||||
// avoid overlay clip author view
|
||||
containerStackView.bringSubviewToFront(authorContainerView)
|
||||
// avoid overlay behind other views
|
||||
defer {
|
||||
containerStackView.bringSubviewToFront(authorContainerView)
|
||||
}
|
||||
|
||||
// status
|
||||
statusContainerStackView.addArrangedSubview(activeTextLabel)
|
||||
activeTextLabel.setContentCompressionResistancePriority(.required - 1, for: .vertical)
|
||||
|
||||
|
||||
// TODO:
|
||||
// link preview
|
||||
// statusContainerStackView.addArrangedSubview(linkPreview)
|
||||
// linkPreview.setContentHuggingPriority(.defaultHigh, for: .vertical)
|
||||
|
||||
// image
|
||||
statusContainerStackView.addArrangedSubview(statusMosaicImageViewContainer)
|
||||
|
||||
|
@ -382,18 +383,18 @@ extension StatusView {
|
|||
|
||||
pollTableView.translatesAutoresizingMaskIntoConstraints = false
|
||||
statusContainerStackView.addArrangedSubview(pollTableView)
|
||||
pollTableViewHeightLaoutConstraint = pollTableView.heightAnchor.constraint(equalToConstant: 44.0).priority(.required - 1)
|
||||
pollTableViewHeightLayoutConstraint = pollTableView.heightAnchor.constraint(equalToConstant: 44.0).priority(.required - 1)
|
||||
NSLayoutConstraint.activate([
|
||||
pollTableViewHeightLaoutConstraint,
|
||||
pollTableViewHeightLayoutConstraint,
|
||||
])
|
||||
|
||||
statusPollTableViewHeightObservation = pollTableView.observe(\.contentSize, options: .new, changeHandler: { [weak self] tableView, _ in
|
||||
guard let self = self else { return }
|
||||
guard self.pollTableView.contentSize.height != .zero else {
|
||||
self.pollTableViewHeightLaoutConstraint.constant = 44
|
||||
self.pollTableViewHeightLayoutConstraint.constant = 44
|
||||
return
|
||||
}
|
||||
self.pollTableViewHeightLaoutConstraint.constant = self.pollTableView.contentSize.height
|
||||
self.pollTableViewHeightLayoutConstraint.constant = self.pollTableView.contentSize.height
|
||||
})
|
||||
|
||||
statusContainerStackView.addArrangedSubview(pollStatusStackView)
|
||||
|
@ -409,7 +410,9 @@ extension StatusView {
|
|||
|
||||
// action toolbar container
|
||||
containerStackView.addArrangedSubview(actionToolbarContainer)
|
||||
containerStackView.sendSubviewToBack(actionToolbarContainer)
|
||||
actionToolbarContainer.setContentCompressionResistancePriority(.defaultLow, for: .vertical)
|
||||
actionToolbarContainer.setContentHuggingPriority(.required - 1, for: .vertical)
|
||||
|
||||
headerContainerView.isHidden = true
|
||||
statusMosaicImageViewContainer.isHidden = true
|
||||
|
@ -428,8 +431,12 @@ extension StatusView {
|
|||
headerInfoLabelTapGestureRecognizer.addTarget(self, action: #selector(StatusView.headerInfoLabelTapGestureRecognizerHandler(_:)))
|
||||
headerInfoLabel.isUserInteractionEnabled = true
|
||||
headerInfoLabel.addGestureRecognizer(headerInfoLabelTapGestureRecognizer)
|
||||
|
||||
avatarButton.addTarget(self, action: #selector(StatusView.avatarButtonDidPressed(_:)), for: .touchUpInside)
|
||||
|
||||
let avatarImageViewTapGestureRecognizer = UITapGestureRecognizer.singleTapGestureRecognizer
|
||||
avatarImageViewTapGestureRecognizer.addTarget(self, action: #selector(StatusView.avatarImageViewDidPressed(_:)))
|
||||
avatarImageView.addGestureRecognizer(avatarImageViewTapGestureRecognizer)
|
||||
avatarImageView.isUserInteractionEnabled = true
|
||||
|
||||
avatarStackedContainerButton.addTarget(self, action: #selector(StatusView.avatarStackedContainerButtonDidPressed(_:)), for: .touchUpInside)
|
||||
revealContentWarningButton.addTarget(self, action: #selector(StatusView.revealContentWarningButtonDidPressed(_:)), for: .touchUpInside)
|
||||
pollVoteButton.addTarget(self, action: #selector(StatusView.pollVoteButtonPressed(_:)), for: .touchUpInside)
|
||||
|
@ -438,51 +445,25 @@ extension StatusView {
|
|||
}
|
||||
|
||||
extension StatusView {
|
||||
|
||||
private func cleanUpContentWarning() {
|
||||
contentWarningOverlayView.blurContentImageView.image = nil
|
||||
}
|
||||
|
||||
func drawContentWarningImageView() {
|
||||
guard window != nil else {
|
||||
return
|
||||
}
|
||||
|
||||
guard needsDrawContentOverlay, statusContainerStackView.frame != .zero else {
|
||||
cleanUpContentWarning()
|
||||
return
|
||||
|
||||
func updateContentWarningDisplay(isHidden: Bool, animated: Bool, completion: (() -> Void)? = nil) {
|
||||
func updateOverlayView() {
|
||||
contentWarningOverlayView.contentOverlayView.alpha = isHidden ? 0 : 1
|
||||
contentWarningOverlayView.isUserInteractionEnabled = !isHidden
|
||||
}
|
||||
|
||||
let format = UIGraphicsImageRendererFormat()
|
||||
format.opaque = false
|
||||
let image = UIGraphicsImageRenderer(size: statusContainerStackView.frame.size, format: format).image { context in
|
||||
statusContainerStackView.drawHierarchy(in: statusContainerStackView.bounds, afterScreenUpdates: true)
|
||||
}
|
||||
.blur(radius: StatusView.contentWarningBlurRadius)
|
||||
contentWarningOverlayView.blurContentImageView.contentScaleFactor = traitCollection.displayScale
|
||||
contentWarningOverlayView.blurContentImageView.image = image
|
||||
}
|
||||
|
||||
func updateContentWarningDisplay(isHidden: Bool, animated: Bool) {
|
||||
needsDrawContentOverlay = !isHidden
|
||||
|
||||
if !isHidden {
|
||||
drawContentWarningImageView()
|
||||
}
|
||||
|
||||
contentWarningOverlayView.blurContentWarningTitleLabel.isHidden = isHidden
|
||||
|
||||
if animated {
|
||||
UIView.animate(withDuration: 0.33, delay: 0, options: .curveEaseInOut) { [weak self] in
|
||||
guard let self = self else { return }
|
||||
self.contentWarningOverlayView.alpha = isHidden ? 0 : 1
|
||||
UIView.animate(withDuration: 0.33, delay: 0, options: .curveEaseInOut) {
|
||||
updateOverlayView()
|
||||
} completion: { _ in
|
||||
// do nothing
|
||||
completion!()
|
||||
}
|
||||
} else {
|
||||
contentWarningOverlayView.alpha = isHidden ? 0 : 1
|
||||
updateOverlayView()
|
||||
completion?()
|
||||
}
|
||||
|
||||
contentWarningOverlayView.blurContentWarningTitleLabel.isHidden = isHidden
|
||||
contentWarningOverlayView.blurContentWarningLabel.isHidden = isHidden
|
||||
}
|
||||
|
||||
func updateRevealContentWarningButton(isRevealing: Bool) {
|
||||
|
@ -512,14 +493,14 @@ extension StatusView {
|
|||
delegate?.statusView(self, headerInfoLabelDidPressed: headerInfoLabel)
|
||||
}
|
||||
|
||||
@objc private func avatarButtonDidPressed(_ sender: UIButton) {
|
||||
@objc private func avatarImageViewDidPressed(_ sender: UITapGestureRecognizer) {
|
||||
os_log(.info, log: .debug, "%{public}s[%{public}ld], %{public}s", ((#file as NSString).lastPathComponent), #line, #function)
|
||||
delegate?.statusView(self, avatarButtonDidPressed: sender)
|
||||
delegate?.statusView(self, avatarImageViewDidPressed: avatarImageView)
|
||||
}
|
||||
|
||||
@objc private func avatarStackedContainerButtonDidPressed(_ sender: UIButton) {
|
||||
os_log(.info, log: .debug, "%{public}s[%{public}ld], %{public}s", ((#file as NSString).lastPathComponent), #line, #function)
|
||||
delegate?.statusView(self, avatarButtonDidPressed: sender)
|
||||
delegate?.statusView(self, avatarImageViewDidPressed: avatarStackedContainerButton.topLeadingAvatarStackedImageView)
|
||||
}
|
||||
|
||||
@objc private func revealContentWarningButtonDidPressed(_ sender: UIButton) {
|
||||
|
@ -562,9 +543,8 @@ extension StatusView: PlayerContainerViewDelegate {
|
|||
extension StatusView: AvatarConfigurableView {
|
||||
static var configurableAvatarImageSize: CGSize { return Self.avatarImageSize }
|
||||
static var configurableAvatarImageCornerRadius: CGFloat { return 4 }
|
||||
var configurableAvatarImageView: UIImageView? { return nil }
|
||||
var configurableAvatarButton: UIButton? { return avatarButton }
|
||||
var configurableVerifiedBadgeImageView: UIImageView? { nil }
|
||||
var configurableAvatarImageView: UIImageView? { avatarImageView }
|
||||
var configurableAvatarButton: UIButton? { nil }
|
||||
}
|
||||
|
||||
#if canImport(SwiftUI) && DEBUG
|
||||
|
@ -592,7 +572,7 @@ struct StatusView_Previews: PreviewProvider {
|
|||
UIViewPreview(width: 375) {
|
||||
let statusView = StatusView()
|
||||
statusView.headerContainerView.isHidden = false
|
||||
statusView.avatarButton.isHidden = true
|
||||
statusView.avatarImageView.isHidden = true
|
||||
statusView.avatarStackedContainerButton.isHidden = false
|
||||
statusView.avatarStackedContainerButton.topLeadingAvatarStackedImageView.configure(
|
||||
with: AvatarConfigurableViewConfiguration(
|
||||
|
@ -642,7 +622,6 @@ struct StatusView_Previews: PreviewProvider {
|
|||
statusView.setNeedsLayout()
|
||||
statusView.layoutIfNeeded()
|
||||
statusView.updateContentWarningDisplay(isHidden: false, animated: false)
|
||||
statusView.drawContentWarningImageView()
|
||||
let images = MosaicImageView_Previews.images
|
||||
let mosaics = statusView.statusMosaicImageViewContainer.setupImageViews(count: 4, maxSize: CGSize(width: 375, height: 162))
|
||||
for (i, mosaic) in mosaics.enumerated() {
|
||||
|
|
|
@ -7,7 +7,9 @@
|
|||
|
||||
import os.log
|
||||
import UIKit
|
||||
final class AvatarStackedImageView: UIImageView { }
|
||||
import FLAnimatedImage
|
||||
|
||||
final class AvatarStackedImageView: FLAnimatedImageView { }
|
||||
|
||||
// MARK: - AvatarConfigurableView
|
||||
extension AvatarStackedImageView: AvatarConfigurableView {
|
||||
|
|
|
@ -21,7 +21,7 @@ protocol StatusTableViewCellDelegate: AnyObject {
|
|||
var playerViewControllerDelegate: AVPlayerViewControllerDelegate? { get }
|
||||
|
||||
func statusTableViewCell(_ cell: StatusTableViewCell, statusView: StatusView, headerInfoLabelDidPressed label: UILabel)
|
||||
func statusTableViewCell(_ cell: StatusTableViewCell, statusView: StatusView, avatarButtonDidPressed button: UIButton)
|
||||
func statusTableViewCell(_ cell: StatusTableViewCell, statusView: StatusView, avatarImageViewDidPressed imageView: UIImageView)
|
||||
func statusTableViewCell(_ cell: StatusTableViewCell, statusView: StatusView, revealContentWarningButtonDidPressed button: UIButton)
|
||||
func statusTableViewCell(_ cell: StatusTableViewCell, statusView: StatusView, contentWarningOverlayViewDidPressed contentWarningOverlayView: ContentWarningOverlayView)
|
||||
func statusTableViewCell(_ cell: StatusTableViewCell, statusView: StatusView, pollVoteButtonPressed button: UIButton)
|
||||
|
@ -93,16 +93,6 @@ final class StatusTableViewCell: UITableViewCell, StatusCell {
|
|||
_init()
|
||||
}
|
||||
|
||||
override func layoutSubviews() {
|
||||
super.layoutSubviews()
|
||||
|
||||
// precondition: app is active
|
||||
guard UIApplication.shared.applicationState == .active else { return }
|
||||
DispatchQueue.main.async {
|
||||
self.statusView.drawContentWarningImageView()
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
extension StatusTableViewCell {
|
||||
|
@ -154,18 +144,7 @@ extension StatusTableViewCell {
|
|||
|
||||
resetSeparatorLineLayout()
|
||||
}
|
||||
|
||||
override func setHighlighted(_ highlighted: Bool, animated: Bool) {
|
||||
super.setHighlighted(highlighted, animated: animated)
|
||||
|
||||
resetContentOverlayBlurImageBackgroundColor(selected: highlighted)
|
||||
}
|
||||
|
||||
override func setSelected(_ selected: Bool, animated: Bool) {
|
||||
super.setSelected(selected, animated: animated)
|
||||
|
||||
resetContentOverlayBlurImageBackgroundColor(selected: selected)
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
@ -199,11 +178,7 @@ extension StatusTableViewCell {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
private func resetContentOverlayBlurImageBackgroundColor(selected: Bool) {
|
||||
let imageViewBackgroundColor: UIColor? = selected ? selectedBackgroundView?.backgroundColor : backgroundColor
|
||||
statusView.contentWarningOverlayView.blurContentImageView.backgroundColor = imageViewBackgroundColor
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// MARK: - MosaicImageViewContainerPresentable
|
||||
|
@ -301,9 +276,9 @@ extension StatusTableViewCell: StatusViewDelegate {
|
|||
func statusView(_ statusView: StatusView, headerInfoLabelDidPressed label: UILabel) {
|
||||
delegate?.statusTableViewCell(self, statusView: statusView, headerInfoLabelDidPressed: label)
|
||||
}
|
||||
|
||||
func statusView(_ statusView: StatusView, avatarButtonDidPressed button: UIButton) {
|
||||
delegate?.statusTableViewCell(self, statusView: statusView, avatarButtonDidPressed: button)
|
||||
|
||||
func statusView(_ statusView: StatusView, avatarImageViewDidPressed imageView: UIImageView) {
|
||||
delegate?.statusTableViewCell(self, statusView: statusView, avatarImageViewDidPressed: imageView)
|
||||
}
|
||||
|
||||
func statusView(_ statusView: StatusView, revealContentWarningButtonDidPressed button: UIButton) {
|
||||
|
|
|
@ -10,10 +10,6 @@ import UIKit
|
|||
import UserNotifications
|
||||
import AppShared
|
||||
|
||||
#if DEBUG
|
||||
import GDPerformanceView_Swift
|
||||
#endif
|
||||
|
||||
#if ASDK
|
||||
import AsyncDisplayKit
|
||||
#endif
|
||||
|
|
|
@ -9,6 +9,10 @@ import UIKit
|
|||
import Combine
|
||||
import CoreDataStack
|
||||
|
||||
#if DEBUG
|
||||
import FPSIndicator
|
||||
#endif
|
||||
|
||||
class SceneDelegate: UIResponder, UIWindowSceneDelegate {
|
||||
|
||||
var observations = Set<NSKeyValueObservation>()
|
||||
|
@ -16,6 +20,11 @@ class SceneDelegate: UIResponder, UIWindowSceneDelegate {
|
|||
var window: UIWindow?
|
||||
var coordinator: SceneCoordinator?
|
||||
|
||||
#if DEBUG
|
||||
var fpsIndicator: FPSIndicator?
|
||||
#endif
|
||||
|
||||
|
||||
func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {
|
||||
guard let windowScene = scene as? UIWindowScene else { return }
|
||||
|
||||
|
@ -38,6 +47,10 @@ class SceneDelegate: UIResponder, UIWindowSceneDelegate {
|
|||
self.window?.overrideUserInterfaceStyle = defaults.customUserInterfaceStyle
|
||||
}
|
||||
.store(in: &observations)
|
||||
|
||||
#if DEBUG
|
||||
fpsIndicator = FPSIndicator(windowScene: windowScene)
|
||||
#endif
|
||||
}
|
||||
|
||||
func sceneDidDisconnect(_ scene: UIScene) {
|
||||
|
|
1
Podfile
1
Podfile
|
@ -17,7 +17,6 @@ target 'Mastodon' do
|
|||
|
||||
# DEBUG
|
||||
pod 'FLEX', '~> 4.4.0', :configurations => ['Debug', 'ASDK - Debug']
|
||||
pod 'GDPerformanceView-Swift', '~> 2.1.1', :configurations => ['Debug', 'ASDK - Debug']
|
||||
|
||||
target 'MastodonTests' do
|
||||
inherit! :search_paths
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
PODS:
|
||||
- DateToolsSwift (5.0.0)
|
||||
- FLEX (4.4.1)
|
||||
- GDPerformanceView-Swift (2.1.1)
|
||||
- Kanna (5.2.4)
|
||||
- Keys (1.0.1)
|
||||
- PINCache (3.0.3):
|
||||
|
@ -45,7 +44,6 @@ PODS:
|
|||
DEPENDENCIES:
|
||||
- DateToolsSwift (~> 5.0.0)
|
||||
- FLEX (~> 4.4.0)
|
||||
- GDPerformanceView-Swift (~> 2.1.1)
|
||||
- Kanna (~> 5.2.2)
|
||||
- Keys (from `Pods/CocoaPodsKeys`)
|
||||
- SwiftGen (~> 6.4.0)
|
||||
|
@ -56,7 +54,6 @@ SPEC REPOS:
|
|||
trunk:
|
||||
- DateToolsSwift
|
||||
- FLEX
|
||||
- GDPerformanceView-Swift
|
||||
- Kanna
|
||||
- PINCache
|
||||
- PINOperation
|
||||
|
@ -72,7 +69,6 @@ EXTERNAL SOURCES:
|
|||
SPEC CHECKSUMS:
|
||||
DateToolsSwift: 4207ada6ad615d8dc076323d27037c94916dbfa6
|
||||
FLEX: 7ca2c8cd3a435ff501ff6d2f2141e9bdc934eaab
|
||||
GDPerformanceView-Swift: 22d964fe40b19e3d914dba2586237d064de8fd77
|
||||
Kanna: b9d00d7c11428308c7f95e1f1f84b8205f567a8f
|
||||
Keys: a576f4c9c1c641ca913a959a9c62ed3f215a8de9
|
||||
PINCache: 7a8fc1a691173d21dbddbf86cd515de6efa55086
|
||||
|
@ -82,6 +78,6 @@ SPEC CHECKSUMS:
|
|||
Texture: 2f109e937850d94d1d07232041c9c7313ccddb81
|
||||
"UITextField+Shake": 298ac5a0f239d731bdab999b19b628c956ca0ac3
|
||||
|
||||
PODFILE CHECKSUM: a0d0a385a2888802244e7841940a7d5a55315e1f
|
||||
PODFILE CHECKSUM: f2f99b5771c5c36ef69d13999b88cea5b0e8bfe1
|
||||
|
||||
COCOAPODS: 1.10.1
|
||||
|
|
Loading…
Reference in New Issue