chore: format file
This commit is contained in:
parent
2e86449c41
commit
80d76acc27
|
@ -5,11 +5,10 @@
|
||||||
// Created by sxiaojian on 2021/4/13.
|
// Created by sxiaojian on 2021/4/13.
|
||||||
//
|
//
|
||||||
|
|
||||||
import Foundation
|
|
||||||
import CoreData
|
import CoreData
|
||||||
|
import Foundation
|
||||||
|
|
||||||
enum NotificationItem {
|
enum NotificationItem {
|
||||||
|
|
||||||
case notification(objectID: NSManagedObjectID)
|
case notification(objectID: NSManagedObjectID)
|
||||||
|
|
||||||
case bottomLoader
|
case bottomLoader
|
||||||
|
@ -20,7 +19,7 @@ extension NotificationItem: Equatable {
|
||||||
switch (lhs, rhs) {
|
switch (lhs, rhs) {
|
||||||
case (.bottomLoader, .bottomLoader):
|
case (.bottomLoader, .bottomLoader):
|
||||||
return true
|
return true
|
||||||
case (.notification(let idLeft),.notification(let idRight)):
|
case (.notification(let idLeft), .notification(let idRight)):
|
||||||
return idLeft == idRight
|
return idLeft == idRight
|
||||||
default:
|
default:
|
||||||
return false
|
return false
|
||||||
|
|
|
@ -5,12 +5,12 @@
|
||||||
// Created by sxiaojian on 2021/4/13.
|
// Created by sxiaojian on 2021/4/13.
|
||||||
//
|
//
|
||||||
|
|
||||||
|
import Combine
|
||||||
import CoreData
|
import CoreData
|
||||||
import CoreDataStack
|
import CoreDataStack
|
||||||
import Foundation
|
import Foundation
|
||||||
import MastodonSDK
|
import MastodonSDK
|
||||||
import UIKit
|
import UIKit
|
||||||
import Combine
|
|
||||||
|
|
||||||
enum NotificationSection: Equatable, Hashable {
|
enum NotificationSection: Equatable, Hashable {
|
||||||
case main
|
case main
|
||||||
|
@ -25,8 +25,8 @@ extension NotificationSection {
|
||||||
dependency: NeedsDependency,
|
dependency: NeedsDependency,
|
||||||
requestUserID: String
|
requestUserID: String
|
||||||
) -> UITableViewDiffableDataSource<NotificationSection, NotificationItem> {
|
) -> UITableViewDiffableDataSource<NotificationSection, NotificationItem> {
|
||||||
return UITableViewDiffableDataSource(tableView: tableView) {
|
UITableViewDiffableDataSource(tableView: tableView) {
|
||||||
[weak delegate,weak dependency]
|
[weak delegate, weak dependency]
|
||||||
(tableView, indexPath, notificationItem) -> UITableViewCell? in
|
(tableView, indexPath, notificationItem) -> UITableViewCell? in
|
||||||
guard let dependency = dependency else { return nil }
|
guard let dependency = dependency else { return nil }
|
||||||
switch notificationItem {
|
switch notificationItem {
|
||||||
|
@ -136,7 +136,6 @@ extension NotificationSection {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
extension NotificationSection {
|
extension NotificationSection {
|
||||||
static func configure(
|
static func configure(
|
||||||
cell: NotificationStatusTableViewCell,
|
cell: NotificationStatusTableViewCell,
|
||||||
|
@ -147,7 +146,6 @@ extension NotificationSection {
|
||||||
requestUserID: String,
|
requestUserID: String,
|
||||||
statusItemAttribute: Item.StatusAttribute
|
statusItemAttribute: Item.StatusAttribute
|
||||||
) {
|
) {
|
||||||
|
|
||||||
// setup attribute
|
// setup attribute
|
||||||
statusItemAttribute.setupForStatus(status: status)
|
statusItemAttribute.setupForStatus(status: status)
|
||||||
|
|
||||||
|
@ -176,7 +174,6 @@ extension NotificationSection {
|
||||||
cell.statusView.avatarStackedContainerButton.isHidden = true
|
cell.statusView.avatarStackedContainerButton.isHidden = true
|
||||||
cell.statusView.configure(with: AvatarConfigurableViewConfiguration(avatarImageURL: status.author.avatarImageURL()))
|
cell.statusView.configure(with: AvatarConfigurableViewConfiguration(avatarImageURL: status.author.avatarImageURL()))
|
||||||
|
|
||||||
|
|
||||||
// set text
|
// set text
|
||||||
cell.statusView.activeTextLabel.configure(content: (status.reblog ?? status).content)
|
cell.statusView.activeTextLabel.configure(content: (status.reblog ?? status).content)
|
||||||
|
|
||||||
|
@ -338,7 +335,6 @@ extension NotificationSection {
|
||||||
cell.statusView.dateLabel.text = createdAt.shortTimeAgoSinceNow
|
cell.statusView.dateLabel.text = createdAt.shortTimeAgoSinceNow
|
||||||
}
|
}
|
||||||
.store(in: &cell.disposeBag)
|
.store(in: &cell.disposeBag)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static func configureHeader(
|
static func configureHeader(
|
||||||
|
@ -366,7 +362,6 @@ extension NotificationSection {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static func configurePoll(
|
static func configurePoll(
|
||||||
cell: NotificationStatusTableViewCell,
|
cell: NotificationStatusTableViewCell,
|
||||||
poll: Poll?,
|
poll: Poll?,
|
||||||
|
@ -486,7 +481,7 @@ extension NotificationSection {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
extension NotificationSection {
|
extension NotificationSection {
|
||||||
private static func formattedNumberTitleForActionButton(_ number: Int?) -> String {
|
private static func formattedNumberTitleForActionButton(_ number: Int?) -> String {
|
||||||
guard let number = number, number > 0 else { return "" }
|
guard let number = number, number > 0 else { return "" }
|
||||||
return String(number)
|
return String(number)
|
||||||
|
|
|
@ -87,7 +87,7 @@ class GestureSubscription<S: Subscriber>: Subscription where S.Input == GestureT
|
||||||
|
|
||||||
extension UIView {
|
extension UIView {
|
||||||
func gesture(_ gestureType: GestureType = .tap()) -> GesturePublisher {
|
func gesture(_ gestureType: GestureType = .tap()) -> GesturePublisher {
|
||||||
self.isUserInteractionEnabled = true
|
isUserInteractionEnabled = true
|
||||||
return GesturePublisher(view: self, gestureType: gestureType)
|
return GesturePublisher(view: self, gestureType: gestureType)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,16 +5,15 @@
|
||||||
// Created by sxiaojian on 2021/4/12.
|
// Created by sxiaojian on 2021/4/12.
|
||||||
//
|
//
|
||||||
|
|
||||||
import UIKit
|
|
||||||
import Combine
|
import Combine
|
||||||
import OSLog
|
|
||||||
import CoreData
|
import CoreData
|
||||||
import CoreDataStack
|
import CoreDataStack
|
||||||
import MastodonSDK
|
|
||||||
import GameplayKit
|
import GameplayKit
|
||||||
|
import MastodonSDK
|
||||||
|
import OSLog
|
||||||
|
import UIKit
|
||||||
|
|
||||||
final class NotificationViewController: UIViewController, NeedsDependency {
|
final class NotificationViewController: UIViewController, NeedsDependency {
|
||||||
|
|
||||||
weak var context: AppContext! { willSet { precondition(!isViewLoaded) } }
|
weak var context: AppContext! { willSet { precondition(!isViewLoaded) } }
|
||||||
weak var coordinator: SceneCoordinator! { willSet { precondition(!isViewLoaded) } }
|
weak var coordinator: SceneCoordinator! { willSet { precondition(!isViewLoaded) } }
|
||||||
|
|
||||||
|
@ -22,7 +21,7 @@ final class NotificationViewController: UIViewController, NeedsDependency {
|
||||||
private(set) lazy var viewModel = NotificationViewModel(context: context)
|
private(set) lazy var viewModel = NotificationViewModel(context: context)
|
||||||
|
|
||||||
let segmentControl: UISegmentedControl = {
|
let segmentControl: UISegmentedControl = {
|
||||||
let control = UISegmentedControl(items: [L10n.Scene.Notification.Title.everything,L10n.Scene.Notification.Title.mentions])
|
let control = UISegmentedControl(items: [L10n.Scene.Notification.Title.everything, L10n.Scene.Notification.Title.mentions])
|
||||||
control.selectedSegmentIndex = 0
|
control.selectedSegmentIndex = 0
|
||||||
return control
|
return control
|
||||||
}()
|
}()
|
||||||
|
@ -41,11 +40,9 @@ final class NotificationViewController: UIViewController, NeedsDependency {
|
||||||
}()
|
}()
|
||||||
|
|
||||||
let refreshControl = UIRefreshControl()
|
let refreshControl = UIRefreshControl()
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
extension NotificationViewController {
|
extension NotificationViewController {
|
||||||
|
|
||||||
override func viewDidLoad() {
|
override func viewDidLoad() {
|
||||||
super.viewDidLoad()
|
super.viewDidLoad()
|
||||||
view.backgroundColor = Asset.Colors.Background.pure.color
|
view.backgroundColor = Asset.Colors.Background.pure.color
|
||||||
|
@ -80,7 +77,6 @@ extension NotificationViewController {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.store(in: &disposeBag)
|
.store(in: &disposeBag)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override func viewWillAppear(_ animated: Bool) {
|
override func viewWillAppear(_ animated: Bool) {
|
||||||
|
@ -110,12 +106,11 @@ extension NotificationViewController {
|
||||||
self.tableView.reloadData()
|
self.tableView.reloadData()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
extension NotificationViewController {
|
extension NotificationViewController {
|
||||||
@objc private func segmentedControlValueChanged(_ sender: UISegmentedControl) {
|
@objc private func segmentedControlValueChanged(_ sender: UISegmentedControl) {
|
||||||
os_log("%{public}s[%{public}ld], %{public}s: select at index: %ld", ((#file as NSString).lastPathComponent), #line, #function, sender.selectedSegmentIndex)
|
os_log("%{public}s[%{public}ld], %{public}s: select at index: %ld", (#file as NSString).lastPathComponent, #line, #function, sender.selectedSegmentIndex)
|
||||||
guard let domain = viewModel.activeMastodonAuthenticationBox.value?.domain else {
|
guard let domain = viewModel.activeMastodonAuthenticationBox.value?.domain else {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -136,8 +131,8 @@ extension NotificationViewController {
|
||||||
}
|
}
|
||||||
|
|
||||||
// MARK: - UITableViewDelegate
|
// MARK: - UITableViewDelegate
|
||||||
|
|
||||||
extension NotificationViewController: UITableViewDelegate {
|
extension NotificationViewController: UITableViewDelegate {
|
||||||
|
|
||||||
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
|
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
|
||||||
guard let diffableDataSource = viewModel.diffableDataSource else { return }
|
guard let diffableDataSource = viewModel.diffableDataSource else { return }
|
||||||
guard let item = diffableDataSource.itemIdentifier(for: indexPath) else { return }
|
guard let item = diffableDataSource.itemIdentifier(for: indexPath) else { return }
|
||||||
|
@ -145,9 +140,9 @@ extension NotificationViewController: UITableViewDelegate {
|
||||||
case .notification(let objectID):
|
case .notification(let objectID):
|
||||||
let notification = context.managedObjectContext.object(with: objectID) as! MastodonNotification
|
let notification = context.managedObjectContext.object(with: objectID) as! MastodonNotification
|
||||||
if notification.status != nil {
|
if notification.status != nil {
|
||||||
// TODO goto status detail vc
|
// TODO: goto status detail vc
|
||||||
} else {
|
} else {
|
||||||
let viewModel = ProfileViewModel(context: self.context, optionalMastodonUser: notification.account)
|
let viewModel = ProfileViewModel(context: context, optionalMastodonUser: notification.account)
|
||||||
DispatchQueue.main.async {
|
DispatchQueue.main.async {
|
||||||
self.coordinator.present(scene: .profile(viewModel: viewModel), from: self, transition: .show)
|
self.coordinator.present(scene: .profile(viewModel: viewModel), from: self, transition: .show)
|
||||||
}
|
}
|
||||||
|
@ -162,26 +157,26 @@ extension NotificationViewController: UITableViewDelegate {
|
||||||
guard let item = diffableDataSource.itemIdentifier(for: indexPath) else { return }
|
guard let item = diffableDataSource.itemIdentifier(for: indexPath) else { return }
|
||||||
switch item {
|
switch item {
|
||||||
case .bottomLoader:
|
case .bottomLoader:
|
||||||
if !tableView.isDragging && !tableView.isDecelerating {
|
if !tableView.isDragging, !tableView.isDecelerating {
|
||||||
viewModel.loadoldestStateMachine.enter(NotificationViewModel.LoadOldestState.Loading.self)
|
viewModel.loadoldestStateMachine.enter(NotificationViewModel.LoadOldestState.Loading.self)
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// MARK: - ContentOffsetAdjustableTimelineViewControllerDelegate
|
// MARK: - ContentOffsetAdjustableTimelineViewControllerDelegate
|
||||||
|
|
||||||
extension NotificationViewController: ContentOffsetAdjustableTimelineViewControllerDelegate {
|
extension NotificationViewController: ContentOffsetAdjustableTimelineViewControllerDelegate {
|
||||||
func navigationBar() -> UINavigationBar? {
|
func navigationBar() -> UINavigationBar? {
|
||||||
return navigationController?.navigationBar
|
navigationController?.navigationBar
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
extension NotificationViewController: NotificationTableViewCellDelegate {
|
extension NotificationViewController: NotificationTableViewCellDelegate {
|
||||||
func userAvatarDidPressed(notification: MastodonNotification) {
|
func userAvatarDidPressed(notification: MastodonNotification) {
|
||||||
let viewModel = ProfileViewModel(context: self.context, optionalMastodonUser: notification.account)
|
let viewModel = ProfileViewModel(context: context, optionalMastodonUser: notification.account)
|
||||||
DispatchQueue.main.async {
|
DispatchQueue.main.async {
|
||||||
self.coordinator.present(scene: .profile(viewModel: viewModel), from: self, transition: .show)
|
self.coordinator.present(scene: .profile(viewModel: viewModel), from: self, transition: .show)
|
||||||
}
|
}
|
||||||
|
@ -190,11 +185,10 @@ extension NotificationViewController: NotificationTableViewCellDelegate {
|
||||||
func parent() -> UIViewController {
|
func parent() -> UIViewController {
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// MARK: - UIScrollViewDelegate
|
// MARK: - UIScrollViewDelegate
|
||||||
|
|
||||||
extension NotificationViewController {
|
extension NotificationViewController {
|
||||||
func scrollViewDidScroll(_ scrollView: UIScrollView) {
|
func scrollViewDidScroll(_ scrollView: UIScrollView) {
|
||||||
handleScrollViewDidScroll(scrollView)
|
handleScrollViewDidScroll(scrollView)
|
||||||
|
@ -204,6 +198,6 @@ extension NotificationViewController {
|
||||||
extension NotificationViewController: LoadMoreConfigurableTableViewContainer {
|
extension NotificationViewController: LoadMoreConfigurableTableViewContainer {
|
||||||
typealias BottomLoaderTableViewCell = CommonBottomLoader
|
typealias BottomLoaderTableViewCell = CommonBottomLoader
|
||||||
typealias LoadingState = NotificationViewModel.LoadOldestState.Loading
|
typealias LoadingState = NotificationViewModel.LoadOldestState.Loading
|
||||||
var loadMoreConfigurableTableView: UITableView { return tableView }
|
var loadMoreConfigurableTableView: UITableView { tableView }
|
||||||
var loadMoreConfigurableStateMachine: GKStateMachine { return viewModel.loadoldestStateMachine }
|
var loadMoreConfigurableStateMachine: GKStateMachine { viewModel.loadoldestStateMachine }
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,13 +5,13 @@
|
||||||
// Created by sxiaojian on 2021/4/13.
|
// Created by sxiaojian on 2021/4/13.
|
||||||
//
|
//
|
||||||
|
|
||||||
import os.log
|
|
||||||
import func QuartzCore.CACurrentMediaTime
|
|
||||||
import Foundation
|
|
||||||
import CoreData
|
import CoreData
|
||||||
import CoreDataStack
|
import CoreDataStack
|
||||||
|
import Foundation
|
||||||
import GameplayKit
|
import GameplayKit
|
||||||
import MastodonSDK
|
import MastodonSDK
|
||||||
|
import os.log
|
||||||
|
import func QuartzCore.CACurrentMediaTime
|
||||||
|
|
||||||
extension NotificationViewModel {
|
extension NotificationViewModel {
|
||||||
class LoadLatestState: GKState {
|
class LoadLatestState: GKState {
|
||||||
|
@ -22,7 +22,7 @@ extension NotificationViewModel {
|
||||||
}
|
}
|
||||||
|
|
||||||
override func didEnter(from previousState: GKState?) {
|
override func didEnter(from previousState: GKState?) {
|
||||||
os_log("%{public}s[%{public}ld], %{public}s: enter %s, previous: %s", ((#file as NSString).lastPathComponent), #line, #function, self.debugDescription, previousState.debugDescription)
|
os_log("%{public}s[%{public}ld], %{public}s: enter %s, previous: %s", (#file as NSString).lastPathComponent, #line, #function, debugDescription, previousState.debugDescription)
|
||||||
viewModel?.loadLatestStateMachinePublisher.send(self)
|
viewModel?.loadLatestStateMachinePublisher.send(self)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -31,13 +31,13 @@ extension NotificationViewModel {
|
||||||
extension NotificationViewModel.LoadLatestState {
|
extension NotificationViewModel.LoadLatestState {
|
||||||
class Initial: NotificationViewModel.LoadLatestState {
|
class Initial: NotificationViewModel.LoadLatestState {
|
||||||
override func isValidNextState(_ stateClass: AnyClass) -> Bool {
|
override func isValidNextState(_ stateClass: AnyClass) -> Bool {
|
||||||
return stateClass == Loading.self
|
stateClass == Loading.self
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class Loading: NotificationViewModel.LoadLatestState {
|
class Loading: NotificationViewModel.LoadLatestState {
|
||||||
override func isValidNextState(_ stateClass: AnyClass) -> Bool {
|
override func isValidNextState(_ stateClass: AnyClass) -> Bool {
|
||||||
return stateClass == Fail.self || stateClass == Idle.self
|
stateClass == Fail.self || stateClass == Idle.self
|
||||||
}
|
}
|
||||||
|
|
||||||
override func didEnter(from previousState: GKState?) {
|
override func didEnter(from previousState: GKState?) {
|
||||||
|
@ -63,7 +63,7 @@ extension NotificationViewModel.LoadLatestState {
|
||||||
switch completion {
|
switch completion {
|
||||||
case .failure(let error):
|
case .failure(let error):
|
||||||
viewModel.isFetchingLatestNotification.value = false
|
viewModel.isFetchingLatestNotification.value = false
|
||||||
os_log(.info, log: .debug, "%{public}s[%{public}ld], %{public}s: fetch notification failed. %s", ((#file as NSString).lastPathComponent), #line, #function, error.localizedDescription)
|
os_log(.info, log: .debug, "%{public}s[%{public}ld], %{public}s: fetch notification failed. %s", (#file as NSString).lastPathComponent, #line, #function, error.localizedDescription)
|
||||||
case .finished:
|
case .finished:
|
||||||
// handle isFetchingLatestTimeline in fetch controller delegate
|
// handle isFetchingLatestTimeline in fetch controller delegate
|
||||||
break
|
break
|
||||||
|
@ -76,21 +76,18 @@ extension NotificationViewModel.LoadLatestState {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.store(in: &viewModel.disposeBag)
|
.store(in: &viewModel.disposeBag)
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class Fail: NotificationViewModel.LoadLatestState {
|
class Fail: NotificationViewModel.LoadLatestState {
|
||||||
override func isValidNextState(_ stateClass: AnyClass) -> Bool {
|
override func isValidNextState(_ stateClass: AnyClass) -> Bool {
|
||||||
return stateClass == Loading.self || stateClass == Idle.self
|
stateClass == Loading.self || stateClass == Idle.self
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class Idle: NotificationViewModel.LoadLatestState {
|
class Idle: NotificationViewModel.LoadLatestState {
|
||||||
override func isValidNextState(_ stateClass: AnyClass) -> Bool {
|
override func isValidNextState(_ stateClass: AnyClass) -> Bool {
|
||||||
return stateClass == Loading.self
|
stateClass == Loading.self
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,11 +5,11 @@
|
||||||
// Created by sxiaojian on 2021/4/14.
|
// Created by sxiaojian on 2021/4/14.
|
||||||
//
|
//
|
||||||
|
|
||||||
import os.log
|
import CoreDataStack
|
||||||
import Foundation
|
import Foundation
|
||||||
import GameplayKit
|
import GameplayKit
|
||||||
import MastodonSDK
|
import MastodonSDK
|
||||||
import CoreDataStack
|
import os.log
|
||||||
|
|
||||||
extension NotificationViewModel {
|
extension NotificationViewModel {
|
||||||
class LoadOldestState: GKState {
|
class LoadOldestState: GKState {
|
||||||
|
@ -20,7 +20,7 @@ extension NotificationViewModel {
|
||||||
}
|
}
|
||||||
|
|
||||||
override func didEnter(from previousState: GKState?) {
|
override func didEnter(from previousState: GKState?) {
|
||||||
os_log("%{public}s[%{public}ld], %{public}s: enter %s, previous: %s", ((#file as NSString).lastPathComponent), #line, #function, self.debugDescription, previousState.debugDescription)
|
os_log("%{public}s[%{public}ld], %{public}s: enter %s, previous: %s", (#file as NSString).lastPathComponent, #line, #function, debugDescription, previousState.debugDescription)
|
||||||
viewModel?.loadOldestStateMachinePublisher.send(self)
|
viewModel?.loadOldestStateMachinePublisher.send(self)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -37,7 +37,7 @@ extension NotificationViewModel.LoadOldestState {
|
||||||
|
|
||||||
class Loading: NotificationViewModel.LoadOldestState {
|
class Loading: NotificationViewModel.LoadOldestState {
|
||||||
override func isValidNextState(_ stateClass: AnyClass) -> Bool {
|
override func isValidNextState(_ stateClass: AnyClass) -> Bool {
|
||||||
return stateClass == Fail.self || stateClass == Idle.self || stateClass == NoMore.self
|
stateClass == Fail.self || stateClass == Idle.self || stateClass == NoMore.self
|
||||||
}
|
}
|
||||||
|
|
||||||
override func didEnter(from previousState: GKState?) {
|
override func didEnter(from previousState: GKState?) {
|
||||||
|
@ -80,7 +80,7 @@ extension NotificationViewModel.LoadOldestState {
|
||||||
.sink { completion in
|
.sink { completion in
|
||||||
switch completion {
|
switch completion {
|
||||||
case .failure(let error):
|
case .failure(let error):
|
||||||
os_log(.info, log: .debug, "%{public}s[%{public}ld], %{public}s: fetch notification failed. %s", ((#file as NSString).lastPathComponent), #line, #function, error.localizedDescription)
|
os_log(.info, log: .debug, "%{public}s[%{public}ld], %{public}s: fetch notification failed. %s", (#file as NSString).lastPathComponent, #line, #function, error.localizedDescription)
|
||||||
case .finished:
|
case .finished:
|
||||||
// handle isFetchingLatestTimeline in fetch controller delegate
|
// handle isFetchingLatestTimeline in fetch controller delegate
|
||||||
break
|
break
|
||||||
|
@ -111,20 +111,20 @@ extension NotificationViewModel.LoadOldestState {
|
||||||
|
|
||||||
class Fail: NotificationViewModel.LoadOldestState {
|
class Fail: NotificationViewModel.LoadOldestState {
|
||||||
override func isValidNextState(_ stateClass: AnyClass) -> Bool {
|
override func isValidNextState(_ stateClass: AnyClass) -> Bool {
|
||||||
return stateClass == Loading.self || stateClass == Idle.self
|
stateClass == Loading.self || stateClass == Idle.self
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class Idle: NotificationViewModel.LoadOldestState {
|
class Idle: NotificationViewModel.LoadOldestState {
|
||||||
override func isValidNextState(_ stateClass: AnyClass) -> Bool {
|
override func isValidNextState(_ stateClass: AnyClass) -> Bool {
|
||||||
return stateClass == Loading.self
|
stateClass == Loading.self
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class NoMore: NotificationViewModel.LoadOldestState {
|
class NoMore: NotificationViewModel.LoadOldestState {
|
||||||
override func isValidNextState(_ stateClass: AnyClass) -> Bool {
|
override func isValidNextState(_ stateClass: AnyClass) -> Bool {
|
||||||
// reset state if needs
|
// reset state if needs
|
||||||
return stateClass == Idle.self
|
stateClass == Idle.self
|
||||||
}
|
}
|
||||||
|
|
||||||
override func didEnter(from previousState: GKState?) {
|
override func didEnter(from previousState: GKState?) {
|
||||||
|
|
|
@ -5,13 +5,12 @@
|
||||||
// Created by sxiaojian on 2021/4/13.
|
// Created by sxiaojian on 2021/4/13.
|
||||||
//
|
//
|
||||||
|
|
||||||
import os.log
|
|
||||||
import UIKit
|
|
||||||
import CoreData
|
import CoreData
|
||||||
import CoreDataStack
|
import CoreDataStack
|
||||||
|
import os.log
|
||||||
|
import UIKit
|
||||||
|
|
||||||
extension NotificationViewModel {
|
extension NotificationViewModel {
|
||||||
|
|
||||||
func setupDiffableDataSource(
|
func setupDiffableDataSource(
|
||||||
for tableView: UITableView,
|
for tableView: UITableView,
|
||||||
delegate: NotificationTableViewCellDelegate,
|
delegate: NotificationTableViewCellDelegate,
|
||||||
|
@ -33,19 +32,18 @@ extension NotificationViewModel {
|
||||||
requestUserID: userid
|
requestUserID: userid
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
extension NotificationViewModel: NSFetchedResultsControllerDelegate {
|
extension NotificationViewModel: NSFetchedResultsControllerDelegate {
|
||||||
func controllerWillChangeContent(_ controller: NSFetchedResultsController<NSFetchRequestResult>) {
|
func controllerWillChangeContent(_ controller: NSFetchedResultsController<NSFetchRequestResult>) {
|
||||||
os_log("%{public}s[%{public}ld], %{public}s", ((#file as NSString).lastPathComponent), #line, #function)
|
os_log("%{public}s[%{public}ld], %{public}s", (#file as NSString).lastPathComponent, #line, #function)
|
||||||
}
|
}
|
||||||
|
|
||||||
func controller(_ controller: NSFetchedResultsController<NSFetchRequestResult>, didChangeContentWith snapshot: NSDiffableDataSourceSnapshotReference) {
|
func controller(_ controller: NSFetchedResultsController<NSFetchRequestResult>, didChangeContentWith snapshot: NSDiffableDataSourceSnapshotReference) {
|
||||||
os_log("%{public}s[%{public}ld], %{public}s", ((#file as NSString).lastPathComponent), #line, #function)
|
os_log("%{public}s[%{public}ld], %{public}s", (#file as NSString).lastPathComponent, #line, #function)
|
||||||
|
|
||||||
guard let tableView = self.tableView else { return }
|
guard let tableView = self.tableView else { return }
|
||||||
guard let navigationBar = self.contentOffsetAdjustableTimelineViewControllerDelegate?.navigationBar() else { return }
|
guard let navigationBar = contentOffsetAdjustableTimelineViewControllerDelegate?.navigationBar() else { return }
|
||||||
|
|
||||||
guard let diffableDataSource = self.diffableDataSource else { return }
|
guard let diffableDataSource = self.diffableDataSource else { return }
|
||||||
let oldSnapshot = diffableDataSource.snapshot()
|
let oldSnapshot = diffableDataSource.snapshot()
|
||||||
|
@ -56,7 +54,6 @@ extension NotificationViewModel: NSFetchedResultsControllerDelegate {
|
||||||
managedObjectContext.parent = parentManagedObjectContext
|
managedObjectContext.parent = parentManagedObjectContext
|
||||||
|
|
||||||
managedObjectContext.perform {
|
managedObjectContext.perform {
|
||||||
|
|
||||||
let notifications: [MastodonNotification] = {
|
let notifications: [MastodonNotification] = {
|
||||||
let request = MastodonNotification.sortedFetchRequest
|
let request = MastodonNotification.sortedFetchRequest
|
||||||
request.returnsObjectsAsFaults = false
|
request.returnsObjectsAsFaults = false
|
||||||
|
@ -71,8 +68,8 @@ extension NotificationViewModel: NSFetchedResultsControllerDelegate {
|
||||||
|
|
||||||
var newSnapshot = NSDiffableDataSourceSnapshot<NotificationSection, NotificationItem>()
|
var newSnapshot = NSDiffableDataSourceSnapshot<NotificationSection, NotificationItem>()
|
||||||
newSnapshot.appendSections([.main])
|
newSnapshot.appendSections([.main])
|
||||||
newSnapshot.appendItems(notifications.map({NotificationItem.notification(objectID: $0.objectID)}), toSection: .main)
|
newSnapshot.appendItems(notifications.map { NotificationItem.notification(objectID: $0.objectID) }, toSection: .main)
|
||||||
if !notifications.isEmpty && self.noMoreNotification.value == false {
|
if !notifications.isEmpty, self.noMoreNotification.value == false {
|
||||||
newSnapshot.appendItems([.bottomLoader], toSection: .main)
|
newSnapshot.appendItems([.bottomLoader], toSection: .main)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -5,16 +5,15 @@
|
||||||
// Created by sxiaojian on 2021/4/12.
|
// Created by sxiaojian on 2021/4/12.
|
||||||
//
|
//
|
||||||
|
|
||||||
import Foundation
|
|
||||||
import Combine
|
import Combine
|
||||||
import UIKit
|
|
||||||
import CoreData
|
import CoreData
|
||||||
import CoreDataStack
|
import CoreDataStack
|
||||||
|
import Foundation
|
||||||
import GameplayKit
|
import GameplayKit
|
||||||
import MastodonSDK
|
import MastodonSDK
|
||||||
|
import UIKit
|
||||||
|
|
||||||
final class NotificationViewModel: NSObject {
|
final class NotificationViewModel: NSObject {
|
||||||
|
|
||||||
var disposeBag = Set<AnyCancellable>()
|
var disposeBag = Set<AnyCancellable>()
|
||||||
|
|
||||||
// input
|
// input
|
||||||
|
@ -23,8 +22,8 @@ final class NotificationViewModel: NSObject {
|
||||||
weak var contentOffsetAdjustableTimelineViewControllerDelegate: ContentOffsetAdjustableTimelineViewControllerDelegate?
|
weak var contentOffsetAdjustableTimelineViewControllerDelegate: ContentOffsetAdjustableTimelineViewControllerDelegate?
|
||||||
|
|
||||||
let viewDidLoad = PassthroughSubject<Void, Never>()
|
let viewDidLoad = PassthroughSubject<Void, Never>()
|
||||||
let selectedIndex = CurrentValueSubject<Int,Never>(0)
|
let selectedIndex = CurrentValueSubject<Int, Never>(0)
|
||||||
let noMoreNotification = CurrentValueSubject<Bool,Never>(false)
|
let noMoreNotification = CurrentValueSubject<Bool, Never>(false)
|
||||||
|
|
||||||
let activeMastodonAuthenticationBox: CurrentValueSubject<AuthenticationService.MastodonAuthenticationBox?, Never>
|
let activeMastodonAuthenticationBox: CurrentValueSubject<AuthenticationService.MastodonAuthenticationBox?, Never>
|
||||||
let fetchedResultsController: NSFetchedResultsController<MastodonNotification>!
|
let fetchedResultsController: NSFetchedResultsController<MastodonNotification>!
|
||||||
|
@ -33,7 +32,7 @@ final class NotificationViewModel: NSObject {
|
||||||
|
|
||||||
let isFetchingLatestNotification = CurrentValueSubject<Bool, Never>(false)
|
let isFetchingLatestNotification = CurrentValueSubject<Bool, Never>(false)
|
||||||
|
|
||||||
//output
|
// output
|
||||||
var diffableDataSource: UITableViewDiffableDataSource<NotificationSection, NotificationItem>!
|
var diffableDataSource: UITableViewDiffableDataSource<NotificationSection, NotificationItem>!
|
||||||
// top loader
|
// top loader
|
||||||
private(set) lazy var loadLatestStateMachine: GKStateMachine = {
|
private(set) lazy var loadLatestStateMachine: GKStateMachine = {
|
||||||
|
@ -63,6 +62,7 @@ final class NotificationViewModel: NSObject {
|
||||||
stateMachine.enter(LoadOldestState.Initial.self)
|
stateMachine.enter(LoadOldestState.Initial.self)
|
||||||
return stateMachine
|
return stateMachine
|
||||||
}()
|
}()
|
||||||
|
|
||||||
lazy var loadOldestStateMachinePublisher = CurrentValueSubject<LoadOldestState?, Never>(nil)
|
lazy var loadOldestStateMachinePublisher = CurrentValueSubject<LoadOldestState?, Never>(nil)
|
||||||
|
|
||||||
init(context: AppContext) {
|
init(context: AppContext) {
|
||||||
|
@ -71,7 +71,7 @@ final class NotificationViewModel: NSObject {
|
||||||
self.fetchedResultsController = {
|
self.fetchedResultsController = {
|
||||||
let fetchRequest = MastodonNotification.sortedFetchRequest
|
let fetchRequest = MastodonNotification.sortedFetchRequest
|
||||||
fetchRequest.returnsObjectsAsFaults = false
|
fetchRequest.returnsObjectsAsFaults = false
|
||||||
fetchRequest.relationshipKeyPathsForPrefetching = [#keyPath(MastodonNotification.status),#keyPath(MastodonNotification.account)]
|
fetchRequest.relationshipKeyPathsForPrefetching = [#keyPath(MastodonNotification.status), #keyPath(MastodonNotification.account)]
|
||||||
let controller = NSFetchedResultsController(
|
let controller = NSFetchedResultsController(
|
||||||
fetchRequest: fetchRequest,
|
fetchRequest: fetchRequest,
|
||||||
managedObjectContext: context.managedObjectContext,
|
managedObjectContext: context.managedObjectContext,
|
||||||
|
@ -83,7 +83,7 @@ final class NotificationViewModel: NSObject {
|
||||||
}()
|
}()
|
||||||
|
|
||||||
super.init()
|
super.init()
|
||||||
self.fetchedResultsController.delegate = self
|
fetchedResultsController.delegate = self
|
||||||
context.authenticationService.activeMastodonAuthenticationBox
|
context.authenticationService.activeMastodonAuthenticationBox
|
||||||
.sink(receiveValue: { [weak self] box in
|
.sink(receiveValue: { [weak self] box in
|
||||||
guard let self = self else { return }
|
guard let self = self else { return }
|
||||||
|
@ -95,7 +95,7 @@ final class NotificationViewModel: NSObject {
|
||||||
.store(in: &disposeBag)
|
.store(in: &disposeBag)
|
||||||
|
|
||||||
notificationPredicate
|
notificationPredicate
|
||||||
.compactMap{ $0 }
|
.compactMap { $0 }
|
||||||
.sink { [weak self] predicate in
|
.sink { [weak self] predicate in
|
||||||
guard let self = self else { return }
|
guard let self = self else { return }
|
||||||
self.fetchedResultsController.fetchRequest.predicate = predicate
|
self.fetchedResultsController.fetchRequest.predicate = predicate
|
||||||
|
@ -112,12 +112,11 @@ final class NotificationViewModel: NSObject {
|
||||||
}
|
}
|
||||||
.store(in: &disposeBag)
|
.store(in: &disposeBag)
|
||||||
|
|
||||||
self.viewDidLoad
|
viewDidLoad
|
||||||
.sink { [weak self] in
|
.sink { [weak self] in
|
||||||
|
|
||||||
guard let domain = self?.activeMastodonAuthenticationBox.value?.domain else { return }
|
guard let domain = self?.activeMastodonAuthenticationBox.value?.domain else { return }
|
||||||
self?.notificationPredicate.value = MastodonNotification.predicate(domain: domain)
|
self?.notificationPredicate.value = MastodonNotification.predicate(domain: domain)
|
||||||
|
|
||||||
}
|
}
|
||||||
.store(in: &disposeBag)
|
.store(in: &disposeBag)
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,7 +12,7 @@ import UIKit
|
||||||
final class NotificationStatusTableViewCell: UITableViewCell {
|
final class NotificationStatusTableViewCell: UITableViewCell {
|
||||||
static let actionImageBorderWidth: CGFloat = 2
|
static let actionImageBorderWidth: CGFloat = 2
|
||||||
|
|
||||||
static let statusPadding: UIEdgeInsets = UIEdgeInsets(top: 50, left: 73, bottom: 24, right: 24)
|
static let statusPadding = UIEdgeInsets(top: 50, left: 73, bottom: 24, right: 24)
|
||||||
var disposeBag = Set<AnyCancellable>()
|
var disposeBag = Set<AnyCancellable>()
|
||||||
var pollCountdownSubscription: AnyCancellable?
|
var pollCountdownSubscription: AnyCancellable?
|
||||||
var delegate: NotificationTableViewCellDelegate?
|
var delegate: NotificationTableViewCellDelegate?
|
||||||
|
|
|
@ -6,16 +6,16 @@
|
||||||
//
|
//
|
||||||
|
|
||||||
import Combine
|
import Combine
|
||||||
|
import CoreDataStack
|
||||||
import Foundation
|
import Foundation
|
||||||
import UIKit
|
import UIKit
|
||||||
import CoreDataStack
|
|
||||||
|
|
||||||
protocol NotificationTableViewCellDelegate: class {
|
protocol NotificationTableViewCellDelegate: AnyObject {
|
||||||
var context: AppContext! { get }
|
var context: AppContext! { get }
|
||||||
|
|
||||||
func parent() -> UIViewController
|
func parent() -> UIViewController
|
||||||
|
|
||||||
func userAvatarDidPressed(notification:MastodonNotification)
|
func userAvatarDidPressed(notification: MastodonNotification)
|
||||||
}
|
}
|
||||||
|
|
||||||
final class NotificationTableViewCell: UITableViewCell {
|
final class NotificationTableViewCell: UITableViewCell {
|
||||||
|
@ -113,7 +113,6 @@ extension NotificationTableViewCell {
|
||||||
])
|
])
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
override func traitCollectionDidChange(_ previousTraitCollection: UITraitCollection?) {
|
override func traitCollectionDidChange(_ previousTraitCollection: UITraitCollection?) {
|
||||||
super.traitCollectionDidChange(previousTraitCollection)
|
super.traitCollectionDidChange(previousTraitCollection)
|
||||||
actionImageBackground.layer.borderColor = Asset.Colors.Background.pure.color.cgColor
|
actionImageBackground.layer.borderColor = Asset.Colors.Background.pure.color.cgColor
|
||||||
|
|
|
@ -5,10 +5,10 @@
|
||||||
// Created by sxiaojian on 2021/4/13.
|
// Created by sxiaojian on 2021/4/13.
|
||||||
//
|
//
|
||||||
|
|
||||||
import Foundation
|
|
||||||
import Combine
|
import Combine
|
||||||
import CoreData
|
import CoreData
|
||||||
import CoreDataStack
|
import CoreDataStack
|
||||||
|
import Foundation
|
||||||
import MastodonSDK
|
import MastodonSDK
|
||||||
import OSLog
|
import OSLog
|
||||||
|
|
||||||
|
@ -16,8 +16,8 @@ extension APIService {
|
||||||
func allNotifications(
|
func allNotifications(
|
||||||
domain: String,
|
domain: String,
|
||||||
query: Mastodon.API.Notifications.Query,
|
query: Mastodon.API.Notifications.Query,
|
||||||
mastodonAuthenticationBox: AuthenticationService.MastodonAuthenticationBox
|
mastodonAuthenticationBox: AuthenticationService.MastodonAuthenticationBox) -> AnyPublisher<Mastodon.Response.Content<[Mastodon.Entity.Notification]>, Error>
|
||||||
) -> AnyPublisher<Mastodon.Response.Content<[Mastodon.Entity.Notification]>, Error> {
|
{
|
||||||
let authorization = mastodonAuthenticationBox.userAuthorization
|
let authorization = mastodonAuthenticationBox.userAuthorization
|
||||||
return Mastodon.API.Notifications.getNotifications(
|
return Mastodon.API.Notifications.getNotifications(
|
||||||
session: session,
|
session: session,
|
||||||
|
@ -28,10 +28,10 @@ extension APIService {
|
||||||
let log = OSLog.api
|
let log = OSLog.api
|
||||||
return self.backgroundManagedObjectContext.performChanges {
|
return self.backgroundManagedObjectContext.performChanges {
|
||||||
response.value.forEach { notification in
|
response.value.forEach { notification in
|
||||||
let (mastodonUser,_) = APIService.CoreData.createOrMergeMastodonUser(into: self.backgroundManagedObjectContext, for: nil, in: domain, entity: notification.account, userCache: nil, networkDate: Date(), log: log)
|
let (mastodonUser, _) = APIService.CoreData.createOrMergeMastodonUser(into: self.backgroundManagedObjectContext, for: nil, in: domain, entity: notification.account, userCache: nil, networkDate: Date(), log: log)
|
||||||
var status: Status?
|
var status: Status?
|
||||||
if let statusEntity = notification.status {
|
if let statusEntity = notification.status {
|
||||||
let (statusInCoreData,_,_) = APIService.CoreData.createOrMergeStatus(
|
let (statusInCoreData, _, _) = APIService.CoreData.createOrMergeStatus(
|
||||||
into: self.backgroundManagedObjectContext,
|
into: self.backgroundManagedObjectContext,
|
||||||
for: nil,
|
for: nil,
|
||||||
domain: domain,
|
domain: domain,
|
||||||
|
@ -45,7 +45,6 @@ extension APIService {
|
||||||
// use constrain to avoid repeated save
|
// use constrain to avoid repeated save
|
||||||
let notification = MastodonNotification.insert(into: self.backgroundManagedObjectContext, domain: domain, property: MastodonNotification.Property(id: notification.id, type: notification.type.rawValue, account: mastodonUser, status: status, createdAt: notification.createdAt))
|
let notification = MastodonNotification.insert(into: self.backgroundManagedObjectContext, domain: domain, property: MastodonNotification.Property(id: notification.id, type: notification.type.rawValue, account: mastodonUser, status: status, createdAt: notification.createdAt))
|
||||||
os_log(.info, log: log, "%{public}s[%{public}ld], %{public}s: fetch mastodon user [%s](%s)", (#file as NSString).lastPathComponent, #line, #function, notification.type, notification.account.username)
|
os_log(.info, log: log, "%{public}s[%{public}ld], %{public}s: fetch mastodon user [%s](%s)", (#file as NSString).lastPathComponent, #line, #function, notification.type, notification.account.username)
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.setFailureType(to: Error.self)
|
.setFailureType(to: Error.self)
|
||||||
|
|
Loading…
Reference in New Issue