Merge branch 'release/0.9.1'

This commit is contained in:
CMK 2021-07-20 20:34:40 +08:00
commit 5e6e532e07
159 changed files with 3620 additions and 979 deletions

View File

@ -7,12 +7,14 @@
import os
import Foundation
import Combine
import CoreData
import AppShared
public final class CoreDataStack {
private(set) var storeDescriptions: [NSPersistentStoreDescription]
public let didFinishLoad = CurrentValueSubject<Bool, Never>(false)
init(persistentStoreDescriptions storeDescriptions: [NSPersistentStoreDescription]) {
self.storeDescriptions = storeDescriptions
@ -33,7 +35,10 @@ public final class CoreDataStack {
*/
let container = CoreDataStack.persistentContainer()
CoreDataStack.configure(persistentContainer: container, storeDescriptions: storeDescriptions)
CoreDataStack.load(persistentContainer: container)
CoreDataStack.load(persistentContainer: container) { [weak self] in
guard let self = self else { return }
self.didFinishLoad.value = true
}
return container
}()
@ -52,7 +57,7 @@ public final class CoreDataStack {
container.persistentStoreDescriptions = storeDescriptions
}
static func load(persistentContainer container: NSPersistentContainer) {
static func load(persistentContainer container: NSPersistentContainer, callback: @escaping () -> Void) {
container.loadPersistentStores(completionHandler: { (storeDescription, error) in
if let error = error as NSError? {
// Replace this implementation with code to handle the error appropriately.
@ -85,6 +90,8 @@ public final class CoreDataStack {
container.viewContext.automaticallyMergesChangesFromParent = true
os_log("%{public}s[%{public}ld], %{public}s: %s", ((#file as NSString).lastPathComponent), #line, #function, storeDescription.debugDescription)
callback()
})
}
@ -96,7 +103,10 @@ extension CoreDataStack {
let oldStoreURL = persistentContainer.persistentStoreCoordinator.url(for: persistentContainer.persistentStoreCoordinator.persistentStores.first!)
try! persistentContainer.persistentStoreCoordinator.destroyPersistentStore(at: oldStoreURL, ofType: NSSQLiteStoreType, options: nil)
CoreDataStack.load(persistentContainer: persistentContainer)
CoreDataStack.load(persistentContainer: persistentContainer) { [weak self] in
guard let self = self else { return }
self.didFinishLoad.value = true
}
}
}

View File

@ -22,7 +22,7 @@
"publish_post_failure": {
"title": "Publish Failure",
"message": "Failed to publish the post.\nPlease check your internet connection.",
"attchments_message": {
"attachments_message": {
"video_attach_with_photo": "Cannot attach a video to a post that already contains images.",
"more_than_one_video": "Cannot attach more than one video."
}
@ -524,7 +524,7 @@
},
"boring_zone": {
"title": "The Boring Zone",
"account_settings": "Account settings",
"account_settings": "Account Settings",
"terms": "Terms of Service",
"privacy": "Privacy Policy"
},

File diff suppressed because it is too large Load Diff

View File

@ -12,7 +12,7 @@
<key>CoreDataStack.xcscheme_^#shared#^_</key>
<dict>
<key>orderHint</key>
<integer>21</integer>
<integer>24</integer>
</dict>
<key>Mastodon - ASDK.xcscheme_^#shared#^_</key>
<dict>
@ -37,7 +37,12 @@
<key>NotificationService.xcscheme_^#shared#^_</key>
<dict>
<key>orderHint</key>
<integer>20</integer>
<integer>22</integer>
</dict>
<key>ShareActionExtension.xcscheme_^#shared#^_</key>
<dict>
<key>orderHint</key>
<integer>21</integer>
</dict>
</dict>
<key>SuppressBuildableAutocreation</key>

View File

@ -105,8 +105,8 @@
"repositoryURL": "https://github.com/onevcat/Kingfisher.git",
"state": {
"branch": null,
"revision": "15d199e84677303a7004ed2c5ecaa1a90f3863f8",
"version": "6.2.1"
"revision": "44450a8f564d7c0165f736ba2250649ff8d3e556",
"version": "6.3.0"
}
},
{
@ -123,8 +123,8 @@
"repositoryURL": "https://github.com/kean/Nuke.git",
"state": {
"branch": null,
"revision": "69ae6d5b8c4b898450432f94bd35f863d3830cfc",
"version": "10.3.0"
"revision": "83e1edaa5a30c567eb129c21c6d00f2f552d2c6f",
"version": "10.3.1"
}
},
{
@ -163,6 +163,15 @@
"version": "1.0.0"
}
},
{
"package": "Introspect",
"repositoryURL": "https://github.com/siteline/SwiftUI-Introspect.git",
"state": {
"branch": null,
"revision": "2e09be8af614401bc9f87d40093ec19ce56ccaf2",
"version": "0.1.3"
}
},
{
"package": "SwiftyJSON",
"repositoryURL": "https://github.com/SwiftyJSON/SwiftyJSON.git",

View File

@ -34,7 +34,7 @@ extension CategoryPickerSection {
cell.categoryView.titleLabel.textColor = .white
}
} else {
cell.categoryView.bgView.backgroundColor = Asset.Colors.Background.secondaryGroupedSystemBackground.color
cell.categoryView.bgView.backgroundColor = Asset.Theme.Mastodon.secondaryGroupedSystemBackground.color
cell.categoryView.bgView.applyShadow(color: Asset.Colors.brandBlue.color, alpha: 0, x: 0, y: 0, blur: 0.0)
if case .all = item {
cell.categoryView.titleLabel.textColor = Asset.Colors.brandBlue.color

View File

@ -33,16 +33,6 @@ extension SearchResultSection {
let cell = tableView.dequeueReusableCell(withIdentifier: String(describing: SearchResultTableViewCell.self), for: indexPath) as! SearchResultTableViewCell
cell.config(with: tag)
return cell
// case .hashtagObjectID(let hashtagObjectID):
// let cell = tableView.dequeueReusableCell(withIdentifier: String(describing: SearchingTableViewCell.self), for: indexPath) as! SearchingTableViewCell
// let tag = dependency.context.managedObjectContext.object(with: hashtagObjectID) as! Tag
// cell.config(with: tag)
// return cell
// case .accountObjectID(let accountObjectID):
// let cell = tableView.dequeueReusableCell(withIdentifier: String(describing: SearchingTableViewCell.self), for: indexPath) as! SearchingTableViewCell
// let user = dependency.context.managedObjectContext.object(with: accountObjectID) as! MastodonUser
// cell.config(with: user)
// return cell
case .status(let statusObjectID, let attribute):
let cell = tableView.dequeueReusableCell(withIdentifier: String(describing: StatusTableViewCell.self), for: indexPath) as! StatusTableViewCell
if let status = try? dependency.context.managedObjectContext.existingObject(with: statusObjectID) as? Status {
@ -73,8 +63,6 @@ extension SearchResultSection {
cell.loadMoreLabel.isHidden = true
}
return cell
default:
fatalError()
} // end switch
} // end UITableViewDiffableDataSource
} // end func

View File

@ -44,14 +44,26 @@ extension NotificationSection {
avatarImageURL: notification.account.avatarImageURL()
)
)
cell.actionImageView.image = UIImage(
func createActionImage() -> UIImage? {
return UIImage(
systemName: notification.notificationType.actionImageName,
withConfiguration: UIImage.SymbolConfiguration(
pointSize: 12, weight: .semibold
)
)?
.withRenderingMode(.alwaysTemplate)
.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

View File

@ -103,7 +103,7 @@ extension PollSection {
cell.pollOptionView.optionPercentageLabel.isHidden = false
cell.pollOptionView.optionPercentageLabel.text = String(Int(100 * percentage)) + "%"
cell.pollOptionView.voteProgressStripView.isHidden = false
cell.pollOptionView.voteProgressStripView.tintColor = voted ? Asset.Colors.brandBlue.color : Asset.Colors.Background.Poll.disabled.color
cell.pollOptionView.voteProgressStripView.tintColor = voted ? Asset.Colors.brandBlue.color : Asset.Colors.Poll.disabled.color
cell.pollOptionView.voteProgressStripView.setProgress(CGFloat(percentage), animated: animated)
}
}

View File

@ -9,6 +9,7 @@ import UIKit
import Foundation
import ActiveLabel
import os.log
import MastodonUI
extension ActiveLabel {
@ -58,7 +59,7 @@ extension ActiveLabel {
}
extension ActiveLabel {
func configure(text: String) {
public func configure(text: String) {
attributedText = nil
activeEntities.removeAll()
self.text = text
@ -69,7 +70,7 @@ extension ActiveLabel {
extension ActiveLabel {
/// status content
func configure(content: String, emojiDict: MastodonStatusContent.EmojiDict) {
public func configure(content: String, emojiDict: MastodonStatusContent.EmojiDict) {
attributedText = nil
activeEntities.removeAll()
@ -83,7 +84,7 @@ extension ActiveLabel {
}
}
func configure(contentParseResult parseResult: MastodonStatusContent.ParseResult?) {
public func configure(contentParseResult parseResult: MastodonStatusContent.ParseResult?) {
attributedText = nil
activeEntities.removeAll()
text = parseResult?.trimmed ?? ""
@ -92,14 +93,14 @@ extension ActiveLabel {
}
/// account note
func configure(note: String, emojiDict: MastodonStatusContent.EmojiDict) {
public func configure(note: String, emojiDict: MastodonStatusContent.EmojiDict) {
configure(content: note, emojiDict: emojiDict)
}
}
extension ActiveLabel {
/// account field
func configure(field: String, emojiDict: MastodonStatusContent.EmojiDict) {
public func configure(field: String, emojiDict: MastodonStatusContent.EmojiDict) {
configure(content: field, emojiDict: emojiDict)
}
}

View File

@ -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

View File

@ -32,23 +32,6 @@ internal enum Asset {
internal static let plusCircle = ImageAsset(name: "Circles/plus.circle")
}
internal enum Colors {
internal enum Background {
internal enum Poll {
internal static let disabled = ColorAsset(name: "Colors/Background/Poll/disabled")
}
internal static let alertYellow = ColorAsset(name: "Colors/Background/alert.yellow")
internal static let dangerBorder = ColorAsset(name: "Colors/Background/danger.border")
internal static let danger = ColorAsset(name: "Colors/Background/danger")
internal static let mediaTypeIndicotor = ColorAsset(name: "Colors/Background/media.type.indicotor")
internal static let onboardingBackground = ColorAsset(name: "Colors/Background/onboarding.background")
internal static let secondaryGroupedSystemBackground = ColorAsset(name: "Colors/Background/secondary.grouped.system.background")
internal static let secondarySystemBackground = ColorAsset(name: "Colors/Background/secondary.system.background")
internal static let systemBackground = ColorAsset(name: "Colors/Background/system.background")
internal static let systemElevatedBackground = ColorAsset(name: "Colors/Background/system.elevated.background")
internal static let systemGroupedBackground = ColorAsset(name: "Colors/Background/system.grouped.background")
internal static let tertiarySystemBackground = ColorAsset(name: "Colors/Background/tertiary.system.background")
internal static let tertiarySystemGroupedBackground = ColorAsset(name: "Colors/Background/tertiary.system.grouped.background")
}
internal enum Border {
internal static let composePoll = ColorAsset(name: "Colors/Border/compose.poll")
internal static let notificationStatus = ColorAsset(name: "Colors/Border/notification.status")
@ -73,6 +56,9 @@ internal enum Asset {
internal static let mention = ColorAsset(name: "Colors/Notification/mention")
internal static let reblog = ColorAsset(name: "Colors/Notification/reblog")
}
internal enum Poll {
internal static let disabled = ColorAsset(name: "Colors/Poll/disabled")
}
internal enum Shadow {
internal static let searchCard = ColorAsset(name: "Colors/Shadow/SearchCard")
}
@ -87,12 +73,15 @@ internal enum Asset {
internal static let invalid = ColorAsset(name: "Colors/TextField/invalid")
internal static let valid = ColorAsset(name: "Colors/TextField/valid")
}
internal static let alertYellow = ColorAsset(name: "Colors/alert.yellow")
internal static let battleshipGrey = ColorAsset(name: "Colors/battleshipGrey")
internal static let brandBlue = ColorAsset(name: "Colors/brand.blue")
internal static let brandBlueDarken20 = ColorAsset(name: "Colors/brand.blue.darken.20")
internal static let dangerBorder = ColorAsset(name: "Colors/danger.border")
internal static let danger = ColorAsset(name: "Colors/danger")
internal static let disabled = ColorAsset(name: "Colors/disabled")
internal static let inactive = ColorAsset(name: "Colors/inactive")
internal static let mediaTypeIndicotor = ColorAsset(name: "Colors/media.type.indicotor")
internal static let successGreen = ColorAsset(name: "Colors/success.green")
internal static let systemOrange = ColorAsset(name: "Colors/system.orange")
}
@ -103,10 +92,6 @@ internal enum Asset {
internal static let faceSmilingAdaptive = ImageAsset(name: "Human/face.smiling.adaptive")
}
internal enum Scene {
internal enum Compose {
internal static let background = ColorAsset(name: "Scene/Compose/background")
internal static let toolbarBackground = ColorAsset(name: "Scene/Compose/toolbar.background")
}
internal enum Profile {
internal enum Banner {
internal static let bioEditBackgroundGray = ColorAsset(name: "Scene/Profile/Banner/bio.edit.background.gray")
@ -136,6 +121,7 @@ internal enum Asset {
}
internal enum Theme {
internal enum Mastodon {
internal static let composeToolbarBackground = ColorAsset(name: "Theme/Mastodon/compose.toolbar.background")
internal static let contentWarningOverlayBackground = ColorAsset(name: "Theme/Mastodon/content.warning.overlay.background")
internal static let navigationBarBackground = ColorAsset(name: "Theme/Mastodon/navigation.bar.background")
internal static let profileFieldCollectionViewBackground = ColorAsset(name: "Theme/Mastodon/profile.field.collection.view.background")
@ -153,6 +139,7 @@ internal enum Asset {
internal static let tabBarItemInactiveIconColor = ColorAsset(name: "Theme/Mastodon/tab.bar.item.inactive.icon.color")
}
internal enum System {
internal static let composeToolbarBackground = ColorAsset(name: "Theme/system/compose.toolbar.background")
internal static let contentWarningOverlayBackground = ColorAsset(name: "Theme/system/content.warning.overlay.background")
internal static let navigationBarBackground = ColorAsset(name: "Theme/system/navigation.bar.background")
internal static let profileFieldCollectionViewBackground = ColorAsset(name: "Theme/system/profile.field.collection.view.background")
@ -170,6 +157,23 @@ internal enum Asset {
internal static let tabBarItemInactiveIconColor = ColorAsset(name: "Theme/system/tab.bar.item.inactive.icon.color")
}
}
internal enum Deprecated {
internal enum Background {
internal static let danger = ColorAsset(name: "_Deprecated/Background/danger")
internal static let onboardingBackground = ColorAsset(name: "_Deprecated/Background/onboarding.background")
internal static let secondaryGroupedSystemBackground = ColorAsset(name: "_Deprecated/Background/secondary.grouped.system.background")
internal static let secondarySystemBackground = ColorAsset(name: "_Deprecated/Background/secondary.system.background")
internal static let systemBackground = ColorAsset(name: "_Deprecated/Background/system.background")
internal static let systemElevatedBackground = ColorAsset(name: "_Deprecated/Background/system.elevated.background")
internal static let systemGroupedBackground = ColorAsset(name: "_Deprecated/Background/system.grouped.background")
internal static let tertiarySystemBackground = ColorAsset(name: "_Deprecated/Background/tertiary.system.background")
internal static let tertiarySystemGroupedBackground = ColorAsset(name: "_Deprecated/Background/tertiary.system.grouped.background")
}
internal enum Compose {
internal static let background = ColorAsset(name: "_Deprecated/Compose/background")
internal static let toolbarBackground = ColorAsset(name: "_Deprecated/Compose/toolbar.background")
}
}
}
// swiftlint:enable identifier_name line_length nesting type_body_length type_name

View File

@ -58,11 +58,11 @@ internal enum L10n {
internal static let message = L10n.tr("Localizable", "Common.Alerts.PublishPostFailure.Message")
/// Publish Failure
internal static let title = L10n.tr("Localizable", "Common.Alerts.PublishPostFailure.Title")
internal enum AttchmentsMessage {
internal enum AttachmentsMessage {
/// Cannot attach more than one video.
internal static let moreThanOneVideo = L10n.tr("Localizable", "Common.Alerts.PublishPostFailure.AttchmentsMessage.MoreThanOneVideo")
internal static let moreThanOneVideo = L10n.tr("Localizable", "Common.Alerts.PublishPostFailure.AttachmentsMessage.MoreThanOneVideo")
/// Cannot attach a video to a post that already contains images.
internal static let videoAttachWithPhoto = L10n.tr("Localizable", "Common.Alerts.PublishPostFailure.AttchmentsMessage.VideoAttachWithPhoto")
internal static let videoAttachWithPhoto = L10n.tr("Localizable", "Common.Alerts.PublishPostFailure.AttachmentsMessage.VideoAttachWithPhoto")
}
}
internal enum SavePhotoFailure {
@ -950,7 +950,7 @@ internal enum L10n {
internal static let trueBlackDarkMode = L10n.tr("Localizable", "Scene.Settings.Section.AppearanceSettings.TrueBlackDarkMode")
}
internal enum BoringZone {
/// Account settings
/// Account Settings
internal static let accountSettings = L10n.tr("Localizable", "Scene.Settings.Section.BoringZone.AccountSettings")
/// Privacy Policy
internal static let privacy = L10n.tr("Localizable", "Scene.Settings.Section.BoringZone.Privacy")

View File

@ -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
}

View File

@ -5,59 +5,59 @@
// Created by MainasuK Cirno on 2021-3-30.
//
import Foundation
import ActiveLabel
enum MastodonField {
@available(*, deprecated, message: "rely on server meta rendering")
static func parse(field string: String, emojiDict: MastodonStatusContent.EmojiDict) -> ParseResult {
// use content parser get emoji entities
let value = string
var string = string
var entities: [ActiveEntity] = []
do {
let contentParseresult = try MastodonStatusContent.parse(content: string, emojiDict: emojiDict)
string = contentParseresult.trimmed
entities.append(contentsOf: contentParseresult.activeEntities)
} catch {
// assertionFailure(error.localizedDescription)
}
let mentionMatches = string.matches(pattern: "(?:@([a-zA-Z0-9_]+)(@[a-zA-Z0-9_.-]+)?)")
let hashtagMatches = string.matches(pattern: "(?:#([^\\s.]+))")
let urlMatches = string.matches(pattern: "(?i)https?://\\S+(?:/|\\b)")
for match in mentionMatches {
guard let text = string.substring(with: match, at: 0) else { continue }
let entity = ActiveEntity(range: match.range, type: .mention(text, userInfo: nil))
entities.append(entity)
}
for match in hashtagMatches {
guard let text = string.substring(with: match, at: 0) else { continue }
let entity = ActiveEntity(range: match.range, type: .hashtag(text, userInfo: nil))
entities.append(entity)
}
for match in urlMatches {
guard let text = string.substring(with: match, at: 0) else { continue }
let entity = ActiveEntity(range: match.range, type: .url(text, trimmed: text, url: text, userInfo: nil))
entities.append(entity)
}
return ParseResult(value: value, trimmed: string, activeEntities: entities)
}
}
extension MastodonField {
struct ParseResult {
let value: String
let trimmed: String
let activeEntities: [ActiveEntity]
}
}
//import Foundation
//import ActiveLabel
//
//enum MastodonField {
//
// @available(*, deprecated, message: "rely on server meta rendering")
// public static func parse(field string: String, emojiDict: MastodonStatusContent.EmojiDict) -> ParseResult {
// // use content parser get emoji entities
// let value = string
//
// var string = string
// var entities: [ActiveEntity] = []
//
// do {
// let contentParseresult = try MastodonStatusContent.parse(content: string, emojiDict: emojiDict)
// string = contentParseresult.trimmed
// entities.append(contentsOf: contentParseresult.activeEntities)
// } catch {
// // assertionFailure(error.localizedDescription)
// }
//
// let mentionMatches = string.matches(pattern: "(?:@([a-zA-Z0-9_]+)(@[a-zA-Z0-9_.-]+)?)")
// let hashtagMatches = string.matches(pattern: "(?:#([^\\s.]+))")
// let urlMatches = string.matches(pattern: "(?i)https?://\\S+(?:/|\\b)")
//
//
// for match in mentionMatches {
// guard let text = string.substring(with: match, at: 0) else { continue }
// let entity = ActiveEntity(range: match.range, type: .mention(text, userInfo: nil))
// entities.append(entity)
// }
//
// for match in hashtagMatches {
// guard let text = string.substring(with: match, at: 0) else { continue }
// let entity = ActiveEntity(range: match.range, type: .hashtag(text, userInfo: nil))
// entities.append(entity)
// }
//
// for match in urlMatches {
// guard let text = string.substring(with: match, at: 0) else { continue }
// let entity = ActiveEntity(range: match.range, type: .url(text, trimmed: text, url: text, userInfo: nil))
// entities.append(entity)
// }
//
// return ParseResult(value: value, trimmed: string, activeEntities: entities)
// }
//
//}
//
//extension MastodonField {
// public struct ParseResult {
// let value: String
// let trimmed: String
// let activeEntities: [ActiveEntity]
// }
//}

View File

@ -7,9 +7,9 @@
import Foundation
final class MastodonMetricFormatter: Formatter {
final public class MastodonMetricFormatter: Formatter {
func string(from number: Int) -> String? {
public func string(from number: Int) -> String? {
let isPositive = number >= 0
let symbol = isPositive ? "" : "-"

View File

@ -7,19 +7,19 @@
import Foundation
enum MastodonRegex {
public enum MastodonRegex {
/// mention, hashtag.
/// @...
/// #...
static let highlightPattern = "(?:@([a-zA-Z0-9_]+)(@[a-zA-Z0-9_.-]+)?|#([^\\s.]+))"
public static let highlightPattern = "(?:@([a-zA-Z0-9_]+)(@[a-zA-Z0-9_.-]+)?|#([^\\s.]+))"
/// emoji
/// :shortcode:
/// accept ^\B: or \s: but not accept \B: to force user input a space to make emoji take effect
/// precondition :\B with following space
static let emojiPattern = "(?:(^\\B:|\\s:)([a-zA-Z0-9_]+)(:\\B(?=\\s)))"
public static let emojiPattern = "(?:(^\\B:|\\s:)([a-zA-Z0-9_]+)(:\\B(?=\\s)))"
/// mention, hashtag, emoji
/// @
/// #
/// :
static let autoCompletePattern = "(?:@([a-zA-Z0-9_]+)(@[a-zA-Z0-9_.-]+)?|#([^\\s.]+))|(^\\B:|\\s:)([a-zA-Z0-9_]+)"
public static let autoCompletePattern = "(?:@([a-zA-Z0-9_]+)(@[a-zA-Z0-9_.-]+)?|#([^\\s.]+))|(^\\B:|\\s:)([a-zA-Z0-9_]+)"
}

View File

@ -8,7 +8,7 @@
import UIKit
extension MastodonStatusContent {
struct Appearance {
public struct Appearance {
let attributes: [NSAttributedString.Key: Any]
let urlAttributes: [NSAttributedString.Key: Any]
let hashtagAttributes: [NSAttributedString.Key: Any]

View File

@ -9,20 +9,20 @@ import Foundation
import ActiveLabel
extension MastodonStatusContent {
struct ParseResult: Hashable {
let document: String
let original: String
let trimmed: String
let activeEntities: [ActiveEntity]
public struct ParseResult: Hashable {
public let document: String
public let original: String
public let trimmed: String
public let activeEntities: [ActiveEntity]
static func == (lhs: MastodonStatusContent.ParseResult, rhs: MastodonStatusContent.ParseResult) -> Bool {
public static func == (lhs: MastodonStatusContent.ParseResult, rhs: MastodonStatusContent.ParseResult) -> Bool {
return lhs.document == rhs.document
&& lhs.original == rhs.original
&& lhs.trimmed == rhs.trimmed
&& lhs.activeEntities.count == rhs.activeEntities.count // FIXME:
}
func hash(into hasher: inout Hasher) {
public func hash(into hasher: inout Hasher) {
hasher.combine(document)
hasher.combine(original)
hasher.combine(trimmed)
@ -57,7 +57,7 @@ extension ActiveEntityType {
static let appScheme = "mastodon"
init?(url: URL) {
public init?(url: URL) {
guard let scheme = url.scheme?.lowercased() else { return nil }
guard scheme == ActiveEntityType.appScheme else {
self = .url("", trimmed: "", url: url.absoluteString, userInfo: nil)
@ -78,7 +78,7 @@ extension ActiveEntityType {
return nil
}
var uri: URL? {
public var uri: URL? {
switch self {
case .url(_, _, let url, _):
return URL(string: url)

View File

@ -10,14 +10,14 @@ import Combine
import ActiveLabel
import Fuzi
enum MastodonStatusContent {
public enum MastodonStatusContent {
typealias EmojiShortcode = String
typealias EmojiDict = [EmojiShortcode: URL]
public typealias EmojiShortcode = String
public typealias EmojiDict = [EmojiShortcode: URL]
static let workingQueue = DispatchQueue(label: "org.joinmastodon.app.ActiveLabel.working-queue", qos: .userInteractive, attributes: .concurrent)
static func parseResult(content: String, emojiDict: MastodonStatusContent.EmojiDict) -> AnyPublisher<MastodonStatusContent.ParseResult?, Never> {
public static func parseResult(content: String, emojiDict: MastodonStatusContent.EmojiDict) -> AnyPublisher<MastodonStatusContent.ParseResult?, Never> {
return Future { promise in
self.workingQueue.async {
let parseResult = try? MastodonStatusContent.parse(content: content, emojiDict: emojiDict)
@ -27,7 +27,7 @@ enum MastodonStatusContent {
.eraseToAnyPublisher()
}
static func parse(content: String, emojiDict: EmojiDict) throws -> MastodonStatusContent.ParseResult {
public static func parse(content: String, emojiDict: EmojiDict) throws -> MastodonStatusContent.ParseResult {
let document: String = {
var content = content
for (shortcode, url) in emojiDict {

View File

@ -19,7 +19,8 @@ extension UserDefaults {
@objc dynamic var preferredStaticAvatar: Bool {
get {
register(defaults: [#function: false])
// default false
// without set register to profile timeline performance
return bool(forKey: #function)
}
set { self[#function] = newValue }

View File

@ -6,6 +6,7 @@
//
import UIKit
import MastodonExtension
extension UserDefaults {

View File

@ -1,12 +0,0 @@
//
// SplashPreference.swift
// Mastodon
//
// Created by Cirno MainasuK on 2020-2-4.
//
import UIKit
extension UserDefaults {
// TODO: splash scene
}

View File

@ -6,6 +6,7 @@
//
import UIKit
import MastodonExtension
extension UserDefaults {

View File

@ -24,11 +24,22 @@ extension AvatarConfigurableView {
public func configure(with configuration: AvatarConfigurableViewConfiguration) {
let placeholderImage: UIImage = {
guard let placeholderImage = configuration.placeholderImage else {
#if APP_EXTENSION
let placeholderImage = configuration.placeholderImage ?? UIImage.placeholder(size: Self.configurableAvatarImageSize, color: .systemFill)
if Self.configurableAvatarImageCornerRadius < Self.configurableAvatarImageSize.width * 0.5 {
return placeholderImage
.af.imageAspectScaled(toFill: Self.configurableAvatarImageSize)
.af.imageRounded(withCornerRadius: Self.configurableAvatarImageCornerRadius, divideRadiusByImageScale: false)
} else {
return placeholderImage.af.imageRoundedIntoCircle()
}
#else
return AppContext.shared.placeholderImageCacheService.image(
color: .systemFill,
size: Self.configurableAvatarImageSize,
cornerRadius: Self.configurableAvatarImageCornerRadius
)
#endif
}
return placeholderImage
}()

View File

@ -526,6 +526,9 @@ extension StatusProviderFacade {
guard let provider = provider else { return }
guard let status = status?.reblog ?? status else { return }
let generator = UIImpactFeedbackGenerator(style: .light)
generator.impactOccurred()
let composeViewModel = ComposeViewModel(context: provider.context, composeKind: .reply(repliedToStatusObjectID: status.objectID))
provider.coordinator.present(scene: .compose(viewModel: composeViewModel), from: provider, transition: .modal(animated: true, completion: nil))
}

View File

@ -49,7 +49,7 @@ extension UserProviderFacade {
private static func _toggleUserFollowRelationship(
context: AppContext,
activeMastodonAuthenticationBox: AuthenticationService.MastodonAuthenticationBox,
activeMastodonAuthenticationBox: MastodonAuthenticationBox,
mastodonUser: AnyPublisher<MastodonUser?, Never>
) -> AnyPublisher<Mastodon.Response.Content<Mastodon.Entity.Relationship>, Error> {
mastodonUser
@ -111,7 +111,7 @@ extension UserProviderFacade {
private static func _toggleUserBlockRelationship(
context: AppContext,
activeMastodonAuthenticationBox: AuthenticationService.MastodonAuthenticationBox,
activeMastodonAuthenticationBox: MastodonAuthenticationBox,
mastodonUser: AnyPublisher<MastodonUser?, Never>
) -> AnyPublisher<Mastodon.Response.Content<Mastodon.Entity.Relationship>, Error> {
mastodonUser
@ -174,7 +174,7 @@ extension UserProviderFacade {
private static func _toggleUserMuteRelationship(
context: AppContext,
activeMastodonAuthenticationBox: AuthenticationService.MastodonAuthenticationBox,
activeMastodonAuthenticationBox: MastodonAuthenticationBox,
mastodonUser: AnyPublisher<MastodonUser?, Never>
) -> AnyPublisher<Mastodon.Response.Content<Mastodon.Entity.Relationship>, Error> {
mastodonUser

View File

@ -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
}
}

View File

@ -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
}
}

View File

@ -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
}
}

View File

@ -5,9 +5,9 @@
"color-space" : "srgb",
"components" : {
"alpha" : "1.000",
"blue" : "90",
"green" : "64",
"red" : "223"
"blue" : "0.259",
"green" : "0.180",
"red" : "0.639"
}
},
"idiom" : "universal"

View File

@ -5,9 +5,9 @@
"color-space" : "srgb",
"components" : {
"alpha" : "0.600",
"blue" : "0",
"green" : "0",
"red" : "0"
"blue" : "0.000",
"green" : "0.000",
"red" : "0.000"
}
},
"idiom" : "universal"

View File

@ -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
}
}

View File

@ -5,9 +5,9 @@
"color-space" : "srgb",
"components" : {
"alpha" : "1.000",
"blue" : "254",
"green" : "255",
"red" : "254"
"blue" : "0.871",
"green" : "0.847",
"red" : "0.839"
}
},
"idiom" : "universal"
@ -23,9 +23,9 @@
"color-space" : "srgb",
"components" : {
"alpha" : "1.000",
"blue" : "67",
"green" : "53",
"red" : "49"
"blue" : "0.263",
"green" : "0.208",
"red" : "0.192"
}
},
"idiom" : "universal"

View File

@ -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
}
}

View File

@ -5,9 +5,9 @@
"color-space" : "srgb",
"components" : {
"alpha" : "1.000",
"blue" : "232",
"green" : "225",
"red" : "217"
"blue" : "0.353",
"green" : "0.251",
"red" : "0.875"
}
},
"idiom" : "universal"

View File

@ -5,9 +5,9 @@
"color-space" : "srgb",
"components" : {
"alpha" : "1.000",
"blue" : "66",
"green" : "46",
"red" : "163"
"blue" : "0.910",
"green" : "0.882",
"red" : "0.851"
}
},
"idiom" : "universal"

View File

@ -5,9 +5,9 @@
"color-space" : "srgb",
"components" : {
"alpha" : "1.000",
"blue" : "232",
"green" : "225",
"red" : "217"
"blue" : "0.996",
"green" : "1.000",
"red" : "0.996"
}
},
"idiom" : "universal"
@ -23,9 +23,9 @@
"color-space" : "srgb",
"components" : {
"alpha" : "1.000",
"blue" : "34",
"green" : "27",
"red" : "25"
"blue" : "0.263",
"green" : "0.208",
"red" : "0.192"
}
},
"idiom" : "universal"

View File

@ -5,9 +5,9 @@
"color-space" : "srgb",
"components" : {
"alpha" : "1.000",
"blue" : "254",
"green" : "255",
"red" : "254"
"blue" : "0.910",
"green" : "0.882",
"red" : "0.851"
}
},
"idiom" : "universal"
@ -23,9 +23,9 @@
"color-space" : "srgb",
"components" : {
"alpha" : "1.000",
"blue" : "0x37",
"green" : "0x2C",
"red" : "0x28"
"blue" : "0.133",
"green" : "0.106",
"red" : "0.098"
}
},
"idiom" : "universal"

View File

@ -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
}
}

View File

@ -23,9 +23,9 @@
"color-space" : "srgb",
"components" : {
"alpha" : "1.000",
"blue" : "55",
"green" : "44",
"red" : "40"
"blue" : "0.216",
"green" : "0.173",
"red" : "0.157"
}
},
"idiom" : "universal"

View File

@ -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
}
}

View File

@ -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
}
}

View File

@ -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
}
}

View File

@ -23,9 +23,9 @@
"color-space" : "srgb",
"components" : {
"alpha" : "1.000",
"blue" : "0x37",
"green" : "0x2C",
"red" : "0x28"
"blue" : "0.216",
"green" : "0.173",
"red" : "0.157"
}
},
"idiom" : "universal"

View File

@ -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
}
}

View File

@ -0,0 +1,9 @@
{
"info" : {
"author" : "xcode",
"version" : 1
},
"properties" : {
"provides-namespace" : true
}
}

View File

@ -10,8 +10,8 @@
"Common.Alerts.DiscardPostContent.Title" = "Discard Draft";
"Common.Alerts.EditProfileFailure.Message" = "Cannot edit profile. Please try again.";
"Common.Alerts.EditProfileFailure.Title" = "Edit Profile Error";
"Common.Alerts.PublishPostFailure.AttchmentsMessage.MoreThanOneVideo" = "Cannot attach more than one video.";
"Common.Alerts.PublishPostFailure.AttchmentsMessage.VideoAttachWithPhoto" = "Cannot attach a video to a post that already contains images.";
"Common.Alerts.PublishPostFailure.AttachmentsMessage.MoreThanOneVideo" = "Cannot attach more than one video.";
"Common.Alerts.PublishPostFailure.AttachmentsMessage.VideoAttachWithPhoto" = "Cannot attach a video to a post that already contains images.";
"Common.Alerts.PublishPostFailure.Message" = "Failed to publish the post.
Please check your internet connection.";
"Common.Alerts.PublishPostFailure.Title" = "Publish Failure";
@ -323,7 +323,7 @@ any server.";
"Scene.Settings.Section.Appearance.Title" = "Appearance";
"Scene.Settings.Section.AppearanceSettings.DisableAvatarAnimation" = "Disable animated avatars";
"Scene.Settings.Section.AppearanceSettings.TrueBlackDarkMode" = "True black dark mode";
"Scene.Settings.Section.BoringZone.AccountSettings" = "Account settings";
"Scene.Settings.Section.BoringZone.AccountSettings" = "Account Settings";
"Scene.Settings.Section.BoringZone.Privacy" = "Privacy Policy";
"Scene.Settings.Section.BoringZone.Terms" = "Terms of Service";
"Scene.Settings.Section.BoringZone.Title" = "The Boring Zone";

View File

@ -10,8 +10,8 @@
"Common.Alerts.DiscardPostContent.Title" = "Discard Draft";
"Common.Alerts.EditProfileFailure.Message" = "Cannot edit profile. Please try again.";
"Common.Alerts.EditProfileFailure.Title" = "Edit Profile Error";
"Common.Alerts.PublishPostFailure.AttchmentsMessage.MoreThanOneVideo" = "Cannot attach more than one video.";
"Common.Alerts.PublishPostFailure.AttchmentsMessage.VideoAttachWithPhoto" = "Cannot attach a video to a post that already contains images.";
"Common.Alerts.PublishPostFailure.AttachmentsMessage.MoreThanOneVideo" = "Cannot attach more than one video.";
"Common.Alerts.PublishPostFailure.AttachmentsMessage.VideoAttachWithPhoto" = "Cannot attach a video to a post that already contains images.";
"Common.Alerts.PublishPostFailure.Message" = "Failed to publish the post.
Please check your internet connection.";
"Common.Alerts.PublishPostFailure.Title" = "Publish Failure";
@ -323,7 +323,7 @@ any server.";
"Scene.Settings.Section.Appearance.Title" = "Appearance";
"Scene.Settings.Section.AppearanceSettings.DisableAvatarAnimation" = "Disable animated avatars";
"Scene.Settings.Section.AppearanceSettings.TrueBlackDarkMode" = "True black dark mode";
"Scene.Settings.Section.BoringZone.AccountSettings" = "Account settings";
"Scene.Settings.Section.BoringZone.AccountSettings" = "Account Settings";
"Scene.Settings.Section.BoringZone.Privacy" = "Privacy Policy";
"Scene.Settings.Section.BoringZone.Terms" = "Terms of Service";
"Scene.Settings.Section.BoringZone.Title" = "The Boring Zone";

View File

@ -6,9 +6,12 @@
//
import UIKit
import Combine
final class AutoCompleteTopChevronView: UIView {
var disposeBag = Set<AnyCancellable>()
static let chevronSize = CGSize(width: 20, height: 12)
private let shadowView = UIView()
@ -16,10 +19,10 @@ final class AutoCompleteTopChevronView: UIView {
private let maskLayer = CAShapeLayer()
var chevronMinX: CGFloat = 0
var topViewBackgroundColor = Asset.Scene.Compose.background.color {
var topViewBackgroundColor = ThemeService.shared.currentTheme.value.systemElevatedBackgroundColor {
didSet { setNeedsLayout() }
}
var bottomViewBackgroundColor = Asset.Colors.Background.systemBackground.color {
var bottomViewBackgroundColor = ThemeService.shared.currentTheme.value.systemBackgroundColor {
didSet { setNeedsLayout() }
}
@ -70,6 +73,15 @@ extension AutoCompleteTopChevronView {
shadowLayer.fillColor = topViewBackgroundColor.cgColor
shadowView.layer.addSublayer(shadowLayer)
setupBackgroundColor(theme: ThemeService.shared.currentTheme.value)
ThemeService.shared.currentTheme
.receive(on: DispatchQueue.main)
.sink { [weak self] theme in
guard let self = self else { return }
self.setupBackgroundColor(theme: theme)
}
.store(in: &disposeBag)
}
override func layoutSubviews() {
@ -114,6 +126,13 @@ extension AutoCompleteTopChevronView {
}
extension AutoCompleteTopChevronView {
private func setupBackgroundColor(theme: Theme) {
topViewBackgroundColor = theme.systemElevatedBackgroundColor
bottomViewBackgroundColor = theme.systemBackgroundColor
}
}
extension AutoCompleteTopChevronView {
func invertMask(in rect: CGRect) -> CAShapeLayer {
let path = UIBezierPath()
@ -153,7 +172,7 @@ struct AutoCompleteTopChevronView_Previews: PreviewProvider {
view.chevronMinX = 10
return view
}
.background(Color(Asset.Scene.Compose.background.color))
.background(Color(ThemeService.shared.currentTheme.value.systemElevatedBackgroundColor))
.padding(20)
.previewLayout(.fixed(width: 375 + 40, height: 100 + 40))
UIViewPreview(width: 375) {
@ -166,7 +185,7 @@ struct AutoCompleteTopChevronView_Previews: PreviewProvider {
view.chevronMinX = 10
return view
}
.background(Color(Asset.Scene.Compose.background.color))
.background(Color(ThemeService.shared.currentTheme.value.systemElevatedBackgroundColor))
.preferredColorScheme(.dark)
.padding(20)
.previewLayout(.fixed(width: 375 + 40, height: 100 + 40))

View File

@ -8,6 +8,7 @@
import os.log
import UIKit
import Combine
import MastodonUI
protocol ComposeStatusAttachmentCollectionViewCellDelegate: AnyObject {
func composeStatusAttachmentCollectionViewCell(_ cell: ComposeStatusAttachmentCollectionViewCell, removeButtonDidPressed button: UIButton)
@ -15,6 +16,8 @@ protocol ComposeStatusAttachmentCollectionViewCellDelegate: AnyObject {
final class ComposeStatusAttachmentCollectionViewCell: UICollectionViewCell {
let logger = Logger(subsystem: "ComposeStatusAttachmentCollectionViewCell", category: "UI")
var disposeBag = Set<AnyCancellable>()
static let verticalMarginHeight: CGFloat = ComposeStatusAttachmentCollectionViewCell.removeButtonSize.height * 0.5
@ -29,10 +32,10 @@ final class ComposeStatusAttachmentCollectionViewCell: UICollectionViewCell {
let image = UIImage(systemName: "minus")!.withConfiguration(UIImage.SymbolConfiguration(pointSize: 14, weight: .bold))
button.tintColor = .white
button.setImage(image, for: .normal)
button.setBackgroundImage(.placeholder(color: Asset.Colors.Background.danger.color), for: .normal)
button.setBackgroundImage(.placeholder(color: Asset.Colors.danger.color), for: .normal)
button.layer.masksToBounds = true
button.layer.cornerRadius = ComposeStatusAttachmentCollectionViewCell.removeButtonSize.width * 0.5
button.layer.borderColor = Asset.Colors.Background.dangerBorder.color.cgColor
button.layer.borderColor = Asset.Colors.dangerBorder.color.cgColor
button.layer.borderWidth = 1
return button
}()
@ -58,7 +61,7 @@ final class ComposeStatusAttachmentCollectionViewCell: UICollectionViewCell {
}
deinit {
os_log(.info, log: .debug, "%{public}s[%{public}ld], %{public}s", ((#file as NSString).lastPathComponent), #line, #function)
logger.debug("\((#file as NSString).lastPathComponent, privacy: .public)[\(#line, privacy: .public)], \(#function, privacy: .public)")
}
}
@ -96,7 +99,7 @@ extension ComposeStatusAttachmentCollectionViewCell {
extension ComposeStatusAttachmentCollectionViewCell {
@objc private func removeButtonDidPressed(_ sender: UIButton) {
os_log(.info, log: .debug, "%{public}s[%{public}ld], %{public}s", ((#file as NSString).lastPathComponent), #line, #function)
logger.debug("\((#file as NSString).lastPathComponent, privacy: .public)[\(#line, privacy: .public)], \(#function, privacy: .public)")
delegate?.composeStatusAttachmentCollectionViewCell(self, removeButtonDidPressed: sender)
}

View File

@ -5,14 +5,16 @@
// Created by MainasuK Cirno on 2021-6-28.
//
import os.log
import UIKit
import Combine
import MetaTextView
import UITextView_Placeholder
final class ComposeStatusContentTableViewCell: UITableViewCell {
let logger = Logger(subsystem: "ComposeStatusContentTableViewCell", category: "UI")
var disposeBag = Set<AnyCancellable>()
let statusView = ReplicaStatusView()
@ -149,7 +151,7 @@ extension ComposeStatusContentTableViewCell: UITextViewDelegate {
}
func textViewDidChange(_ textView: UITextView) {
os_log(.info, log: .debug, "%{public}s[%{public}ld], %{public}s: text: %s", ((#file as NSString).lastPathComponent), #line, #function, textView.text)
logger.debug("\((#file as NSString).lastPathComponent, privacy: .public)[\(#line, privacy: .public)], \(#function, privacy: .public): text: \(textView.text ?? "<nil>")")
guard textView === statusContentWarningEditorView.textView else { return }
// replace line break with space
textView.text = textView.text.replacingOccurrences(of: "\n", with: " ")

View File

@ -14,6 +14,7 @@ import MetaTextView
import MastodonMeta
import Meta
import Nuke
import MastodonUI
final class ComposeViewController: UIViewController, NeedsDependency {
@ -188,7 +189,7 @@ extension ComposeViewController {
])
tableView.delegate = self
viewModel.setupDiffableDataSource(
viewModel.setupDataSource(
tableView: tableView,
metaTextDelegate: self,
metaTextViewDelegate: self,
@ -263,7 +264,6 @@ extension ComposeViewController {
self.view.layoutIfNeeded()
}
}
self.updateKeyboardBackground(isKeyboardDisplay: isShow)
return
}
// isShow AND dock state
@ -279,14 +279,12 @@ extension ComposeViewController {
self.autoCompleteViewController.tableView.contentInset.bottom = autoCompleteTableViewBottomInset
self.autoCompleteViewController.tableView.verticalScrollIndicatorInsets.bottom = autoCompleteTableViewBottomInset
// adjust inset for collectionView
// adjust inset for tableView
let contentFrame = self.view.convert(self.tableView.frame, to: nil)
let padding = contentFrame.maxY + extraMargin - endFrame.minY
guard padding > 0 else {
self.tableView.contentInset.bottom = self.view.safeAreaInsets.bottom + extraMargin
self.tableView.verticalScrollIndicatorInsets.bottom = self.view.safeAreaInsets.bottom + extraMargin
self.updateKeyboardBackground(isKeyboardDisplay: false)
return
}
@ -296,7 +294,6 @@ extension ComposeViewController {
self.composeToolbarViewBottomLayoutConstraint.constant = endFrame.height
self.view.layoutIfNeeded()
}
self.updateKeyboardBackground(isKeyboardDisplay: isShow)
})
.store(in: &disposeBag)
@ -587,13 +584,10 @@ extension ComposeViewController {
return imagePicker
}
private func updateKeyboardBackground(isKeyboardDisplay: Bool) {
composeToolbarBackgroundView.backgroundColor = Asset.Scene.Compose.toolbarBackground.color
}
private func setupBackgroundColor(theme: Theme) {
view.backgroundColor = theme.systemElevatedBackgroundColor
tableView.backgroundColor = theme.systemElevatedBackgroundColor
composeToolbarBackgroundView.backgroundColor = theme.composeToolbarBackgroundColor
}
}

View File

@ -16,7 +16,7 @@ import MetaTextView
extension ComposeViewModel {
func setupDiffableDataSource(
func setupDataSource(
tableView: UITableView,
metaTextDelegate: MetaTextDelegate,
metaTextViewDelegate: UITextViewDelegate,

View File

@ -28,7 +28,7 @@ final class ComposeViewModel: NSObject {
let isContentWarningComposing = CurrentValueSubject<Bool, Never>(false)
let selectedStatusVisibility: CurrentValueSubject<ComposeToolbarView.VisibilitySelectionType, Never>
let activeAuthentication: CurrentValueSubject<MastodonAuthentication?, Never>
let activeAuthenticationBox: CurrentValueSubject<AuthenticationService.MastodonAuthenticationBox?, Never>
let activeAuthenticationBox: CurrentValueSubject<MastodonAuthenticationBox?, Never>
let traitCollectionDidChangePublisher = CurrentValueSubject<Void, Never>(Void()) // use CurrentValueSubject to make initial event emit
let repliedToCellFrame = CurrentValueSubject<CGRect, Never>(.zero)
let autoCompleteRetryLayoutTimes = CurrentValueSubject<Int, Never>(0)
@ -202,13 +202,13 @@ final class ComposeViewModel: NSObject {
}
.assign(to: \.value, on: characterCount)
.store(in: &disposeBag)
// bind compose bar button item UI state
let isComposeContentEmpty = composeStatusAttribute.composeContent
.map { ($0 ?? "").isEmpty }
let isComposeContentValid = composeStatusAttribute.composeContent
.map { composeContent -> Bool in
let composeContent = composeContent ?? ""
return composeContent.count <= ComposeViewModel.composeContentLimit
let isComposeContentValid = characterCount
.map { characterCount -> Bool in
return characterCount <= ComposeViewModel.composeContentLimit
}
let isMediaEmpty = attachmentServices
.map { $0.isEmpty }
@ -224,10 +224,10 @@ final class ComposeViewModel: NSObject {
}
let isPublishBarButtonItemEnabledPrecondition1 = Publishers.CombineLatest4(
isComposeContentEmpty.eraseToAnyPublisher(),
isComposeContentValid.eraseToAnyPublisher(),
isMediaEmpty.eraseToAnyPublisher(),
isMediaUploadAllSuccess.eraseToAnyPublisher()
isComposeContentEmpty,
isComposeContentValid,
isMediaEmpty,
isMediaUploadAllSuccess
)
.map { isComposeContentEmpty, isComposeContentValid, isMediaEmpty, isMediaUploadAllSuccess -> Bool in
if isMediaEmpty {
@ -239,10 +239,10 @@ final class ComposeViewModel: NSObject {
.eraseToAnyPublisher()
let isPublishBarButtonItemEnabledPrecondition2 = Publishers.CombineLatest4(
isComposeContentEmpty.eraseToAnyPublisher(),
isComposeContentValid.eraseToAnyPublisher(),
isPollComposing.eraseToAnyPublisher(),
isPollAttributeAllValid.eraseToAnyPublisher()
isComposeContentEmpty,
isComposeContentValid,
isPollComposing,
isPollAttributeAllValid
)
.map { isComposeContentEmpty, isComposeContentValid, isPollComposing, isPollAttributeAllValid -> Bool in
if isPollComposing {
@ -390,9 +390,9 @@ extension ComposeViewModel {
var failureReason: String? {
switch self {
case .videoAttachWithPhoto:
return L10n.Common.Alerts.PublishPostFailure.AttchmentsMessage.videoAttachWithPhoto
return L10n.Common.Alerts.PublishPostFailure.AttachmentsMessage.videoAttachWithPhoto
case .moreThanOneVideo:
return L10n.Common.Alerts.PublishPostFailure.AttchmentsMessage.moreThanOneVideo
return L10n.Common.Alerts.PublishPostFailure.AttachmentsMessage.moreThanOneVideo
}
}
}

View File

@ -88,7 +88,7 @@ extension ComposeStatusAttachmentTableViewCell {
guard let image = thumbnailImage else {
let placeholder = UIImage.placeholder(
size: size,
color: Asset.Colors.Background.systemGroupedBackground.color
color: ThemeService.shared.currentTheme.value.systemGroupedBackgroundColor
)
.af.imageRounded(
withCornerRadius: AttachmentContainerView.containerViewCornerRadius
@ -116,9 +116,11 @@ extension ComposeStatusAttachmentTableViewCell {
} else {
guard let uploadState = uploadState else { return }
switch uploadState {
case is MastodonAttachmentService.UploadState.Finish,
is MastodonAttachmentService.UploadState.Fail:
case is MastodonAttachmentService.UploadState.Finish:
cell.attachmentContainerView.activityIndicatorView.stopAnimating()
case is MastodonAttachmentService.UploadState.Fail:
cell.attachmentContainerView.activityIndicatorView.stopAnimating()
// FIXME: not display
cell.attachmentContainerView.emptyStateView.label.text = {
if let file = attachmentService.file.value {
switch file {

View File

@ -6,6 +6,7 @@
//
import UIKit
import MastodonUI
extension AttachmentContainerView {
final class EmptyStateView: UIView {

View File

@ -96,10 +96,14 @@ final class ComposeToolbarView: UIView {
extension ComposeToolbarView {
private func _init() {
// magic keyboard color (iOS 14):
// light with white background: RGB 214 216 222
// dark with black background: RGB 43 43 43
backgroundColor = Asset.Scene.Compose.toolbarBackground.color
setupBackgroundColor(theme: ThemeService.shared.currentTheme.value)
ThemeService.shared.currentTheme
.receive(on: DispatchQueue.main)
.sink { [weak self] theme in
guard let self = self else { return }
self.setupBackgroundColor(theme: theme)
}
.store(in: &disposeBag)
let stackView = UIStackView()
stackView.axis = .horizontal
@ -215,6 +219,10 @@ extension ComposeToolbarView {
extension ComposeToolbarView {
private func setupBackgroundColor(theme: Theme) {
backgroundColor = theme.composeToolbarBackgroundColor
}
private static func configureToolbarButtonAppearance(button: UIButton) {
button.tintColor = Asset.Colors.brandBlue.color
button.setBackgroundImage(.placeholder(size: ComposeToolbarView.toolbarButtonSize, color: .systemFill), for: .highlighted)

View File

@ -48,7 +48,7 @@ final class ReplicaStatusView: UIView {
let headerIconLabel: UILabel = {
let label = UILabel()
label.attributedText = StatusView.iconAttributedString(image: StatusView.reblogIconImage)
label.attributedText = ReplicaStatusView.iconAttributedString(image: ReplicaStatusView.reblogIconImage)
return label
}()
@ -67,7 +67,6 @@ final class ReplicaStatusView: UIView {
return view
}()
let avatarImageView: UIImageView = FLAnimatedImageView()
let avatarStackedContainerButton: AvatarStackContainerButton = AvatarStackContainerButton()
let nameLabel: ActiveLabel = {
let label = ActiveLabel(style: .statusName)
@ -157,7 +156,7 @@ extension ReplicaStatusView {
headerContainerStackView.topAnchor.constraint(equalTo: headerContainerView.topAnchor),
headerContainerStackView.leadingAnchor.constraint(equalTo: headerContainerView.leadingAnchor),
headerContainerStackView.trailingAnchor.constraint(equalTo: headerContainerView.trailingAnchor),
headerContainerView.bottomAnchor.constraint(equalTo: headerContainerStackView.bottomAnchor, constant: StatusView.containerStackViewSpacing).priority(.defaultHigh),
headerContainerView.bottomAnchor.constraint(equalTo: headerContainerStackView.bottomAnchor, constant: ReplicaStatusView.containerStackViewSpacing).priority(.defaultHigh),
])
containerStackView.addArrangedSubview(headerContainerView)
defer {
@ -167,15 +166,15 @@ extension ReplicaStatusView {
// author container: [avatar | author meta container | reveal button]
let authorContainerStackView = UIStackView()
authorContainerStackView.axis = .horizontal
authorContainerStackView.spacing = StatusView.avatarToLabelSpacing
authorContainerStackView.spacing = ReplicaStatusView.avatarToLabelSpacing
authorContainerStackView.distribution = .fill
// avatar
avatarView.translatesAutoresizingMaskIntoConstraints = false
authorContainerStackView.addArrangedSubview(avatarView)
NSLayoutConstraint.activate([
avatarView.widthAnchor.constraint(equalToConstant: StatusView.avatarImageSize.width).priority(.required - 1),
avatarView.heightAnchor.constraint(equalToConstant: StatusView.avatarImageSize.height).priority(.required - 1),
avatarView.widthAnchor.constraint(equalToConstant: ReplicaStatusView.avatarImageSize.width).priority(.required - 1),
avatarView.heightAnchor.constraint(equalToConstant: ReplicaStatusView.avatarImageSize.height).priority(.required - 1),
])
avatarImageView.translatesAutoresizingMaskIntoConstraints = false
avatarView.addSubview(avatarImageView)
@ -185,14 +184,6 @@ extension ReplicaStatusView {
avatarImageView.trailingAnchor.constraint(equalTo: avatarView.trailingAnchor),
avatarImageView.bottomAnchor.constraint(equalTo: avatarView.bottomAnchor),
])
avatarStackedContainerButton.translatesAutoresizingMaskIntoConstraints = false
avatarView.addSubview(avatarStackedContainerButton)
NSLayoutConstraint.activate([
avatarStackedContainerButton.topAnchor.constraint(equalTo: avatarView.topAnchor),
avatarStackedContainerButton.leadingAnchor.constraint(equalTo: avatarView.leadingAnchor),
avatarStackedContainerButton.trailingAnchor.constraint(equalTo: avatarView.trailingAnchor),
avatarStackedContainerButton.bottomAnchor.constraint(equalTo: avatarView.bottomAnchor),
])
// author meta container: [title container | subtitle container]
let authorMetaContainerStackView = UIStackView()
@ -235,7 +226,7 @@ extension ReplicaStatusView {
authorContainerStackView.topAnchor.constraint(equalTo: authorContainerView.topAnchor),
authorContainerStackView.leadingAnchor.constraint(equalTo: authorContainerView.leadingAnchor),
authorContainerStackView.trailingAnchor.constraint(equalTo: authorContainerView.trailingAnchor),
authorContainerView.bottomAnchor.constraint(equalTo: authorContainerStackView.bottomAnchor, constant: StatusView.containerStackViewSpacing).priority(.defaultHigh),
authorContainerView.bottomAnchor.constraint(equalTo: authorContainerStackView.bottomAnchor, constant: ReplicaStatusView.containerStackViewSpacing).priority(.defaultHigh),
])
containerStackView.addArrangedSubview(authorContainerView)
@ -252,8 +243,6 @@ extension ReplicaStatusView {
// status
statusContainerStackView.addArrangedSubview(contentMetaText.textView)
contentMetaText.textView.setContentCompressionResistancePriority(.required - 1, for: .vertical)
avatarStackedContainerButton.isHidden = true
}
}

View File

@ -6,6 +6,7 @@
//
import UIKit
import MastodonUI
final class StatusContentWarningEditorView: UIView {
@ -72,28 +73,6 @@ extension StatusContentWarningEditorView {
containerStackView.addArrangedSubview(iconImageView)
iconImageView.setContentHuggingPriority(.required - 1, for: .horizontal)
containerStackView.addArrangedSubview(textView)
// iconImageView.translatesAutoresizingMaskIntoConstraints = false
// addSubview(iconImageView)
// NSLayoutConstraint.activate([
// iconImageView.leadingAnchor.constraint(equalTo: layoutMarginsGuide.leadingAnchor),
// iconImageView.widthAnchor.constraint(equalToConstant: StatusView.avatarImageSize.width).priority(.defaultHigh), // center alignment to avatar
// ])
// iconImageView.setContentHuggingPriority(.required - 2, for: .horizontal)
//
// textView.translatesAutoresizingMaskIntoConstraints = false
// addSubview(textView)
// NSLayoutConstraint.activate([
// textView.centerYAnchor.constraint(equalTo: centerYAnchor),
// textView.topAnchor.constraint(equalTo: topAnchor, constant: 6),
// textView.leadingAnchor.constraint(equalTo: iconImageView.trailingAnchor, constant: StatusView.avatarToLabelSpacing - 4), // align to name label. minus magic 4pt to remove addition inset
// textView.trailingAnchor.constraint(equalTo: layoutMarginsGuide.trailingAnchor),
// bottomAnchor.constraint(equalTo: textView.bottomAnchor, constant: 6),
// textView.heightAnchor.constraint(greaterThanOrEqualToConstant: 44).priority(.defaultHigh),
// ])
//
// textView.setContentHuggingPriority(.required - 1, for: .vertical)
// textView.setContentCompressionResistancePriority(.required - 1, for: .vertical)
}
}

View File

@ -5,13 +5,15 @@
// Created by MainasuK Cirno on 2021-2-5.
//
#if DEBUG
import os.log
import UIKit
import CoreData
import CoreDataStack
#if DEBUG
import FLEX
import SwiftUI
import MastodonUI
extension HomeTimelineViewController {
var debugMenu: UIMenu {
@ -363,5 +365,6 @@ extension HomeTimelineViewController {
transition: .modal(animated: true, completion: nil)
)
}
}
#endif

View File

@ -7,6 +7,7 @@
import os.log
import UIKit
import MastodonUI
protocol HomeTimelineNavigationBarTitleViewDelegate: AnyObject {
func homeTimelineNavigationBarTitleView(_ titleView: HomeTimelineNavigationBarTitleView, logoButtonDidPressed sender: UIButton)
@ -113,7 +114,7 @@ extension HomeTimelineNavigationBarTitleView {
configureButton(
title: L10n.Scene.HomeTimeline.NavigationBarState.offline,
textColor: .white,
backgroundColor: Asset.Colors.Background.danger.color
backgroundColor: Asset.Colors.danger.color
)
button.isHidden = false
case .publishingPostLabel:

View File

@ -43,6 +43,15 @@ class MainTabBarController: UITabBarController {
}
}
var largeImage: UIImage {
switch self {
case .home: return UIImage(systemName: "house.fill", withConfiguration: UIImage.SymbolConfiguration(pointSize: 80))!
case .search: return UIImage(systemName: "magnifyingglass", withConfiguration: UIImage.SymbolConfiguration(pointSize: 80))!
case .notification: return UIImage(systemName: "bell.fill", withConfiguration: UIImage.SymbolConfiguration(pointSize: 80))!
case .me: return UIImage(systemName: "person.fill", withConfiguration: UIImage.SymbolConfiguration(pointSize: 80))!
}
}
func viewController(context: AppContext, coordinator: SceneCoordinator) -> UIViewController {
let viewController: UIViewController
switch self {
@ -112,14 +121,20 @@ extension MainTabBarController {
let tabs = Tab.allCases
let viewControllers: [UIViewController] = tabs.map { tab in
let viewController = tab.viewController(context: context, coordinator: coordinator)
viewController.tabBarItem.title = "" // set text to empty string for image only style (SDK failed to layout when set to nil)
viewController.tabBarItem.title = tab.title
viewController.tabBarItem.image = tab.image
viewController.tabBarItem.accessibilityLabel = tab.title
viewController.tabBarItem.largeContentSizeImage = tab.largeImage
viewController.tabBarItem.imageInsets = UIEdgeInsets(top: 6, left: 0, bottom: -6, right: 0)
return viewController
}
setViewControllers(viewControllers, animated: false)
selectedIndex = 0
UITabBarItem.appearance().setTitleTextAttributes([.foregroundColor : UIColor.clear], for: .normal)
UITabBarItem.appearance().setTitleTextAttributes([.foregroundColor : UIColor.clear], for: .highlighted)
UITabBarItem.appearance().setTitleTextAttributes([.foregroundColor : UIColor.clear], for: .selected)
context.apiService.error
.receive(on: DispatchQueue.main)
.sink { [weak self] error in

View File

@ -26,7 +26,7 @@ final class NotificationViewModel: NSObject {
let selectedIndex = CurrentValueSubject<NotificationSegment, Never>(.EveryThing)
let noMoreNotification = CurrentValueSubject<Bool, Never>(false)
let activeMastodonAuthenticationBox: CurrentValueSubject<AuthenticationService.MastodonAuthenticationBox?, Never>
let activeMastodonAuthenticationBox: CurrentValueSubject<MastodonAuthenticationBox?, Never>
let fetchedResultsController: NSFetchedResultsController<MastodonNotification>!
let notificationPredicate = CurrentValueSubject<NSPredicate?, Never>(nil)
let cellFrameCache = NSCache<NSString, NSValue>()

View File

@ -51,16 +51,17 @@ final class NotificationStatusTableViewCell: UITableViewCell, StatusCell {
return imageView
}()
let traitCollectionDidChange = PassthroughSubject<Void, Never>()
let actionImageView: UIImageView = {
let imageView = UIImageView()
imageView.contentMode = .center
imageView.tintColor = Asset.Colors.Background.systemBackground.color
imageView.isOpaque = true
imageView.layer.masksToBounds = true
imageView.layer.cornerRadius = NotificationStatusTableViewCell.actionImageViewSize.width * 0.5
imageView.layer.cornerCurve = .circular
imageView.layer.borderWidth = NotificationStatusTableViewCell.actionImageBorderWidth
imageView.layer.borderColor = Asset.Colors.Background.systemBackground.color.cgColor
imageView.layer.shouldRasterize = true
imageView.layer.rasterizationScale = UIScreen.main.scale
return imageView
@ -197,8 +198,8 @@ extension NotificationStatusTableViewCell {
NSLayoutConstraint.activate([
actionImageView.centerYAnchor.constraint(equalTo: avatarContainer.bottomAnchor),
actionImageView.centerXAnchor.constraint(equalTo: avatarContainer.trailingAnchor),
actionImageView.widthAnchor.constraint(equalToConstant: NotificationStatusTableViewCell.actionImageViewSize.width),
actionImageView.heightAnchor.constraint(equalToConstant: NotificationStatusTableViewCell.actionImageViewSize.height),
actionImageView.widthAnchor.constraint(equalToConstant: NotificationStatusTableViewCell.actionImageViewSize.width).priority(.required - 1),
actionImageView.heightAnchor.constraint(equalTo: actionImageView.widthAnchor, multiplier: 1.0),
])
containerStackView.addArrangedSubview(contentStackView)
@ -282,14 +283,23 @@ extension NotificationStatusTableViewCell {
nameLabel.addGestureRecognizer(authorNameLabelTapGestureRecognizer)
resetSeparatorLineLayout()
setupBackgroundColor(theme: ThemeService.shared.currentTheme.value)
ThemeService.shared.currentTheme
.receive(on: DispatchQueue.main)
.sink { [weak self] theme in
guard let self = self else { return }
self.setupBackgroundColor(theme: theme)
}
.store(in: &disposeBag)
}
override func traitCollectionDidChange(_ previousTraitCollection: UITraitCollection?) {
super.traitCollectionDidChange(previousTraitCollection)
resetSeparatorLineLayout()
avatarImageView.layer.borderColor = Asset.Colors.Background.systemBackground.color.cgColor
statusContainerView.layer.borderColor = Asset.Colors.Border.notificationStatus.color.cgColor
setupBackgroundColor(theme: ThemeService.shared.currentTheme.value)
traitCollectionDidChange.send()
}
private func configure(isFiltered: Bool) {
@ -297,12 +307,14 @@ extension NotificationStatusTableViewCell {
filteredLabel.isHidden = !isFiltered
isUserInteractionEnabled = !isFiltered
}
}
extension NotificationStatusTableViewCell {
private func setupBackgroundColor(theme: Theme) {
actionImageView.layer.borderColor = theme.systemBackgroundColor.cgColor
avatarImageView.layer.borderColor = Asset.Theme.Mastodon.systemBackground.color.cgColor
statusContainerView.layer.borderColor = Asset.Colors.Border.notificationStatus.color.cgColor
statusContainerView.backgroundColor = UIColor(dynamicProvider: { traitCollection in
return traitCollection.userInterfaceStyle == .light ? theme.systemBackgroundColor : theme.tertiarySystemGroupedBackgroundColor
})

View File

@ -115,7 +115,7 @@ extension MastodonPickServerViewController {
tableViewTopPaddingView.trailingAnchor.constraint(equalTo: view.trailingAnchor),
tableViewTopPaddingViewHeightLayoutConstraint,
])
tableViewTopPaddingView.backgroundColor = Asset.Colors.Background.systemGroupedBackground.color
tableViewTopPaddingView.backgroundColor = Asset.Theme.Mastodon.systemGroupedBackground.color
view.addSubview(tableView)
NSLayoutConstraint.activate([
@ -422,7 +422,7 @@ extension MastodonPickServerViewController: UITableViewDelegate {
func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
let headerView = UIView()
headerView.backgroundColor = Asset.Colors.Background.systemGroupedBackground.color
headerView.backgroundColor = Asset.Theme.Mastodon.systemGroupedBackground.color
return headerView
}

View File

@ -55,7 +55,7 @@ extension PickServerCategoriesCell {
private func _init() {
selectionStyle = .none
backgroundColor = Asset.Colors.Background.systemGroupedBackground.color
backgroundColor = Asset.Theme.Mastodon.systemGroupedBackground.color
metricView.translatesAutoresizingMaskIntoConstraints = false
contentView.addSubview(metricView)

View File

@ -27,7 +27,7 @@ class PickServerCell: UITableViewCell {
let containerView: UIView = {
let view = UIView()
view.layoutMargins = UIEdgeInsets(top: 16, left: 16, bottom: 10, right: 16)
view.backgroundColor = Asset.Colors.Background.secondaryGroupedSystemBackground.color
view.backgroundColor = Asset.Theme.Mastodon.secondaryGroupedSystemBackground.color
view.translatesAutoresizingMaskIntoConstraints = false
return view
}()
@ -101,7 +101,7 @@ class PickServerCell: UITableViewCell {
let separator: UIView = {
let view = UIView()
view.backgroundColor = Asset.Colors.Background.systemGroupedBackground.color
view.backgroundColor = Asset.Theme.Mastodon.systemGroupedBackground.color
view.translatesAutoresizingMaskIntoConstraints = false
return view
}()

View File

@ -13,14 +13,14 @@ final class PickServerLoaderTableViewCell: TimelineLoaderTableViewCell {
let containerView: UIView = {
let view = UIView()
view.layoutMargins = UIEdgeInsets(top: 16, left: 16, bottom: 10, right: 16)
view.backgroundColor = Asset.Colors.Background.secondaryGroupedSystemBackground.color
view.backgroundColor = Asset.Theme.Mastodon.secondaryGroupedSystemBackground.color
view.translatesAutoresizingMaskIntoConstraints = false
return view
}()
let seperator: UIView = {
let view = UIView()
view.backgroundColor = Asset.Colors.Background.systemGroupedBackground.color
view.backgroundColor = Asset.Theme.Mastodon.systemGroupedBackground.color
view.translatesAutoresizingMaskIntoConstraints = false
return view
}()

View File

@ -17,7 +17,7 @@ class PickServerSearchCell: UITableViewCell {
private var bgView: UIView = {
let view = UIView()
view.backgroundColor = Asset.Colors.Background.secondaryGroupedSystemBackground.color
view.backgroundColor = Asset.Theme.Mastodon.secondaryGroupedSystemBackground.color
view.translatesAutoresizingMaskIntoConstraints = false
view.layer.maskedCorners = [
.layerMinXMinYCorner,
@ -108,7 +108,7 @@ class PickServerSearchCell: UITableViewCell {
extension PickServerSearchCell {
private func _init() {
selectionStyle = .none
backgroundColor = Asset.Colors.Background.systemGroupedBackground.color
backgroundColor = Asset.Theme.Mastodon.systemGroupedBackground.color
searchTextField.addTarget(self, action: #selector(textFieldDidChange(_:)), for: .editingChanged)
searchTextField.delegate = self

View File

@ -35,7 +35,7 @@ extension PickServerTitleCell {
private func _init() {
selectionStyle = .none
backgroundColor = Asset.Colors.Background.systemGroupedBackground.color
backgroundColor = Asset.Theme.Mastodon.systemGroupedBackground.color
contentView.addSubview(titleLabel)
NSLayoutConstraint.activate([

View File

@ -48,7 +48,7 @@ extension PickServerCategoryView {
addSubview(bgView)
addSubview(titleLabel)
bgView.backgroundColor = Asset.Colors.Background.secondaryGroupedSystemBackground.color
bgView.backgroundColor = Asset.Theme.Mastodon.secondaryGroupedSystemBackground.color
NSLayoutConstraint.activate([
bgView.leadingAnchor.constraint(equalTo: self.leadingAnchor),

View File

@ -44,7 +44,7 @@ final class PickServerEmptyStateView: UIView {
extension PickServerEmptyStateView {
private func _init() {
backgroundColor = Asset.Colors.Background.secondaryGroupedSystemBackground.color
backgroundColor = Asset.Theme.Mastodon.secondaryGroupedSystemBackground.color
layer.maskedCorners = [
.layerMinXMaxYCorner,
.layerMaxXMaxYCorner

View File

@ -84,7 +84,7 @@ final class MastodonRegisterViewController: UIViewController, NeedsDependency, O
button.setImage(image?.withRenderingMode(UIImage.RenderingMode.alwaysTemplate), for: UIControl.State.normal)
button.imageView?.tintColor = Asset.Colors.Label.secondary.color
button.backgroundColor = Asset.Colors.Background.secondaryGroupedSystemBackground.color
button.backgroundColor = Asset.Theme.Mastodon.secondaryGroupedSystemBackground.color
button.layer.cornerRadius = 10
button.clipsToBounds = true
@ -99,7 +99,7 @@ final class MastodonRegisterViewController: UIViewController, NeedsDependency, O
icon.backgroundColor = UIColor(dynamicProvider: { collection in
switch collection.userInterfaceStyle {
case .dark:
return Asset.Colors.Background.secondaryGroupedSystemBackground.color
return Asset.Theme.Mastodon.secondaryGroupedSystemBackground.color
default:
return .white
}
@ -119,7 +119,7 @@ final class MastodonRegisterViewController: UIViewController, NeedsDependency, O
textField.returnKeyType = .next
textField.autocapitalizationType = .none
textField.autocorrectionType = .no
textField.backgroundColor = Asset.Colors.Background.secondaryGroupedSystemBackground.color
textField.backgroundColor = Asset.Theme.Mastodon.secondaryGroupedSystemBackground.color
textField.textColor = Asset.Colors.Label.primary.color
textField.attributedPlaceholder = NSAttributedString(string: L10n.Scene.Register.Input.Username.placeholder,
attributes: [NSAttributedString.Key.foregroundColor: Asset.Colors.Label.secondary.color,
@ -170,7 +170,7 @@ final class MastodonRegisterViewController: UIViewController, NeedsDependency, O
textField.returnKeyType = .next
textField.autocapitalizationType = .none
textField.autocorrectionType = .no
textField.backgroundColor = Asset.Colors.Background.secondaryGroupedSystemBackground.color
textField.backgroundColor = Asset.Theme.Mastodon.secondaryGroupedSystemBackground.color
textField.textColor = Asset.Colors.Label.primary.color
textField.attributedPlaceholder = NSAttributedString(string: L10n.Scene.Register.Input.DisplayName.placeholder,
attributes: [NSAttributedString.Key.foregroundColor: Asset.Colors.Label.secondary.color,
@ -189,7 +189,7 @@ final class MastodonRegisterViewController: UIViewController, NeedsDependency, O
textField.autocapitalizationType = .none
textField.autocorrectionType = .no
textField.keyboardType = .emailAddress
textField.backgroundColor = Asset.Colors.Background.secondaryGroupedSystemBackground.color
textField.backgroundColor = Asset.Theme.Mastodon.secondaryGroupedSystemBackground.color
textField.textColor = Asset.Colors.Label.primary.color
textField.attributedPlaceholder = NSAttributedString(string: L10n.Scene.Register.Input.Email.placeholder,
attributes: [NSAttributedString.Key.foregroundColor: Asset.Colors.Label.secondary.color,
@ -216,7 +216,7 @@ final class MastodonRegisterViewController: UIViewController, NeedsDependency, O
textField.autocorrectionType = .no
textField.keyboardType = .asciiCapable
textField.isSecureTextEntry = true
textField.backgroundColor = Asset.Colors.Background.secondaryGroupedSystemBackground.color
textField.backgroundColor = Asset.Theme.Mastodon.secondaryGroupedSystemBackground.color
textField.textColor = Asset.Colors.Label.primary.color
textField.attributedPlaceholder = NSAttributedString(string: L10n.Scene.Register.Input.Password.placeholder,
attributes: [NSAttributedString.Key.foregroundColor: Asset.Colors.Label.secondary.color,
@ -248,7 +248,7 @@ final class MastodonRegisterViewController: UIViewController, NeedsDependency, O
textField.returnKeyType = .next // set to "Return" depends on if the last input field or not
textField.autocapitalizationType = .none
textField.autocorrectionType = .no
textField.backgroundColor = Asset.Colors.Background.secondaryGroupedSystemBackground.color
textField.backgroundColor = Asset.Theme.Mastodon.secondaryGroupedSystemBackground.color
textField.textColor = Asset.Colors.Label.primary.color
textField.attributedPlaceholder = NSAttributedString(string: L10n.Scene.Register.Input.Invite.registrationUserInviteRequest,
attributes: [NSAttributedString.Key.foregroundColor: Asset.Colors.Label.secondary.color,

View File

@ -49,7 +49,7 @@ final class MastodonServerRulesViewController: UIViewController, NeedsDependency
let bottomContainerView: UIView = {
let view = UIView()
view.backgroundColor = Asset.Colors.Background.systemGroupedBackground.color
view.backgroundColor = Asset.Theme.Mastodon.systemGroupedBackground.color
return view
}()
@ -60,7 +60,7 @@ final class MastodonServerRulesViewController: UIViewController, NeedsDependency
textView.isSelectable = true
textView.isEditable = false
textView.isScrollEnabled = false
textView.backgroundColor = Asset.Colors.Background.systemGroupedBackground.color
textView.backgroundColor = Asset.Theme.Mastodon.systemGroupedBackground.color
return textView
}()

View File

@ -20,7 +20,7 @@ extension OnboardingViewControllerAppearance {
static var viewBottomPaddingHeight: CGFloat { return 11 }
func setupOnboardingAppearance() {
view.backgroundColor = Asset.Colors.Background.systemGroupedBackground.color
view.backgroundColor = Asset.Theme.Mastodon.systemGroupedBackground.color
setupNavigationBarAppearance()
@ -42,7 +42,7 @@ extension OnboardingViewControllerAppearance {
func setupNavigationBarBackgroundView() {
let navigationBarBackgroundView: UIView = {
let view = UIView()
view.backgroundColor = Asset.Colors.Background.systemGroupedBackground.color
view.backgroundColor = Asset.Theme.Mastodon.systemGroupedBackground.color
return view
}()

View File

@ -17,7 +17,7 @@ final class FavoriteViewModel {
// input
let context: AppContext
let activeMastodonAuthenticationBox: CurrentValueSubject<AuthenticationService.MastodonAuthenticationBox?, Never>
let activeMastodonAuthenticationBox: CurrentValueSubject<MastodonAuthenticationBox?, Never>
let statusFetchedResultsController: StatusFetchedResultsController
let cellFrameCache = NSCache<NSNumber, NSValue>()

View File

@ -465,7 +465,7 @@ extension ProfileHeaderViewController: PHPickerViewControllerDelegate {
func picker(_ picker: PHPickerViewController, didFinishPicking results: [PHPickerResult]) {
picker.dismiss(animated: true, completion: nil)
guard let result = results.first else { return }
PHPickerResultLoader.loadImageData(from: result)
ItemProviderLoader.loadImageData(from: result)
.sink { [weak self] completion in
guard let _ = self else { return }
switch completion {

View File

@ -76,7 +76,7 @@ final class ProfileHeaderView: UIView {
let avatarImageView: UIImageView = {
let imageView = FLAnimatedImageView()
let placeholderImage = UIImage
.placeholder(size: ProfileHeaderView.avatarImageViewSize, color: Asset.Colors.Background.systemGroupedBackground.color)
.placeholder(size: ProfileHeaderView.avatarImageViewSize, color: Asset.Theme.Mastodon.systemGroupedBackground.color)
.af.imageRounded(withCornerRadius: ProfileHeaderView.avatarImageViewCornerRadius, divideRadiusByImageScale: false)
imageView.image = placeholderImage
return imageView

View File

@ -6,6 +6,7 @@
//
import UIKit
import MastodonUI
final class ProfileRelationshipActionButton: RoundedEdgesButton {

View File

@ -115,7 +115,7 @@ class ProfileViewModel: NSObject {
context.authenticationService.activeMastodonAuthenticationBox.eraseToAnyPublisher(),
pendingRetryPublisher.eraseToAnyPublisher()
)
.compactMap { mastodonUserID, activeMastodonAuthenticationBox, _ -> (String, AuthenticationService.MastodonAuthenticationBox)? in
.compactMap { mastodonUserID, activeMastodonAuthenticationBox, _ -> (String, MastodonAuthenticationBox)? in
guard let mastodonUserID = mastodonUserID, let activeMastodonAuthenticationBox = activeMastodonAuthenticationBox else { return nil }
guard mastodonUserID != activeMastodonAuthenticationBox.userID else { return nil }
return (mastodonUserID, activeMastodonAuthenticationBox)
@ -441,9 +441,9 @@ extension ProfileViewModel {
case .request: return Asset.Colors.brandBlue.color
case .pending: return Asset.Colors.brandBlue.color
case .following: return Asset.Colors.brandBlue.color
case .muting: return Asset.Colors.Background.alertYellow.color
case .muting: return Asset.Colors.alertYellow.color
case .blocked: return Asset.Colors.brandBlue.color
case .blocking: return Asset.Colors.Background.danger.color
case .blocking: return Asset.Colors.danger.color
case .suspended: return Asset.Colors.brandBlue.color
case .edit: return Asset.Colors.brandBlue.color
case .editing: return Asset.Colors.brandBlue.color

View File

@ -17,7 +17,7 @@ extension ReportViewModel {
func requestRecentStatus(
domain: String,
accountId: String,
authorizationBox: AuthenticationService.MastodonAuthenticationBox
authorizationBox: MastodonAuthenticationBox
) {
context.apiService.userTimeline(
domain: domain,

View File

@ -165,7 +165,7 @@ class ReportViewModel: NSObject {
.store(in: &disposeBag)
}
func bindForStep2(input: Input, domain: String, activeMastodonAuthenticationBox: AuthenticationService.MastodonAuthenticationBox) -> AnyPublisher<(Bool, Error?), Never> {
func bindForStep2(input: Input, domain: String, activeMastodonAuthenticationBox: MastodonAuthenticationBox) -> AnyPublisher<(Bool, Error?), Never> {
let skip = input.step2Skip.map { [weak self] value -> Void in
guard let self = self else { return value }
self.reportQuery.comment = nil

View File

@ -17,7 +17,7 @@ extension SearchViewController {
let header = SearchRecommendCollectionHeader()
header.titleLabel.text = L10n.Scene.Search.Recommend.HashTag.title
header.descriptionLabel.text = L10n.Scene.Search.Recommend.HashTag.description
header.seeAllButton.addTarget(self, action: #selector(SearchViewController.hashtagSeeAllButtonPressed(_:)), for: .touchUpInside)
header.seeAllButton.isHidden = true
stackView.addArrangedSubview(header)
hashtagCollectionView.register(SearchRecommendTagsCollectionViewCell.self, forCellWithReuseIdentifier: String(describing: SearchRecommendTagsCollectionViewCell.self))

View File

@ -42,7 +42,7 @@ final class SearchViewModel: NSObject {
context.authenticationService.activeMastodonAuthenticationBox,
viewDidAppeared
)
.compactMap { activeMastodonAuthenticationBox, _ -> AuthenticationService.MastodonAuthenticationBox? in
.compactMap { activeMastodonAuthenticationBox, _ -> MastodonAuthenticationBox? in
return activeMastodonAuthenticationBox
}
.throttle(for: 1, scheduler: DispatchQueue.main, latest: false)
@ -72,7 +72,7 @@ final class SearchViewModel: NSObject {
context.authenticationService.activeMastodonAuthenticationBox,
viewDidAppeared
)
.compactMap { activeMastodonAuthenticationBox, _ -> AuthenticationService.MastodonAuthenticationBox? in
.compactMap { activeMastodonAuthenticationBox, _ -> MastodonAuthenticationBox? in
return activeMastodonAuthenticationBox
}
.throttle(for: 1, scheduler: DispatchQueue.main, latest: false)

View File

@ -63,7 +63,7 @@ extension PlayerContainerView {
extension PlayerContainerView.MediaTypeIndicatorView {
private func _init() {
backgroundColor = Asset.Colors.Background.mediaTypeIndicotor.color
backgroundColor = Asset.Colors.mediaTypeIndicotor.color
layoutMargins = UIEdgeInsets(top: 3, left: 13, bottom: 0, right: 6)
addSubview(label)

View File

@ -29,7 +29,8 @@ final class PollOptionView: UIView {
let checkmarkBackgroundView: UIView = {
let view = UIView()
view.backgroundColor = Asset.Colors.Background.tertiarySystemBackground.color
// FIXME: missing update trigger
view.backgroundColor = ThemeService.shared.currentTheme.value.tertiarySystemBackgroundColor
return view
}()

View File

@ -58,7 +58,6 @@ extension ThreadReplyLoaderTableViewCell {
func _init() {
selectionStyle = .none
backgroundColor = Asset.Colors.Background.systemGroupedBackground.color
loadMoreButton.translatesAutoresizingMaskIntoConstraints = false
contentView.addSubview(loadMoreButton)
@ -124,7 +123,7 @@ extension ThreadReplyLoaderTableViewCell {
}
private func setupBackgroundColor(theme: Theme) {
loadMoreButton.backgroundColor = theme.secondarySystemGroupedBackgroundColor
backgroundColor = theme.systemGroupedBackgroundColor
}
}

View File

@ -32,7 +32,7 @@ class SuggestionAccountViewController: UIViewController, NeedsDependency {
lazy var tableHeader: UIView = {
let view = UIView()
view.backgroundColor = Asset.Colors.Background.systemGroupedBackground.color
view.backgroundColor = ThemeService.shared.currentTheme.value.systemGroupedBackgroundColor
view.frame = CGRect(origin: .zero, size: CGSize(width: tableView.frame.width, height: 156))
return view
}()
@ -67,12 +67,12 @@ extension SuggestionAccountViewController {
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = ThemeService.shared.currentTheme.value.systemBackgroundColor
setupBackgroundColor(theme: ThemeService.shared.currentTheme.value)
ThemeService.shared.currentTheme
.receive(on: RunLoop.main)
.sink { [weak self] theme in
guard let self = self else { return }
self.view.backgroundColor = theme.systemBackgroundColor
self.setupBackgroundColor(theme: theme)
}
.store(in: &disposeBag)
@ -146,6 +146,11 @@ extension SuggestionAccountViewController {
tableView.tableHeaderView = tableHeader
}
private func setupBackgroundColor(theme: Theme) {
view.backgroundColor = theme.systemBackgroundColor
tableHeader.backgroundColor = theme.systemGroupedBackgroundColor
}
}
extension SuggestionAccountViewController: UICollectionViewDelegateFlowLayout {

View File

@ -16,7 +16,7 @@ extension APIService {
func toggleBlock(
for mastodonUser: MastodonUser,
activeMastodonAuthenticationBox: AuthenticationService.MastodonAuthenticationBox
activeMastodonAuthenticationBox: MastodonAuthenticationBox
) -> AnyPublisher<Mastodon.Response.Content<Mastodon.Entity.Relationship>, Error> {
let impactFeedbackGenerator = UIImpactFeedbackGenerator(style: .light)
let notificationFeedbackGenerator = UINotificationFeedbackGenerator()
@ -86,7 +86,7 @@ extension APIService {
// update database local and return block query update type for remote request
func blockUpdateLocal(
mastodonUserObjectID: NSManagedObjectID,
mastodonAuthenticationBox: AuthenticationService.MastodonAuthenticationBox
mastodonAuthenticationBox: MastodonAuthenticationBox
) -> AnyPublisher<(Mastodon.API.Account.BlockQueryType, MastodonUser.ID), Error> {
let domain = mastodonAuthenticationBox.domain
let requestMastodonUserID = mastodonAuthenticationBox.userID
@ -132,7 +132,7 @@ extension APIService {
func blockUpdateRemote(
blockQueryType: Mastodon.API.Account.BlockQueryType,
mastodonUserID: MastodonUser.ID,
mastodonAuthenticationBox: AuthenticationService.MastodonAuthenticationBox
mastodonAuthenticationBox: MastodonAuthenticationBox
) -> AnyPublisher<Mastodon.Response.Content<Mastodon.Entity.Relationship>, Error> {
let domain = mastodonAuthenticationBox.domain
let authorization = mastodonAuthenticationBox.userAuthorization

View File

@ -17,7 +17,7 @@ extension APIService {
func getDomainblocks(
domain: String,
limit: Int = onceRequestDomainBlocksMaxCount,
authorizationBox: AuthenticationService.MastodonAuthenticationBox
authorizationBox: MastodonAuthenticationBox
) -> AnyPublisher<Mastodon.Response.Content<[String]>, Error> {
let authorization = authorizationBox.userAuthorization
@ -71,7 +71,7 @@ extension APIService {
func blockDomain(
user: MastodonUser,
authorizationBox: AuthenticationService.MastodonAuthenticationBox
authorizationBox: MastodonAuthenticationBox
) -> AnyPublisher<Mastodon.Response.Content<Mastodon.Entity.Empty>, Error> {
let authorization = authorizationBox.userAuthorization
@ -105,7 +105,7 @@ extension APIService {
func unblockDomain(
user: MastodonUser,
authorizationBox: AuthenticationService.MastodonAuthenticationBox
authorizationBox: MastodonAuthenticationBox
) -> AnyPublisher<Mastodon.Response.Content<Mastodon.Entity.Empty>, Error> {
let authorization = authorizationBox.userAuthorization

View File

@ -61,7 +61,7 @@ extension APIService {
func favorite(
statusID: Mastodon.Entity.Status.ID,
favoriteKind: Mastodon.API.Favorites.FavoriteKind,
mastodonAuthenticationBox: AuthenticationService.MastodonAuthenticationBox
mastodonAuthenticationBox: MastodonAuthenticationBox
) -> AnyPublisher<Mastodon.Response.Content<Mastodon.Entity.Status>, Error> {
let authorization = mastodonAuthenticationBox.userAuthorization
let requestMastodonUserID = mastodonAuthenticationBox.userID
@ -139,7 +139,7 @@ extension APIService {
func favoritedStatuses(
limit: Int = onceRequestStatusMaxCount,
maxID: String? = nil,
mastodonAuthenticationBox: AuthenticationService.MastodonAuthenticationBox
mastodonAuthenticationBox: MastodonAuthenticationBox
) -> AnyPublisher<Mastodon.Response.Content<[Mastodon.Entity.Status]>, Error> {
let requestMastodonUserID = mastodonAuthenticationBox.userID

View File

@ -15,7 +15,7 @@ import MastodonSDK
extension APIService {
func filters(
mastodonAuthenticationBox: AuthenticationService.MastodonAuthenticationBox
mastodonAuthenticationBox: MastodonAuthenticationBox
) -> AnyPublisher<Mastodon.Response.Content<[Mastodon.Entity.Filter]>, Error> {
let authorization = mastodonAuthenticationBox.userAuthorization
let domain = mastodonAuthenticationBox.domain

View File

@ -24,7 +24,7 @@ extension APIService {
/// - Returns: publisher for `Relationship`
func toggleFollow(
for mastodonUser: MastodonUser,
activeMastodonAuthenticationBox: AuthenticationService.MastodonAuthenticationBox
activeMastodonAuthenticationBox: MastodonAuthenticationBox
) -> AnyPublisher<Mastodon.Response.Content<Mastodon.Entity.Relationship>, Error> {
let impactFeedbackGenerator = UIImpactFeedbackGenerator(style: .light)
@ -96,7 +96,7 @@ extension APIService {
// update database local and return follow query update type for remote request
func followUpdateLocal(
mastodonUserObjectID: NSManagedObjectID,
mastodonAuthenticationBox: AuthenticationService.MastodonAuthenticationBox
mastodonAuthenticationBox: MastodonAuthenticationBox
) -> AnyPublisher<(Mastodon.API.Account.FollowQueryType, MastodonUser.ID), Error> {
let domain = mastodonAuthenticationBox.domain
let requestMastodonUserID = mastodonAuthenticationBox.userID
@ -156,7 +156,7 @@ extension APIService {
func followUpdateRemote(
followQueryType: Mastodon.API.Account.FollowQueryType,
mastodonUserID: MastodonUser.ID,
mastodonAuthenticationBox: AuthenticationService.MastodonAuthenticationBox
mastodonAuthenticationBox: MastodonAuthenticationBox
) -> AnyPublisher<Mastodon.Response.Content<Mastodon.Entity.Relationship>, Error> {
let domain = mastodonAuthenticationBox.domain
let authorization = mastodonAuthenticationBox.userAuthorization

View File

@ -17,7 +17,7 @@ import MastodonSDK
extension APIService {
func acceptFollowRequest(
mastodonUserID: MastodonUser.ID,
mastodonAuthenticationBox: AuthenticationService.MastodonAuthenticationBox
mastodonAuthenticationBox: MastodonAuthenticationBox
) -> AnyPublisher<Mastodon.Response.Content<Mastodon.Entity.Relationship>, Error> {
let domain = mastodonAuthenticationBox.domain
let authorization = mastodonAuthenticationBox.userAuthorization
@ -61,7 +61,7 @@ extension APIService {
func rejectFollowRequest(
mastodonUserID: MastodonUser.ID,
mastodonAuthenticationBox: AuthenticationService.MastodonAuthenticationBox
mastodonAuthenticationBox: MastodonAuthenticationBox
) -> AnyPublisher<Mastodon.Response.Content<Mastodon.Entity.Relationship>, Error> {
let domain = mastodonAuthenticationBox.domain
let authorization = mastodonAuthenticationBox.userAuthorization

Some files were not shown because too many files have changed in this diff Show More