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