diff --git a/CoreDataStack/CoreData.xcdatamodeld/CoreData.xcdatamodel/contents b/CoreDataStack/CoreData.xcdatamodeld/CoreData.xcdatamodel/contents
index 5bc61b648..14c7dc2ec 100644
--- a/CoreDataStack/CoreData.xcdatamodeld/CoreData.xcdatamodel/contents
+++ b/CoreDataStack/CoreData.xcdatamodeld/CoreData.xcdatamodel/contents
@@ -85,7 +85,7 @@
-
+
@@ -132,6 +132,7 @@
+
@@ -181,8 +182,10 @@
+
+
@@ -281,12 +284,12 @@
-
+
-
+
diff --git a/CoreDataStack/Entity/MastodonUser.swift b/CoreDataStack/Entity/MastodonUser.swift
index 6b27b4cd8..b7a101152 100644
--- a/CoreDataStack/Entity/MastodonUser.swift
+++ b/CoreDataStack/Entity/MastodonUser.swift
@@ -47,6 +47,7 @@ final public class MastodonUser: NSManagedObject {
// one-to-many relationship
@NSManaged public private(set) var statuses: Set?
+ @NSManaged public private(set) var notifications: Set?
// many-to-many relationship
@NSManaged public private(set) var favourite: Set?
diff --git a/CoreDataStack/Entity/SearchHistory.swift b/CoreDataStack/Entity/SearchHistory.swift
index da6d98bc2..3894d1c1b 100644
--- a/CoreDataStack/Entity/SearchHistory.swift
+++ b/CoreDataStack/Entity/SearchHistory.swift
@@ -11,6 +11,8 @@ import CoreData
public final class SearchHistory: NSManagedObject {
public typealias ID = UUID
@NSManaged public private(set) var identifier: ID
+ @NSManaged public private(set) var domain: String
+ @NSManaged public private(set) var userID: MastodonUser.ID
@NSManaged public private(set) var createAt: Date
@NSManaged public private(set) var updatedAt: Date
@@ -37,9 +39,12 @@ extension SearchHistory {
@discardableResult
public static func insert(
into context: NSManagedObjectContext,
+ property: Property,
account: MastodonUser
) -> SearchHistory {
let searchHistory: SearchHistory = context.insertObject()
+ searchHistory.domain = property.domain
+ searchHistory.userID = property.userID
searchHistory.account = account
return searchHistory
}
@@ -47,9 +52,12 @@ extension SearchHistory {
@discardableResult
public static func insert(
into context: NSManagedObjectContext,
+ property: Property,
hashtag: Tag
) -> SearchHistory {
let searchHistory: SearchHistory = context.insertObject()
+ searchHistory.domain = property.domain
+ searchHistory.userID = property.userID
searchHistory.hashtag = hashtag
return searchHistory
}
@@ -57,22 +65,54 @@ extension SearchHistory {
@discardableResult
public static func insert(
into context: NSManagedObjectContext,
+ property: Property,
status: Status
) -> SearchHistory {
let searchHistory: SearchHistory = context.insertObject()
+ searchHistory.domain = property.domain
+ searchHistory.userID = property.userID
searchHistory.status = status
return searchHistory
}
}
-public extension SearchHistory {
- func update(updatedAt: Date) {
+extension SearchHistory {
+ public func update(updatedAt: Date) {
setValue(updatedAt, forKey: #keyPath(SearchHistory.updatedAt))
}
}
+extension SearchHistory {
+ public struct Property {
+ public let domain: String
+ public let userID: MastodonUser.ID
+
+ public init(domain: String, userID: MastodonUser.ID) {
+ self.domain = domain
+ self.userID = userID
+ }
+ }
+}
+
extension SearchHistory: Managed {
public static var defaultSortDescriptors: [NSSortDescriptor] {
return [NSSortDescriptor(keyPath: \SearchHistory.updatedAt, ascending: false)]
}
}
+
+extension SearchHistory {
+ static func predicate(domain: String) -> NSPredicate {
+ return NSPredicate(format: "%K == %@", #keyPath(SearchHistory.domain), domain)
+ }
+
+ static func predicate(userID: String) -> NSPredicate {
+ return NSPredicate(format: "%K == %@", #keyPath(SearchHistory.userID), userID)
+ }
+
+ public static func predicate(domain: String, userID: String) -> NSPredicate {
+ return NSCompoundPredicate(andPredicateWithSubpredicates: [
+ predicate(domain: domain),
+ predicate(userID: userID)
+ ])
+ }
+}
diff --git a/Mastodon.xcodeproj/project.pbxproj b/Mastodon.xcodeproj/project.pbxproj
index bbe751571..fa8b06c3d 100644
--- a/Mastodon.xcodeproj/project.pbxproj
+++ b/Mastodon.xcodeproj/project.pbxproj
@@ -4308,7 +4308,7 @@
CLANG_ENABLE_MODULES = YES;
CODE_SIGN_ENTITLEMENTS = Mastodon/Mastodon.entitlements;
CODE_SIGN_STYLE = Automatic;
- CURRENT_PROJECT_VERSION = 41;
+ CURRENT_PROJECT_VERSION = 43;
DEVELOPMENT_ASSET_PATHS = "Mastodon/Resources/Preview\\ Assets.xcassets";
DEVELOPMENT_TEAM = 5Z4GVSS33P;
INFOPLIST_FILE = Mastodon/Info.plist;
@@ -4316,7 +4316,7 @@
"$(inherited)",
"@executable_path/Frameworks",
);
- MARKETING_VERSION = 0.9.1;
+ MARKETING_VERSION = 0.9.2;
PRODUCT_BUNDLE_IDENTIFIER = org.joinmastodon.app;
PRODUCT_NAME = "$(TARGET_NAME)";
PROVISIONING_PROFILE_SPECIFIER = "";
@@ -4335,7 +4335,7 @@
CLANG_ENABLE_MODULES = YES;
CODE_SIGN_ENTITLEMENTS = Mastodon/Mastodon.entitlements;
CODE_SIGN_STYLE = Automatic;
- CURRENT_PROJECT_VERSION = 41;
+ CURRENT_PROJECT_VERSION = 43;
DEVELOPMENT_ASSET_PATHS = "Mastodon/Resources/Preview\\ Assets.xcassets";
DEVELOPMENT_TEAM = 5Z4GVSS33P;
INFOPLIST_FILE = Mastodon/Info.plist;
@@ -4343,7 +4343,7 @@
"$(inherited)",
"@executable_path/Frameworks",
);
- MARKETING_VERSION = 0.9.1;
+ MARKETING_VERSION = 0.9.2;
PRODUCT_BUNDLE_IDENTIFIER = org.joinmastodon.app;
PRODUCT_NAME = "$(TARGET_NAME)";
PROVISIONING_PROFILE_SPECIFIER = "";
@@ -4600,7 +4600,7 @@
buildSettings = {
CODE_SIGN_ENTITLEMENTS = ShareActionExtension/ShareActionExtension.entitlements;
CODE_SIGN_STYLE = Automatic;
- CURRENT_PROJECT_VERSION = 41;
+ CURRENT_PROJECT_VERSION = 43;
DEVELOPMENT_TEAM = 5Z4GVSS33P;
INFOPLIST_FILE = ShareActionExtension/Info.plist;
LD_RUNPATH_SEARCH_PATHS = (
@@ -4608,13 +4608,13 @@
"@executable_path/Frameworks",
"@executable_path/../../Frameworks",
);
- MARKETING_VERSION = 0.9.1;
+ MARKETING_VERSION = 0.9.2;
PRODUCT_BUNDLE_IDENTIFIER = org.joinmastodon.app.ShareActionExtension;
PRODUCT_NAME = "$(TARGET_NAME)";
SKIP_INSTALL = YES;
SWIFT_ACTIVE_COMPILATION_CONDITIONS = "APP_EXTENSION $(inherited)";
SWIFT_VERSION = 5.0;
- TARGETED_DEVICE_FAMILY = "1,2";
+ TARGETED_DEVICE_FAMILY = 1;
};
name = Debug;
};
@@ -4624,7 +4624,7 @@
buildSettings = {
CODE_SIGN_ENTITLEMENTS = ShareActionExtension/ShareActionExtension.entitlements;
CODE_SIGN_STYLE = Automatic;
- CURRENT_PROJECT_VERSION = 41;
+ CURRENT_PROJECT_VERSION = 43;
DEVELOPMENT_TEAM = 5Z4GVSS33P;
INFOPLIST_FILE = ShareActionExtension/Info.plist;
LD_RUNPATH_SEARCH_PATHS = (
@@ -4632,13 +4632,13 @@
"@executable_path/Frameworks",
"@executable_path/../../Frameworks",
);
- MARKETING_VERSION = 0.9.1;
+ MARKETING_VERSION = 0.9.2;
PRODUCT_BUNDLE_IDENTIFIER = org.joinmastodon.app.ShareActionExtension;
PRODUCT_NAME = "$(TARGET_NAME)";
SKIP_INSTALL = YES;
SWIFT_ACTIVE_COMPILATION_CONDITIONS = "APP_EXTENSION $(inherited)";
SWIFT_VERSION = 5.0;
- TARGETED_DEVICE_FAMILY = "1,2";
+ TARGETED_DEVICE_FAMILY = 1;
};
name = "ASDK - Debug";
};
@@ -4648,7 +4648,7 @@
buildSettings = {
CODE_SIGN_ENTITLEMENTS = ShareActionExtension/ShareActionExtension.entitlements;
CODE_SIGN_STYLE = Automatic;
- CURRENT_PROJECT_VERSION = 41;
+ CURRENT_PROJECT_VERSION = 43;
DEVELOPMENT_TEAM = 5Z4GVSS33P;
INFOPLIST_FILE = ShareActionExtension/Info.plist;
LD_RUNPATH_SEARCH_PATHS = (
@@ -4656,13 +4656,13 @@
"@executable_path/Frameworks",
"@executable_path/../../Frameworks",
);
- MARKETING_VERSION = 0.9.1;
+ MARKETING_VERSION = 0.9.2;
PRODUCT_BUNDLE_IDENTIFIER = org.joinmastodon.app.ShareActionExtension;
PRODUCT_NAME = "$(TARGET_NAME)";
SKIP_INSTALL = YES;
SWIFT_ACTIVE_COMPILATION_CONDITIONS = "APP_EXTENSION $(inherited)";
SWIFT_VERSION = 5.0;
- TARGETED_DEVICE_FAMILY = "1,2";
+ TARGETED_DEVICE_FAMILY = 1;
};
name = "ASDK - Release";
};
@@ -4672,7 +4672,7 @@
buildSettings = {
CODE_SIGN_ENTITLEMENTS = ShareActionExtension/ShareActionExtension.entitlements;
CODE_SIGN_STYLE = Automatic;
- CURRENT_PROJECT_VERSION = 41;
+ CURRENT_PROJECT_VERSION = 43;
DEVELOPMENT_TEAM = 5Z4GVSS33P;
INFOPLIST_FILE = ShareActionExtension/Info.plist;
LD_RUNPATH_SEARCH_PATHS = (
@@ -4680,13 +4680,13 @@
"@executable_path/Frameworks",
"@executable_path/../../Frameworks",
);
- MARKETING_VERSION = 0.9.1;
+ MARKETING_VERSION = 0.9.2;
PRODUCT_BUNDLE_IDENTIFIER = org.joinmastodon.app.ShareActionExtension;
PRODUCT_NAME = "$(TARGET_NAME)";
SKIP_INSTALL = YES;
SWIFT_ACTIVE_COMPILATION_CONDITIONS = "APP_EXTENSION $(inherited)";
SWIFT_VERSION = 5.0;
- TARGETED_DEVICE_FAMILY = "1,2";
+ TARGETED_DEVICE_FAMILY = 1;
};
name = Release;
};
@@ -4761,7 +4761,7 @@
CLANG_ENABLE_MODULES = YES;
CODE_SIGN_ENTITLEMENTS = Mastodon/Mastodon.entitlements;
CODE_SIGN_STYLE = Automatic;
- CURRENT_PROJECT_VERSION = 41;
+ CURRENT_PROJECT_VERSION = 43;
DEVELOPMENT_ASSET_PATHS = "Mastodon/Resources/Preview\\ Assets.xcassets";
DEVELOPMENT_TEAM = 5Z4GVSS33P;
INFOPLIST_FILE = Mastodon/Info.plist;
@@ -4769,7 +4769,7 @@
"$(inherited)",
"@executable_path/Frameworks",
);
- MARKETING_VERSION = 0.9.1;
+ MARKETING_VERSION = 0.9.2;
PRODUCT_BUNDLE_IDENTIFIER = org.joinmastodon.app;
PRODUCT_NAME = "$(TARGET_NAME)";
PROVISIONING_PROFILE_SPECIFIER = "";
@@ -4876,7 +4876,7 @@
buildSettings = {
CODE_SIGN_ENTITLEMENTS = NotificationService/NotificationService.entitlements;
CODE_SIGN_STYLE = Automatic;
- CURRENT_PROJECT_VERSION = 41;
+ CURRENT_PROJECT_VERSION = 43;
DEVELOPMENT_TEAM = 5Z4GVSS33P;
INFOPLIST_FILE = NotificationService/Info.plist;
LD_RUNPATH_SEARCH_PATHS = (
@@ -4884,7 +4884,7 @@
"@executable_path/Frameworks",
"@executable_path/../../Frameworks",
);
- MARKETING_VERSION = 0.9.1;
+ MARKETING_VERSION = 0.9.2;
PRODUCT_BUNDLE_IDENTIFIER = org.joinmastodon.app.NotificationService;
PRODUCT_NAME = "$(TARGET_NAME)";
SKIP_INSTALL = YES;
@@ -4995,7 +4995,7 @@
CLANG_ENABLE_MODULES = YES;
CODE_SIGN_ENTITLEMENTS = Mastodon/Mastodon.entitlements;
CODE_SIGN_STYLE = Automatic;
- CURRENT_PROJECT_VERSION = 41;
+ CURRENT_PROJECT_VERSION = 43;
DEVELOPMENT_ASSET_PATHS = "Mastodon/Resources/Preview\\ Assets.xcassets";
DEVELOPMENT_TEAM = 5Z4GVSS33P;
INFOPLIST_FILE = Mastodon/Info.plist;
@@ -5003,7 +5003,7 @@
"$(inherited)",
"@executable_path/Frameworks",
);
- MARKETING_VERSION = 0.9.1;
+ MARKETING_VERSION = 0.9.2;
PRODUCT_BUNDLE_IDENTIFIER = org.joinmastodon.app;
PRODUCT_NAME = "$(TARGET_NAME)";
PROVISIONING_PROFILE_SPECIFIER = "";
@@ -5110,7 +5110,7 @@
buildSettings = {
CODE_SIGN_ENTITLEMENTS = NotificationService/NotificationService.entitlements;
CODE_SIGN_STYLE = Automatic;
- CURRENT_PROJECT_VERSION = 41;
+ CURRENT_PROJECT_VERSION = 43;
DEVELOPMENT_TEAM = 5Z4GVSS33P;
INFOPLIST_FILE = NotificationService/Info.plist;
LD_RUNPATH_SEARCH_PATHS = (
@@ -5118,7 +5118,7 @@
"@executable_path/Frameworks",
"@executable_path/../../Frameworks",
);
- MARKETING_VERSION = 0.9.1;
+ MARKETING_VERSION = 0.9.2;
PRODUCT_BUNDLE_IDENTIFIER = org.joinmastodon.app.NotificationService;
PRODUCT_NAME = "$(TARGET_NAME)";
SKIP_INSTALL = YES;
@@ -5164,7 +5164,7 @@
buildSettings = {
CODE_SIGN_ENTITLEMENTS = NotificationService/NotificationService.entitlements;
CODE_SIGN_STYLE = Automatic;
- CURRENT_PROJECT_VERSION = 41;
+ CURRENT_PROJECT_VERSION = 43;
DEVELOPMENT_TEAM = 5Z4GVSS33P;
INFOPLIST_FILE = NotificationService/Info.plist;
LD_RUNPATH_SEARCH_PATHS = (
@@ -5172,7 +5172,7 @@
"@executable_path/Frameworks",
"@executable_path/../../Frameworks",
);
- MARKETING_VERSION = 0.9.1;
+ MARKETING_VERSION = 0.9.2;
PRODUCT_BUNDLE_IDENTIFIER = org.joinmastodon.app.NotificationService;
PRODUCT_NAME = "$(TARGET_NAME)";
SKIP_INSTALL = YES;
@@ -5187,7 +5187,7 @@
buildSettings = {
CODE_SIGN_ENTITLEMENTS = NotificationService/NotificationService.entitlements;
CODE_SIGN_STYLE = Automatic;
- CURRENT_PROJECT_VERSION = 41;
+ CURRENT_PROJECT_VERSION = 43;
DEVELOPMENT_TEAM = 5Z4GVSS33P;
INFOPLIST_FILE = NotificationService/Info.plist;
LD_RUNPATH_SEARCH_PATHS = (
@@ -5195,7 +5195,7 @@
"@executable_path/Frameworks",
"@executable_path/../../Frameworks",
);
- MARKETING_VERSION = 0.9.1;
+ MARKETING_VERSION = 0.9.2;
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 238c933d4..fd09596bc 100644
--- a/Mastodon.xcodeproj/xcuserdata/mainasuk.xcuserdatad/xcschemes/xcschememanagement.plist
+++ b/Mastodon.xcodeproj/xcuserdata/mainasuk.xcuserdatad/xcschemes/xcschememanagement.plist
@@ -12,7 +12,7 @@
CoreDataStack.xcscheme_^#shared#^_
orderHint
- 21
+ 22
Mastodon - ASDK.xcscheme_^#shared#^_
@@ -37,12 +37,12 @@
NotificationService.xcscheme_^#shared#^_
orderHint
- 22
+ 23
ShareActionExtension.xcscheme_^#shared#^_
orderHint
- 23
+ 21
SuppressBuildableAutocreation
diff --git a/Mastodon/Diffiable/FetchedResultsController/SearchHistoryFetchedResultController.swift b/Mastodon/Diffiable/FetchedResultsController/SearchHistoryFetchedResultController.swift
index b83bfe662..6d4461eab 100644
--- a/Mastodon/Diffiable/FetchedResultsController/SearchHistoryFetchedResultController.swift
+++ b/Mastodon/Diffiable/FetchedResultsController/SearchHistoryFetchedResultController.swift
@@ -17,6 +17,8 @@ final class SearchHistoryFetchedResultController: NSObject {
var disposeBag = Set()
let fetchedResultsController: NSFetchedResultsController
+ let domain = CurrentValueSubject(nil)
+ let userID = CurrentValueSubject(nil)
// output
let objectIDs = CurrentValueSubject<[NSManagedObjectID], Never>([])
@@ -38,6 +40,23 @@ final class SearchHistoryFetchedResultController: NSObject {
super.init()
fetchedResultsController.delegate = self
+
+ Publishers.CombineLatest(
+ self.domain.removeDuplicates(),
+ self.userID.removeDuplicates()
+ )
+ .receive(on: DispatchQueue.main)
+ .sink { [weak self] domain, userID in
+ guard let self = self else { return }
+ let predicates = [SearchHistory.predicate(domain: domain ?? "", userID: userID ?? "")]
+ self.fetchedResultsController.fetchRequest.predicate = NSCompoundPredicate(andPredicateWithSubpredicates: predicates)
+ do {
+ try self.fetchedResultsController.performFetch()
+ } catch {
+ assertionFailure(error.localizedDescription)
+ }
+ }
+ .store(in: &disposeBag)
}
}
diff --git a/Mastodon/Diffiable/Item/SettingsItem.swift b/Mastodon/Diffiable/Item/SettingsItem.swift
index e23b3f36f..777df750d 100644
--- a/Mastodon/Diffiable/Item/SettingsItem.swift
+++ b/Mastodon/Diffiable/Item/SettingsItem.swift
@@ -8,12 +8,10 @@
import UIKit
import CoreData
-enum SettingsItem: Hashable {
+enum SettingsItem {
case appearance(settingObjectID: NSManagedObjectID)
case notification(settingObjectID: NSManagedObjectID, switchMode: NotificationSwitchMode)
- case preferenceDarkMode(settingObjectID: NSManagedObjectID)
- case preferenceDisableAvatarAnimation(settingObjectID: NSManagedObjectID)
- case preferenceUsingDefaultBrowser(settingObjectID: NSManagedObjectID)
+ case preference(settingObjectID: NSManagedObjectID, preferenceType: PreferenceType)
case boringZone(item: Link)
case spicyZone(item: Link)
}
@@ -26,7 +24,7 @@ extension SettingsItem {
case dark
}
- enum NotificationSwitchMode: CaseIterable {
+ enum NotificationSwitchMode: CaseIterable, Hashable {
case favorite
case follow
case reblog
@@ -41,8 +39,22 @@ extension SettingsItem {
}
}
}
+
+ enum PreferenceType: CaseIterable {
+ case darkMode
+ case disableAvatarAnimation
+ case useDefaultBrowser
+
+ var title: String {
+ switch self {
+ case .darkMode: return L10n.Scene.Settings.Section.AppearanceSettings.trueBlackDarkMode
+ case .disableAvatarAnimation: return L10n.Scene.Settings.Section.AppearanceSettings.disableAvatarAnimation
+ case .useDefaultBrowser: return L10n.Scene.Settings.Section.Preference.usingDefaultBrowser
+ }
+ }
+ }
- enum Link: CaseIterable {
+ enum Link: CaseIterable, Hashable {
case accountSettings
case termsOfService
case privacyPolicy
@@ -71,3 +83,27 @@ extension SettingsItem {
}
}
+
+extension SettingsItem: Hashable {
+ func hash(into hasher: inout Hasher) {
+ switch self {
+ case .appearance(let settingObjectID):
+ hasher.combine(String(describing: SettingsItem.AppearanceMode.self))
+ hasher.combine(settingObjectID)
+ case .notification(let settingObjectID, let switchMode):
+ hasher.combine(String(describing: SettingsItem.notification.self))
+ hasher.combine(settingObjectID)
+ hasher.combine(switchMode)
+ case .preference(let settingObjectID, let preferenceType):
+ hasher.combine(String(describing: SettingsItem.preference.self))
+ hasher.combine(settingObjectID)
+ hasher.combine(preferenceType)
+ case .boringZone(let link):
+ hasher.combine(String(describing: SettingsItem.boringZone.self))
+ hasher.combine(link)
+ case .spicyZone(let link):
+ hasher.combine(String(describing: SettingsItem.spicyZone.self))
+ hasher.combine(link)
+ }
+ }
+}
diff --git a/Mastodon/Diffiable/Section/SettingsSection.swift b/Mastodon/Diffiable/Section/SettingsSection.swift
index 4d3c13d27..e329bd120 100644
--- a/Mastodon/Diffiable/Section/SettingsSection.swift
+++ b/Mastodon/Diffiable/Section/SettingsSection.swift
@@ -5,7 +5,9 @@
// Created by MainasuK Cirno on 2021-4-25.
//
-import Foundation
+import UIKit
+import CoreData
+import CoreDataStack
enum SettingsSection: Hashable {
case appearance
@@ -24,3 +26,125 @@ enum SettingsSection: Hashable {
}
}
}
+
+extension SettingsSection {
+ static func tableViewDiffableDataSource(
+ for tableView: UITableView,
+ managedObjectContext: NSManagedObjectContext,
+ settingsAppearanceTableViewCellDelegate: SettingsAppearanceTableViewCellDelegate,
+ settingsToggleCellDelegate: SettingsToggleCellDelegate
+ ) -> UITableViewDiffableDataSource {
+ UITableViewDiffableDataSource(tableView: tableView) { [
+ weak settingsAppearanceTableViewCellDelegate,
+ weak settingsToggleCellDelegate
+ ] tableView, indexPath, item -> UITableViewCell? in
+ switch item {
+ case .appearance(let objectID):
+ let cell = tableView.dequeueReusableCell(withIdentifier: String(describing: SettingsAppearanceTableViewCell.self), for: indexPath) as! SettingsAppearanceTableViewCell
+ managedObjectContext.performAndWait {
+ let setting = managedObjectContext.object(with: objectID) as! Setting
+ cell.update(with: setting.appearance)
+ ManagedObjectObserver.observe(object: setting)
+ .receive(on: DispatchQueue.main)
+ .sink(receiveCompletion: { _ in
+ // do nothing
+ }, receiveValue: { [weak cell] change in
+ guard let cell = cell else { return }
+ guard case .update(let object) = change.changeType,
+ let setting = object as? Setting else { return }
+ cell.update(with: setting.appearance)
+ })
+ .store(in: &cell.disposeBag)
+ }
+ cell.delegate = settingsAppearanceTableViewCellDelegate
+ return cell
+ case .notification(let objectID, let switchMode):
+ let cell = tableView.dequeueReusableCell(withIdentifier: String(describing: SettingsToggleTableViewCell.self), for: indexPath) as! SettingsToggleTableViewCell
+ managedObjectContext.performAndWait {
+ let setting = managedObjectContext.object(with: objectID) as! Setting
+ if let subscription = setting.activeSubscription {
+ SettingsSection.configureSettingToggle(cell: cell, switchMode: switchMode, subscription: subscription)
+ }
+ ManagedObjectObserver.observe(object: setting)
+ .sink(receiveCompletion: { _ in
+ // do nothing
+ }, receiveValue: { [weak cell] change in
+ guard let cell = cell else { return }
+ guard case .update(let object) = change.changeType,
+ let setting = object as? Setting else { return }
+ guard let subscription = setting.activeSubscription else { return }
+ SettingsSection.configureSettingToggle(cell: cell, switchMode: switchMode, subscription: subscription)
+ })
+ .store(in: &cell.disposeBag)
+ }
+ cell.delegate = settingsToggleCellDelegate
+ return cell
+ case .preference(let objectID, _):
+ let cell = tableView.dequeueReusableCell(withIdentifier: String(describing: SettingsToggleTableViewCell.self), for: indexPath) as! SettingsToggleTableViewCell
+ cell.delegate = settingsToggleCellDelegate
+ managedObjectContext.performAndWait {
+ let setting = managedObjectContext.object(with: objectID) as! Setting
+ SettingsSection.configureSettingToggle(cell: cell, item: item, setting: setting)
+
+ ManagedObjectObserver.observe(object: setting)
+ .receive(on: DispatchQueue.main)
+ .sink(receiveCompletion: { _ in
+ // do nothing
+ }, receiveValue: { [weak cell] change in
+ guard let cell = cell else { return }
+ guard case .update(let object) = change.changeType,
+ let setting = object as? Setting else { return }
+ SettingsSection.configureSettingToggle(cell: cell, item: item, setting: setting)
+ })
+ .store(in: &cell.disposeBag)
+ }
+ return cell
+ case .boringZone(let item),
+ .spicyZone(let item):
+ let cell = tableView.dequeueReusableCell(withIdentifier: String(describing: SettingsLinkTableViewCell.self), for: indexPath) as! SettingsLinkTableViewCell
+ cell.update(with: item)
+ return cell
+ }
+ }
+ }
+}
+
+extension SettingsSection {
+
+ static func configureSettingToggle(
+ cell: SettingsToggleTableViewCell,
+ item: SettingsItem,
+ setting: Setting
+ ) {
+ guard case let .preference(_, preferenceType) = item else { return }
+
+ cell.textLabel?.text = preferenceType.title
+
+ switch preferenceType {
+ case .darkMode:
+ cell.switchButton.isOn = setting.preferredTrueBlackDarkMode
+ case .disableAvatarAnimation:
+ cell.switchButton.isOn = setting.preferredStaticAvatar
+ case .useDefaultBrowser:
+ cell.switchButton.isOn = setting.preferredUsingDefaultBrowser
+ }
+ }
+
+ static func configureSettingToggle(
+ cell: SettingsToggleTableViewCell,
+ switchMode: SettingsItem.NotificationSwitchMode,
+ subscription: NotificationSubscription
+ ) {
+ cell.textLabel?.text = switchMode.title
+
+ let enabled: Bool?
+ switch switchMode {
+ case .favorite: enabled = subscription.alert.favourite
+ case .follow: enabled = subscription.alert.follow
+ case .reblog: enabled = subscription.alert.reblog
+ case .mention: enabled = subscription.alert.mention
+ }
+ cell.update(enabled: enabled)
+ }
+
+}
diff --git a/Mastodon/Generated/Assets.swift b/Mastodon/Generated/Assets.swift
index 0f405ef05..0fe48777f 100644
--- a/Mastodon/Generated/Assets.swift
+++ b/Mastodon/Generated/Assets.swift
@@ -34,7 +34,6 @@ internal enum Asset {
internal enum Colors {
internal enum Border {
internal static let composePoll = ColorAsset(name: "Colors/Border/compose.poll")
- internal static let notificationStatus = ColorAsset(name: "Colors/Border/notification.status")
internal static let searchCard = ColorAsset(name: "Colors/Border/searchCard")
internal static let status = ColorAsset(name: "Colors/Border/status")
}
@@ -65,9 +64,6 @@ internal enum Asset {
internal enum Slider {
internal static let track = ColorAsset(name: "Colors/Slider/track")
}
- internal enum TabBar {
- internal static let itemInactive = ColorAsset(name: "Colors/TabBar/item.inactive")
- }
internal enum TextField {
internal static let background = ColorAsset(name: "Colors/TextField/background")
internal static let invalid = ColorAsset(name: "Colors/TextField/invalid")
@@ -135,6 +131,7 @@ internal enum Asset {
internal static let tableViewCellSelectionBackground = ColorAsset(name: "Theme/Mastodon/table.view.cell.selection.background")
internal static let tertiarySystemBackground = ColorAsset(name: "Theme/Mastodon/tertiary.system.background")
internal static let tertiarySystemGroupedBackground = ColorAsset(name: "Theme/Mastodon/tertiary.system.grouped.background")
+ internal static let notificationStatusBorderColor = ColorAsset(name: "Theme/Mastodon/notification.status.border.color")
internal static let separator = ColorAsset(name: "Theme/Mastodon/separator")
internal static let tabBarItemInactiveIconColor = ColorAsset(name: "Theme/Mastodon/tab.bar.item.inactive.icon.color")
}
@@ -153,6 +150,7 @@ internal enum Asset {
internal static let tableViewCellSelectionBackground = ColorAsset(name: "Theme/system/table.view.cell.selection.background")
internal static let tertiarySystemBackground = ColorAsset(name: "Theme/system/tertiary.system.background")
internal static let tertiarySystemGroupedBackground = ColorAsset(name: "Theme/system/tertiary.system.grouped.background")
+ internal static let notificationStatusBorderColor = ColorAsset(name: "Theme/system/notification.status.border.color")
internal static let separator = ColorAsset(name: "Theme/system/separator")
internal static let tabBarItemInactiveIconColor = ColorAsset(name: "Theme/system/tab.bar.item.inactive.icon.color")
}
diff --git a/Mastodon/Helper/MastodonStatusContent.swift b/Mastodon/Helper/MastodonStatusContent.swift
index 90e697daf..917c456d2 100755
--- a/Mastodon/Helper/MastodonStatusContent.swift
+++ b/Mastodon/Helper/MastodonStatusContent.swift
@@ -29,7 +29,7 @@ public enum MastodonStatusContent {
public static func parse(content: String, emojiDict: EmojiDict) throws -> MastodonStatusContent.ParseResult {
let document: String = {
- var content = content
+ var content = content.replacingOccurrences(of: "
", with: "\r\n")
for (shortcode, url) in emojiDict {
let emojiNode = "\(shortcode)"
let pattern = ":\(shortcode):"
diff --git a/Mastodon/Resources/Assets.xcassets/Colors/TabBar/Contents.json b/Mastodon/Resources/Assets.xcassets/Colors/TabBar/Contents.json
deleted file mode 100644
index 6e965652d..000000000
--- a/Mastodon/Resources/Assets.xcassets/Colors/TabBar/Contents.json
+++ /dev/null
@@ -1,9 +0,0 @@
-{
- "info" : {
- "author" : "xcode",
- "version" : 1
- },
- "properties" : {
- "provides-namespace" : true
- }
-}
diff --git a/Mastodon/Resources/Assets.xcassets/Colors/Border/notification.status.colorset/Contents.json b/Mastodon/Resources/Assets.xcassets/Theme/Mastodon/notification.status.border.color.colorset/Contents.json
similarity index 76%
rename from Mastodon/Resources/Assets.xcassets/Colors/Border/notification.status.colorset/Contents.json
rename to Mastodon/Resources/Assets.xcassets/Theme/Mastodon/notification.status.border.color.colorset/Contents.json
index 1067c15d9..c04af0902 100644
--- a/Mastodon/Resources/Assets.xcassets/Colors/Border/notification.status.colorset/Contents.json
+++ b/Mastodon/Resources/Assets.xcassets/Theme/Mastodon/notification.status.border.color.colorset/Contents.json
@@ -5,9 +5,9 @@
"color-space" : "srgb",
"components" : {
"alpha" : "1.000",
- "blue" : "232",
- "green" : "225",
- "red" : "217"
+ "blue" : "0.910",
+ "green" : "0.882",
+ "red" : "0.851"
}
},
"idiom" : "universal"
@@ -23,9 +23,9 @@
"color-space" : "srgb",
"components" : {
"alpha" : "1.000",
- "blue" : "110",
- "green" : "87",
- "red" : "79"
+ "blue" : "0.431",
+ "green" : "0.341",
+ "red" : "0.310"
}
},
"idiom" : "universal"
diff --git a/Mastodon/Resources/Assets.xcassets/Colors/TabBar/item.inactive.colorset/Contents.json b/Mastodon/Resources/Assets.xcassets/Theme/system/notification.status.border.color.colorset/Contents.json
similarity index 76%
rename from Mastodon/Resources/Assets.xcassets/Colors/TabBar/item.inactive.colorset/Contents.json
rename to Mastodon/Resources/Assets.xcassets/Theme/system/notification.status.border.color.colorset/Contents.json
index 48fc40b01..c04af0902 100644
--- a/Mastodon/Resources/Assets.xcassets/Colors/TabBar/item.inactive.colorset/Contents.json
+++ b/Mastodon/Resources/Assets.xcassets/Theme/system/notification.status.border.color.colorset/Contents.json
@@ -5,9 +5,9 @@
"color-space" : "srgb",
"components" : {
"alpha" : "1.000",
- "blue" : "140",
- "green" : "130",
- "red" : "110"
+ "blue" : "0.910",
+ "green" : "0.882",
+ "red" : "0.851"
}
},
"idiom" : "universal"
@@ -23,9 +23,9 @@
"color-space" : "srgb",
"components" : {
"alpha" : "1.000",
- "blue" : "200",
- "green" : "174",
- "red" : "155"
+ "blue" : "0.431",
+ "green" : "0.341",
+ "red" : "0.310"
}
},
"idiom" : "universal"
diff --git a/Mastodon/Scene/Notification/TableViewCell/NotificationStatusTableViewCell.swift b/Mastodon/Scene/Notification/TableViewCell/NotificationStatusTableViewCell.swift
index ab7b6a518..684d9187c 100644
--- a/Mastodon/Scene/Notification/TableViewCell/NotificationStatusTableViewCell.swift
+++ b/Mastodon/Scene/Notification/TableViewCell/NotificationStatusTableViewCell.swift
@@ -90,7 +90,7 @@ final class NotificationStatusTableViewCell: UITableViewCell, StatusCell {
view.layer.cornerRadius = 6
view.layer.cornerCurve = .continuous
view.layer.borderWidth = 2
- view.layer.borderColor = Asset.Colors.Border.notificationStatus.color.cgColor
+ view.layer.borderColor = ThemeService.shared.currentTheme.value.notificationStatusBorderColor.cgColor
return view
}()
let statusView = StatusView()
@@ -272,9 +272,7 @@ extension NotificationStatusTableViewCell {
extension NotificationStatusTableViewCell {
private func setupBackgroundColor(theme: Theme) {
-// actionImageView.layer.borderColor = theme.systemBackgroundColor.cgColor
-// avatarImageView.layer.borderColor = Asset.Theme.Mastodon.systemBackground.color.cgColor
- statusContainerView.layer.borderColor = Asset.Colors.Border.notificationStatus.color.cgColor
+ statusContainerView.layer.borderColor = theme.notificationStatusBorderColor.resolvedColor(with: traitCollection).cgColor
statusContainerView.backgroundColor = UIColor(dynamicProvider: { traitCollection in
return traitCollection.userInterfaceStyle == .light ? theme.systemBackgroundColor : theme.tertiarySystemGroupedBackgroundColor
})
diff --git a/Mastodon/Scene/Search/SearchDetail/SearchHistory/SearchHistoryViewModel.swift b/Mastodon/Scene/Search/SearchDetail/SearchHistory/SearchHistoryViewModel.swift
index acfd995ff..934c55b1b 100644
--- a/Mastodon/Scene/Search/SearchDetail/SearchHistory/SearchHistoryViewModel.swift
+++ b/Mastodon/Scene/Search/SearchDetail/SearchHistory/SearchHistoryViewModel.swift
@@ -25,6 +25,15 @@ final class SearchHistoryViewModel {
self.context = context
self.searchHistoryFetchedResultController = SearchHistoryFetchedResultController(managedObjectContext: context.managedObjectContext)
+ context.authenticationService.activeMastodonAuthenticationBox
+ .receive(on: DispatchQueue.main)
+ .sink { [weak self] box in
+ guard let self = self else { return }
+ self.searchHistoryFetchedResultController.domain.value = box?.domain
+ self.searchHistoryFetchedResultController.userID.value = box?.userID
+ }
+ .store(in: &disposeBag)
+
// may block main queue by large dataset
searchHistoryFetchedResultController.objectIDs
.removeDuplicates()
@@ -81,6 +90,9 @@ extension SearchHistoryViewModel {
extension SearchHistoryViewModel {
func persistSearchHistory(for item: SearchHistoryItem) {
+ guard let box = context.authenticationService.activeMastodonAuthenticationBox.value else { return }
+ let property = SearchHistory.Property(domain: box.domain, userID: box.userID)
+
switch item {
case .account(let objectID):
let managedObjectContext = context.backgroundManagedObjectContext
@@ -89,7 +101,7 @@ extension SearchHistoryViewModel {
if let searchHistory = user.searchHistory {
searchHistory.update(updatedAt: Date())
} else {
- SearchHistory.insert(into: managedObjectContext, account: user)
+ SearchHistory.insert(into: managedObjectContext, property: property, account: user)
}
}
.sink { result in
@@ -104,7 +116,7 @@ extension SearchHistoryViewModel {
if let searchHistory = hashtag.searchHistory {
searchHistory.update(updatedAt: Date())
} else {
- SearchHistory.insert(into: managedObjectContext, hashtag: hashtag)
+ SearchHistory.insert(into: managedObjectContext, property: property, hashtag: hashtag)
}
}
.sink { result in
diff --git a/Mastodon/Scene/Search/SearchDetail/SearchResult/SearchResultViewModel.swift b/Mastodon/Scene/Search/SearchDetail/SearchResult/SearchResultViewModel.swift
index 0ace96226..181302a24 100644
--- a/Mastodon/Scene/Search/SearchDetail/SearchResult/SearchResultViewModel.swift
+++ b/Mastodon/Scene/Search/SearchDetail/SearchResult/SearchResultViewModel.swift
@@ -142,6 +142,7 @@ extension SearchResultViewModel {
extension SearchResultViewModel {
func persistSearchHistory(for item: SearchResultItem) {
guard let box = context.authenticationService.activeMastodonAuthenticationBox.value else { return }
+ let property = SearchHistory.Property(domain: box.domain, userID: box.userID)
let domain = box.domain
switch item {
@@ -160,7 +161,7 @@ extension SearchResultViewModel {
if let searchHistory = user.searchHistory {
searchHistory.update(updatedAt: Date())
} else {
- SearchHistory.insert(into: managedObjectContext, account: user)
+ SearchHistory.insert(into: managedObjectContext, property: property, account: user)
}
}
.sink { result in
@@ -178,7 +179,7 @@ extension SearchResultViewModel {
if let searchHistory = hashtag.searchHistory {
searchHistory.update(updatedAt: Date())
} else {
- SearchHistory.insert(into: managedObjectContext, hashtag: hashtag)
+ SearchHistory.insert(into: managedObjectContext, property: property, hashtag: hashtag)
}
}
.sink { result in
diff --git a/Mastodon/Scene/Settings/SettingsViewController.swift b/Mastodon/Scene/Settings/SettingsViewController.swift
index a295272ee..744900bed 100644
--- a/Mastodon/Scene/Settings/SettingsViewController.swift
+++ b/Mastodon/Scene/Settings/SettingsViewController.swift
@@ -358,13 +358,10 @@ extension SettingsViewController: UITableViewDelegate {
case .appearance:
// do nothing
break
- case .preferenceDarkMode, .preferenceDisableAvatarAnimation:
- // do nothing
- break
case .notification:
// do nothing
break
- case .preferenceUsingDefaultBrowser:
+ case .preference:
// do nothing
break
case .boringZone(let link), .spicyZone(let link):
@@ -476,48 +473,30 @@ extension SettingsViewController: SettingsToggleCellDelegate {
// do nothing
}
.store(in: &disposeBag)
- case .preferenceDarkMode(let settingObjectID):
+ case .preference(let settingObjectID, let preferenceType):
let managedObjectContext = context.backgroundManagedObjectContext
managedObjectContext.performChanges {
let setting = managedObjectContext.object(with: settingObjectID) as! Setting
- setting.update(preferredTrueBlackDarkMode: isOn)
- }
- .sink { result in
- switch result {
- case .success:
- ThemeService.shared.set(themeName: isOn ? .system : .mastodon)
- case .failure(let error):
- assertionFailure(error.localizedDescription)
- break
+ switch preferenceType {
+ case .darkMode:
+ setting.update(preferredTrueBlackDarkMode: isOn)
+ case .disableAvatarAnimation:
+ setting.update(preferredStaticAvatar: isOn)
+ case .useDefaultBrowser:
+ setting.update(preferredUsingDefaultBrowser: isOn)
}
}
- .store(in: &disposeBag)
- case .preferenceDisableAvatarAnimation(let settingObjectID):
- let managedObjectContext = context.backgroundManagedObjectContext
- managedObjectContext.performChanges {
- let setting = managedObjectContext.object(with: settingObjectID) as! Setting
- setting.update(preferredStaticAvatar: isOn)
- }
.sink { result in
switch result {
case .success:
- UserDefaults.shared.preferredStaticAvatar = isOn
- case .failure(let error):
- assertionFailure(error.localizedDescription)
- break
- }
- }
- .store(in: &disposeBag)
- case .preferenceUsingDefaultBrowser(let settingObjectID):
- let managedObjectContext = context.backgroundManagedObjectContext
- managedObjectContext.performChanges {
- let setting = managedObjectContext.object(with: settingObjectID) as! Setting
- setting.update(preferredUsingDefaultBrowser: isOn)
- }
- .sink { result in
- switch result {
- case .success:
- UserDefaults.shared.preferredUsingDefaultBrowser = isOn
+ switch preferenceType {
+ case .darkMode:
+ ThemeService.shared.set(themeName: isOn ? .system : .mastodon)
+ case .disableAvatarAnimation:
+ UserDefaults.shared.preferredStaticAvatar = isOn
+ case .useDefaultBrowser:
+ UserDefaults.shared.preferredUsingDefaultBrowser = isOn
+ }
case .failure(let error):
assertionFailure(error.localizedDescription)
break
diff --git a/Mastodon/Scene/Settings/SettingsViewModel.swift b/Mastodon/Scene/Settings/SettingsViewModel.swift
index 2d7fafde3..b586195e6 100644
--- a/Mastodon/Scene/Settings/SettingsViewModel.swift
+++ b/Mastodon/Scene/Settings/SettingsViewModel.swift
@@ -122,9 +122,9 @@ extension SettingsViewModel {
// preference
snapshot.appendSections([.preference])
let preferenceItems: [SettingsItem] = [
- .preferenceDarkMode(settingObjectID: setting.objectID),
- .preferenceDisableAvatarAnimation(settingObjectID: setting.objectID),
- .preferenceUsingDefaultBrowser(settingObjectID: setting.objectID),
+ .preference(settingObjectID: setting.objectID, preferenceType: .darkMode),
+ .preference(settingObjectID: setting.objectID, preferenceType: .disableAvatarAnimation),
+ .preference(settingObjectID: setting.objectID, preferenceType: .useDefaultBrowser),
]
snapshot.appendItems(preferenceItems,toSection: .preference)
@@ -163,123 +163,12 @@ extension SettingsViewModel {
settingsAppearanceTableViewCellDelegate: SettingsAppearanceTableViewCellDelegate,
settingsToggleCellDelegate: SettingsToggleCellDelegate
) {
- dataSource = UITableViewDiffableDataSource(tableView: tableView) { [
- weak self,
- weak settingsAppearanceTableViewCellDelegate,
- weak settingsToggleCellDelegate
- ] tableView, indexPath, item -> UITableViewCell? in
- guard let self = self else { return nil }
- switch item {
- case .appearance(let objectID):
- let cell = tableView.dequeueReusableCell(withIdentifier: String(describing: SettingsAppearanceTableViewCell.self), for: indexPath) as! SettingsAppearanceTableViewCell
- self.context.managedObjectContext.performAndWait {
- let setting = self.context.managedObjectContext.object(with: objectID) as! Setting
- cell.update(with: setting.appearance)
- ManagedObjectObserver.observe(object: setting)
- .receive(on: DispatchQueue.main)
- .sink(receiveCompletion: { _ in
- // do nothing
- }, receiveValue: { [weak cell] change in
- guard let cell = cell else { return }
- guard case .update(let object) = change.changeType,
- let setting = object as? Setting else { return }
- cell.update(with: setting.appearance)
- })
- .store(in: &cell.disposeBag)
- }
- cell.delegate = settingsAppearanceTableViewCellDelegate
- return cell
- case .preferenceDarkMode(let objectID),
- .preferenceDisableAvatarAnimation(let objectID),
- .preferenceUsingDefaultBrowser(let objectID):
- let cell = tableView.dequeueReusableCell(withIdentifier: String(describing: SettingsToggleTableViewCell.self), for: indexPath) as! SettingsToggleTableViewCell
- cell.delegate = settingsToggleCellDelegate
- self.context.managedObjectContext.performAndWait {
- let setting = self.context.managedObjectContext.object(with: objectID) as! Setting
- SettingsViewModel.configureSettingToggle(cell: cell, item: item, setting: setting)
-
- ManagedObjectObserver.observe(object: setting)
- .receive(on: DispatchQueue.main)
- .sink(receiveCompletion: { _ in
- // do nothing
- }, receiveValue: { [weak cell] change in
- guard let cell = cell else { return }
- guard case .update(let object) = change.changeType,
- let setting = object as? Setting else { return }
- SettingsViewModel.configureSettingToggle(cell: cell, item: item, setting: setting)
- })
- .store(in: &cell.disposeBag)
- }
- return cell
- case .notification(let objectID, let switchMode):
- let cell = tableView.dequeueReusableCell(withIdentifier: String(describing: SettingsToggleTableViewCell.self), for: indexPath) as! SettingsToggleTableViewCell
- self.context.managedObjectContext.performAndWait {
- let setting = self.context.managedObjectContext.object(with: objectID) as! Setting
- if let subscription = setting.activeSubscription {
- SettingsViewModel.configureSettingToggle(cell: cell, switchMode: switchMode, subscription: subscription)
- }
- ManagedObjectObserver.observe(object: setting)
- .sink(receiveCompletion: { _ in
- // do nothing
- }, receiveValue: { [weak cell] change in
- guard let cell = cell else { return }
- guard case .update(let object) = change.changeType,
- let setting = object as? Setting else { return }
- guard let subscription = setting.activeSubscription else { return }
- SettingsViewModel.configureSettingToggle(cell: cell, switchMode: switchMode, subscription: subscription)
- })
- .store(in: &cell.disposeBag)
- }
- cell.delegate = settingsToggleCellDelegate
- return cell
- case .boringZone(let item), .spicyZone(let item):
- let cell = tableView.dequeueReusableCell(withIdentifier: String(describing: SettingsLinkTableViewCell.self), for: indexPath) as! SettingsLinkTableViewCell
- cell.update(with: item)
- return cell
- }
- }
-
+ dataSource = SettingsSection.tableViewDiffableDataSource(
+ for: tableView,
+ managedObjectContext: context.managedObjectContext,
+ settingsAppearanceTableViewCellDelegate: settingsAppearanceTableViewCellDelegate,
+ settingsToggleCellDelegate: settingsToggleCellDelegate
+ )
processDataSource(self.setting.value)
}
}
-
-extension SettingsViewModel {
-
- static func configureSettingToggle(
- cell: SettingsToggleTableViewCell,
- item: SettingsItem,
- setting: Setting
- ) {
- switch item {
- case .preferenceDarkMode:
- cell.textLabel?.text = L10n.Scene.Settings.Section.AppearanceSettings.trueBlackDarkMode
- cell.switchButton.isOn = setting.preferredTrueBlackDarkMode
- case .preferenceDisableAvatarAnimation:
- cell.textLabel?.text = L10n.Scene.Settings.Section.AppearanceSettings.disableAvatarAnimation
- cell.switchButton.isOn = setting.preferredStaticAvatar
- case .preferenceUsingDefaultBrowser:
- cell.textLabel?.text = L10n.Scene.Settings.Section.Preference.usingDefaultBrowser
- cell.switchButton.isOn = setting.preferredUsingDefaultBrowser
- default:
- assertionFailure()
- }
- }
-
- static func configureSettingToggle(
- cell: SettingsToggleTableViewCell,
- switchMode: SettingsItem.NotificationSwitchMode,
- subscription: NotificationSubscription
- ) {
- cell.textLabel?.text = switchMode.title
-
- let enabled: Bool?
- switch switchMode {
- case .favorite: enabled = subscription.alert.favourite
- case .follow: enabled = subscription.alert.follow
- case .reblog: enabled = subscription.alert.reblog
- case .mention: enabled = subscription.alert.mention
- }
- cell.update(enabled: enabled)
- }
-
-}
diff --git a/Mastodon/Scene/Settings/View/Cell/SettingsToggleTableViewCell.swift b/Mastodon/Scene/Settings/View/Cell/SettingsToggleTableViewCell.swift
index 86698d840..2bc70e65e 100644
--- a/Mastodon/Scene/Settings/View/Cell/SettingsToggleTableViewCell.swift
+++ b/Mastodon/Scene/Settings/View/Cell/SettingsToggleTableViewCell.swift
@@ -22,6 +22,12 @@ class SettingsToggleTableViewCell: UITableViewCell {
}()
weak var delegate: SettingsToggleCellDelegate?
+
+ override func prepareForReuse() {
+ super.prepareForReuse()
+
+ disposeBag.removeAll()
+ }
// MARK: - Methods
override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
diff --git a/Mastodon/Service/ThemeService/MastodonTheme.swift b/Mastodon/Service/ThemeService/MastodonTheme.swift
index 2418877ff..60093f04d 100644
--- a/Mastodon/Service/ThemeService/MastodonTheme.swift
+++ b/Mastodon/Service/ThemeService/MastodonTheme.swift
@@ -34,4 +34,5 @@ struct MastodonTheme: Theme {
let contentWarningOverlayBackgroundColor = Asset.Theme.Mastodon.contentWarningOverlayBackground.color
let profileFieldCollectionViewBackgroundColor = Asset.Theme.Mastodon.profileFieldCollectionViewBackground.color
let composeToolbarBackgroundColor = Asset.Theme.Mastodon.composeToolbarBackground.color
+ let notificationStatusBorderColor = Asset.Theme.System.notificationStatusBorderColor.color
}
diff --git a/Mastodon/Service/ThemeService/SystemTheme.swift b/Mastodon/Service/ThemeService/SystemTheme.swift
index b91ba1caf..0be42c6ed 100644
--- a/Mastodon/Service/ThemeService/SystemTheme.swift
+++ b/Mastodon/Service/ThemeService/SystemTheme.swift
@@ -34,4 +34,5 @@ struct SystemTheme: Theme {
let contentWarningOverlayBackgroundColor = Asset.Theme.System.contentWarningOverlayBackground.color
let profileFieldCollectionViewBackgroundColor = Asset.Theme.System.profileFieldCollectionViewBackground.color
let composeToolbarBackgroundColor = Asset.Theme.System.composeToolbarBackground.color
+ let notificationStatusBorderColor = Asset.Theme.System.notificationStatusBorderColor.color
}
diff --git a/Mastodon/Service/ThemeService/Theme.swift b/Mastodon/Service/ThemeService/Theme.swift
index 29f90db8d..15def6f53 100644
--- a/Mastodon/Service/ThemeService/Theme.swift
+++ b/Mastodon/Service/ThemeService/Theme.swift
@@ -35,6 +35,7 @@ public protocol Theme {
var contentWarningOverlayBackgroundColor: UIColor { get }
var profileFieldCollectionViewBackgroundColor: UIColor { get }
var composeToolbarBackgroundColor: UIColor { get }
+ var notificationStatusBorderColor: UIColor { get }
}