diff --git a/Mastodon.xcodeproj/project.pbxproj b/Mastodon.xcodeproj/project.pbxproj index 77344fa8d..862b47e6d 100644 --- a/Mastodon.xcodeproj/project.pbxproj +++ b/Mastodon.xcodeproj/project.pbxproj @@ -266,6 +266,7 @@ DB5086BE25CC0D9900C2C187 /* SplashPreference.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB5086BD25CC0D9900C2C187 /* SplashPreference.swift */; }; DB51D172262832380062B7A1 /* BlurHashDecode.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB51D170262832380062B7A1 /* BlurHashDecode.swift */; }; DB51D173262832380062B7A1 /* BlurHashEncode.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB51D171262832380062B7A1 /* BlurHashEncode.swift */; }; + DB52D33A26839DD800D43133 /* ImageTask.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB52D33926839DD800D43133 /* ImageTask.swift */; }; DB55D33025FB630A0002F825 /* TwitterTextEditor+String.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB55D32F25FB630A0002F825 /* TwitterTextEditor+String.swift */; }; DB59F0FE25EF5D96001F1DAB /* StatusProvider+UITableViewDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB59F0FD25EF5D96001F1DAB /* StatusProvider+UITableViewDelegate.swift */; }; DB59F10425EF5EBC001F1DAB /* TableViewCellHeightCacheableContainer.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB59F10325EF5EBC001F1DAB /* TableViewCellHeightCacheableContainer.swift */; }; @@ -883,6 +884,7 @@ DB5086BD25CC0D9900C2C187 /* SplashPreference.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SplashPreference.swift; sourceTree = ""; }; DB51D170262832380062B7A1 /* BlurHashDecode.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BlurHashDecode.swift; sourceTree = ""; }; DB51D171262832380062B7A1 /* BlurHashEncode.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BlurHashEncode.swift; sourceTree = ""; }; + DB52D33926839DD800D43133 /* ImageTask.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ImageTask.swift; sourceTree = ""; }; DB55D32F25FB630A0002F825 /* TwitterTextEditor+String.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "TwitterTextEditor+String.swift"; sourceTree = ""; }; DB59F0FD25EF5D96001F1DAB /* StatusProvider+UITableViewDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "StatusProvider+UITableViewDelegate.swift"; sourceTree = ""; }; DB59F10325EF5EBC001F1DAB /* TableViewCellHeightCacheableContainer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TableViewCellHeightCacheableContainer.swift; sourceTree = ""; }; @@ -2267,6 +2269,7 @@ DB6D1B23263684C600ACB481 /* UserDefaults.swift */, DB97131E2666078B00BD1E90 /* Date.swift */, DBAC6489267DC355007FE9FD /* NSDiffableDataSourceSnapshot.swift */, + DB52D33926839DD800D43133 /* ImageTask.swift */, ); path = Extension; sourceTree = ""; @@ -3260,6 +3263,7 @@ DBCBCC012680AF2A000F5B51 /* AsyncHomeTimelineViewModel+Diffable.swift in Sources */, DBCC3B36261440BA0045B23D /* UINavigationController.swift in Sources */, DBB525852612D6DD002F1F29 /* ProfileStatusDashboardMeterView.swift in Sources */, + DB52D33A26839DD800D43133 /* ImageTask.swift in Sources */, 2D84350525FF858100EECE90 /* UIScrollView.swift in Sources */, DB49A61F25FF32AA00B98345 /* EmojiService+CustomEmojiViewModel.swift in Sources */, 2D76316B25C14D4C00929FB9 /* PublicTimelineViewModel.swift in Sources */, @@ -3796,7 +3800,7 @@ CLANG_ENABLE_MODULES = YES; CODE_SIGN_ENTITLEMENTS = Mastodon/Mastodon.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 20; + CURRENT_PROJECT_VERSION = 21; DEVELOPMENT_ASSET_PATHS = "Mastodon/Resources/Preview\\ Assets.xcassets"; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = Mastodon/Info.plist; @@ -3804,7 +3808,7 @@ "$(inherited)", "@executable_path/Frameworks", ); - MARKETING_VERSION = 0.7.4; + MARKETING_VERSION = 0.7.5; PRODUCT_BUNDLE_IDENTIFIER = org.joinmastodon.app; PRODUCT_NAME = "$(TARGET_NAME)"; PROVISIONING_PROFILE_SPECIFIER = ""; @@ -3823,7 +3827,7 @@ CLANG_ENABLE_MODULES = YES; CODE_SIGN_ENTITLEMENTS = Mastodon/Mastodon.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 20; + CURRENT_PROJECT_VERSION = 21; DEVELOPMENT_ASSET_PATHS = "Mastodon/Resources/Preview\\ Assets.xcassets"; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = Mastodon/Info.plist; @@ -3831,7 +3835,7 @@ "$(inherited)", "@executable_path/Frameworks", ); - MARKETING_VERSION = 0.7.4; + MARKETING_VERSION = 0.7.5; PRODUCT_BUNDLE_IDENTIFIER = org.joinmastodon.app; PRODUCT_NAME = "$(TARGET_NAME)"; PROVISIONING_PROFILE_SPECIFIER = ""; @@ -4151,7 +4155,7 @@ CLANG_ENABLE_MODULES = YES; CODE_SIGN_ENTITLEMENTS = Mastodon/Mastodon.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 20; + CURRENT_PROJECT_VERSION = 21; DEVELOPMENT_ASSET_PATHS = "Mastodon/Resources/Preview\\ Assets.xcassets"; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = Mastodon/Info.plist; @@ -4159,7 +4163,7 @@ "$(inherited)", "@executable_path/Frameworks", ); - MARKETING_VERSION = 0.7.4; + MARKETING_VERSION = 0.7.5; PRODUCT_BUNDLE_IDENTIFIER = org.joinmastodon.app; PRODUCT_NAME = "$(TARGET_NAME)"; PROVISIONING_PROFILE_SPECIFIER = ""; @@ -4265,7 +4269,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = NotificationService/NotificationService.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 20; + CURRENT_PROJECT_VERSION = 21; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = NotificationService/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -4273,7 +4277,7 @@ "@executable_path/Frameworks", "@executable_path/../../Frameworks", ); - MARKETING_VERSION = 0.7.4; + MARKETING_VERSION = 0.7.5; PRODUCT_BUNDLE_IDENTIFIER = org.joinmastodon.app.NotificationService; PRODUCT_NAME = "$(TARGET_NAME)"; SKIP_INSTALL = YES; @@ -4384,7 +4388,7 @@ CLANG_ENABLE_MODULES = YES; CODE_SIGN_ENTITLEMENTS = Mastodon/Mastodon.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 20; + CURRENT_PROJECT_VERSION = 21; DEVELOPMENT_ASSET_PATHS = "Mastodon/Resources/Preview\\ Assets.xcassets"; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = Mastodon/Info.plist; @@ -4392,7 +4396,7 @@ "$(inherited)", "@executable_path/Frameworks", ); - MARKETING_VERSION = 0.7.4; + MARKETING_VERSION = 0.7.5; PRODUCT_BUNDLE_IDENTIFIER = org.joinmastodon.app; PRODUCT_NAME = "$(TARGET_NAME)"; PROVISIONING_PROFILE_SPECIFIER = ""; @@ -4498,7 +4502,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = NotificationService/NotificationService.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 20; + CURRENT_PROJECT_VERSION = 21; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = NotificationService/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -4506,7 +4510,7 @@ "@executable_path/Frameworks", "@executable_path/../../Frameworks", ); - MARKETING_VERSION = 0.7.4; + MARKETING_VERSION = 0.7.5; PRODUCT_BUNDLE_IDENTIFIER = org.joinmastodon.app.NotificationService; PRODUCT_NAME = "$(TARGET_NAME)"; SKIP_INSTALL = YES; @@ -4552,7 +4556,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = NotificationService/NotificationService.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 20; + CURRENT_PROJECT_VERSION = 21; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = NotificationService/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -4560,7 +4564,7 @@ "@executable_path/Frameworks", "@executable_path/../../Frameworks", ); - MARKETING_VERSION = 0.7.4; + MARKETING_VERSION = 0.7.5; PRODUCT_BUNDLE_IDENTIFIER = org.joinmastodon.app.NotificationService; PRODUCT_NAME = "$(TARGET_NAME)"; SKIP_INSTALL = YES; @@ -4575,7 +4579,7 @@ buildSettings = { CODE_SIGN_ENTITLEMENTS = NotificationService/NotificationService.entitlements; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 20; + CURRENT_PROJECT_VERSION = 21; DEVELOPMENT_TEAM = 5Z4GVSS33P; INFOPLIST_FILE = NotificationService/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( @@ -4583,7 +4587,7 @@ "@executable_path/Frameworks", "@executable_path/../../Frameworks", ); - MARKETING_VERSION = 0.7.4; + MARKETING_VERSION = 0.7.5; PRODUCT_BUNDLE_IDENTIFIER = org.joinmastodon.app.NotificationService; PRODUCT_NAME = "$(TARGET_NAME)"; SKIP_INSTALL = YES; diff --git a/Mastodon.xcodeproj/xcuserdata/mainasuk.xcuserdatad/xcschemes/xcschememanagement.plist b/Mastodon.xcodeproj/xcuserdata/mainasuk.xcuserdatad/xcschemes/xcschememanagement.plist index fd0e14aac..f1135b12e 100644 --- a/Mastodon.xcodeproj/xcuserdata/mainasuk.xcuserdatad/xcschemes/xcschememanagement.plist +++ b/Mastodon.xcodeproj/xcuserdata/mainasuk.xcuserdatad/xcschemes/xcschememanagement.plist @@ -12,22 +12,22 @@ CoreDataStack.xcscheme_^#shared#^_ orderHint - 21 + 20 Mastodon - ASDK.xcscheme_^#shared#^_ orderHint - 1 + 2 Mastodon - RTL.xcscheme_^#shared#^_ orderHint - 1 + 3 Mastodon - Release.xcscheme_^#shared#^_ orderHint - 0 + 1 Mastodon.xcscheme_^#shared#^_ @@ -37,7 +37,7 @@ NotificationService.xcscheme_^#shared#^_ orderHint - 2 + 21 SuppressBuildableAutocreation diff --git a/Mastodon/Diffiable/Section/StatusSection.swift b/Mastodon/Diffiable/Section/StatusSection.swift index acf14ca83..43bc791c0 100644 --- a/Mastodon/Diffiable/Section/StatusSection.swift +++ b/Mastodon/Diffiable/Section/StatusSection.swift @@ -685,7 +685,9 @@ extension StatusSection { case .success: statusItemAttribute.isImageLoaded.value = true } - } + }? + .store(in: &cell.statusView.statusMosaicImageViewContainer.imageTasks) + imageView.accessibilityLabel = meta.altText diff --git a/Mastodon/Extension/ImageTask.swift b/Mastodon/Extension/ImageTask.swift new file mode 100644 index 000000000..86be32d15 --- /dev/null +++ b/Mastodon/Extension/ImageTask.swift @@ -0,0 +1,15 @@ +// +// ImageTask.swift +// Mastodon +// +// Created by Cirno MainasuK on 2021-6-24. +// + +import Foundation +import Nuke + +extension ImageTask { + func store(in set: inout Set) { + set.insert(self) + } +} diff --git a/Mastodon/Resources/Assets.xcassets/Colors/ContentWarningOverlay/background.colorset/Contents.json b/Mastodon/Resources/Assets.xcassets/Colors/ContentWarningOverlay/background.colorset/Contents.json index 87b9a1350..009d3156b 100644 --- a/Mastodon/Resources/Assets.xcassets/Colors/ContentWarningOverlay/background.colorset/Contents.json +++ b/Mastodon/Resources/Assets.xcassets/Colors/ContentWarningOverlay/background.colorset/Contents.json @@ -23,9 +23,9 @@ "color-space" : "srgb", "components" : { "alpha" : "1.000", - "blue" : "0.922", - "green" : "0.898", - "red" : "0.867" + "blue" : "0x43", + "green" : "0x35", + "red" : "0x31" } }, "idiom" : "universal" diff --git a/Mastodon/Scene/Profile/Timeline/UserTimelineViewModel.swift b/Mastodon/Scene/Profile/Timeline/UserTimelineViewModel.swift index 03e5e627d..c282e6719 100644 --- a/Mastodon/Scene/Profile/Timeline/UserTimelineViewModel.swift +++ b/Mastodon/Scene/Profile/Timeline/UserTimelineViewModel.swift @@ -62,10 +62,10 @@ final class UserTimelineViewModel { .store(in: &disposeBag) Publishers.CombineLatest4( - statusFetchedResultsController.objectIDs.eraseToAnyPublisher(), - isBlocking.eraseToAnyPublisher(), - isBlockedBy.eraseToAnyPublisher(), - isSuspended.eraseToAnyPublisher() + statusFetchedResultsController.objectIDs.removeDuplicates(), + isBlocking, + isBlockedBy, + isSuspended ) .receive(on: DispatchQueue.main) .debounce(for: .milliseconds(300), scheduler: DispatchQueue.main) @@ -76,12 +76,12 @@ final class UserTimelineViewModel { var items: [Item] = [] var snapshot = NSDiffableDataSourceSnapshot() snapshot.appendSections([.main]) - + defer { // not animate when empty items fix loader first appear layout issue diffableDataSource.apply(snapshot, animatingDifferences: !items.isEmpty) } - + guard !isBlocking else { snapshot.appendItems([Item.emptyStateHeader(attribute: Item.EmptyStateHeaderAttribute(reason: .blocking))], toSection: .main) return @@ -97,14 +97,14 @@ final class UserTimelineViewModel { snapshot.appendItems([Item.emptyStateHeader(attribute: Item.EmptyStateHeaderAttribute(reason: .suspended(name: name)))], toSection: .main) return } - + var oldSnapshotAttributeDict: [NSManagedObjectID : Item.StatusAttribute] = [:] let oldSnapshot = diffableDataSource.snapshot() for item in oldSnapshot.itemIdentifiers { guard case let .status(objectID, attribute) = item else { continue } oldSnapshotAttributeDict[objectID] = attribute } - + for objectID in objectIDs { let attribute = oldSnapshotAttributeDict[objectID] ?? Item.StatusAttribute() items.append(.status(objectID: objectID, attribute: attribute)) diff --git a/Mastodon/Scene/Share/View/Container/MosaicImageViewContainer.swift b/Mastodon/Scene/Share/View/Container/MosaicImageViewContainer.swift index ecd375087..d60d40fe7 100644 --- a/Mastodon/Scene/Share/View/Container/MosaicImageViewContainer.swift +++ b/Mastodon/Scene/Share/View/Container/MosaicImageViewContainer.swift @@ -8,6 +8,7 @@ import os.log import func AVFoundation.AVMakeRect import UIKit +import Nuke protocol MosaicImageViewContainerPresentable: AnyObject { var mosaicImageViewContainer: MosaicImageViewContainer { get } @@ -22,6 +23,8 @@ protocol MosaicImageViewContainerDelegate: AnyObject { final class MosaicImageViewContainer: UIView { weak var delegate: MosaicImageViewContainerDelegate? + + var imageTasks = Set() let container = UIStackView() private(set) lazy var imageViews: [UIImageView] = { @@ -93,6 +96,9 @@ extension MosaicImageViewContainer { extension MosaicImageViewContainer { func reset() { + imageTasks.forEach { $0?.cancel() } + imageTasks.removeAll() + container.arrangedSubviews.forEach { subview in container.removeArrangedSubview(subview) subview.removeFromSuperview()