Merge branch 'release/0.9.1'
This commit is contained in:
commit
5e6e532e07
|
@ -7,12 +7,14 @@
|
|||
|
||||
import os
|
||||
import Foundation
|
||||
import Combine
|
||||
import CoreData
|
||||
import AppShared
|
||||
|
||||
public final class CoreDataStack {
|
||||
|
||||
private(set) var storeDescriptions: [NSPersistentStoreDescription]
|
||||
public let didFinishLoad = CurrentValueSubject<Bool, Never>(false)
|
||||
|
||||
init(persistentStoreDescriptions storeDescriptions: [NSPersistentStoreDescription]) {
|
||||
self.storeDescriptions = storeDescriptions
|
||||
|
@ -33,7 +35,10 @@ public final class CoreDataStack {
|
|||
*/
|
||||
let container = CoreDataStack.persistentContainer()
|
||||
CoreDataStack.configure(persistentContainer: container, storeDescriptions: storeDescriptions)
|
||||
CoreDataStack.load(persistentContainer: container)
|
||||
CoreDataStack.load(persistentContainer: container) { [weak self] in
|
||||
guard let self = self else { return }
|
||||
self.didFinishLoad.value = true
|
||||
}
|
||||
|
||||
return container
|
||||
}()
|
||||
|
@ -52,7 +57,7 @@ public final class CoreDataStack {
|
|||
container.persistentStoreDescriptions = storeDescriptions
|
||||
}
|
||||
|
||||
static func load(persistentContainer container: NSPersistentContainer) {
|
||||
static func load(persistentContainer container: NSPersistentContainer, callback: @escaping () -> Void) {
|
||||
container.loadPersistentStores(completionHandler: { (storeDescription, error) in
|
||||
if let error = error as NSError? {
|
||||
// Replace this implementation with code to handle the error appropriately.
|
||||
|
@ -85,6 +90,8 @@ public final class CoreDataStack {
|
|||
container.viewContext.automaticallyMergesChangesFromParent = true
|
||||
|
||||
os_log("%{public}s[%{public}ld], %{public}s: %s", ((#file as NSString).lastPathComponent), #line, #function, storeDescription.debugDescription)
|
||||
|
||||
callback()
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -96,7 +103,10 @@ extension CoreDataStack {
|
|||
let oldStoreURL = persistentContainer.persistentStoreCoordinator.url(for: persistentContainer.persistentStoreCoordinator.persistentStores.first!)
|
||||
try! persistentContainer.persistentStoreCoordinator.destroyPersistentStore(at: oldStoreURL, ofType: NSSQLiteStoreType, options: nil)
|
||||
|
||||
CoreDataStack.load(persistentContainer: persistentContainer)
|
||||
CoreDataStack.load(persistentContainer: persistentContainer) { [weak self] in
|
||||
guard let self = self else { return }
|
||||
self.didFinishLoad.value = true
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -22,7 +22,7 @@
|
|||
"publish_post_failure": {
|
||||
"title": "Publish Failure",
|
||||
"message": "Failed to publish the post.\nPlease check your internet connection.",
|
||||
"attchments_message": {
|
||||
"attachments_message": {
|
||||
"video_attach_with_photo": "Cannot attach a video to a post that already contains images.",
|
||||
"more_than_one_video": "Cannot attach more than one video."
|
||||
}
|
||||
|
@ -524,7 +524,7 @@
|
|||
},
|
||||
"boring_zone": {
|
||||
"title": "The Boring Zone",
|
||||
"account_settings": "Account settings",
|
||||
"account_settings": "Account Settings",
|
||||
"terms": "Terms of Service",
|
||||
"privacy": "Privacy Policy"
|
||||
},
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -12,7 +12,7 @@
|
|||
<key>CoreDataStack.xcscheme_^#shared#^_</key>
|
||||
<dict>
|
||||
<key>orderHint</key>
|
||||
<integer>21</integer>
|
||||
<integer>24</integer>
|
||||
</dict>
|
||||
<key>Mastodon - ASDK.xcscheme_^#shared#^_</key>
|
||||
<dict>
|
||||
|
@ -37,7 +37,12 @@
|
|||
<key>NotificationService.xcscheme_^#shared#^_</key>
|
||||
<dict>
|
||||
<key>orderHint</key>
|
||||
<integer>20</integer>
|
||||
<integer>22</integer>
|
||||
</dict>
|
||||
<key>ShareActionExtension.xcscheme_^#shared#^_</key>
|
||||
<dict>
|
||||
<key>orderHint</key>
|
||||
<integer>21</integer>
|
||||
</dict>
|
||||
</dict>
|
||||
<key>SuppressBuildableAutocreation</key>
|
||||
|
|
|
@ -105,8 +105,8 @@
|
|||
"repositoryURL": "https://github.com/onevcat/Kingfisher.git",
|
||||
"state": {
|
||||
"branch": null,
|
||||
"revision": "15d199e84677303a7004ed2c5ecaa1a90f3863f8",
|
||||
"version": "6.2.1"
|
||||
"revision": "44450a8f564d7c0165f736ba2250649ff8d3e556",
|
||||
"version": "6.3.0"
|
||||
}
|
||||
},
|
||||
{
|
||||
|
@ -123,8 +123,8 @@
|
|||
"repositoryURL": "https://github.com/kean/Nuke.git",
|
||||
"state": {
|
||||
"branch": null,
|
||||
"revision": "69ae6d5b8c4b898450432f94bd35f863d3830cfc",
|
||||
"version": "10.3.0"
|
||||
"revision": "83e1edaa5a30c567eb129c21c6d00f2f552d2c6f",
|
||||
"version": "10.3.1"
|
||||
}
|
||||
},
|
||||
{
|
||||
|
@ -163,6 +163,15 @@
|
|||
"version": "1.0.0"
|
||||
}
|
||||
},
|
||||
{
|
||||
"package": "Introspect",
|
||||
"repositoryURL": "https://github.com/siteline/SwiftUI-Introspect.git",
|
||||
"state": {
|
||||
"branch": null,
|
||||
"revision": "2e09be8af614401bc9f87d40093ec19ce56ccaf2",
|
||||
"version": "0.1.3"
|
||||
}
|
||||
},
|
||||
{
|
||||
"package": "SwiftyJSON",
|
||||
"repositoryURL": "https://github.com/SwiftyJSON/SwiftyJSON.git",
|
||||
|
|
|
@ -34,7 +34,7 @@ extension CategoryPickerSection {
|
|||
cell.categoryView.titleLabel.textColor = .white
|
||||
}
|
||||
} else {
|
||||
cell.categoryView.bgView.backgroundColor = Asset.Colors.Background.secondaryGroupedSystemBackground.color
|
||||
cell.categoryView.bgView.backgroundColor = Asset.Theme.Mastodon.secondaryGroupedSystemBackground.color
|
||||
cell.categoryView.bgView.applyShadow(color: Asset.Colors.brandBlue.color, alpha: 0, x: 0, y: 0, blur: 0.0)
|
||||
if case .all = item {
|
||||
cell.categoryView.titleLabel.textColor = Asset.Colors.brandBlue.color
|
||||
|
|
|
@ -33,16 +33,6 @@ extension SearchResultSection {
|
|||
let cell = tableView.dequeueReusableCell(withIdentifier: String(describing: SearchResultTableViewCell.self), for: indexPath) as! SearchResultTableViewCell
|
||||
cell.config(with: tag)
|
||||
return cell
|
||||
// case .hashtagObjectID(let hashtagObjectID):
|
||||
// let cell = tableView.dequeueReusableCell(withIdentifier: String(describing: SearchingTableViewCell.self), for: indexPath) as! SearchingTableViewCell
|
||||
// let tag = dependency.context.managedObjectContext.object(with: hashtagObjectID) as! Tag
|
||||
// cell.config(with: tag)
|
||||
// return cell
|
||||
// case .accountObjectID(let accountObjectID):
|
||||
// let cell = tableView.dequeueReusableCell(withIdentifier: String(describing: SearchingTableViewCell.self), for: indexPath) as! SearchingTableViewCell
|
||||
// let user = dependency.context.managedObjectContext.object(with: accountObjectID) as! MastodonUser
|
||||
// cell.config(with: user)
|
||||
// return cell
|
||||
case .status(let statusObjectID, let attribute):
|
||||
let cell = tableView.dequeueReusableCell(withIdentifier: String(describing: StatusTableViewCell.self), for: indexPath) as! StatusTableViewCell
|
||||
if let status = try? dependency.context.managedObjectContext.existingObject(with: statusObjectID) as? Status {
|
||||
|
@ -73,8 +63,6 @@ extension SearchResultSection {
|
|||
cell.loadMoreLabel.isHidden = true
|
||||
}
|
||||
return cell
|
||||
default:
|
||||
fatalError()
|
||||
} // end switch
|
||||
} // end UITableViewDiffableDataSource
|
||||
} // end func
|
||||
|
|
|
@ -44,14 +44,26 @@ extension NotificationSection {
|
|||
avatarImageURL: notification.account.avatarImageURL()
|
||||
)
|
||||
)
|
||||
cell.actionImageView.image = UIImage(
|
||||
systemName: notification.notificationType.actionImageName,
|
||||
withConfiguration: UIImage.SymbolConfiguration(
|
||||
pointSize: 12, weight: .semibold
|
||||
)
|
||||
)?
|
||||
.withRenderingMode(.alwaysTemplate)
|
||||
.af.imageAspectScaled(toFit: CGSize(width: 14, height: 14))
|
||||
|
||||
func createActionImage() -> UIImage? {
|
||||
return UIImage(
|
||||
systemName: notification.notificationType.actionImageName,
|
||||
withConfiguration: UIImage.SymbolConfiguration(
|
||||
pointSize: 12, weight: .semibold
|
||||
)
|
||||
)?
|
||||
.withTintColor(.systemBackground)
|
||||
.af.imageAspectScaled(toFit: CGSize(width: 14, height: 14))
|
||||
}
|
||||
|
||||
cell.actionImageView.image = createActionImage()
|
||||
cell.traitCollectionDidChange
|
||||
.receive(on: DispatchQueue.main)
|
||||
.sink { [weak cell] in
|
||||
guard let cell = cell else { return }
|
||||
cell.actionImageView.image = createActionImage()
|
||||
}
|
||||
.store(in: &cell.disposeBag)
|
||||
|
||||
cell.actionImageView.backgroundColor = notification.notificationType.color
|
||||
|
||||
|
|
|
@ -103,7 +103,7 @@ extension PollSection {
|
|||
cell.pollOptionView.optionPercentageLabel.isHidden = false
|
||||
cell.pollOptionView.optionPercentageLabel.text = String(Int(100 * percentage)) + "%"
|
||||
cell.pollOptionView.voteProgressStripView.isHidden = false
|
||||
cell.pollOptionView.voteProgressStripView.tintColor = voted ? Asset.Colors.brandBlue.color : Asset.Colors.Background.Poll.disabled.color
|
||||
cell.pollOptionView.voteProgressStripView.tintColor = voted ? Asset.Colors.brandBlue.color : Asset.Colors.Poll.disabled.color
|
||||
cell.pollOptionView.voteProgressStripView.setProgress(CGFloat(percentage), animated: animated)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -9,6 +9,7 @@ import UIKit
|
|||
import Foundation
|
||||
import ActiveLabel
|
||||
import os.log
|
||||
import MastodonUI
|
||||
|
||||
extension ActiveLabel {
|
||||
|
||||
|
@ -58,7 +59,7 @@ extension ActiveLabel {
|
|||
}
|
||||
|
||||
extension ActiveLabel {
|
||||
func configure(text: String) {
|
||||
public func configure(text: String) {
|
||||
attributedText = nil
|
||||
activeEntities.removeAll()
|
||||
self.text = text
|
||||
|
@ -69,7 +70,7 @@ extension ActiveLabel {
|
|||
extension ActiveLabel {
|
||||
|
||||
/// status content
|
||||
func configure(content: String, emojiDict: MastodonStatusContent.EmojiDict) {
|
||||
public func configure(content: String, emojiDict: MastodonStatusContent.EmojiDict) {
|
||||
attributedText = nil
|
||||
activeEntities.removeAll()
|
||||
|
||||
|
@ -83,7 +84,7 @@ extension ActiveLabel {
|
|||
}
|
||||
}
|
||||
|
||||
func configure(contentParseResult parseResult: MastodonStatusContent.ParseResult?) {
|
||||
public func configure(contentParseResult parseResult: MastodonStatusContent.ParseResult?) {
|
||||
attributedText = nil
|
||||
activeEntities.removeAll()
|
||||
text = parseResult?.trimmed ?? ""
|
||||
|
@ -92,14 +93,14 @@ extension ActiveLabel {
|
|||
}
|
||||
|
||||
/// account note
|
||||
func configure(note: String, emojiDict: MastodonStatusContent.EmojiDict) {
|
||||
public func configure(note: String, emojiDict: MastodonStatusContent.EmojiDict) {
|
||||
configure(content: note, emojiDict: emojiDict)
|
||||
}
|
||||
}
|
||||
|
||||
extension ActiveLabel {
|
||||
/// account field
|
||||
func configure(field: String, emojiDict: MastodonStatusContent.EmojiDict) {
|
||||
public func configure(field: String, emojiDict: MastodonStatusContent.EmojiDict) {
|
||||
configure(content: field, emojiDict: emojiDict)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,154 +0,0 @@
|
|||
//
|
||||
// CGImage.swift
|
||||
// Mastodon
|
||||
//
|
||||
// Created by MainasuK Cirno on 2021-3-31.
|
||||
//
|
||||
|
||||
import CoreImage
|
||||
|
||||
extension CGImage {
|
||||
// Reference
|
||||
// https://www.itu.int/dms_pubrec/itu-r/rec/bt/R-REC-BT.709-6-201506-I!!PDF-E.pdf
|
||||
// Luma Y = 0.2126R + 0.7152G + 0.0722B
|
||||
var brightness: CGFloat? {
|
||||
let context = CIContext() // default with metal accelerate
|
||||
let ciImage = CIImage(cgImage: self)
|
||||
let rec709Image = context.createCGImage(
|
||||
ciImage,
|
||||
from: ciImage.extent,
|
||||
format: .RGBA8,
|
||||
colorSpace: CGColorSpace(name: CGColorSpace.itur_709) // BT.709 a.k.a Rec.709
|
||||
)
|
||||
guard let image = rec709Image,
|
||||
image.bitsPerPixel == 32,
|
||||
let data = rec709Image?.dataProvider?.data,
|
||||
let pointer = CFDataGetBytePtr(data) else { return nil }
|
||||
|
||||
let length = CFDataGetLength(data)
|
||||
guard length > 0 else { return nil }
|
||||
|
||||
var luma: CGFloat = 0.0
|
||||
for i in stride(from: 0, to: length, by: 4) {
|
||||
let r = pointer[i]
|
||||
let g = pointer[i + 1]
|
||||
let b = pointer[i + 2]
|
||||
let Y = 0.2126 * CGFloat(r) + 0.7152 * CGFloat(g) + 0.0722 * CGFloat(b)
|
||||
luma += Y
|
||||
}
|
||||
luma /= CGFloat(width * height)
|
||||
return luma
|
||||
}
|
||||
}
|
||||
|
||||
#if canImport(SwiftUI) && DEBUG
|
||||
import SwiftUI
|
||||
import UIKit
|
||||
|
||||
class BrightnessView: UIView {
|
||||
let label = UILabel()
|
||||
let imageView = UIImageView()
|
||||
|
||||
override init(frame: CGRect) {
|
||||
super.init(frame: frame)
|
||||
|
||||
let stackView = UIStackView()
|
||||
stackView.axis = .horizontal
|
||||
stackView.translatesAutoresizingMaskIntoConstraints = false
|
||||
addSubview(stackView)
|
||||
NSLayoutConstraint.activate([
|
||||
stackView.topAnchor.constraint(equalTo: topAnchor),
|
||||
stackView.leadingAnchor.constraint(equalTo: leadingAnchor),
|
||||
stackView.trailingAnchor.constraint(equalTo: trailingAnchor),
|
||||
stackView.bottomAnchor.constraint(equalTo: bottomAnchor),
|
||||
])
|
||||
stackView.distribution = .fillEqually
|
||||
stackView.addArrangedSubview(imageView)
|
||||
stackView.addArrangedSubview(label)
|
||||
|
||||
imageView.contentMode = .scaleAspectFill
|
||||
imageView.layer.masksToBounds = true
|
||||
label.textAlignment = .center
|
||||
label.numberOfLines = 0
|
||||
}
|
||||
|
||||
required init?(coder: NSCoder) {
|
||||
fatalError("init(coder:) has not been implemented")
|
||||
}
|
||||
|
||||
func setImage(_ image: UIImage) {
|
||||
imageView.image = image
|
||||
|
||||
guard let brightness = image.cgImage?.brightness,
|
||||
let style = image.domainLumaCoefficientsStyle else {
|
||||
label.text = "<nil>"
|
||||
return
|
||||
}
|
||||
let styleDescription: String = {
|
||||
switch style {
|
||||
case .light: return "Light"
|
||||
case .dark: return "Dark"
|
||||
case .unspecified: fallthrough
|
||||
@unknown default:
|
||||
return "Unknown"
|
||||
}
|
||||
}()
|
||||
|
||||
label.text = styleDescription + "\n" + "\(brightness)"
|
||||
}
|
||||
}
|
||||
|
||||
struct CGImage_Brightness_Previews: PreviewProvider {
|
||||
|
||||
static var previews: some View {
|
||||
Group {
|
||||
UIViewPreview(width: 375) {
|
||||
let view = BrightnessView()
|
||||
view.setImage(.placeholder(color: .black))
|
||||
return view
|
||||
}
|
||||
.previewLayout(.fixed(width: 375, height: 44))
|
||||
UIViewPreview(width: 375) {
|
||||
let view = BrightnessView()
|
||||
view.setImage(.placeholder(color: .gray))
|
||||
return view
|
||||
}
|
||||
.previewLayout(.fixed(width: 375, height: 44))
|
||||
UIViewPreview(width: 375) {
|
||||
let view = BrightnessView()
|
||||
view.setImage(.placeholder(color: .separator))
|
||||
return view
|
||||
}
|
||||
.previewLayout(.fixed(width: 375, height: 44))
|
||||
UIViewPreview(width: 375) {
|
||||
let view = BrightnessView()
|
||||
view.setImage(.placeholder(color: .red))
|
||||
return view
|
||||
}
|
||||
.previewLayout(.fixed(width: 375, height: 44))
|
||||
UIViewPreview(width: 375) {
|
||||
let view = BrightnessView()
|
||||
view.setImage(.placeholder(color: .green))
|
||||
return view
|
||||
}
|
||||
.previewLayout(.fixed(width: 375, height: 44))
|
||||
UIViewPreview(width: 375) {
|
||||
let view = BrightnessView()
|
||||
view.setImage(.placeholder(color: .blue))
|
||||
return view
|
||||
}
|
||||
.previewLayout(.fixed(width: 375, height: 44))
|
||||
UIViewPreview(width: 375) {
|
||||
let view = BrightnessView()
|
||||
view.setImage(.placeholder(color: .secondarySystemGroupedBackground))
|
||||
return view
|
||||
}
|
||||
.previewLayout(.fixed(width: 375, height: 44))
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
|
@ -32,23 +32,6 @@ internal enum Asset {
|
|||
internal static let plusCircle = ImageAsset(name: "Circles/plus.circle")
|
||||
}
|
||||
internal enum Colors {
|
||||
internal enum Background {
|
||||
internal enum Poll {
|
||||
internal static let disabled = ColorAsset(name: "Colors/Background/Poll/disabled")
|
||||
}
|
||||
internal static let alertYellow = ColorAsset(name: "Colors/Background/alert.yellow")
|
||||
internal static let dangerBorder = ColorAsset(name: "Colors/Background/danger.border")
|
||||
internal static let danger = ColorAsset(name: "Colors/Background/danger")
|
||||
internal static let mediaTypeIndicotor = ColorAsset(name: "Colors/Background/media.type.indicotor")
|
||||
internal static let onboardingBackground = ColorAsset(name: "Colors/Background/onboarding.background")
|
||||
internal static let secondaryGroupedSystemBackground = ColorAsset(name: "Colors/Background/secondary.grouped.system.background")
|
||||
internal static let secondarySystemBackground = ColorAsset(name: "Colors/Background/secondary.system.background")
|
||||
internal static let systemBackground = ColorAsset(name: "Colors/Background/system.background")
|
||||
internal static let systemElevatedBackground = ColorAsset(name: "Colors/Background/system.elevated.background")
|
||||
internal static let systemGroupedBackground = ColorAsset(name: "Colors/Background/system.grouped.background")
|
||||
internal static let tertiarySystemBackground = ColorAsset(name: "Colors/Background/tertiary.system.background")
|
||||
internal static let tertiarySystemGroupedBackground = ColorAsset(name: "Colors/Background/tertiary.system.grouped.background")
|
||||
}
|
||||
internal enum Border {
|
||||
internal static let composePoll = ColorAsset(name: "Colors/Border/compose.poll")
|
||||
internal static let notificationStatus = ColorAsset(name: "Colors/Border/notification.status")
|
||||
|
@ -73,6 +56,9 @@ internal enum Asset {
|
|||
internal static let mention = ColorAsset(name: "Colors/Notification/mention")
|
||||
internal static let reblog = ColorAsset(name: "Colors/Notification/reblog")
|
||||
}
|
||||
internal enum Poll {
|
||||
internal static let disabled = ColorAsset(name: "Colors/Poll/disabled")
|
||||
}
|
||||
internal enum Shadow {
|
||||
internal static let searchCard = ColorAsset(name: "Colors/Shadow/SearchCard")
|
||||
}
|
||||
|
@ -87,12 +73,15 @@ internal enum Asset {
|
|||
internal static let invalid = ColorAsset(name: "Colors/TextField/invalid")
|
||||
internal static let valid = ColorAsset(name: "Colors/TextField/valid")
|
||||
}
|
||||
internal static let alertYellow = ColorAsset(name: "Colors/alert.yellow")
|
||||
internal static let battleshipGrey = ColorAsset(name: "Colors/battleshipGrey")
|
||||
internal static let brandBlue = ColorAsset(name: "Colors/brand.blue")
|
||||
internal static let brandBlueDarken20 = ColorAsset(name: "Colors/brand.blue.darken.20")
|
||||
internal static let dangerBorder = ColorAsset(name: "Colors/danger.border")
|
||||
internal static let danger = ColorAsset(name: "Colors/danger")
|
||||
internal static let disabled = ColorAsset(name: "Colors/disabled")
|
||||
internal static let inactive = ColorAsset(name: "Colors/inactive")
|
||||
internal static let mediaTypeIndicotor = ColorAsset(name: "Colors/media.type.indicotor")
|
||||
internal static let successGreen = ColorAsset(name: "Colors/success.green")
|
||||
internal static let systemOrange = ColorAsset(name: "Colors/system.orange")
|
||||
}
|
||||
|
@ -103,10 +92,6 @@ internal enum Asset {
|
|||
internal static let faceSmilingAdaptive = ImageAsset(name: "Human/face.smiling.adaptive")
|
||||
}
|
||||
internal enum Scene {
|
||||
internal enum Compose {
|
||||
internal static let background = ColorAsset(name: "Scene/Compose/background")
|
||||
internal static let toolbarBackground = ColorAsset(name: "Scene/Compose/toolbar.background")
|
||||
}
|
||||
internal enum Profile {
|
||||
internal enum Banner {
|
||||
internal static let bioEditBackgroundGray = ColorAsset(name: "Scene/Profile/Banner/bio.edit.background.gray")
|
||||
|
@ -136,6 +121,7 @@ internal enum Asset {
|
|||
}
|
||||
internal enum Theme {
|
||||
internal enum Mastodon {
|
||||
internal static let composeToolbarBackground = ColorAsset(name: "Theme/Mastodon/compose.toolbar.background")
|
||||
internal static let contentWarningOverlayBackground = ColorAsset(name: "Theme/Mastodon/content.warning.overlay.background")
|
||||
internal static let navigationBarBackground = ColorAsset(name: "Theme/Mastodon/navigation.bar.background")
|
||||
internal static let profileFieldCollectionViewBackground = ColorAsset(name: "Theme/Mastodon/profile.field.collection.view.background")
|
||||
|
@ -153,6 +139,7 @@ internal enum Asset {
|
|||
internal static let tabBarItemInactiveIconColor = ColorAsset(name: "Theme/Mastodon/tab.bar.item.inactive.icon.color")
|
||||
}
|
||||
internal enum System {
|
||||
internal static let composeToolbarBackground = ColorAsset(name: "Theme/system/compose.toolbar.background")
|
||||
internal static let contentWarningOverlayBackground = ColorAsset(name: "Theme/system/content.warning.overlay.background")
|
||||
internal static let navigationBarBackground = ColorAsset(name: "Theme/system/navigation.bar.background")
|
||||
internal static let profileFieldCollectionViewBackground = ColorAsset(name: "Theme/system/profile.field.collection.view.background")
|
||||
|
@ -170,6 +157,23 @@ internal enum Asset {
|
|||
internal static let tabBarItemInactiveIconColor = ColorAsset(name: "Theme/system/tab.bar.item.inactive.icon.color")
|
||||
}
|
||||
}
|
||||
internal enum Deprecated {
|
||||
internal enum Background {
|
||||
internal static let danger = ColorAsset(name: "_Deprecated/Background/danger")
|
||||
internal static let onboardingBackground = ColorAsset(name: "_Deprecated/Background/onboarding.background")
|
||||
internal static let secondaryGroupedSystemBackground = ColorAsset(name: "_Deprecated/Background/secondary.grouped.system.background")
|
||||
internal static let secondarySystemBackground = ColorAsset(name: "_Deprecated/Background/secondary.system.background")
|
||||
internal static let systemBackground = ColorAsset(name: "_Deprecated/Background/system.background")
|
||||
internal static let systemElevatedBackground = ColorAsset(name: "_Deprecated/Background/system.elevated.background")
|
||||
internal static let systemGroupedBackground = ColorAsset(name: "_Deprecated/Background/system.grouped.background")
|
||||
internal static let tertiarySystemBackground = ColorAsset(name: "_Deprecated/Background/tertiary.system.background")
|
||||
internal static let tertiarySystemGroupedBackground = ColorAsset(name: "_Deprecated/Background/tertiary.system.grouped.background")
|
||||
}
|
||||
internal enum Compose {
|
||||
internal static let background = ColorAsset(name: "_Deprecated/Compose/background")
|
||||
internal static let toolbarBackground = ColorAsset(name: "_Deprecated/Compose/toolbar.background")
|
||||
}
|
||||
}
|
||||
}
|
||||
// swiftlint:enable identifier_name line_length nesting type_body_length type_name
|
||||
|
||||
|
|
|
@ -58,11 +58,11 @@ internal enum L10n {
|
|||
internal static let message = L10n.tr("Localizable", "Common.Alerts.PublishPostFailure.Message")
|
||||
/// Publish Failure
|
||||
internal static let title = L10n.tr("Localizable", "Common.Alerts.PublishPostFailure.Title")
|
||||
internal enum AttchmentsMessage {
|
||||
internal enum AttachmentsMessage {
|
||||
/// Cannot attach more than one video.
|
||||
internal static let moreThanOneVideo = L10n.tr("Localizable", "Common.Alerts.PublishPostFailure.AttchmentsMessage.MoreThanOneVideo")
|
||||
internal static let moreThanOneVideo = L10n.tr("Localizable", "Common.Alerts.PublishPostFailure.AttachmentsMessage.MoreThanOneVideo")
|
||||
/// Cannot attach a video to a post that already contains images.
|
||||
internal static let videoAttachWithPhoto = L10n.tr("Localizable", "Common.Alerts.PublishPostFailure.AttchmentsMessage.VideoAttachWithPhoto")
|
||||
internal static let videoAttachWithPhoto = L10n.tr("Localizable", "Common.Alerts.PublishPostFailure.AttachmentsMessage.VideoAttachWithPhoto")
|
||||
}
|
||||
}
|
||||
internal enum SavePhotoFailure {
|
||||
|
@ -950,7 +950,7 @@ internal enum L10n {
|
|||
internal static let trueBlackDarkMode = L10n.tr("Localizable", "Scene.Settings.Section.AppearanceSettings.TrueBlackDarkMode")
|
||||
}
|
||||
internal enum BoringZone {
|
||||
/// Account settings
|
||||
/// Account Settings
|
||||
internal static let accountSettings = L10n.tr("Localizable", "Scene.Settings.Section.BoringZone.AccountSettings")
|
||||
/// Privacy Policy
|
||||
internal static let privacy = L10n.tr("Localizable", "Scene.Settings.Section.BoringZone.Privacy")
|
||||
|
|
|
@ -0,0 +1,17 @@
|
|||
//
|
||||
// MastodonAuthenticationBox.swift
|
||||
// Mastodon
|
||||
//
|
||||
// Created by MainasuK Cirno on 2021-7-20.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import MastodonSDK
|
||||
import CoreDataStack
|
||||
|
||||
struct MastodonAuthenticationBox {
|
||||
let domain: String
|
||||
let userID: MastodonUser.ID
|
||||
let appAuthorization: Mastodon.API.OAuth.Authorization
|
||||
let userAuthorization: Mastodon.API.OAuth.Authorization
|
||||
}
|
|
@ -5,59 +5,59 @@
|
|||
// Created by MainasuK Cirno on 2021-3-30.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import ActiveLabel
|
||||
|
||||
enum MastodonField {
|
||||
|
||||
@available(*, deprecated, message: "rely on server meta rendering")
|
||||
static func parse(field string: String, emojiDict: MastodonStatusContent.EmojiDict) -> ParseResult {
|
||||
// use content parser get emoji entities
|
||||
let value = string
|
||||
|
||||
var string = string
|
||||
var entities: [ActiveEntity] = []
|
||||
|
||||
do {
|
||||
let contentParseresult = try MastodonStatusContent.parse(content: string, emojiDict: emojiDict)
|
||||
string = contentParseresult.trimmed
|
||||
entities.append(contentsOf: contentParseresult.activeEntities)
|
||||
} catch {
|
||||
// assertionFailure(error.localizedDescription)
|
||||
}
|
||||
|
||||
let mentionMatches = string.matches(pattern: "(?:@([a-zA-Z0-9_]+)(@[a-zA-Z0-9_.-]+)?)")
|
||||
let hashtagMatches = string.matches(pattern: "(?:#([^\\s.]+))")
|
||||
let urlMatches = string.matches(pattern: "(?i)https?://\\S+(?:/|\\b)")
|
||||
|
||||
|
||||
for match in mentionMatches {
|
||||
guard let text = string.substring(with: match, at: 0) else { continue }
|
||||
let entity = ActiveEntity(range: match.range, type: .mention(text, userInfo: nil))
|
||||
entities.append(entity)
|
||||
}
|
||||
|
||||
for match in hashtagMatches {
|
||||
guard let text = string.substring(with: match, at: 0) else { continue }
|
||||
let entity = ActiveEntity(range: match.range, type: .hashtag(text, userInfo: nil))
|
||||
entities.append(entity)
|
||||
}
|
||||
|
||||
for match in urlMatches {
|
||||
guard let text = string.substring(with: match, at: 0) else { continue }
|
||||
let entity = ActiveEntity(range: match.range, type: .url(text, trimmed: text, url: text, userInfo: nil))
|
||||
entities.append(entity)
|
||||
}
|
||||
|
||||
return ParseResult(value: value, trimmed: string, activeEntities: entities)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
extension MastodonField {
|
||||
struct ParseResult {
|
||||
let value: String
|
||||
let trimmed: String
|
||||
let activeEntities: [ActiveEntity]
|
||||
}
|
||||
}
|
||||
//import Foundation
|
||||
//import ActiveLabel
|
||||
//
|
||||
//enum MastodonField {
|
||||
//
|
||||
// @available(*, deprecated, message: "rely on server meta rendering")
|
||||
// public static func parse(field string: String, emojiDict: MastodonStatusContent.EmojiDict) -> ParseResult {
|
||||
// // use content parser get emoji entities
|
||||
// let value = string
|
||||
//
|
||||
// var string = string
|
||||
// var entities: [ActiveEntity] = []
|
||||
//
|
||||
// do {
|
||||
// let contentParseresult = try MastodonStatusContent.parse(content: string, emojiDict: emojiDict)
|
||||
// string = contentParseresult.trimmed
|
||||
// entities.append(contentsOf: contentParseresult.activeEntities)
|
||||
// } catch {
|
||||
// // assertionFailure(error.localizedDescription)
|
||||
// }
|
||||
//
|
||||
// let mentionMatches = string.matches(pattern: "(?:@([a-zA-Z0-9_]+)(@[a-zA-Z0-9_.-]+)?)")
|
||||
// let hashtagMatches = string.matches(pattern: "(?:#([^\\s.]+))")
|
||||
// let urlMatches = string.matches(pattern: "(?i)https?://\\S+(?:/|\\b)")
|
||||
//
|
||||
//
|
||||
// for match in mentionMatches {
|
||||
// guard let text = string.substring(with: match, at: 0) else { continue }
|
||||
// let entity = ActiveEntity(range: match.range, type: .mention(text, userInfo: nil))
|
||||
// entities.append(entity)
|
||||
// }
|
||||
//
|
||||
// for match in hashtagMatches {
|
||||
// guard let text = string.substring(with: match, at: 0) else { continue }
|
||||
// let entity = ActiveEntity(range: match.range, type: .hashtag(text, userInfo: nil))
|
||||
// entities.append(entity)
|
||||
// }
|
||||
//
|
||||
// for match in urlMatches {
|
||||
// guard let text = string.substring(with: match, at: 0) else { continue }
|
||||
// let entity = ActiveEntity(range: match.range, type: .url(text, trimmed: text, url: text, userInfo: nil))
|
||||
// entities.append(entity)
|
||||
// }
|
||||
//
|
||||
// return ParseResult(value: value, trimmed: string, activeEntities: entities)
|
||||
// }
|
||||
//
|
||||
//}
|
||||
//
|
||||
//extension MastodonField {
|
||||
// public struct ParseResult {
|
||||
// let value: String
|
||||
// let trimmed: String
|
||||
// let activeEntities: [ActiveEntity]
|
||||
// }
|
||||
//}
|
||||
|
|
|
@ -7,9 +7,9 @@
|
|||
|
||||
import Foundation
|
||||
|
||||
final class MastodonMetricFormatter: Formatter {
|
||||
final public class MastodonMetricFormatter: Formatter {
|
||||
|
||||
func string(from number: Int) -> String? {
|
||||
public func string(from number: Int) -> String? {
|
||||
let isPositive = number >= 0
|
||||
let symbol = isPositive ? "" : "-"
|
||||
|
||||
|
|
|
@ -7,19 +7,19 @@
|
|||
|
||||
import Foundation
|
||||
|
||||
enum MastodonRegex {
|
||||
public enum MastodonRegex {
|
||||
/// mention, hashtag.
|
||||
/// @...
|
||||
/// #...
|
||||
static let highlightPattern = "(?:@([a-zA-Z0-9_]+)(@[a-zA-Z0-9_.-]+)?|#([^\\s.]+))"
|
||||
public static let highlightPattern = "(?:@([a-zA-Z0-9_]+)(@[a-zA-Z0-9_.-]+)?|#([^\\s.]+))"
|
||||
/// emoji
|
||||
/// :shortcode:
|
||||
/// accept ^\B: or \s: but not accept \B: to force user input a space to make emoji take effect
|
||||
/// precondition :\B with following space
|
||||
static let emojiPattern = "(?:(^\\B:|\\s:)([a-zA-Z0-9_]+)(:\\B(?=\\s)))"
|
||||
public static let emojiPattern = "(?:(^\\B:|\\s:)([a-zA-Z0-9_]+)(:\\B(?=\\s)))"
|
||||
/// mention, hashtag, emoji
|
||||
/// @…
|
||||
/// #…
|
||||
/// :…
|
||||
static let autoCompletePattern = "(?:@([a-zA-Z0-9_]+)(@[a-zA-Z0-9_.-]+)?|#([^\\s.]+))|(^\\B:|\\s:)([a-zA-Z0-9_]+)"
|
||||
public static let autoCompletePattern = "(?:@([a-zA-Z0-9_]+)(@[a-zA-Z0-9_.-]+)?|#([^\\s.]+))|(^\\B:|\\s:)([a-zA-Z0-9_]+)"
|
||||
}
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
import UIKit
|
||||
|
||||
extension MastodonStatusContent {
|
||||
struct Appearance {
|
||||
public struct Appearance {
|
||||
let attributes: [NSAttributedString.Key: Any]
|
||||
let urlAttributes: [NSAttributedString.Key: Any]
|
||||
let hashtagAttributes: [NSAttributedString.Key: Any]
|
||||
|
|
|
@ -9,20 +9,20 @@ import Foundation
|
|||
import ActiveLabel
|
||||
|
||||
extension MastodonStatusContent {
|
||||
struct ParseResult: Hashable {
|
||||
let document: String
|
||||
let original: String
|
||||
let trimmed: String
|
||||
let activeEntities: [ActiveEntity]
|
||||
public struct ParseResult: Hashable {
|
||||
public let document: String
|
||||
public let original: String
|
||||
public let trimmed: String
|
||||
public let activeEntities: [ActiveEntity]
|
||||
|
||||
static func == (lhs: MastodonStatusContent.ParseResult, rhs: MastodonStatusContent.ParseResult) -> Bool {
|
||||
public static func == (lhs: MastodonStatusContent.ParseResult, rhs: MastodonStatusContent.ParseResult) -> Bool {
|
||||
return lhs.document == rhs.document
|
||||
&& lhs.original == rhs.original
|
||||
&& lhs.trimmed == rhs.trimmed
|
||||
&& lhs.activeEntities.count == rhs.activeEntities.count // FIXME:
|
||||
}
|
||||
|
||||
func hash(into hasher: inout Hasher) {
|
||||
public func hash(into hasher: inout Hasher) {
|
||||
hasher.combine(document)
|
||||
hasher.combine(original)
|
||||
hasher.combine(trimmed)
|
||||
|
@ -57,7 +57,7 @@ extension ActiveEntityType {
|
|||
|
||||
static let appScheme = "mastodon"
|
||||
|
||||
init?(url: URL) {
|
||||
public init?(url: URL) {
|
||||
guard let scheme = url.scheme?.lowercased() else { return nil }
|
||||
guard scheme == ActiveEntityType.appScheme else {
|
||||
self = .url("", trimmed: "", url: url.absoluteString, userInfo: nil)
|
||||
|
@ -78,7 +78,7 @@ extension ActiveEntityType {
|
|||
return nil
|
||||
}
|
||||
|
||||
var uri: URL? {
|
||||
public var uri: URL? {
|
||||
switch self {
|
||||
case .url(_, _, let url, _):
|
||||
return URL(string: url)
|
||||
|
|
|
@ -10,14 +10,14 @@ import Combine
|
|||
import ActiveLabel
|
||||
import Fuzi
|
||||
|
||||
enum MastodonStatusContent {
|
||||
public enum MastodonStatusContent {
|
||||
|
||||
typealias EmojiShortcode = String
|
||||
typealias EmojiDict = [EmojiShortcode: URL]
|
||||
public typealias EmojiShortcode = String
|
||||
public typealias EmojiDict = [EmojiShortcode: URL]
|
||||
|
||||
static let workingQueue = DispatchQueue(label: "org.joinmastodon.app.ActiveLabel.working-queue", qos: .userInteractive, attributes: .concurrent)
|
||||
|
||||
static func parseResult(content: String, emojiDict: MastodonStatusContent.EmojiDict) -> AnyPublisher<MastodonStatusContent.ParseResult?, Never> {
|
||||
public static func parseResult(content: String, emojiDict: MastodonStatusContent.EmojiDict) -> AnyPublisher<MastodonStatusContent.ParseResult?, Never> {
|
||||
return Future { promise in
|
||||
self.workingQueue.async {
|
||||
let parseResult = try? MastodonStatusContent.parse(content: content, emojiDict: emojiDict)
|
||||
|
@ -27,7 +27,7 @@ enum MastodonStatusContent {
|
|||
.eraseToAnyPublisher()
|
||||
}
|
||||
|
||||
static func parse(content: String, emojiDict: EmojiDict) throws -> MastodonStatusContent.ParseResult {
|
||||
public static func parse(content: String, emojiDict: EmojiDict) throws -> MastodonStatusContent.ParseResult {
|
||||
let document: String = {
|
||||
var content = content
|
||||
for (shortcode, url) in emojiDict {
|
||||
|
|
|
@ -19,7 +19,8 @@ extension UserDefaults {
|
|||
|
||||
@objc dynamic var preferredStaticAvatar: Bool {
|
||||
get {
|
||||
register(defaults: [#function: false])
|
||||
// default false
|
||||
// without set register to profile timeline performance
|
||||
return bool(forKey: #function)
|
||||
}
|
||||
set { self[#function] = newValue }
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
//
|
||||
|
||||
import UIKit
|
||||
import MastodonExtension
|
||||
|
||||
extension UserDefaults {
|
||||
|
||||
|
|
|
@ -1,12 +0,0 @@
|
|||
//
|
||||
// SplashPreference.swift
|
||||
// Mastodon
|
||||
//
|
||||
// Created by Cirno MainasuK on 2020-2-4.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
|
||||
extension UserDefaults {
|
||||
// TODO: splash scene
|
||||
}
|
|
@ -6,6 +6,7 @@
|
|||
//
|
||||
|
||||
import UIKit
|
||||
import MastodonExtension
|
||||
|
||||
extension UserDefaults {
|
||||
|
||||
|
|
|
@ -24,11 +24,22 @@ extension AvatarConfigurableView {
|
|||
public func configure(with configuration: AvatarConfigurableViewConfiguration) {
|
||||
let placeholderImage: UIImage = {
|
||||
guard let placeholderImage = configuration.placeholderImage else {
|
||||
#if APP_EXTENSION
|
||||
let placeholderImage = configuration.placeholderImage ?? UIImage.placeholder(size: Self.configurableAvatarImageSize, color: .systemFill)
|
||||
if Self.configurableAvatarImageCornerRadius < Self.configurableAvatarImageSize.width * 0.5 {
|
||||
return placeholderImage
|
||||
.af.imageAspectScaled(toFill: Self.configurableAvatarImageSize)
|
||||
.af.imageRounded(withCornerRadius: Self.configurableAvatarImageCornerRadius, divideRadiusByImageScale: false)
|
||||
} else {
|
||||
return placeholderImage.af.imageRoundedIntoCircle()
|
||||
}
|
||||
#else
|
||||
return AppContext.shared.placeholderImageCacheService.image(
|
||||
color: .systemFill,
|
||||
size: Self.configurableAvatarImageSize,
|
||||
cornerRadius: Self.configurableAvatarImageCornerRadius
|
||||
)
|
||||
#endif
|
||||
}
|
||||
return placeholderImage
|
||||
}()
|
||||
|
@ -115,7 +126,7 @@ extension AvatarConfigurableView {
|
|||
}
|
||||
|
||||
struct AvatarConfigurableViewConfiguration {
|
||||
|
||||
|
||||
let avatarImageURL: URL?
|
||||
let placeholderImage: UIImage?
|
||||
let borderColor: UIColor?
|
||||
|
|
|
@ -525,7 +525,10 @@ extension StatusProviderFacade {
|
|||
.sink { [weak provider] status in
|
||||
guard let provider = provider else { return }
|
||||
guard let status = status?.reblog ?? status else { return }
|
||||
|
||||
|
||||
let generator = UIImpactFeedbackGenerator(style: .light)
|
||||
generator.impactOccurred()
|
||||
|
||||
let composeViewModel = ComposeViewModel(context: provider.context, composeKind: .reply(repliedToStatusObjectID: status.objectID))
|
||||
provider.coordinator.present(scene: .compose(viewModel: composeViewModel), from: provider, transition: .modal(animated: true, completion: nil))
|
||||
}
|
||||
|
|
|
@ -49,7 +49,7 @@ extension UserProviderFacade {
|
|||
|
||||
private static func _toggleUserFollowRelationship(
|
||||
context: AppContext,
|
||||
activeMastodonAuthenticationBox: AuthenticationService.MastodonAuthenticationBox,
|
||||
activeMastodonAuthenticationBox: MastodonAuthenticationBox,
|
||||
mastodonUser: AnyPublisher<MastodonUser?, Never>
|
||||
) -> AnyPublisher<Mastodon.Response.Content<Mastodon.Entity.Relationship>, Error> {
|
||||
mastodonUser
|
||||
|
@ -111,7 +111,7 @@ extension UserProviderFacade {
|
|||
|
||||
private static func _toggleUserBlockRelationship(
|
||||
context: AppContext,
|
||||
activeMastodonAuthenticationBox: AuthenticationService.MastodonAuthenticationBox,
|
||||
activeMastodonAuthenticationBox: MastodonAuthenticationBox,
|
||||
mastodonUser: AnyPublisher<MastodonUser?, Never>
|
||||
) -> AnyPublisher<Mastodon.Response.Content<Mastodon.Entity.Relationship>, Error> {
|
||||
mastodonUser
|
||||
|
@ -174,7 +174,7 @@ extension UserProviderFacade {
|
|||
|
||||
private static func _toggleUserMuteRelationship(
|
||||
context: AppContext,
|
||||
activeMastodonAuthenticationBox: AuthenticationService.MastodonAuthenticationBox,
|
||||
activeMastodonAuthenticationBox: MastodonAuthenticationBox,
|
||||
mastodonUser: AnyPublisher<MastodonUser?, Never>
|
||||
) -> AnyPublisher<Mastodon.Response.Content<Mastodon.Entity.Relationship>, Error> {
|
||||
mastodonUser
|
||||
|
|
|
@ -1,38 +0,0 @@
|
|||
{
|
||||
"colors" : [
|
||||
{
|
||||
"color" : {
|
||||
"color-space" : "srgb",
|
||||
"components" : {
|
||||
"alpha" : "1.000",
|
||||
"blue" : "0xE8",
|
||||
"green" : "0xE1",
|
||||
"red" : "0xD9"
|
||||
}
|
||||
},
|
||||
"idiom" : "universal"
|
||||
},
|
||||
{
|
||||
"appearances" : [
|
||||
{
|
||||
"appearance" : "luminosity",
|
||||
"value" : "dark"
|
||||
}
|
||||
],
|
||||
"color" : {
|
||||
"color-space" : "srgb",
|
||||
"components" : {
|
||||
"alpha" : "1.000",
|
||||
"blue" : "34",
|
||||
"green" : "27",
|
||||
"red" : "25"
|
||||
}
|
||||
},
|
||||
"idiom" : "universal"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
}
|
||||
}
|
|
@ -1,38 +0,0 @@
|
|||
{
|
||||
"colors" : [
|
||||
{
|
||||
"color" : {
|
||||
"color-space" : "srgb",
|
||||
"components" : {
|
||||
"alpha" : "1.000",
|
||||
"blue" : "0xFE",
|
||||
"green" : "0xFF",
|
||||
"red" : "0xFE"
|
||||
}
|
||||
},
|
||||
"idiom" : "universal"
|
||||
},
|
||||
{
|
||||
"appearances" : [
|
||||
{
|
||||
"appearance" : "luminosity",
|
||||
"value" : "dark"
|
||||
}
|
||||
],
|
||||
"color" : {
|
||||
"color-space" : "srgb",
|
||||
"components" : {
|
||||
"alpha" : "1.000",
|
||||
"blue" : "55",
|
||||
"green" : "44",
|
||||
"red" : "40"
|
||||
}
|
||||
},
|
||||
"idiom" : "universal"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
}
|
||||
}
|
|
@ -1,38 +0,0 @@
|
|||
{
|
||||
"colors" : [
|
||||
{
|
||||
"color" : {
|
||||
"color-space" : "srgb",
|
||||
"components" : {
|
||||
"alpha" : "1.000",
|
||||
"blue" : "0xE8",
|
||||
"green" : "0xE1",
|
||||
"red" : "0xD9"
|
||||
}
|
||||
},
|
||||
"idiom" : "universal"
|
||||
},
|
||||
{
|
||||
"appearances" : [
|
||||
{
|
||||
"appearance" : "luminosity",
|
||||
"value" : "dark"
|
||||
}
|
||||
],
|
||||
"color" : {
|
||||
"color-space" : "srgb",
|
||||
"components" : {
|
||||
"alpha" : "1.000",
|
||||
"blue" : "67",
|
||||
"green" : "53",
|
||||
"red" : "49"
|
||||
}
|
||||
},
|
||||
"idiom" : "universal"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
}
|
||||
}
|
|
@ -5,9 +5,9 @@
|
|||
"color-space" : "srgb",
|
||||
"components" : {
|
||||
"alpha" : "1.000",
|
||||
"blue" : "90",
|
||||
"green" : "64",
|
||||
"red" : "223"
|
||||
"blue" : "0.259",
|
||||
"green" : "0.180",
|
||||
"red" : "0.639"
|
||||
}
|
||||
},
|
||||
"idiom" : "universal"
|
|
@ -5,9 +5,9 @@
|
|||
"color-space" : "srgb",
|
||||
"components" : {
|
||||
"alpha" : "0.600",
|
||||
"blue" : "0",
|
||||
"green" : "0",
|
||||
"red" : "0"
|
||||
"blue" : "0.000",
|
||||
"green" : "0.000",
|
||||
"red" : "0.000"
|
||||
}
|
||||
},
|
||||
"idiom" : "universal"
|
|
@ -1,38 +0,0 @@
|
|||
{
|
||||
"colors" : [
|
||||
{
|
||||
"color" : {
|
||||
"color-space" : "srgb",
|
||||
"components" : {
|
||||
"alpha" : "1.000",
|
||||
"blue" : "222",
|
||||
"green" : "216",
|
||||
"red" : "214"
|
||||
}
|
||||
},
|
||||
"idiom" : "universal"
|
||||
},
|
||||
{
|
||||
"appearances" : [
|
||||
{
|
||||
"appearance" : "luminosity",
|
||||
"value" : "dark"
|
||||
}
|
||||
],
|
||||
"color" : {
|
||||
"color-space" : "srgb",
|
||||
"components" : {
|
||||
"alpha" : "1.000",
|
||||
"blue" : "32",
|
||||
"green" : "32",
|
||||
"red" : "32"
|
||||
}
|
||||
},
|
||||
"idiom" : "universal"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
}
|
||||
}
|
|
@ -5,9 +5,9 @@
|
|||
"color-space" : "srgb",
|
||||
"components" : {
|
||||
"alpha" : "1.000",
|
||||
"blue" : "254",
|
||||
"green" : "255",
|
||||
"red" : "254"
|
||||
"blue" : "0.871",
|
||||
"green" : "0.847",
|
||||
"red" : "0.839"
|
||||
}
|
||||
},
|
||||
"idiom" : "universal"
|
||||
|
@ -23,9 +23,9 @@
|
|||
"color-space" : "srgb",
|
||||
"components" : {
|
||||
"alpha" : "1.000",
|
||||
"blue" : "67",
|
||||
"green" : "53",
|
||||
"red" : "49"
|
||||
"blue" : "0.263",
|
||||
"green" : "0.208",
|
||||
"red" : "0.192"
|
||||
}
|
||||
},
|
||||
"idiom" : "universal"
|
|
@ -0,0 +1,38 @@
|
|||
{
|
||||
"colors" : [
|
||||
{
|
||||
"color" : {
|
||||
"color-space" : "srgb",
|
||||
"components" : {
|
||||
"alpha" : "1.000",
|
||||
"blue" : "0.871",
|
||||
"green" : "0.847",
|
||||
"red" : "0.839"
|
||||
}
|
||||
},
|
||||
"idiom" : "universal"
|
||||
},
|
||||
{
|
||||
"appearances" : [
|
||||
{
|
||||
"appearance" : "luminosity",
|
||||
"value" : "dark"
|
||||
}
|
||||
],
|
||||
"color" : {
|
||||
"color-space" : "srgb",
|
||||
"components" : {
|
||||
"alpha" : "0.920",
|
||||
"blue" : "0.125",
|
||||
"green" : "0.125",
|
||||
"red" : "0.125"
|
||||
}
|
||||
},
|
||||
"idiom" : "universal"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
}
|
||||
}
|
|
@ -5,9 +5,9 @@
|
|||
"color-space" : "srgb",
|
||||
"components" : {
|
||||
"alpha" : "1.000",
|
||||
"blue" : "232",
|
||||
"green" : "225",
|
||||
"red" : "217"
|
||||
"blue" : "0.353",
|
||||
"green" : "0.251",
|
||||
"red" : "0.875"
|
||||
}
|
||||
},
|
||||
"idiom" : "universal"
|
|
@ -5,9 +5,9 @@
|
|||
"color-space" : "srgb",
|
||||
"components" : {
|
||||
"alpha" : "1.000",
|
||||
"blue" : "66",
|
||||
"green" : "46",
|
||||
"red" : "163"
|
||||
"blue" : "0.910",
|
||||
"green" : "0.882",
|
||||
"red" : "0.851"
|
||||
}
|
||||
},
|
||||
"idiom" : "universal"
|
|
@ -5,9 +5,9 @@
|
|||
"color-space" : "srgb",
|
||||
"components" : {
|
||||
"alpha" : "1.000",
|
||||
"blue" : "232",
|
||||
"green" : "225",
|
||||
"red" : "217"
|
||||
"blue" : "0.996",
|
||||
"green" : "1.000",
|
||||
"red" : "0.996"
|
||||
}
|
||||
},
|
||||
"idiom" : "universal"
|
||||
|
@ -23,9 +23,9 @@
|
|||
"color-space" : "srgb",
|
||||
"components" : {
|
||||
"alpha" : "1.000",
|
||||
"blue" : "34",
|
||||
"green" : "27",
|
||||
"red" : "25"
|
||||
"blue" : "0.263",
|
||||
"green" : "0.208",
|
||||
"red" : "0.192"
|
||||
}
|
||||
},
|
||||
"idiom" : "universal"
|
|
@ -5,9 +5,9 @@
|
|||
"color-space" : "srgb",
|
||||
"components" : {
|
||||
"alpha" : "1.000",
|
||||
"blue" : "254",
|
||||
"green" : "255",
|
||||
"red" : "254"
|
||||
"blue" : "0.910",
|
||||
"green" : "0.882",
|
||||
"red" : "0.851"
|
||||
}
|
||||
},
|
||||
"idiom" : "universal"
|
||||
|
@ -23,9 +23,9 @@
|
|||
"color-space" : "srgb",
|
||||
"components" : {
|
||||
"alpha" : "1.000",
|
||||
"blue" : "0x37",
|
||||
"green" : "0x2C",
|
||||
"red" : "0x28"
|
||||
"blue" : "0.133",
|
||||
"green" : "0.106",
|
||||
"red" : "0.098"
|
||||
}
|
||||
},
|
||||
"idiom" : "universal"
|
|
@ -0,0 +1,38 @@
|
|||
{
|
||||
"colors" : [
|
||||
{
|
||||
"color" : {
|
||||
"color-space" : "srgb",
|
||||
"components" : {
|
||||
"alpha" : "1.000",
|
||||
"blue" : "0.996",
|
||||
"green" : "1.000",
|
||||
"red" : "0.996"
|
||||
}
|
||||
},
|
||||
"idiom" : "universal"
|
||||
},
|
||||
{
|
||||
"appearances" : [
|
||||
{
|
||||
"appearance" : "luminosity",
|
||||
"value" : "dark"
|
||||
}
|
||||
],
|
||||
"color" : {
|
||||
"color-space" : "srgb",
|
||||
"components" : {
|
||||
"alpha" : "1.000",
|
||||
"blue" : "0.216",
|
||||
"green" : "0.173",
|
||||
"red" : "0.157"
|
||||
}
|
||||
},
|
||||
"idiom" : "universal"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
}
|
||||
}
|
|
@ -23,9 +23,9 @@
|
|||
"color-space" : "srgb",
|
||||
"components" : {
|
||||
"alpha" : "1.000",
|
||||
"blue" : "55",
|
||||
"green" : "44",
|
||||
"red" : "40"
|
||||
"blue" : "0.216",
|
||||
"green" : "0.173",
|
||||
"red" : "0.157"
|
||||
}
|
||||
},
|
||||
"idiom" : "universal"
|
|
@ -0,0 +1,38 @@
|
|||
{
|
||||
"colors" : [
|
||||
{
|
||||
"color" : {
|
||||
"color-space" : "srgb",
|
||||
"components" : {
|
||||
"alpha" : "1.000",
|
||||
"blue" : "0.910",
|
||||
"green" : "0.882",
|
||||
"red" : "0.851"
|
||||
}
|
||||
},
|
||||
"idiom" : "universal"
|
||||
},
|
||||
{
|
||||
"appearances" : [
|
||||
{
|
||||
"appearance" : "luminosity",
|
||||
"value" : "dark"
|
||||
}
|
||||
],
|
||||
"color" : {
|
||||
"color-space" : "srgb",
|
||||
"components" : {
|
||||
"alpha" : "1.000",
|
||||
"blue" : "0.133",
|
||||
"green" : "0.106",
|
||||
"red" : "0.098"
|
||||
}
|
||||
},
|
||||
"idiom" : "universal"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
}
|
||||
}
|
|
@ -0,0 +1,38 @@
|
|||
{
|
||||
"colors" : [
|
||||
{
|
||||
"color" : {
|
||||
"color-space" : "srgb",
|
||||
"components" : {
|
||||
"alpha" : "1.000",
|
||||
"blue" : "0.996",
|
||||
"green" : "1.000",
|
||||
"red" : "0.996"
|
||||
}
|
||||
},
|
||||
"idiom" : "universal"
|
||||
},
|
||||
{
|
||||
"appearances" : [
|
||||
{
|
||||
"appearance" : "luminosity",
|
||||
"value" : "dark"
|
||||
}
|
||||
],
|
||||
"color" : {
|
||||
"color-space" : "srgb",
|
||||
"components" : {
|
||||
"alpha" : "1.000",
|
||||
"blue" : "0.216",
|
||||
"green" : "0.173",
|
||||
"red" : "0.157"
|
||||
}
|
||||
},
|
||||
"idiom" : "universal"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
}
|
||||
}
|
|
@ -0,0 +1,38 @@
|
|||
{
|
||||
"colors" : [
|
||||
{
|
||||
"color" : {
|
||||
"color-space" : "srgb",
|
||||
"components" : {
|
||||
"alpha" : "1.000",
|
||||
"blue" : "0.910",
|
||||
"green" : "0.882",
|
||||
"red" : "0.851"
|
||||
}
|
||||
},
|
||||
"idiom" : "universal"
|
||||
},
|
||||
{
|
||||
"appearances" : [
|
||||
{
|
||||
"appearance" : "luminosity",
|
||||
"value" : "dark"
|
||||
}
|
||||
],
|
||||
"color" : {
|
||||
"color-space" : "srgb",
|
||||
"components" : {
|
||||
"alpha" : "1.000",
|
||||
"blue" : "0.263",
|
||||
"green" : "0.208",
|
||||
"red" : "0.192"
|
||||
}
|
||||
},
|
||||
"idiom" : "universal"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
}
|
||||
}
|
|
@ -23,9 +23,9 @@
|
|||
"color-space" : "srgb",
|
||||
"components" : {
|
||||
"alpha" : "1.000",
|
||||
"blue" : "0x37",
|
||||
"green" : "0x2C",
|
||||
"red" : "0x28"
|
||||
"blue" : "0.216",
|
||||
"green" : "0.173",
|
||||
"red" : "0.157"
|
||||
}
|
||||
},
|
||||
"idiom" : "universal"
|
|
@ -0,0 +1,38 @@
|
|||
{
|
||||
"colors" : [
|
||||
{
|
||||
"color" : {
|
||||
"color-space" : "srgb",
|
||||
"components" : {
|
||||
"alpha" : "1.000",
|
||||
"blue" : "0.871",
|
||||
"green" : "0.847",
|
||||
"red" : "0.839"
|
||||
}
|
||||
},
|
||||
"idiom" : "universal"
|
||||
},
|
||||
{
|
||||
"appearances" : [
|
||||
{
|
||||
"appearance" : "luminosity",
|
||||
"value" : "dark"
|
||||
}
|
||||
],
|
||||
"color" : {
|
||||
"color-space" : "srgb",
|
||||
"components" : {
|
||||
"alpha" : "0.920",
|
||||
"blue" : "0.125",
|
||||
"green" : "0.125",
|
||||
"red" : "0.125"
|
||||
}
|
||||
},
|
||||
"idiom" : "universal"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
}
|
||||
}
|
|
@ -0,0 +1,9 @@
|
|||
{
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
},
|
||||
"properties" : {
|
||||
"provides-namespace" : true
|
||||
}
|
||||
}
|
|
@ -10,8 +10,8 @@
|
|||
"Common.Alerts.DiscardPostContent.Title" = "Discard Draft";
|
||||
"Common.Alerts.EditProfileFailure.Message" = "Cannot edit profile. Please try again.";
|
||||
"Common.Alerts.EditProfileFailure.Title" = "Edit Profile Error";
|
||||
"Common.Alerts.PublishPostFailure.AttchmentsMessage.MoreThanOneVideo" = "Cannot attach more than one video.";
|
||||
"Common.Alerts.PublishPostFailure.AttchmentsMessage.VideoAttachWithPhoto" = "Cannot attach a video to a post that already contains images.";
|
||||
"Common.Alerts.PublishPostFailure.AttachmentsMessage.MoreThanOneVideo" = "Cannot attach more than one video.";
|
||||
"Common.Alerts.PublishPostFailure.AttachmentsMessage.VideoAttachWithPhoto" = "Cannot attach a video to a post that already contains images.";
|
||||
"Common.Alerts.PublishPostFailure.Message" = "Failed to publish the post.
|
||||
Please check your internet connection.";
|
||||
"Common.Alerts.PublishPostFailure.Title" = "Publish Failure";
|
||||
|
@ -323,7 +323,7 @@ any server.";
|
|||
"Scene.Settings.Section.Appearance.Title" = "Appearance";
|
||||
"Scene.Settings.Section.AppearanceSettings.DisableAvatarAnimation" = "Disable animated avatars";
|
||||
"Scene.Settings.Section.AppearanceSettings.TrueBlackDarkMode" = "True black dark mode";
|
||||
"Scene.Settings.Section.BoringZone.AccountSettings" = "Account settings";
|
||||
"Scene.Settings.Section.BoringZone.AccountSettings" = "Account Settings";
|
||||
"Scene.Settings.Section.BoringZone.Privacy" = "Privacy Policy";
|
||||
"Scene.Settings.Section.BoringZone.Terms" = "Terms of Service";
|
||||
"Scene.Settings.Section.BoringZone.Title" = "The Boring Zone";
|
||||
|
|
|
@ -10,8 +10,8 @@
|
|||
"Common.Alerts.DiscardPostContent.Title" = "Discard Draft";
|
||||
"Common.Alerts.EditProfileFailure.Message" = "Cannot edit profile. Please try again.";
|
||||
"Common.Alerts.EditProfileFailure.Title" = "Edit Profile Error";
|
||||
"Common.Alerts.PublishPostFailure.AttchmentsMessage.MoreThanOneVideo" = "Cannot attach more than one video.";
|
||||
"Common.Alerts.PublishPostFailure.AttchmentsMessage.VideoAttachWithPhoto" = "Cannot attach a video to a post that already contains images.";
|
||||
"Common.Alerts.PublishPostFailure.AttachmentsMessage.MoreThanOneVideo" = "Cannot attach more than one video.";
|
||||
"Common.Alerts.PublishPostFailure.AttachmentsMessage.VideoAttachWithPhoto" = "Cannot attach a video to a post that already contains images.";
|
||||
"Common.Alerts.PublishPostFailure.Message" = "Failed to publish the post.
|
||||
Please check your internet connection.";
|
||||
"Common.Alerts.PublishPostFailure.Title" = "Publish Failure";
|
||||
|
@ -323,7 +323,7 @@ any server.";
|
|||
"Scene.Settings.Section.Appearance.Title" = "Appearance";
|
||||
"Scene.Settings.Section.AppearanceSettings.DisableAvatarAnimation" = "Disable animated avatars";
|
||||
"Scene.Settings.Section.AppearanceSettings.TrueBlackDarkMode" = "True black dark mode";
|
||||
"Scene.Settings.Section.BoringZone.AccountSettings" = "Account settings";
|
||||
"Scene.Settings.Section.BoringZone.AccountSettings" = "Account Settings";
|
||||
"Scene.Settings.Section.BoringZone.Privacy" = "Privacy Policy";
|
||||
"Scene.Settings.Section.BoringZone.Terms" = "Terms of Service";
|
||||
"Scene.Settings.Section.BoringZone.Title" = "The Boring Zone";
|
||||
|
|
|
@ -6,8 +6,11 @@
|
|||
//
|
||||
|
||||
import UIKit
|
||||
import Combine
|
||||
|
||||
final class AutoCompleteTopChevronView: UIView {
|
||||
|
||||
var disposeBag = Set<AnyCancellable>()
|
||||
|
||||
static let chevronSize = CGSize(width: 20, height: 12)
|
||||
|
||||
|
@ -16,10 +19,10 @@ final class AutoCompleteTopChevronView: UIView {
|
|||
private let maskLayer = CAShapeLayer()
|
||||
|
||||
var chevronMinX: CGFloat = 0
|
||||
var topViewBackgroundColor = Asset.Scene.Compose.background.color {
|
||||
var topViewBackgroundColor = ThemeService.shared.currentTheme.value.systemElevatedBackgroundColor {
|
||||
didSet { setNeedsLayout() }
|
||||
}
|
||||
var bottomViewBackgroundColor = Asset.Colors.Background.systemBackground.color {
|
||||
var bottomViewBackgroundColor = ThemeService.shared.currentTheme.value.systemBackgroundColor {
|
||||
didSet { setNeedsLayout() }
|
||||
}
|
||||
|
||||
|
@ -70,6 +73,15 @@ extension AutoCompleteTopChevronView {
|
|||
|
||||
shadowLayer.fillColor = topViewBackgroundColor.cgColor
|
||||
shadowView.layer.addSublayer(shadowLayer)
|
||||
|
||||
setupBackgroundColor(theme: ThemeService.shared.currentTheme.value)
|
||||
ThemeService.shared.currentTheme
|
||||
.receive(on: DispatchQueue.main)
|
||||
.sink { [weak self] theme in
|
||||
guard let self = self else { return }
|
||||
self.setupBackgroundColor(theme: theme)
|
||||
}
|
||||
.store(in: &disposeBag)
|
||||
}
|
||||
|
||||
override func layoutSubviews() {
|
||||
|
@ -114,6 +126,13 @@ extension AutoCompleteTopChevronView {
|
|||
|
||||
}
|
||||
|
||||
extension AutoCompleteTopChevronView {
|
||||
private func setupBackgroundColor(theme: Theme) {
|
||||
topViewBackgroundColor = theme.systemElevatedBackgroundColor
|
||||
bottomViewBackgroundColor = theme.systemBackgroundColor
|
||||
}
|
||||
}
|
||||
|
||||
extension AutoCompleteTopChevronView {
|
||||
func invertMask(in rect: CGRect) -> CAShapeLayer {
|
||||
let path = UIBezierPath()
|
||||
|
@ -153,7 +172,7 @@ struct AutoCompleteTopChevronView_Previews: PreviewProvider {
|
|||
view.chevronMinX = 10
|
||||
return view
|
||||
}
|
||||
.background(Color(Asset.Scene.Compose.background.color))
|
||||
.background(Color(ThemeService.shared.currentTheme.value.systemElevatedBackgroundColor))
|
||||
.padding(20)
|
||||
.previewLayout(.fixed(width: 375 + 40, height: 100 + 40))
|
||||
UIViewPreview(width: 375) {
|
||||
|
@ -166,7 +185,7 @@ struct AutoCompleteTopChevronView_Previews: PreviewProvider {
|
|||
view.chevronMinX = 10
|
||||
return view
|
||||
}
|
||||
.background(Color(Asset.Scene.Compose.background.color))
|
||||
.background(Color(ThemeService.shared.currentTheme.value.systemElevatedBackgroundColor))
|
||||
.preferredColorScheme(.dark)
|
||||
.padding(20)
|
||||
.previewLayout(.fixed(width: 375 + 40, height: 100 + 40))
|
||||
|
|
|
@ -8,13 +8,16 @@
|
|||
import os.log
|
||||
import UIKit
|
||||
import Combine
|
||||
import MastodonUI
|
||||
|
||||
protocol ComposeStatusAttachmentCollectionViewCellDelegate: AnyObject {
|
||||
func composeStatusAttachmentCollectionViewCell(_ cell: ComposeStatusAttachmentCollectionViewCell, removeButtonDidPressed button: UIButton)
|
||||
}
|
||||
|
||||
final class ComposeStatusAttachmentCollectionViewCell: UICollectionViewCell {
|
||||
|
||||
|
||||
let logger = Logger(subsystem: "ComposeStatusAttachmentCollectionViewCell", category: "UI")
|
||||
|
||||
var disposeBag = Set<AnyCancellable>()
|
||||
|
||||
static let verticalMarginHeight: CGFloat = ComposeStatusAttachmentCollectionViewCell.removeButtonSize.height * 0.5
|
||||
|
@ -29,10 +32,10 @@ final class ComposeStatusAttachmentCollectionViewCell: UICollectionViewCell {
|
|||
let image = UIImage(systemName: "minus")!.withConfiguration(UIImage.SymbolConfiguration(pointSize: 14, weight: .bold))
|
||||
button.tintColor = .white
|
||||
button.setImage(image, for: .normal)
|
||||
button.setBackgroundImage(.placeholder(color: Asset.Colors.Background.danger.color), for: .normal)
|
||||
button.setBackgroundImage(.placeholder(color: Asset.Colors.danger.color), for: .normal)
|
||||
button.layer.masksToBounds = true
|
||||
button.layer.cornerRadius = ComposeStatusAttachmentCollectionViewCell.removeButtonSize.width * 0.5
|
||||
button.layer.borderColor = Asset.Colors.Background.dangerBorder.color.cgColor
|
||||
button.layer.borderColor = Asset.Colors.dangerBorder.color.cgColor
|
||||
button.layer.borderWidth = 1
|
||||
return button
|
||||
}()
|
||||
|
@ -58,7 +61,7 @@ final class ComposeStatusAttachmentCollectionViewCell: UICollectionViewCell {
|
|||
}
|
||||
|
||||
deinit {
|
||||
os_log(.info, log: .debug, "%{public}s[%{public}ld], %{public}s", ((#file as NSString).lastPathComponent), #line, #function)
|
||||
logger.debug("\((#file as NSString).lastPathComponent, privacy: .public)[\(#line, privacy: .public)], \(#function, privacy: .public)")
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -96,7 +99,7 @@ extension ComposeStatusAttachmentCollectionViewCell {
|
|||
extension ComposeStatusAttachmentCollectionViewCell {
|
||||
|
||||
@objc private func removeButtonDidPressed(_ sender: UIButton) {
|
||||
os_log(.info, log: .debug, "%{public}s[%{public}ld], %{public}s", ((#file as NSString).lastPathComponent), #line, #function)
|
||||
logger.debug("\((#file as NSString).lastPathComponent, privacy: .public)[\(#line, privacy: .public)], \(#function, privacy: .public)")
|
||||
delegate?.composeStatusAttachmentCollectionViewCell(self, removeButtonDidPressed: sender)
|
||||
}
|
||||
|
||||
|
|
|
@ -5,14 +5,16 @@
|
|||
// Created by MainasuK Cirno on 2021-6-28.
|
||||
//
|
||||
|
||||
|
||||
import os.log
|
||||
import UIKit
|
||||
import Combine
|
||||
import MetaTextView
|
||||
import UITextView_Placeholder
|
||||
|
||||
final class ComposeStatusContentTableViewCell: UITableViewCell {
|
||||
|
||||
let logger = Logger(subsystem: "ComposeStatusContentTableViewCell", category: "UI")
|
||||
|
||||
var disposeBag = Set<AnyCancellable>()
|
||||
|
||||
let statusView = ReplicaStatusView()
|
||||
|
@ -149,7 +151,7 @@ extension ComposeStatusContentTableViewCell: UITextViewDelegate {
|
|||
}
|
||||
|
||||
func textViewDidChange(_ textView: UITextView) {
|
||||
os_log(.info, log: .debug, "%{public}s[%{public}ld], %{public}s: text: %s", ((#file as NSString).lastPathComponent), #line, #function, textView.text)
|
||||
logger.debug("\((#file as NSString).lastPathComponent, privacy: .public)[\(#line, privacy: .public)], \(#function, privacy: .public): text: \(textView.text ?? "<nil>")")
|
||||
guard textView === statusContentWarningEditorView.textView else { return }
|
||||
// replace line break with space
|
||||
textView.text = textView.text.replacingOccurrences(of: "\n", with: " ")
|
|
@ -14,6 +14,7 @@ import MetaTextView
|
|||
import MastodonMeta
|
||||
import Meta
|
||||
import Nuke
|
||||
import MastodonUI
|
||||
|
||||
final class ComposeViewController: UIViewController, NeedsDependency {
|
||||
|
||||
|
@ -188,7 +189,7 @@ extension ComposeViewController {
|
|||
])
|
||||
|
||||
tableView.delegate = self
|
||||
viewModel.setupDiffableDataSource(
|
||||
viewModel.setupDataSource(
|
||||
tableView: tableView,
|
||||
metaTextDelegate: self,
|
||||
metaTextViewDelegate: self,
|
||||
|
@ -263,7 +264,6 @@ extension ComposeViewController {
|
|||
self.view.layoutIfNeeded()
|
||||
}
|
||||
}
|
||||
self.updateKeyboardBackground(isKeyboardDisplay: isShow)
|
||||
return
|
||||
}
|
||||
// isShow AND dock state
|
||||
|
@ -279,14 +279,12 @@ extension ComposeViewController {
|
|||
self.autoCompleteViewController.tableView.contentInset.bottom = autoCompleteTableViewBottomInset
|
||||
self.autoCompleteViewController.tableView.verticalScrollIndicatorInsets.bottom = autoCompleteTableViewBottomInset
|
||||
|
||||
// adjust inset for collectionView
|
||||
// adjust inset for tableView
|
||||
let contentFrame = self.view.convert(self.tableView.frame, to: nil)
|
||||
let padding = contentFrame.maxY + extraMargin - endFrame.minY
|
||||
guard padding > 0 else {
|
||||
self.tableView.contentInset.bottom = self.view.safeAreaInsets.bottom + extraMargin
|
||||
self.tableView.verticalScrollIndicatorInsets.bottom = self.view.safeAreaInsets.bottom + extraMargin
|
||||
|
||||
self.updateKeyboardBackground(isKeyboardDisplay: false)
|
||||
return
|
||||
}
|
||||
|
||||
|
@ -296,7 +294,6 @@ extension ComposeViewController {
|
|||
self.composeToolbarViewBottomLayoutConstraint.constant = endFrame.height
|
||||
self.view.layoutIfNeeded()
|
||||
}
|
||||
self.updateKeyboardBackground(isKeyboardDisplay: isShow)
|
||||
})
|
||||
.store(in: &disposeBag)
|
||||
|
||||
|
@ -586,14 +583,11 @@ extension ComposeViewController {
|
|||
imagePicker.delegate = self
|
||||
return imagePicker
|
||||
}
|
||||
|
||||
private func updateKeyboardBackground(isKeyboardDisplay: Bool) {
|
||||
composeToolbarBackgroundView.backgroundColor = Asset.Scene.Compose.toolbarBackground.color
|
||||
}
|
||||
|
||||
private func setupBackgroundColor(theme: Theme) {
|
||||
view.backgroundColor = theme.systemElevatedBackgroundColor
|
||||
tableView.backgroundColor = theme.systemElevatedBackgroundColor
|
||||
composeToolbarBackgroundView.backgroundColor = theme.composeToolbarBackgroundColor
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -16,7 +16,7 @@ import MetaTextView
|
|||
|
||||
extension ComposeViewModel {
|
||||
|
||||
func setupDiffableDataSource(
|
||||
func setupDataSource(
|
||||
tableView: UITableView,
|
||||
metaTextDelegate: MetaTextDelegate,
|
||||
metaTextViewDelegate: UITextViewDelegate,
|
|
@ -28,7 +28,7 @@ final class ComposeViewModel: NSObject {
|
|||
let isContentWarningComposing = CurrentValueSubject<Bool, Never>(false)
|
||||
let selectedStatusVisibility: CurrentValueSubject<ComposeToolbarView.VisibilitySelectionType, Never>
|
||||
let activeAuthentication: CurrentValueSubject<MastodonAuthentication?, Never>
|
||||
let activeAuthenticationBox: CurrentValueSubject<AuthenticationService.MastodonAuthenticationBox?, Never>
|
||||
let activeAuthenticationBox: CurrentValueSubject<MastodonAuthenticationBox?, Never>
|
||||
let traitCollectionDidChangePublisher = CurrentValueSubject<Void, Never>(Void()) // use CurrentValueSubject to make initial event emit
|
||||
let repliedToCellFrame = CurrentValueSubject<CGRect, Never>(.zero)
|
||||
let autoCompleteRetryLayoutTimes = CurrentValueSubject<Int, Never>(0)
|
||||
|
@ -202,13 +202,13 @@ final class ComposeViewModel: NSObject {
|
|||
}
|
||||
.assign(to: \.value, on: characterCount)
|
||||
.store(in: &disposeBag)
|
||||
|
||||
// bind compose bar button item UI state
|
||||
let isComposeContentEmpty = composeStatusAttribute.composeContent
|
||||
.map { ($0 ?? "").isEmpty }
|
||||
let isComposeContentValid = composeStatusAttribute.composeContent
|
||||
.map { composeContent -> Bool in
|
||||
let composeContent = composeContent ?? ""
|
||||
return composeContent.count <= ComposeViewModel.composeContentLimit
|
||||
let isComposeContentValid = characterCount
|
||||
.map { characterCount -> Bool in
|
||||
return characterCount <= ComposeViewModel.composeContentLimit
|
||||
}
|
||||
let isMediaEmpty = attachmentServices
|
||||
.map { $0.isEmpty }
|
||||
|
@ -224,10 +224,10 @@ final class ComposeViewModel: NSObject {
|
|||
}
|
||||
|
||||
let isPublishBarButtonItemEnabledPrecondition1 = Publishers.CombineLatest4(
|
||||
isComposeContentEmpty.eraseToAnyPublisher(),
|
||||
isComposeContentValid.eraseToAnyPublisher(),
|
||||
isMediaEmpty.eraseToAnyPublisher(),
|
||||
isMediaUploadAllSuccess.eraseToAnyPublisher()
|
||||
isComposeContentEmpty,
|
||||
isComposeContentValid,
|
||||
isMediaEmpty,
|
||||
isMediaUploadAllSuccess
|
||||
)
|
||||
.map { isComposeContentEmpty, isComposeContentValid, isMediaEmpty, isMediaUploadAllSuccess -> Bool in
|
||||
if isMediaEmpty {
|
||||
|
@ -239,10 +239,10 @@ final class ComposeViewModel: NSObject {
|
|||
.eraseToAnyPublisher()
|
||||
|
||||
let isPublishBarButtonItemEnabledPrecondition2 = Publishers.CombineLatest4(
|
||||
isComposeContentEmpty.eraseToAnyPublisher(),
|
||||
isComposeContentValid.eraseToAnyPublisher(),
|
||||
isPollComposing.eraseToAnyPublisher(),
|
||||
isPollAttributeAllValid.eraseToAnyPublisher()
|
||||
isComposeContentEmpty,
|
||||
isComposeContentValid,
|
||||
isPollComposing,
|
||||
isPollAttributeAllValid
|
||||
)
|
||||
.map { isComposeContentEmpty, isComposeContentValid, isPollComposing, isPollAttributeAllValid -> Bool in
|
||||
if isPollComposing {
|
||||
|
@ -390,9 +390,9 @@ extension ComposeViewModel {
|
|||
var failureReason: String? {
|
||||
switch self {
|
||||
case .videoAttachWithPhoto:
|
||||
return L10n.Common.Alerts.PublishPostFailure.AttchmentsMessage.videoAttachWithPhoto
|
||||
return L10n.Common.Alerts.PublishPostFailure.AttachmentsMessage.videoAttachWithPhoto
|
||||
case .moreThanOneVideo:
|
||||
return L10n.Common.Alerts.PublishPostFailure.AttchmentsMessage.moreThanOneVideo
|
||||
return L10n.Common.Alerts.PublishPostFailure.AttachmentsMessage.moreThanOneVideo
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -88,7 +88,7 @@ extension ComposeStatusAttachmentTableViewCell {
|
|||
guard let image = thumbnailImage else {
|
||||
let placeholder = UIImage.placeholder(
|
||||
size: size,
|
||||
color: Asset.Colors.Background.systemGroupedBackground.color
|
||||
color: ThemeService.shared.currentTheme.value.systemGroupedBackgroundColor
|
||||
)
|
||||
.af.imageRounded(
|
||||
withCornerRadius: AttachmentContainerView.containerViewCornerRadius
|
||||
|
@ -116,9 +116,11 @@ extension ComposeStatusAttachmentTableViewCell {
|
|||
} else {
|
||||
guard let uploadState = uploadState else { return }
|
||||
switch uploadState {
|
||||
case is MastodonAttachmentService.UploadState.Finish,
|
||||
is MastodonAttachmentService.UploadState.Fail:
|
||||
case is MastodonAttachmentService.UploadState.Finish:
|
||||
cell.attachmentContainerView.activityIndicatorView.stopAnimating()
|
||||
case is MastodonAttachmentService.UploadState.Fail:
|
||||
cell.attachmentContainerView.activityIndicatorView.stopAnimating()
|
||||
// FIXME: not display
|
||||
cell.attachmentContainerView.emptyStateView.label.text = {
|
||||
if let file = attachmentService.file.value {
|
||||
switch file {
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
//
|
||||
|
||||
import UIKit
|
||||
import MastodonUI
|
||||
|
||||
extension AttachmentContainerView {
|
||||
final class EmptyStateView: UIView {
|
||||
|
|
|
@ -96,11 +96,15 @@ final class ComposeToolbarView: UIView {
|
|||
extension ComposeToolbarView {
|
||||
|
||||
private func _init() {
|
||||
// magic keyboard color (iOS 14):
|
||||
// light with white background: RGB 214 216 222
|
||||
// dark with black background: RGB 43 43 43
|
||||
backgroundColor = Asset.Scene.Compose.toolbarBackground.color
|
||||
|
||||
setupBackgroundColor(theme: ThemeService.shared.currentTheme.value)
|
||||
ThemeService.shared.currentTheme
|
||||
.receive(on: DispatchQueue.main)
|
||||
.sink { [weak self] theme in
|
||||
guard let self = self else { return }
|
||||
self.setupBackgroundColor(theme: theme)
|
||||
}
|
||||
.store(in: &disposeBag)
|
||||
|
||||
let stackView = UIStackView()
|
||||
stackView.axis = .horizontal
|
||||
stackView.spacing = 0
|
||||
|
@ -215,6 +219,10 @@ extension ComposeToolbarView {
|
|||
|
||||
extension ComposeToolbarView {
|
||||
|
||||
private func setupBackgroundColor(theme: Theme) {
|
||||
backgroundColor = theme.composeToolbarBackgroundColor
|
||||
}
|
||||
|
||||
private static func configureToolbarButtonAppearance(button: UIButton) {
|
||||
button.tintColor = Asset.Colors.brandBlue.color
|
||||
button.setBackgroundImage(.placeholder(size: ComposeToolbarView.toolbarButtonSize, color: .systemFill), for: .highlighted)
|
||||
|
|
|
@ -48,7 +48,7 @@ final class ReplicaStatusView: UIView {
|
|||
|
||||
let headerIconLabel: UILabel = {
|
||||
let label = UILabel()
|
||||
label.attributedText = StatusView.iconAttributedString(image: StatusView.reblogIconImage)
|
||||
label.attributedText = ReplicaStatusView.iconAttributedString(image: ReplicaStatusView.reblogIconImage)
|
||||
return label
|
||||
}()
|
||||
|
||||
|
@ -67,7 +67,6 @@ final class ReplicaStatusView: UIView {
|
|||
return view
|
||||
}()
|
||||
let avatarImageView: UIImageView = FLAnimatedImageView()
|
||||
let avatarStackedContainerButton: AvatarStackContainerButton = AvatarStackContainerButton()
|
||||
|
||||
let nameLabel: ActiveLabel = {
|
||||
let label = ActiveLabel(style: .statusName)
|
||||
|
@ -157,7 +156,7 @@ extension ReplicaStatusView {
|
|||
headerContainerStackView.topAnchor.constraint(equalTo: headerContainerView.topAnchor),
|
||||
headerContainerStackView.leadingAnchor.constraint(equalTo: headerContainerView.leadingAnchor),
|
||||
headerContainerStackView.trailingAnchor.constraint(equalTo: headerContainerView.trailingAnchor),
|
||||
headerContainerView.bottomAnchor.constraint(equalTo: headerContainerStackView.bottomAnchor, constant: StatusView.containerStackViewSpacing).priority(.defaultHigh),
|
||||
headerContainerView.bottomAnchor.constraint(equalTo: headerContainerStackView.bottomAnchor, constant: ReplicaStatusView.containerStackViewSpacing).priority(.defaultHigh),
|
||||
])
|
||||
containerStackView.addArrangedSubview(headerContainerView)
|
||||
defer {
|
||||
|
@ -167,15 +166,15 @@ extension ReplicaStatusView {
|
|||
// author container: [avatar | author meta container | reveal button]
|
||||
let authorContainerStackView = UIStackView()
|
||||
authorContainerStackView.axis = .horizontal
|
||||
authorContainerStackView.spacing = StatusView.avatarToLabelSpacing
|
||||
authorContainerStackView.spacing = ReplicaStatusView.avatarToLabelSpacing
|
||||
authorContainerStackView.distribution = .fill
|
||||
|
||||
// avatar
|
||||
avatarView.translatesAutoresizingMaskIntoConstraints = false
|
||||
authorContainerStackView.addArrangedSubview(avatarView)
|
||||
NSLayoutConstraint.activate([
|
||||
avatarView.widthAnchor.constraint(equalToConstant: StatusView.avatarImageSize.width).priority(.required - 1),
|
||||
avatarView.heightAnchor.constraint(equalToConstant: StatusView.avatarImageSize.height).priority(.required - 1),
|
||||
avatarView.widthAnchor.constraint(equalToConstant: ReplicaStatusView.avatarImageSize.width).priority(.required - 1),
|
||||
avatarView.heightAnchor.constraint(equalToConstant: ReplicaStatusView.avatarImageSize.height).priority(.required - 1),
|
||||
])
|
||||
avatarImageView.translatesAutoresizingMaskIntoConstraints = false
|
||||
avatarView.addSubview(avatarImageView)
|
||||
|
@ -185,14 +184,6 @@ extension ReplicaStatusView {
|
|||
avatarImageView.trailingAnchor.constraint(equalTo: avatarView.trailingAnchor),
|
||||
avatarImageView.bottomAnchor.constraint(equalTo: avatarView.bottomAnchor),
|
||||
])
|
||||
avatarStackedContainerButton.translatesAutoresizingMaskIntoConstraints = false
|
||||
avatarView.addSubview(avatarStackedContainerButton)
|
||||
NSLayoutConstraint.activate([
|
||||
avatarStackedContainerButton.topAnchor.constraint(equalTo: avatarView.topAnchor),
|
||||
avatarStackedContainerButton.leadingAnchor.constraint(equalTo: avatarView.leadingAnchor),
|
||||
avatarStackedContainerButton.trailingAnchor.constraint(equalTo: avatarView.trailingAnchor),
|
||||
avatarStackedContainerButton.bottomAnchor.constraint(equalTo: avatarView.bottomAnchor),
|
||||
])
|
||||
|
||||
// author meta container: [title container | subtitle container]
|
||||
let authorMetaContainerStackView = UIStackView()
|
||||
|
@ -235,7 +226,7 @@ extension ReplicaStatusView {
|
|||
authorContainerStackView.topAnchor.constraint(equalTo: authorContainerView.topAnchor),
|
||||
authorContainerStackView.leadingAnchor.constraint(equalTo: authorContainerView.leadingAnchor),
|
||||
authorContainerStackView.trailingAnchor.constraint(equalTo: authorContainerView.trailingAnchor),
|
||||
authorContainerView.bottomAnchor.constraint(equalTo: authorContainerStackView.bottomAnchor, constant: StatusView.containerStackViewSpacing).priority(.defaultHigh),
|
||||
authorContainerView.bottomAnchor.constraint(equalTo: authorContainerStackView.bottomAnchor, constant: ReplicaStatusView.containerStackViewSpacing).priority(.defaultHigh),
|
||||
])
|
||||
containerStackView.addArrangedSubview(authorContainerView)
|
||||
|
||||
|
@ -252,8 +243,6 @@ extension ReplicaStatusView {
|
|||
// status
|
||||
statusContainerStackView.addArrangedSubview(contentMetaText.textView)
|
||||
contentMetaText.textView.setContentCompressionResistancePriority(.required - 1, for: .vertical)
|
||||
|
||||
avatarStackedContainerButton.isHidden = true
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
//
|
||||
|
||||
import UIKit
|
||||
import MastodonUI
|
||||
|
||||
final class StatusContentWarningEditorView: UIView {
|
||||
|
||||
|
@ -72,28 +73,6 @@ extension StatusContentWarningEditorView {
|
|||
containerStackView.addArrangedSubview(iconImageView)
|
||||
iconImageView.setContentHuggingPriority(.required - 1, for: .horizontal)
|
||||
containerStackView.addArrangedSubview(textView)
|
||||
|
||||
// iconImageView.translatesAutoresizingMaskIntoConstraints = false
|
||||
// addSubview(iconImageView)
|
||||
// NSLayoutConstraint.activate([
|
||||
// iconImageView.leadingAnchor.constraint(equalTo: layoutMarginsGuide.leadingAnchor),
|
||||
// iconImageView.widthAnchor.constraint(equalToConstant: StatusView.avatarImageSize.width).priority(.defaultHigh), // center alignment to avatar
|
||||
// ])
|
||||
// iconImageView.setContentHuggingPriority(.required - 2, for: .horizontal)
|
||||
//
|
||||
// textView.translatesAutoresizingMaskIntoConstraints = false
|
||||
// addSubview(textView)
|
||||
// NSLayoutConstraint.activate([
|
||||
// textView.centerYAnchor.constraint(equalTo: centerYAnchor),
|
||||
// textView.topAnchor.constraint(equalTo: topAnchor, constant: 6),
|
||||
// textView.leadingAnchor.constraint(equalTo: iconImageView.trailingAnchor, constant: StatusView.avatarToLabelSpacing - 4), // align to name label. minus magic 4pt to remove addition inset
|
||||
// textView.trailingAnchor.constraint(equalTo: layoutMarginsGuide.trailingAnchor),
|
||||
// bottomAnchor.constraint(equalTo: textView.bottomAnchor, constant: 6),
|
||||
// textView.heightAnchor.constraint(greaterThanOrEqualToConstant: 44).priority(.defaultHigh),
|
||||
// ])
|
||||
//
|
||||
// textView.setContentHuggingPriority(.required - 1, for: .vertical)
|
||||
// textView.setContentCompressionResistancePriority(.required - 1, for: .vertical)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -5,13 +5,15 @@
|
|||
// Created by MainasuK Cirno on 2021-2-5.
|
||||
//
|
||||
|
||||
|
||||
#if DEBUG
|
||||
import os.log
|
||||
import UIKit
|
||||
import CoreData
|
||||
import CoreDataStack
|
||||
|
||||
#if DEBUG
|
||||
import FLEX
|
||||
import SwiftUI
|
||||
import MastodonUI
|
||||
|
||||
extension HomeTimelineViewController {
|
||||
var debugMenu: UIMenu {
|
||||
|
@ -363,5 +365,6 @@ extension HomeTimelineViewController {
|
|||
transition: .modal(animated: true, completion: nil)
|
||||
)
|
||||
}
|
||||
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
|
||||
import os.log
|
||||
import UIKit
|
||||
import MastodonUI
|
||||
|
||||
protocol HomeTimelineNavigationBarTitleViewDelegate: AnyObject {
|
||||
func homeTimelineNavigationBarTitleView(_ titleView: HomeTimelineNavigationBarTitleView, logoButtonDidPressed sender: UIButton)
|
||||
|
@ -113,7 +114,7 @@ extension HomeTimelineNavigationBarTitleView {
|
|||
configureButton(
|
||||
title: L10n.Scene.HomeTimeline.NavigationBarState.offline,
|
||||
textColor: .white,
|
||||
backgroundColor: Asset.Colors.Background.danger.color
|
||||
backgroundColor: Asset.Colors.danger.color
|
||||
)
|
||||
button.isHidden = false
|
||||
case .publishingPostLabel:
|
||||
|
|
|
@ -42,6 +42,15 @@ class MainTabBarController: UITabBarController {
|
|||
case .me: return UIImage(systemName: "person.fill")!
|
||||
}
|
||||
}
|
||||
|
||||
var largeImage: UIImage {
|
||||
switch self {
|
||||
case .home: return UIImage(systemName: "house.fill", withConfiguration: UIImage.SymbolConfiguration(pointSize: 80))!
|
||||
case .search: return UIImage(systemName: "magnifyingglass", withConfiguration: UIImage.SymbolConfiguration(pointSize: 80))!
|
||||
case .notification: return UIImage(systemName: "bell.fill", withConfiguration: UIImage.SymbolConfiguration(pointSize: 80))!
|
||||
case .me: return UIImage(systemName: "person.fill", withConfiguration: UIImage.SymbolConfiguration(pointSize: 80))!
|
||||
}
|
||||
}
|
||||
|
||||
func viewController(context: AppContext, coordinator: SceneCoordinator) -> UIViewController {
|
||||
let viewController: UIViewController
|
||||
|
@ -112,13 +121,19 @@ extension MainTabBarController {
|
|||
let tabs = Tab.allCases
|
||||
let viewControllers: [UIViewController] = tabs.map { tab in
|
||||
let viewController = tab.viewController(context: context, coordinator: coordinator)
|
||||
viewController.tabBarItem.title = "" // set text to empty string for image only style (SDK failed to layout when set to nil)
|
||||
viewController.tabBarItem.title = tab.title
|
||||
viewController.tabBarItem.image = tab.image
|
||||
viewController.tabBarItem.accessibilityLabel = tab.title
|
||||
viewController.tabBarItem.largeContentSizeImage = tab.largeImage
|
||||
viewController.tabBarItem.imageInsets = UIEdgeInsets(top: 6, left: 0, bottom: -6, right: 0)
|
||||
return viewController
|
||||
}
|
||||
setViewControllers(viewControllers, animated: false)
|
||||
selectedIndex = 0
|
||||
|
||||
UITabBarItem.appearance().setTitleTextAttributes([.foregroundColor : UIColor.clear], for: .normal)
|
||||
UITabBarItem.appearance().setTitleTextAttributes([.foregroundColor : UIColor.clear], for: .highlighted)
|
||||
UITabBarItem.appearance().setTitleTextAttributes([.foregroundColor : UIColor.clear], for: .selected)
|
||||
|
||||
context.apiService.error
|
||||
.receive(on: DispatchQueue.main)
|
||||
|
|
|
@ -26,7 +26,7 @@ final class NotificationViewModel: NSObject {
|
|||
let selectedIndex = CurrentValueSubject<NotificationSegment, Never>(.EveryThing)
|
||||
let noMoreNotification = CurrentValueSubject<Bool, Never>(false)
|
||||
|
||||
let activeMastodonAuthenticationBox: CurrentValueSubject<AuthenticationService.MastodonAuthenticationBox?, Never>
|
||||
let activeMastodonAuthenticationBox: CurrentValueSubject<MastodonAuthenticationBox?, Never>
|
||||
let fetchedResultsController: NSFetchedResultsController<MastodonNotification>!
|
||||
let notificationPredicate = CurrentValueSubject<NSPredicate?, Never>(nil)
|
||||
let cellFrameCache = NSCache<NSString, NSValue>()
|
||||
|
|
|
@ -50,17 +50,18 @@ final class NotificationStatusTableViewCell: UITableViewCell, StatusCell {
|
|||
let imageView = FLAnimatedImageView()
|
||||
return imageView
|
||||
}()
|
||||
|
||||
|
||||
let traitCollectionDidChange = PassthroughSubject<Void, Never>()
|
||||
|
||||
let actionImageView: UIImageView = {
|
||||
let imageView = UIImageView()
|
||||
imageView.contentMode = .center
|
||||
imageView.tintColor = Asset.Colors.Background.systemBackground.color
|
||||
imageView.isOpaque = true
|
||||
imageView.layer.masksToBounds = true
|
||||
imageView.layer.cornerRadius = NotificationStatusTableViewCell.actionImageViewSize.width * 0.5
|
||||
imageView.layer.cornerCurve = .circular
|
||||
imageView.layer.borderWidth = NotificationStatusTableViewCell.actionImageBorderWidth
|
||||
imageView.layer.borderColor = Asset.Colors.Background.systemBackground.color.cgColor
|
||||
imageView.layer.shouldRasterize = true
|
||||
imageView.layer.rasterizationScale = UIScreen.main.scale
|
||||
return imageView
|
||||
|
@ -197,8 +198,8 @@ extension NotificationStatusTableViewCell {
|
|||
NSLayoutConstraint.activate([
|
||||
actionImageView.centerYAnchor.constraint(equalTo: avatarContainer.bottomAnchor),
|
||||
actionImageView.centerXAnchor.constraint(equalTo: avatarContainer.trailingAnchor),
|
||||
actionImageView.widthAnchor.constraint(equalToConstant: NotificationStatusTableViewCell.actionImageViewSize.width),
|
||||
actionImageView.heightAnchor.constraint(equalToConstant: NotificationStatusTableViewCell.actionImageViewSize.height),
|
||||
actionImageView.widthAnchor.constraint(equalToConstant: NotificationStatusTableViewCell.actionImageViewSize.width).priority(.required - 1),
|
||||
actionImageView.heightAnchor.constraint(equalTo: actionImageView.widthAnchor, multiplier: 1.0),
|
||||
])
|
||||
|
||||
containerStackView.addArrangedSubview(contentStackView)
|
||||
|
@ -282,14 +283,23 @@ extension NotificationStatusTableViewCell {
|
|||
nameLabel.addGestureRecognizer(authorNameLabelTapGestureRecognizer)
|
||||
|
||||
resetSeparatorLineLayout()
|
||||
|
||||
setupBackgroundColor(theme: ThemeService.shared.currentTheme.value)
|
||||
ThemeService.shared.currentTheme
|
||||
.receive(on: DispatchQueue.main)
|
||||
.sink { [weak self] theme in
|
||||
guard let self = self else { return }
|
||||
self.setupBackgroundColor(theme: theme)
|
||||
}
|
||||
.store(in: &disposeBag)
|
||||
}
|
||||
|
||||
override func traitCollectionDidChange(_ previousTraitCollection: UITraitCollection?) {
|
||||
super.traitCollectionDidChange(previousTraitCollection)
|
||||
|
||||
resetSeparatorLineLayout()
|
||||
avatarImageView.layer.borderColor = Asset.Colors.Background.systemBackground.color.cgColor
|
||||
statusContainerView.layer.borderColor = Asset.Colors.Border.notificationStatus.color.cgColor
|
||||
setupBackgroundColor(theme: ThemeService.shared.currentTheme.value)
|
||||
traitCollectionDidChange.send()
|
||||
}
|
||||
|
||||
private func configure(isFiltered: Bool) {
|
||||
|
@ -297,12 +307,14 @@ extension NotificationStatusTableViewCell {
|
|||
filteredLabel.isHidden = !isFiltered
|
||||
isUserInteractionEnabled = !isFiltered
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
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.backgroundColor = UIColor(dynamicProvider: { traitCollection in
|
||||
return traitCollection.userInterfaceStyle == .light ? theme.systemBackgroundColor : theme.tertiarySystemGroupedBackgroundColor
|
||||
})
|
||||
|
|
|
@ -115,7 +115,7 @@ extension MastodonPickServerViewController {
|
|||
tableViewTopPaddingView.trailingAnchor.constraint(equalTo: view.trailingAnchor),
|
||||
tableViewTopPaddingViewHeightLayoutConstraint,
|
||||
])
|
||||
tableViewTopPaddingView.backgroundColor = Asset.Colors.Background.systemGroupedBackground.color
|
||||
tableViewTopPaddingView.backgroundColor = Asset.Theme.Mastodon.systemGroupedBackground.color
|
||||
|
||||
view.addSubview(tableView)
|
||||
NSLayoutConstraint.activate([
|
||||
|
@ -422,7 +422,7 @@ extension MastodonPickServerViewController: UITableViewDelegate {
|
|||
|
||||
func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
|
||||
let headerView = UIView()
|
||||
headerView.backgroundColor = Asset.Colors.Background.systemGroupedBackground.color
|
||||
headerView.backgroundColor = Asset.Theme.Mastodon.systemGroupedBackground.color
|
||||
return headerView
|
||||
}
|
||||
|
||||
|
|
|
@ -55,7 +55,7 @@ extension PickServerCategoriesCell {
|
|||
|
||||
private func _init() {
|
||||
selectionStyle = .none
|
||||
backgroundColor = Asset.Colors.Background.systemGroupedBackground.color
|
||||
backgroundColor = Asset.Theme.Mastodon.systemGroupedBackground.color
|
||||
|
||||
metricView.translatesAutoresizingMaskIntoConstraints = false
|
||||
contentView.addSubview(metricView)
|
||||
|
|
|
@ -27,7 +27,7 @@ class PickServerCell: UITableViewCell {
|
|||
let containerView: UIView = {
|
||||
let view = UIView()
|
||||
view.layoutMargins = UIEdgeInsets(top: 16, left: 16, bottom: 10, right: 16)
|
||||
view.backgroundColor = Asset.Colors.Background.secondaryGroupedSystemBackground.color
|
||||
view.backgroundColor = Asset.Theme.Mastodon.secondaryGroupedSystemBackground.color
|
||||
view.translatesAutoresizingMaskIntoConstraints = false
|
||||
return view
|
||||
}()
|
||||
|
@ -101,7 +101,7 @@ class PickServerCell: UITableViewCell {
|
|||
|
||||
let separator: UIView = {
|
||||
let view = UIView()
|
||||
view.backgroundColor = Asset.Colors.Background.systemGroupedBackground.color
|
||||
view.backgroundColor = Asset.Theme.Mastodon.systemGroupedBackground.color
|
||||
view.translatesAutoresizingMaskIntoConstraints = false
|
||||
return view
|
||||
}()
|
||||
|
|
|
@ -13,14 +13,14 @@ final class PickServerLoaderTableViewCell: TimelineLoaderTableViewCell {
|
|||
let containerView: UIView = {
|
||||
let view = UIView()
|
||||
view.layoutMargins = UIEdgeInsets(top: 16, left: 16, bottom: 10, right: 16)
|
||||
view.backgroundColor = Asset.Colors.Background.secondaryGroupedSystemBackground.color
|
||||
view.backgroundColor = Asset.Theme.Mastodon.secondaryGroupedSystemBackground.color
|
||||
view.translatesAutoresizingMaskIntoConstraints = false
|
||||
return view
|
||||
}()
|
||||
|
||||
let seperator: UIView = {
|
||||
let view = UIView()
|
||||
view.backgroundColor = Asset.Colors.Background.systemGroupedBackground.color
|
||||
view.backgroundColor = Asset.Theme.Mastodon.systemGroupedBackground.color
|
||||
view.translatesAutoresizingMaskIntoConstraints = false
|
||||
return view
|
||||
}()
|
||||
|
|
|
@ -17,7 +17,7 @@ class PickServerSearchCell: UITableViewCell {
|
|||
|
||||
private var bgView: UIView = {
|
||||
let view = UIView()
|
||||
view.backgroundColor = Asset.Colors.Background.secondaryGroupedSystemBackground.color
|
||||
view.backgroundColor = Asset.Theme.Mastodon.secondaryGroupedSystemBackground.color
|
||||
view.translatesAutoresizingMaskIntoConstraints = false
|
||||
view.layer.maskedCorners = [
|
||||
.layerMinXMinYCorner,
|
||||
|
@ -108,7 +108,7 @@ class PickServerSearchCell: UITableViewCell {
|
|||
extension PickServerSearchCell {
|
||||
private func _init() {
|
||||
selectionStyle = .none
|
||||
backgroundColor = Asset.Colors.Background.systemGroupedBackground.color
|
||||
backgroundColor = Asset.Theme.Mastodon.systemGroupedBackground.color
|
||||
|
||||
searchTextField.addTarget(self, action: #selector(textFieldDidChange(_:)), for: .editingChanged)
|
||||
searchTextField.delegate = self
|
||||
|
|
|
@ -35,7 +35,7 @@ extension PickServerTitleCell {
|
|||
|
||||
private func _init() {
|
||||
selectionStyle = .none
|
||||
backgroundColor = Asset.Colors.Background.systemGroupedBackground.color
|
||||
backgroundColor = Asset.Theme.Mastodon.systemGroupedBackground.color
|
||||
|
||||
contentView.addSubview(titleLabel)
|
||||
NSLayoutConstraint.activate([
|
||||
|
|
|
@ -48,7 +48,7 @@ extension PickServerCategoryView {
|
|||
addSubview(bgView)
|
||||
addSubview(titleLabel)
|
||||
|
||||
bgView.backgroundColor = Asset.Colors.Background.secondaryGroupedSystemBackground.color
|
||||
bgView.backgroundColor = Asset.Theme.Mastodon.secondaryGroupedSystemBackground.color
|
||||
|
||||
NSLayoutConstraint.activate([
|
||||
bgView.leadingAnchor.constraint(equalTo: self.leadingAnchor),
|
||||
|
|
|
@ -44,7 +44,7 @@ final class PickServerEmptyStateView: UIView {
|
|||
extension PickServerEmptyStateView {
|
||||
|
||||
private func _init() {
|
||||
backgroundColor = Asset.Colors.Background.secondaryGroupedSystemBackground.color
|
||||
backgroundColor = Asset.Theme.Mastodon.secondaryGroupedSystemBackground.color
|
||||
layer.maskedCorners = [
|
||||
.layerMinXMaxYCorner,
|
||||
.layerMaxXMaxYCorner
|
||||
|
|
|
@ -84,7 +84,7 @@ final class MastodonRegisterViewController: UIViewController, NeedsDependency, O
|
|||
|
||||
button.setImage(image?.withRenderingMode(UIImage.RenderingMode.alwaysTemplate), for: UIControl.State.normal)
|
||||
button.imageView?.tintColor = Asset.Colors.Label.secondary.color
|
||||
button.backgroundColor = Asset.Colors.Background.secondaryGroupedSystemBackground.color
|
||||
button.backgroundColor = Asset.Theme.Mastodon.secondaryGroupedSystemBackground.color
|
||||
button.layer.cornerRadius = 10
|
||||
button.clipsToBounds = true
|
||||
|
||||
|
@ -99,7 +99,7 @@ final class MastodonRegisterViewController: UIViewController, NeedsDependency, O
|
|||
icon.backgroundColor = UIColor(dynamicProvider: { collection in
|
||||
switch collection.userInterfaceStyle {
|
||||
case .dark:
|
||||
return Asset.Colors.Background.secondaryGroupedSystemBackground.color
|
||||
return Asset.Theme.Mastodon.secondaryGroupedSystemBackground.color
|
||||
default:
|
||||
return .white
|
||||
}
|
||||
|
@ -119,7 +119,7 @@ final class MastodonRegisterViewController: UIViewController, NeedsDependency, O
|
|||
textField.returnKeyType = .next
|
||||
textField.autocapitalizationType = .none
|
||||
textField.autocorrectionType = .no
|
||||
textField.backgroundColor = Asset.Colors.Background.secondaryGroupedSystemBackground.color
|
||||
textField.backgroundColor = Asset.Theme.Mastodon.secondaryGroupedSystemBackground.color
|
||||
textField.textColor = Asset.Colors.Label.primary.color
|
||||
textField.attributedPlaceholder = NSAttributedString(string: L10n.Scene.Register.Input.Username.placeholder,
|
||||
attributes: [NSAttributedString.Key.foregroundColor: Asset.Colors.Label.secondary.color,
|
||||
|
@ -170,7 +170,7 @@ final class MastodonRegisterViewController: UIViewController, NeedsDependency, O
|
|||
textField.returnKeyType = .next
|
||||
textField.autocapitalizationType = .none
|
||||
textField.autocorrectionType = .no
|
||||
textField.backgroundColor = Asset.Colors.Background.secondaryGroupedSystemBackground.color
|
||||
textField.backgroundColor = Asset.Theme.Mastodon.secondaryGroupedSystemBackground.color
|
||||
textField.textColor = Asset.Colors.Label.primary.color
|
||||
textField.attributedPlaceholder = NSAttributedString(string: L10n.Scene.Register.Input.DisplayName.placeholder,
|
||||
attributes: [NSAttributedString.Key.foregroundColor: Asset.Colors.Label.secondary.color,
|
||||
|
@ -189,7 +189,7 @@ final class MastodonRegisterViewController: UIViewController, NeedsDependency, O
|
|||
textField.autocapitalizationType = .none
|
||||
textField.autocorrectionType = .no
|
||||
textField.keyboardType = .emailAddress
|
||||
textField.backgroundColor = Asset.Colors.Background.secondaryGroupedSystemBackground.color
|
||||
textField.backgroundColor = Asset.Theme.Mastodon.secondaryGroupedSystemBackground.color
|
||||
textField.textColor = Asset.Colors.Label.primary.color
|
||||
textField.attributedPlaceholder = NSAttributedString(string: L10n.Scene.Register.Input.Email.placeholder,
|
||||
attributes: [NSAttributedString.Key.foregroundColor: Asset.Colors.Label.secondary.color,
|
||||
|
@ -216,7 +216,7 @@ final class MastodonRegisterViewController: UIViewController, NeedsDependency, O
|
|||
textField.autocorrectionType = .no
|
||||
textField.keyboardType = .asciiCapable
|
||||
textField.isSecureTextEntry = true
|
||||
textField.backgroundColor = Asset.Colors.Background.secondaryGroupedSystemBackground.color
|
||||
textField.backgroundColor = Asset.Theme.Mastodon.secondaryGroupedSystemBackground.color
|
||||
textField.textColor = Asset.Colors.Label.primary.color
|
||||
textField.attributedPlaceholder = NSAttributedString(string: L10n.Scene.Register.Input.Password.placeholder,
|
||||
attributes: [NSAttributedString.Key.foregroundColor: Asset.Colors.Label.secondary.color,
|
||||
|
@ -248,7 +248,7 @@ final class MastodonRegisterViewController: UIViewController, NeedsDependency, O
|
|||
textField.returnKeyType = .next // set to "Return" depends on if the last input field or not
|
||||
textField.autocapitalizationType = .none
|
||||
textField.autocorrectionType = .no
|
||||
textField.backgroundColor = Asset.Colors.Background.secondaryGroupedSystemBackground.color
|
||||
textField.backgroundColor = Asset.Theme.Mastodon.secondaryGroupedSystemBackground.color
|
||||
textField.textColor = Asset.Colors.Label.primary.color
|
||||
textField.attributedPlaceholder = NSAttributedString(string: L10n.Scene.Register.Input.Invite.registrationUserInviteRequest,
|
||||
attributes: [NSAttributedString.Key.foregroundColor: Asset.Colors.Label.secondary.color,
|
||||
|
|
|
@ -49,7 +49,7 @@ final class MastodonServerRulesViewController: UIViewController, NeedsDependency
|
|||
|
||||
let bottomContainerView: UIView = {
|
||||
let view = UIView()
|
||||
view.backgroundColor = Asset.Colors.Background.systemGroupedBackground.color
|
||||
view.backgroundColor = Asset.Theme.Mastodon.systemGroupedBackground.color
|
||||
return view
|
||||
}()
|
||||
|
||||
|
@ -60,7 +60,7 @@ final class MastodonServerRulesViewController: UIViewController, NeedsDependency
|
|||
textView.isSelectable = true
|
||||
textView.isEditable = false
|
||||
textView.isScrollEnabled = false
|
||||
textView.backgroundColor = Asset.Colors.Background.systemGroupedBackground.color
|
||||
textView.backgroundColor = Asset.Theme.Mastodon.systemGroupedBackground.color
|
||||
return textView
|
||||
}()
|
||||
|
||||
|
|
|
@ -20,7 +20,7 @@ extension OnboardingViewControllerAppearance {
|
|||
static var viewBottomPaddingHeight: CGFloat { return 11 }
|
||||
|
||||
func setupOnboardingAppearance() {
|
||||
view.backgroundColor = Asset.Colors.Background.systemGroupedBackground.color
|
||||
view.backgroundColor = Asset.Theme.Mastodon.systemGroupedBackground.color
|
||||
|
||||
setupNavigationBarAppearance()
|
||||
|
||||
|
@ -42,7 +42,7 @@ extension OnboardingViewControllerAppearance {
|
|||
func setupNavigationBarBackgroundView() {
|
||||
let navigationBarBackgroundView: UIView = {
|
||||
let view = UIView()
|
||||
view.backgroundColor = Asset.Colors.Background.systemGroupedBackground.color
|
||||
view.backgroundColor = Asset.Theme.Mastodon.systemGroupedBackground.color
|
||||
return view
|
||||
}()
|
||||
|
||||
|
|
|
@ -17,7 +17,7 @@ final class FavoriteViewModel {
|
|||
|
||||
// input
|
||||
let context: AppContext
|
||||
let activeMastodonAuthenticationBox: CurrentValueSubject<AuthenticationService.MastodonAuthenticationBox?, Never>
|
||||
let activeMastodonAuthenticationBox: CurrentValueSubject<MastodonAuthenticationBox?, Never>
|
||||
let statusFetchedResultsController: StatusFetchedResultsController
|
||||
let cellFrameCache = NSCache<NSNumber, NSValue>()
|
||||
|
||||
|
|
|
@ -465,7 +465,7 @@ extension ProfileHeaderViewController: PHPickerViewControllerDelegate {
|
|||
func picker(_ picker: PHPickerViewController, didFinishPicking results: [PHPickerResult]) {
|
||||
picker.dismiss(animated: true, completion: nil)
|
||||
guard let result = results.first else { return }
|
||||
PHPickerResultLoader.loadImageData(from: result)
|
||||
ItemProviderLoader.loadImageData(from: result)
|
||||
.sink { [weak self] completion in
|
||||
guard let _ = self else { return }
|
||||
switch completion {
|
||||
|
|
|
@ -76,7 +76,7 @@ final class ProfileHeaderView: UIView {
|
|||
let avatarImageView: UIImageView = {
|
||||
let imageView = FLAnimatedImageView()
|
||||
let placeholderImage = UIImage
|
||||
.placeholder(size: ProfileHeaderView.avatarImageViewSize, color: Asset.Colors.Background.systemGroupedBackground.color)
|
||||
.placeholder(size: ProfileHeaderView.avatarImageViewSize, color: Asset.Theme.Mastodon.systemGroupedBackground.color)
|
||||
.af.imageRounded(withCornerRadius: ProfileHeaderView.avatarImageViewCornerRadius, divideRadiusByImageScale: false)
|
||||
imageView.image = placeholderImage
|
||||
return imageView
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
//
|
||||
|
||||
import UIKit
|
||||
import MastodonUI
|
||||
|
||||
final class ProfileRelationshipActionButton: RoundedEdgesButton {
|
||||
|
||||
|
|
|
@ -115,7 +115,7 @@ class ProfileViewModel: NSObject {
|
|||
context.authenticationService.activeMastodonAuthenticationBox.eraseToAnyPublisher(),
|
||||
pendingRetryPublisher.eraseToAnyPublisher()
|
||||
)
|
||||
.compactMap { mastodonUserID, activeMastodonAuthenticationBox, _ -> (String, AuthenticationService.MastodonAuthenticationBox)? in
|
||||
.compactMap { mastodonUserID, activeMastodonAuthenticationBox, _ -> (String, MastodonAuthenticationBox)? in
|
||||
guard let mastodonUserID = mastodonUserID, let activeMastodonAuthenticationBox = activeMastodonAuthenticationBox else { return nil }
|
||||
guard mastodonUserID != activeMastodonAuthenticationBox.userID else { return nil }
|
||||
return (mastodonUserID, activeMastodonAuthenticationBox)
|
||||
|
@ -441,9 +441,9 @@ extension ProfileViewModel {
|
|||
case .request: return Asset.Colors.brandBlue.color
|
||||
case .pending: return Asset.Colors.brandBlue.color
|
||||
case .following: return Asset.Colors.brandBlue.color
|
||||
case .muting: return Asset.Colors.Background.alertYellow.color
|
||||
case .muting: return Asset.Colors.alertYellow.color
|
||||
case .blocked: return Asset.Colors.brandBlue.color
|
||||
case .blocking: return Asset.Colors.Background.danger.color
|
||||
case .blocking: return Asset.Colors.danger.color
|
||||
case .suspended: return Asset.Colors.brandBlue.color
|
||||
case .edit: return Asset.Colors.brandBlue.color
|
||||
case .editing: return Asset.Colors.brandBlue.color
|
||||
|
|
|
@ -17,7 +17,7 @@ extension ReportViewModel {
|
|||
func requestRecentStatus(
|
||||
domain: String,
|
||||
accountId: String,
|
||||
authorizationBox: AuthenticationService.MastodonAuthenticationBox
|
||||
authorizationBox: MastodonAuthenticationBox
|
||||
) {
|
||||
context.apiService.userTimeline(
|
||||
domain: domain,
|
||||
|
|
|
@ -165,7 +165,7 @@ class ReportViewModel: NSObject {
|
|||
.store(in: &disposeBag)
|
||||
}
|
||||
|
||||
func bindForStep2(input: Input, domain: String, activeMastodonAuthenticationBox: AuthenticationService.MastodonAuthenticationBox) -> AnyPublisher<(Bool, Error?), Never> {
|
||||
func bindForStep2(input: Input, domain: String, activeMastodonAuthenticationBox: MastodonAuthenticationBox) -> AnyPublisher<(Bool, Error?), Never> {
|
||||
let skip = input.step2Skip.map { [weak self] value -> Void in
|
||||
guard let self = self else { return value }
|
||||
self.reportQuery.comment = nil
|
||||
|
|
|
@ -17,7 +17,7 @@ extension SearchViewController {
|
|||
let header = SearchRecommendCollectionHeader()
|
||||
header.titleLabel.text = L10n.Scene.Search.Recommend.HashTag.title
|
||||
header.descriptionLabel.text = L10n.Scene.Search.Recommend.HashTag.description
|
||||
header.seeAllButton.addTarget(self, action: #selector(SearchViewController.hashtagSeeAllButtonPressed(_:)), for: .touchUpInside)
|
||||
header.seeAllButton.isHidden = true
|
||||
stackView.addArrangedSubview(header)
|
||||
|
||||
hashtagCollectionView.register(SearchRecommendTagsCollectionViewCell.self, forCellWithReuseIdentifier: String(describing: SearchRecommendTagsCollectionViewCell.self))
|
||||
|
|
|
@ -42,7 +42,7 @@ final class SearchViewModel: NSObject {
|
|||
context.authenticationService.activeMastodonAuthenticationBox,
|
||||
viewDidAppeared
|
||||
)
|
||||
.compactMap { activeMastodonAuthenticationBox, _ -> AuthenticationService.MastodonAuthenticationBox? in
|
||||
.compactMap { activeMastodonAuthenticationBox, _ -> MastodonAuthenticationBox? in
|
||||
return activeMastodonAuthenticationBox
|
||||
}
|
||||
.throttle(for: 1, scheduler: DispatchQueue.main, latest: false)
|
||||
|
@ -72,7 +72,7 @@ final class SearchViewModel: NSObject {
|
|||
context.authenticationService.activeMastodonAuthenticationBox,
|
||||
viewDidAppeared
|
||||
)
|
||||
.compactMap { activeMastodonAuthenticationBox, _ -> AuthenticationService.MastodonAuthenticationBox? in
|
||||
.compactMap { activeMastodonAuthenticationBox, _ -> MastodonAuthenticationBox? in
|
||||
return activeMastodonAuthenticationBox
|
||||
}
|
||||
.throttle(for: 1, scheduler: DispatchQueue.main, latest: false)
|
||||
|
|
|
@ -63,7 +63,7 @@ extension PlayerContainerView {
|
|||
extension PlayerContainerView.MediaTypeIndicatorView {
|
||||
|
||||
private func _init() {
|
||||
backgroundColor = Asset.Colors.Background.mediaTypeIndicotor.color
|
||||
backgroundColor = Asset.Colors.mediaTypeIndicotor.color
|
||||
layoutMargins = UIEdgeInsets(top: 3, left: 13, bottom: 0, right: 6)
|
||||
|
||||
addSubview(label)
|
||||
|
|
|
@ -29,7 +29,8 @@ final class PollOptionView: UIView {
|
|||
|
||||
let checkmarkBackgroundView: UIView = {
|
||||
let view = UIView()
|
||||
view.backgroundColor = Asset.Colors.Background.tertiarySystemBackground.color
|
||||
// FIXME: missing update trigger
|
||||
view.backgroundColor = ThemeService.shared.currentTheme.value.tertiarySystemBackgroundColor
|
||||
return view
|
||||
}()
|
||||
|
||||
|
|
|
@ -58,7 +58,6 @@ extension ThreadReplyLoaderTableViewCell {
|
|||
|
||||
func _init() {
|
||||
selectionStyle = .none
|
||||
backgroundColor = Asset.Colors.Background.systemGroupedBackground.color
|
||||
|
||||
loadMoreButton.translatesAutoresizingMaskIntoConstraints = false
|
||||
contentView.addSubview(loadMoreButton)
|
||||
|
@ -124,7 +123,7 @@ extension ThreadReplyLoaderTableViewCell {
|
|||
}
|
||||
|
||||
private func setupBackgroundColor(theme: Theme) {
|
||||
loadMoreButton.backgroundColor = theme.secondarySystemGroupedBackgroundColor
|
||||
backgroundColor = theme.systemGroupedBackgroundColor
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -32,7 +32,7 @@ class SuggestionAccountViewController: UIViewController, NeedsDependency {
|
|||
|
||||
lazy var tableHeader: UIView = {
|
||||
let view = UIView()
|
||||
view.backgroundColor = Asset.Colors.Background.systemGroupedBackground.color
|
||||
view.backgroundColor = ThemeService.shared.currentTheme.value.systemGroupedBackgroundColor
|
||||
view.frame = CGRect(origin: .zero, size: CGSize(width: tableView.frame.width, height: 156))
|
||||
return view
|
||||
}()
|
||||
|
@ -67,12 +67,12 @@ extension SuggestionAccountViewController {
|
|||
override func viewDidLoad() {
|
||||
super.viewDidLoad()
|
||||
|
||||
view.backgroundColor = ThemeService.shared.currentTheme.value.systemBackgroundColor
|
||||
setupBackgroundColor(theme: ThemeService.shared.currentTheme.value)
|
||||
ThemeService.shared.currentTheme
|
||||
.receive(on: RunLoop.main)
|
||||
.sink { [weak self] theme in
|
||||
guard let self = self else { return }
|
||||
self.view.backgroundColor = theme.systemBackgroundColor
|
||||
self.setupBackgroundColor(theme: theme)
|
||||
}
|
||||
.store(in: &disposeBag)
|
||||
|
||||
|
@ -146,6 +146,11 @@ extension SuggestionAccountViewController {
|
|||
|
||||
tableView.tableHeaderView = tableHeader
|
||||
}
|
||||
|
||||
private func setupBackgroundColor(theme: Theme) {
|
||||
view.backgroundColor = theme.systemBackgroundColor
|
||||
tableHeader.backgroundColor = theme.systemGroupedBackgroundColor
|
||||
}
|
||||
}
|
||||
|
||||
extension SuggestionAccountViewController: UICollectionViewDelegateFlowLayout {
|
||||
|
|
|
@ -16,7 +16,7 @@ extension APIService {
|
|||
|
||||
func toggleBlock(
|
||||
for mastodonUser: MastodonUser,
|
||||
activeMastodonAuthenticationBox: AuthenticationService.MastodonAuthenticationBox
|
||||
activeMastodonAuthenticationBox: MastodonAuthenticationBox
|
||||
) -> AnyPublisher<Mastodon.Response.Content<Mastodon.Entity.Relationship>, Error> {
|
||||
let impactFeedbackGenerator = UIImpactFeedbackGenerator(style: .light)
|
||||
let notificationFeedbackGenerator = UINotificationFeedbackGenerator()
|
||||
|
@ -86,7 +86,7 @@ extension APIService {
|
|||
// update database local and return block query update type for remote request
|
||||
func blockUpdateLocal(
|
||||
mastodonUserObjectID: NSManagedObjectID,
|
||||
mastodonAuthenticationBox: AuthenticationService.MastodonAuthenticationBox
|
||||
mastodonAuthenticationBox: MastodonAuthenticationBox
|
||||
) -> AnyPublisher<(Mastodon.API.Account.BlockQueryType, MastodonUser.ID), Error> {
|
||||
let domain = mastodonAuthenticationBox.domain
|
||||
let requestMastodonUserID = mastodonAuthenticationBox.userID
|
||||
|
@ -132,7 +132,7 @@ extension APIService {
|
|||
func blockUpdateRemote(
|
||||
blockQueryType: Mastodon.API.Account.BlockQueryType,
|
||||
mastodonUserID: MastodonUser.ID,
|
||||
mastodonAuthenticationBox: AuthenticationService.MastodonAuthenticationBox
|
||||
mastodonAuthenticationBox: MastodonAuthenticationBox
|
||||
) -> AnyPublisher<Mastodon.Response.Content<Mastodon.Entity.Relationship>, Error> {
|
||||
let domain = mastodonAuthenticationBox.domain
|
||||
let authorization = mastodonAuthenticationBox.userAuthorization
|
||||
|
|
|
@ -17,7 +17,7 @@ extension APIService {
|
|||
func getDomainblocks(
|
||||
domain: String,
|
||||
limit: Int = onceRequestDomainBlocksMaxCount,
|
||||
authorizationBox: AuthenticationService.MastodonAuthenticationBox
|
||||
authorizationBox: MastodonAuthenticationBox
|
||||
) -> AnyPublisher<Mastodon.Response.Content<[String]>, Error> {
|
||||
let authorization = authorizationBox.userAuthorization
|
||||
|
||||
|
@ -71,7 +71,7 @@ extension APIService {
|
|||
|
||||
func blockDomain(
|
||||
user: MastodonUser,
|
||||
authorizationBox: AuthenticationService.MastodonAuthenticationBox
|
||||
authorizationBox: MastodonAuthenticationBox
|
||||
) -> AnyPublisher<Mastodon.Response.Content<Mastodon.Entity.Empty>, Error> {
|
||||
let authorization = authorizationBox.userAuthorization
|
||||
|
||||
|
@ -105,7 +105,7 @@ extension APIService {
|
|||
|
||||
func unblockDomain(
|
||||
user: MastodonUser,
|
||||
authorizationBox: AuthenticationService.MastodonAuthenticationBox
|
||||
authorizationBox: MastodonAuthenticationBox
|
||||
) -> AnyPublisher<Mastodon.Response.Content<Mastodon.Entity.Empty>, Error> {
|
||||
let authorization = authorizationBox.userAuthorization
|
||||
|
||||
|
|
|
@ -61,7 +61,7 @@ extension APIService {
|
|||
func favorite(
|
||||
statusID: Mastodon.Entity.Status.ID,
|
||||
favoriteKind: Mastodon.API.Favorites.FavoriteKind,
|
||||
mastodonAuthenticationBox: AuthenticationService.MastodonAuthenticationBox
|
||||
mastodonAuthenticationBox: MastodonAuthenticationBox
|
||||
) -> AnyPublisher<Mastodon.Response.Content<Mastodon.Entity.Status>, Error> {
|
||||
let authorization = mastodonAuthenticationBox.userAuthorization
|
||||
let requestMastodonUserID = mastodonAuthenticationBox.userID
|
||||
|
@ -139,7 +139,7 @@ extension APIService {
|
|||
func favoritedStatuses(
|
||||
limit: Int = onceRequestStatusMaxCount,
|
||||
maxID: String? = nil,
|
||||
mastodonAuthenticationBox: AuthenticationService.MastodonAuthenticationBox
|
||||
mastodonAuthenticationBox: MastodonAuthenticationBox
|
||||
) -> AnyPublisher<Mastodon.Response.Content<[Mastodon.Entity.Status]>, Error> {
|
||||
|
||||
let requestMastodonUserID = mastodonAuthenticationBox.userID
|
||||
|
|
|
@ -15,7 +15,7 @@ import MastodonSDK
|
|||
extension APIService {
|
||||
|
||||
func filters(
|
||||
mastodonAuthenticationBox: AuthenticationService.MastodonAuthenticationBox
|
||||
mastodonAuthenticationBox: MastodonAuthenticationBox
|
||||
) -> AnyPublisher<Mastodon.Response.Content<[Mastodon.Entity.Filter]>, Error> {
|
||||
let authorization = mastodonAuthenticationBox.userAuthorization
|
||||
let domain = mastodonAuthenticationBox.domain
|
||||
|
|
|
@ -24,7 +24,7 @@ extension APIService {
|
|||
/// - Returns: publisher for `Relationship`
|
||||
func toggleFollow(
|
||||
for mastodonUser: MastodonUser,
|
||||
activeMastodonAuthenticationBox: AuthenticationService.MastodonAuthenticationBox
|
||||
activeMastodonAuthenticationBox: MastodonAuthenticationBox
|
||||
) -> AnyPublisher<Mastodon.Response.Content<Mastodon.Entity.Relationship>, Error> {
|
||||
|
||||
let impactFeedbackGenerator = UIImpactFeedbackGenerator(style: .light)
|
||||
|
@ -96,7 +96,7 @@ extension APIService {
|
|||
// update database local and return follow query update type for remote request
|
||||
func followUpdateLocal(
|
||||
mastodonUserObjectID: NSManagedObjectID,
|
||||
mastodonAuthenticationBox: AuthenticationService.MastodonAuthenticationBox
|
||||
mastodonAuthenticationBox: MastodonAuthenticationBox
|
||||
) -> AnyPublisher<(Mastodon.API.Account.FollowQueryType, MastodonUser.ID), Error> {
|
||||
let domain = mastodonAuthenticationBox.domain
|
||||
let requestMastodonUserID = mastodonAuthenticationBox.userID
|
||||
|
@ -156,7 +156,7 @@ extension APIService {
|
|||
func followUpdateRemote(
|
||||
followQueryType: Mastodon.API.Account.FollowQueryType,
|
||||
mastodonUserID: MastodonUser.ID,
|
||||
mastodonAuthenticationBox: AuthenticationService.MastodonAuthenticationBox
|
||||
mastodonAuthenticationBox: MastodonAuthenticationBox
|
||||
) -> AnyPublisher<Mastodon.Response.Content<Mastodon.Entity.Relationship>, Error> {
|
||||
let domain = mastodonAuthenticationBox.domain
|
||||
let authorization = mastodonAuthenticationBox.userAuthorization
|
||||
|
|
|
@ -17,7 +17,7 @@ import MastodonSDK
|
|||
extension APIService {
|
||||
func acceptFollowRequest(
|
||||
mastodonUserID: MastodonUser.ID,
|
||||
mastodonAuthenticationBox: AuthenticationService.MastodonAuthenticationBox
|
||||
mastodonAuthenticationBox: MastodonAuthenticationBox
|
||||
) -> AnyPublisher<Mastodon.Response.Content<Mastodon.Entity.Relationship>, Error> {
|
||||
let domain = mastodonAuthenticationBox.domain
|
||||
let authorization = mastodonAuthenticationBox.userAuthorization
|
||||
|
@ -61,7 +61,7 @@ extension APIService {
|
|||
|
||||
func rejectFollowRequest(
|
||||
mastodonUserID: MastodonUser.ID,
|
||||
mastodonAuthenticationBox: AuthenticationService.MastodonAuthenticationBox
|
||||
mastodonAuthenticationBox: MastodonAuthenticationBox
|
||||
) -> AnyPublisher<Mastodon.Response.Content<Mastodon.Entity.Relationship>, Error> {
|
||||
let domain = mastodonAuthenticationBox.domain
|
||||
let authorization = mastodonAuthenticationBox.userAuthorization
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue