feat: restore user recommend scene
This commit is contained in:
parent
6596827837
commit
7da3bbcaa7
|
@ -449,7 +449,8 @@
|
|||
"accessibility": {
|
||||
"show_avatar_image": "Show avatar image",
|
||||
"edit_avatar_image": "Edit avatar image",
|
||||
"show_banner_image": "Show banner image"
|
||||
"show_banner_image": "Show banner image",
|
||||
"double_tap_to_open_the_list": "Double tap to open the list"
|
||||
}
|
||||
},
|
||||
"follower": {
|
||||
|
|
|
@ -546,6 +546,7 @@
|
|||
DBCCC71E25F73297007E1AB6 /* APIService+Reblog.swift in Sources */ = {isa = PBXBuildFile; fileRef = DBCCC71D25F73297007E1AB6 /* APIService+Reblog.swift */; };
|
||||
DBD376AC2692ECDB007FEC24 /* ThemePreference.swift in Sources */ = {isa = PBXBuildFile; fileRef = DBD376AB2692ECDB007FEC24 /* ThemePreference.swift */; };
|
||||
DBD376B2269302A4007FEC24 /* UITableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = DBD376B1269302A4007FEC24 /* UITableViewCell.swift */; };
|
||||
DBD5B1F627BCD3D200BD6B38 /* SuggestionAccountTableViewCell+ViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = DBD5B1F527BCD3D200BD6B38 /* SuggestionAccountTableViewCell+ViewModel.swift */; };
|
||||
DBD9149025DF6D8D00903DFD /* APIService+Onboarding.swift in Sources */ = {isa = PBXBuildFile; fileRef = DBD9148F25DF6D8D00903DFD /* APIService+Onboarding.swift */; };
|
||||
DBE0821525CD382600FD6BBD /* MastodonRegisterViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = DBE0821425CD382600FD6BBD /* MastodonRegisterViewController.swift */; };
|
||||
DBE0822425CD3F1E00FD6BBD /* MastodonRegisterViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = DBE0822325CD3F1E00FD6BBD /* MastodonRegisterViewModel.swift */; };
|
||||
|
@ -1279,6 +1280,7 @@
|
|||
DBCCC71D25F73297007E1AB6 /* APIService+Reblog.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "APIService+Reblog.swift"; sourceTree = "<group>"; };
|
||||
DBD376AB2692ECDB007FEC24 /* ThemePreference.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ThemePreference.swift; sourceTree = "<group>"; };
|
||||
DBD376B1269302A4007FEC24 /* UITableViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UITableViewCell.swift; sourceTree = "<group>"; };
|
||||
DBD5B1F527BCD3D200BD6B38 /* SuggestionAccountTableViewCell+ViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "SuggestionAccountTableViewCell+ViewModel.swift"; sourceTree = "<group>"; };
|
||||
DBD9148F25DF6D8D00903DFD /* APIService+Onboarding.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "APIService+Onboarding.swift"; sourceTree = "<group>"; };
|
||||
DBDC1CF9272C0FD600055C3D /* ku-TR */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "ku-TR"; path = "ku-TR.lproj/Intents.strings"; sourceTree = "<group>"; };
|
||||
DBDC1CFC272C0FD600055C3D /* ku-TR */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "ku-TR"; path = "ku-TR.lproj/InfoPlist.strings"; sourceTree = "<group>"; };
|
||||
|
@ -1768,6 +1770,7 @@
|
|||
isa = PBXGroup;
|
||||
children = (
|
||||
2DAC9E45262FC9FD0062E1A6 /* SuggestionAccountTableViewCell.swift */,
|
||||
DBD5B1F527BCD3D200BD6B38 /* SuggestionAccountTableViewCell+ViewModel.swift */,
|
||||
);
|
||||
path = TableViewCell;
|
||||
sourceTree = "<group>";
|
||||
|
@ -3835,6 +3838,7 @@
|
|||
DBB45B5E27B4EB22002DC5A7 /* AdaptiveMarginStatusTableViewCell.swift in Sources */,
|
||||
DB6180F226391CF40018D199 /* MediaPreviewImageViewModel.swift in Sources */,
|
||||
DBA5E7A3263AD0A3004598BB /* PhotoLibraryService.swift in Sources */,
|
||||
DBD5B1F627BCD3D200BD6B38 /* SuggestionAccountTableViewCell+ViewModel.swift in Sources */,
|
||||
5DDDF1932617442700311060 /* Mastodon+Entity+Account.swift in Sources */,
|
||||
DB63F767279A5EB300455B82 /* NotificationTimelineViewModel.swift in Sources */,
|
||||
2D607AD826242FC500B70763 /* NotificationViewModel.swift in Sources */,
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
<key>AppShared.xcscheme_^#shared#^_</key>
|
||||
<dict>
|
||||
<key>orderHint</key>
|
||||
<integer>28</integer>
|
||||
<integer>20</integer>
|
||||
</dict>
|
||||
<key>CoreDataStack.xcscheme_^#shared#^_</key>
|
||||
<dict>
|
||||
|
@ -97,7 +97,7 @@
|
|||
<key>MastodonIntent.xcscheme_^#shared#^_</key>
|
||||
<dict>
|
||||
<key>orderHint</key>
|
||||
<integer>30</integer>
|
||||
<integer>19</integer>
|
||||
</dict>
|
||||
<key>MastodonIntents.xcscheme_^#shared#^_</key>
|
||||
<dict>
|
||||
|
@ -117,7 +117,7 @@
|
|||
<key>ShareActionExtension.xcscheme_^#shared#^_</key>
|
||||
<dict>
|
||||
<key>orderHint</key>
|
||||
<integer>29</integer>
|
||||
<integer>18</integer>
|
||||
</dict>
|
||||
</dict>
|
||||
<key>SuppressBuildableAutocreation</key>
|
||||
|
|
|
@ -22,12 +22,17 @@ final class UserFetchedResultsController: NSObject {
|
|||
// input
|
||||
@Published var domain: String? = nil
|
||||
@Published var userIDs: [Mastodon.Entity.Account.ID] = []
|
||||
@Published var additionalPredicate: NSPredicate?
|
||||
|
||||
// output
|
||||
let _objectIDs = CurrentValueSubject<[NSManagedObjectID], Never>([])
|
||||
@Published var records: [ManagedObjectRecord<MastodonUser>] = []
|
||||
|
||||
init(managedObjectContext: NSManagedObjectContext, domain: String?, additionalTweetPredicate: NSPredicate?) {
|
||||
init(
|
||||
managedObjectContext: NSManagedObjectContext,
|
||||
domain: String?,
|
||||
additionalPredicate: NSPredicate?
|
||||
) {
|
||||
self.domain = domain ?? ""
|
||||
self.fetchedResultsController = {
|
||||
let fetchRequest = MastodonUser.sortedFetchRequest
|
||||
|
@ -43,6 +48,7 @@ final class UserFetchedResultsController: NSObject {
|
|||
|
||||
return controller
|
||||
}()
|
||||
self.additionalPredicate = additionalPredicate
|
||||
super.init()
|
||||
|
||||
// debounce output to prevent UI update issues
|
||||
|
@ -53,15 +59,16 @@ final class UserFetchedResultsController: NSObject {
|
|||
|
||||
fetchedResultsController.delegate = self
|
||||
|
||||
Publishers.CombineLatest(
|
||||
Publishers.CombineLatest3(
|
||||
self.$domain.removeDuplicates(),
|
||||
self.$userIDs.removeDuplicates()
|
||||
self.$userIDs.removeDuplicates(),
|
||||
self.$additionalPredicate.removeDuplicates()
|
||||
)
|
||||
.receive(on: DispatchQueue.main)
|
||||
.sink { [weak self] domain, ids in
|
||||
.sink { [weak self] domain, ids, additionalPredicate in
|
||||
guard let self = self else { return }
|
||||
var predicates = [MastodonUser.predicate(domain: domain ?? "", ids: ids)]
|
||||
if let additionalPredicate = additionalTweetPredicate {
|
||||
if let additionalPredicate = additionalPredicate {
|
||||
predicates.append(additionalPredicate)
|
||||
}
|
||||
self.fetchedResultsController.fetchRequest.predicate = NSCompoundPredicate(andPredicateWithSubpredicates: predicates)
|
||||
|
|
|
@ -146,10 +146,15 @@ extension RecommendAccountSection {
|
|||
case .account(let record):
|
||||
context.managedObjectContext.performAndWait {
|
||||
guard let user = record.object(in: context.managedObjectContext) else { return }
|
||||
cell.config(with: user)
|
||||
cell.configure(user: user)
|
||||
}
|
||||
|
||||
context.authenticationService.activeMastodonAuthenticationBox
|
||||
.map { $0 as UserIdentifier? }
|
||||
.assign(to: \.userIdentifier, on: cell.viewModel)
|
||||
.store(in: &cell.disposeBag)
|
||||
cell.delegate = configuration.suggestionAccountTableViewCellDelegate
|
||||
}
|
||||
cell.delegate = configuration.suggestionAccountTableViewCellDelegate
|
||||
return cell
|
||||
}
|
||||
}
|
||||
|
|
|
@ -44,7 +44,7 @@ final class FollowerListViewModel {
|
|||
self.userFetchedResultsController = UserFetchedResultsController(
|
||||
managedObjectContext: context.managedObjectContext,
|
||||
domain: domain,
|
||||
additionalTweetPredicate: nil
|
||||
additionalPredicate: nil
|
||||
)
|
||||
self.domain = CurrentValueSubject(domain)
|
||||
self.userID = CurrentValueSubject(userID)
|
||||
|
|
|
@ -44,7 +44,7 @@ final class FollowingListViewModel {
|
|||
self.userFetchedResultsController = UserFetchedResultsController(
|
||||
managedObjectContext: context.managedObjectContext,
|
||||
domain: domain,
|
||||
additionalTweetPredicate: nil
|
||||
additionalPredicate: nil
|
||||
)
|
||||
self.domain = CurrentValueSubject(domain)
|
||||
self.userID = CurrentValueSubject(userID)
|
||||
|
|
|
@ -53,7 +53,7 @@ final class SearchResultViewModel {
|
|||
self.userFetchedResultsController = UserFetchedResultsController(
|
||||
managedObjectContext: context.managedObjectContext,
|
||||
domain: nil,
|
||||
additionalTweetPredicate: nil
|
||||
additionalPredicate: nil
|
||||
)
|
||||
self.statusFetchedResultsController = StatusFetchedResultsController(
|
||||
managedObjectContext: context.managedObjectContext,
|
||||
|
|
|
@ -74,7 +74,7 @@ extension SuggestionAccountViewController {
|
|||
|
||||
setupBackgroundColor(theme: ThemeService.shared.currentTheme.value)
|
||||
ThemeService.shared.currentTheme
|
||||
.receive(on: RunLoop.main)
|
||||
.receive(on: DispatchQueue.main)
|
||||
.sink { [weak self] theme in
|
||||
guard let self = self else { return }
|
||||
self.setupBackgroundColor(theme: theme)
|
||||
|
@ -169,29 +169,31 @@ extension SuggestionAccountViewController: UITableViewDelegate {
|
|||
}
|
||||
|
||||
extension SuggestionAccountViewController: SuggestionAccountTableViewCellDelegate {
|
||||
func accountButtonPressed(objectID: NSManagedObjectID, cell: SuggestionAccountTableViewCell) {
|
||||
// let selected = !viewModel.selectedAccounts.value.contains(objectID)
|
||||
// cell.startAnimating()
|
||||
// viewModel.followAction(objectID: objectID)?
|
||||
// .sink(receiveCompletion: { [weak self] completion in
|
||||
// guard let self = self else { return }
|
||||
// cell.stopAnimating()
|
||||
// switch completion {
|
||||
// case .failure(let error):
|
||||
// os_log("%{public}s[%{public}ld], %{public}s: follow failed. %s", (#file as NSString).lastPathComponent, #line, #function, error.localizedDescription)
|
||||
// case .finished:
|
||||
// var selectedAccounts = self.viewModel.selectedAccounts.value
|
||||
// if selected {
|
||||
// selectedAccounts.append(objectID)
|
||||
// } else {
|
||||
// selectedAccounts.removeAll { $0 == objectID }
|
||||
// }
|
||||
// cell.button.isSelected = selected
|
||||
// self.viewModel.selectedAccounts.value = selectedAccounts
|
||||
// }
|
||||
// }, receiveValue: { _ in
|
||||
// })
|
||||
// .store(in: &disposeBag)
|
||||
func suggestionAccountTableViewCell(
|
||||
_ cell: SuggestionAccountTableViewCell,
|
||||
friendshipDidPressed button: UIButton
|
||||
) {
|
||||
guard let tableViewDiffableDataSource = viewModel.tableViewDiffableDataSource else { return }
|
||||
guard let indexPath = tableView.indexPath(for: cell) else { return }
|
||||
guard let item = tableViewDiffableDataSource.itemIdentifier(for: indexPath) else { return }
|
||||
guard let authenticationBox = context.authenticationService.activeMastodonAuthenticationBox.value else { return }
|
||||
|
||||
switch item {
|
||||
case .account(let user):
|
||||
Task { @MainActor in
|
||||
cell.startAnimating()
|
||||
do {
|
||||
try await DataSourceFacade.responseToUserFollowAction(
|
||||
dependency: self,
|
||||
user: user,
|
||||
authenticationBox: authenticationBox
|
||||
)
|
||||
} catch {
|
||||
// do noting
|
||||
}
|
||||
cell.stopAnimating()
|
||||
} // end Task
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -22,6 +22,7 @@ extension SuggestionAccountViewModel {
|
|||
)
|
||||
|
||||
userFetchedResultsController.$records
|
||||
.removeDuplicates()
|
||||
.receive(on: DispatchQueue.main)
|
||||
.sink { [weak self] records in
|
||||
guard let self = self else { return }
|
||||
|
@ -50,7 +51,7 @@ extension SuggestionAccountViewModel {
|
|||
context: context
|
||||
)
|
||||
|
||||
userFetchedResultsController.$records
|
||||
selectedUserFetchedResultsController.$records
|
||||
.receive(on: DispatchQueue.main)
|
||||
.sink { [weak self] records in
|
||||
guard let self = self else { return }
|
||||
|
@ -58,7 +59,16 @@ extension SuggestionAccountViewModel {
|
|||
|
||||
var snapshot = NSDiffableDataSourceSnapshot<SelectedAccountSection, SelectedAccountItem>()
|
||||
snapshot.appendSections([.main])
|
||||
let items: [SelectedAccountItem] = records.map { SelectedAccountItem.account($0) }
|
||||
var items: [SelectedAccountItem] = records.map { SelectedAccountItem.account($0) }
|
||||
|
||||
if items.count < 10 {
|
||||
let count = 10 - items.count
|
||||
let placeholderItems: [SelectedAccountItem] = (0..<count).map { _ in
|
||||
SelectedAccountItem.placeHolder(uuid: UUID())
|
||||
}
|
||||
items.append(contentsOf: placeholderItems)
|
||||
}
|
||||
|
||||
snapshot.appendItems(items, toSection: .main)
|
||||
|
||||
if #available(iOS 15.0, *) {
|
||||
|
|
|
@ -25,6 +25,7 @@ final class SuggestionAccountViewModel: NSObject {
|
|||
// input
|
||||
let context: AppContext
|
||||
let userFetchedResultsController: UserFetchedResultsController
|
||||
let selectedUserFetchedResultsController: UserFetchedResultsController
|
||||
|
||||
var viewWillAppear = PassthroughSubject<Void, Never>()
|
||||
|
||||
|
@ -32,11 +33,6 @@ final class SuggestionAccountViewModel: NSObject {
|
|||
var collectionViewDiffableDataSource: UICollectionViewDiffableDataSource<SelectedAccountSection, SelectedAccountItem>?
|
||||
var tableViewDiffableDataSource: UITableViewDiffableDataSource<RecommendAccountSection, RecommendAccountItem>?
|
||||
|
||||
@Published var selectedAccounts: [ManagedObjectRecord<MastodonUser>] = []
|
||||
var headerPlaceholderCount = CurrentValueSubject<Int?, Never>(nil)
|
||||
var suggestionAccountsFallback = PassthroughSubject<Void, Never>()
|
||||
|
||||
|
||||
init(
|
||||
context: AppContext
|
||||
) {
|
||||
|
@ -44,53 +40,26 @@ final class SuggestionAccountViewModel: NSObject {
|
|||
self.userFetchedResultsController = UserFetchedResultsController(
|
||||
managedObjectContext: context.managedObjectContext,
|
||||
domain: nil,
|
||||
additionalTweetPredicate: nil
|
||||
additionalPredicate: nil
|
||||
)
|
||||
self.selectedUserFetchedResultsController = UserFetchedResultsController(
|
||||
managedObjectContext: context.managedObjectContext,
|
||||
domain: nil,
|
||||
additionalPredicate: nil
|
||||
)
|
||||
super.init()
|
||||
|
||||
// Publishers.CombineLatest(
|
||||
// $accounts,
|
||||
// $selectedAccounts
|
||||
// )
|
||||
// .receive(on: RunLoop.main)
|
||||
// .sink { [weak self] accounts,selectedAccounts in
|
||||
// self?.applyTableViewDataSource(accounts: accounts)
|
||||
// self?.applySelectedCollectionViewDataSource(accounts: selectedAccounts)
|
||||
// }
|
||||
// .store(in: &disposeBag)
|
||||
|
||||
// Publishers.CombineLatest(
|
||||
// self.selectedAccounts,
|
||||
// self.headerPlaceholderCount
|
||||
// )
|
||||
// .receive(on: RunLoop.main)
|
||||
// .sink { [weak self] selectedAccount,count in
|
||||
// self?.applySelectedCollectionViewDataSource(accounts: selectedAccount)
|
||||
// }
|
||||
// .store(in: &disposeBag)
|
||||
//
|
||||
// viewWillAppear
|
||||
// .sink { [weak self] _ in
|
||||
// self?.checkAccountsFollowState()
|
||||
// }
|
||||
// .store(in: &disposeBag)
|
||||
//
|
||||
// context.authenticationService.activeMastodonAuthentication
|
||||
// .sink { [weak self] activeMastodonAuthentication in
|
||||
// guard let self = self else { return }
|
||||
// guard let activeMastodonAuthentication = activeMastodonAuthentication else {
|
||||
// self.currentMastodonUser.value = nil
|
||||
// return
|
||||
// }
|
||||
// self.currentMastodonUser.value = activeMastodonAuthentication.user
|
||||
// }
|
||||
// .store(in: &disposeBag)
|
||||
|
||||
guard let authenticationBox = context.authenticationService.activeMastodonAuthenticationBox.value else {
|
||||
return
|
||||
}
|
||||
userFetchedResultsController.domain = authenticationBox.domain
|
||||
selectedUserFetchedResultsController.domain = authenticationBox.domain
|
||||
selectedUserFetchedResultsController.additionalPredicate = NSCompoundPredicate(orPredicateWithSubpredicates: [
|
||||
MastodonUser.predicate(followingBy: authenticationBox.userID),
|
||||
MastodonUser.predicate(followRequestedBy: authenticationBox.userID)
|
||||
])
|
||||
|
||||
// fetch recomment users
|
||||
Task {
|
||||
var userIDs: [MastodonUser.ID] = []
|
||||
do {
|
||||
|
@ -111,121 +80,25 @@ final class SuggestionAccountViewModel: NSObject {
|
|||
|
||||
guard !userIDs.isEmpty else { return }
|
||||
userFetchedResultsController.userIDs = userIDs
|
||||
selectedUserFetchedResultsController.userIDs = userIDs
|
||||
}
|
||||
|
||||
// .sink { [weak self] completion in
|
||||
// switch completion {
|
||||
// case .failure(let error):
|
||||
// if let apiError = error as? Mastodon.API.Error {
|
||||
// if apiError.httpResponseStatus == .notFound {
|
||||
// self?.suggestionAccountsFallback.send()
|
||||
// }
|
||||
// }
|
||||
// case .finished:
|
||||
// // handle isFetchingLatestTimeline in fetch controller delegate
|
||||
// break
|
||||
// }
|
||||
// } receiveValue: { [weak self] response in
|
||||
// let ids = response.value.map(\.account.id)
|
||||
// self?.receiveAccounts(ids: ids)
|
||||
// }
|
||||
// .store(in: &disposeBag)
|
||||
//
|
||||
// suggestionAccountsFallback
|
||||
// .sink(receiveValue: { [weak self] _ in
|
||||
// self?.requestSuggestionAccount()
|
||||
// })
|
||||
// .store(in: &disposeBag)
|
||||
// fetch relationship
|
||||
userFetchedResultsController.$records
|
||||
.removeDuplicates()
|
||||
.sink { [weak self] records in
|
||||
guard let _ = self else { return }
|
||||
Task {
|
||||
guard let authenticationBox = context.authenticationService.activeMastodonAuthenticationBox.value else {
|
||||
return
|
||||
}
|
||||
_ = try await context.apiService.relationship(
|
||||
records: records,
|
||||
authenticationBox: authenticationBox
|
||||
)
|
||||
}
|
||||
}
|
||||
.store(in: &disposeBag)
|
||||
}
|
||||
|
||||
// func applyTableViewDataSource(accounts: [NSManagedObjectID]) {
|
||||
// assert(Thread.isMainThread)
|
||||
// guard let dataSource = diffableDataSource else { return }
|
||||
// var snapshot = NSDiffableDataSourceSnapshot<RecommendAccountSection, NSManagedObjectID>()
|
||||
// snapshot.appendSections([.main])
|
||||
// snapshot.appendItems(accounts, toSection: .main)
|
||||
// dataSource.apply(snapshot, animatingDifferences: false, completion: nil)
|
||||
// }
|
||||
//
|
||||
// func applySelectedCollectionViewDataSource(accounts: [NSManagedObjectID]) {
|
||||
// assert(Thread.isMainThread)
|
||||
// guard let count = headerPlaceholderCount.value else { return }
|
||||
// guard let dataSource = collectionDiffableDataSource else { return }
|
||||
// var snapshot = NSDiffableDataSourceSnapshot<SelectedAccountSection, SelectedAccountItem>()
|
||||
// snapshot.appendSections([.main])
|
||||
// let placeholderCount = count - accounts.count
|
||||
// let accountItems = accounts.map { SelectedAccountItem.accountObjectID(accountObjectID: $0) }
|
||||
// snapshot.appendItems(accountItems, toSection: .main)
|
||||
//
|
||||
// if placeholderCount > 0 {
|
||||
// for _ in 0 ..< placeholderCount {
|
||||
// snapshot.appendItems([SelectedAccountItem.placeHolder(uuid: UUID())], toSection: .main)
|
||||
// }
|
||||
// }
|
||||
// dataSource.apply(snapshot, animatingDifferences: false, completion: nil)
|
||||
// }
|
||||
|
||||
// func receiveAccounts(userIDs: [MastodonUser.ID]) {
|
||||
// guard let activeMastodonAuthenticationBox = context.authenticationService.activeMastodonAuthenticationBox.value else {
|
||||
// return
|
||||
// }
|
||||
// let request = MastodonUser.sortedFetchRequest
|
||||
// request.predicate = MastodonUser.predicate(domain: activeMastodonAuthenticationBox.domain, ids: userIDs)
|
||||
// let mastodonUsers: [MastodonUser]? = {
|
||||
// let userFetchRequest = MastodonUser.sortedFetchRequest
|
||||
// userFetchRequest.predicate = MastodonUser.predicate(domain: activeMastodonAuthenticationBox.domain, ids: ids)
|
||||
// userFetchRequest.returnsObjectsAsFaults = false
|
||||
// do {
|
||||
// return try self.context.managedObjectContext.fetch(userFetchRequest)
|
||||
// } catch {
|
||||
// assertionFailure(error.localizedDescription)
|
||||
// return nil
|
||||
// }
|
||||
// }()
|
||||
// if let users = mastodonUsers {
|
||||
// let sortedUsers = users.sorted { (user1, user2) -> Bool in
|
||||
// (ids.firstIndex(of: user1.id) ?? 0) < (ids.firstIndex(of: user2.id) ?? 0)
|
||||
// }
|
||||
// accounts.value = sortedUsers.map(\.objectID)
|
||||
// }
|
||||
// }
|
||||
|
||||
func followAction(objectID: NSManagedObjectID) -> AnyPublisher<Mastodon.Response.Content<Mastodon.Entity.Relationship>, Error>? {
|
||||
fatalError()
|
||||
// guard let activeMastodonAuthenticationBox = context.authenticationService.activeMastodonAuthenticationBox.value else { return nil }
|
||||
//
|
||||
// let mastodonUser = context.managedObjectContext.object(with: objectID) as! MastodonUser
|
||||
// return context.apiService.toggleFollow(
|
||||
// for: mastodonUser,
|
||||
// activeMastodonAuthenticationBox: activeMastodonAuthenticationBox
|
||||
// )
|
||||
}
|
||||
|
||||
// func checkAccountsFollowState() {
|
||||
// fatalError()
|
||||
// guard let currentMastodonUser = currentMastodonUser.value else {
|
||||
// return
|
||||
// }
|
||||
// let users: [MastodonUser] = accounts.value.compactMap {
|
||||
// guard let user = context.managedObjectContext.object(with: $0) as? MastodonUser else {
|
||||
// return nil
|
||||
// }
|
||||
// let isBlock = user.blockingBy.flatMap { $0.contains(currentMastodonUser) } ?? false
|
||||
// let isDomainBlock = user.domainBlockingBy.flatMap { $0.contains(currentMastodonUser) } ?? false
|
||||
// if isBlock || isDomainBlock {
|
||||
// return nil
|
||||
// } else {
|
||||
// return user
|
||||
// }
|
||||
// }
|
||||
// accounts.value = users.map(\.objectID)
|
||||
//
|
||||
// let followingUsers = users.filter { user -> Bool in
|
||||
// let isFollowing = user.followingBy.flatMap { $0.contains(currentMastodonUser) } ?? false
|
||||
// let isPending = user.followRequestedBy.flatMap { $0.contains(currentMastodonUser) } ?? false
|
||||
// return isFollowing || isPending
|
||||
// }.map(\.objectID)
|
||||
//
|
||||
// selectedAccounts.value = followingUsers
|
||||
// }
|
||||
}
|
||||
|
|
|
@ -0,0 +1,139 @@
|
|||
//
|
||||
// SuggestionAccountTableViewCell+ViewModel.swift
|
||||
// Mastodon
|
||||
//
|
||||
// Created by MainasuK on 2022-2-16.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
import Combine
|
||||
import CoreDataStack
|
||||
import MastodonAsset
|
||||
import MastodonMeta
|
||||
import Meta
|
||||
|
||||
extension SuggestionAccountTableViewCell {
|
||||
|
||||
class ViewModel {
|
||||
var disposeBag = Set<AnyCancellable>()
|
||||
|
||||
@Published public var userIdentifier: UserIdentifier? // me
|
||||
|
||||
@Published var avatarImageURL: URL?
|
||||
@Published public var authorName: MetaContent?
|
||||
@Published public var authorUsername: String?
|
||||
|
||||
@Published var isFollowing = false
|
||||
@Published var isPending = false
|
||||
|
||||
func prepareForReuse() {
|
||||
isFollowing = false
|
||||
isPending = false
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
extension SuggestionAccountTableViewCell.ViewModel {
|
||||
func bind(cell: SuggestionAccountTableViewCell) {
|
||||
// avatar
|
||||
$avatarImageURL.removeDuplicates()
|
||||
.sink { url in
|
||||
let configuration = AvatarImageView.Configuration(url: url)
|
||||
cell.avatarButton.avatarImageView.configure(configuration: configuration)
|
||||
cell.avatarButton.avatarImageView.configure(cornerConfiguration: .init(corner: .fixed(radius: 12)))
|
||||
}
|
||||
.store(in: &disposeBag)
|
||||
// name
|
||||
$authorName
|
||||
.sink { metaContent in
|
||||
let metaContent = metaContent ?? PlaintextMetaContent(string: " ")
|
||||
cell.titleLabel.configure(content: metaContent)
|
||||
}
|
||||
.store(in: &disposeBag)
|
||||
// username
|
||||
$authorUsername
|
||||
.map { text -> String in
|
||||
guard let text = text else { return "" }
|
||||
return "@\(text)"
|
||||
}
|
||||
.sink { username in
|
||||
cell.subTitleLabel.text = username
|
||||
}
|
||||
.store(in: &disposeBag)
|
||||
// button
|
||||
Publishers.CombineLatest(
|
||||
$isFollowing,
|
||||
$isPending
|
||||
)
|
||||
.sink { isFollowing, isPending in
|
||||
let isFollowState = isFollowing || isPending
|
||||
let imageName = isFollowState ? "minus.circle.fill" : "plus.circle"
|
||||
let image = UIImage(systemName: imageName, withConfiguration: UIImage.SymbolConfiguration(pointSize: 22, weight: .regular))
|
||||
cell.button.setImage(image, for: .normal)
|
||||
cell.button.tintColor = isFollowState ? Asset.Colors.danger.color : Asset.Colors.Label.secondary.color
|
||||
}
|
||||
.store(in: &disposeBag)
|
||||
}
|
||||
}
|
||||
|
||||
extension SuggestionAccountTableViewCell {
|
||||
func configure(user: MastodonUser) {
|
||||
// author avatar
|
||||
Publishers.CombineLatest(
|
||||
user.publisher(for: \.avatar),
|
||||
UserDefaults.shared.publisher(for: \.preferredStaticAvatar)
|
||||
)
|
||||
.map { _ in user.avatarImageURL() }
|
||||
.assign(to: \.avatarImageURL, on: viewModel)
|
||||
.store(in: &disposeBag)
|
||||
// author name
|
||||
Publishers.CombineLatest(
|
||||
user.publisher(for: \.displayName),
|
||||
user.publisher(for: \.emojis)
|
||||
)
|
||||
.map { _, emojis in
|
||||
do {
|
||||
let content = MastodonContent(content: user.displayNameWithFallback, emojis: emojis.asDictionary)
|
||||
let metaContent = try MastodonMetaContent.convert(document: content)
|
||||
return metaContent
|
||||
} catch {
|
||||
assertionFailure(error.localizedDescription)
|
||||
return PlaintextMetaContent(string: user.displayNameWithFallback)
|
||||
}
|
||||
}
|
||||
.assign(to: \.authorName, on: viewModel)
|
||||
.store(in: &disposeBag)
|
||||
// author username
|
||||
user.publisher(for: \.acct)
|
||||
.map { $0 as String? }
|
||||
.assign(to: \.authorUsername, on: viewModel)
|
||||
.store(in: &disposeBag)
|
||||
// isFollowing
|
||||
Publishers.CombineLatest(
|
||||
viewModel.$userIdentifier,
|
||||
user.publisher(for: \.followingBy)
|
||||
)
|
||||
.map { userIdentifier, followingBy in
|
||||
guard let userIdentifier = userIdentifier else { return false }
|
||||
return followingBy.contains(where: {
|
||||
$0.id == userIdentifier.userID && $0.domain == userIdentifier.domain
|
||||
})
|
||||
}
|
||||
.assign(to: \.isFollowing, on: viewModel)
|
||||
.store(in: &disposeBag)
|
||||
// isPending
|
||||
Publishers.CombineLatest(
|
||||
viewModel.$userIdentifier,
|
||||
user.publisher(for: \.followRequestedBy)
|
||||
)
|
||||
.map { userIdentifier, followRequestedBy in
|
||||
guard let userIdentifier = userIdentifier else { return false }
|
||||
return followRequestedBy.contains(where: {
|
||||
$0.id == userIdentifier.userID && $0.domain == userIdentifier.domain
|
||||
})
|
||||
}
|
||||
.assign(to: \.isPending, on: viewModel)
|
||||
.store(in: &disposeBag)
|
||||
}
|
||||
}
|
|
@ -5,6 +5,7 @@
|
|||
// Created by sxiaojian on 2021/4/21.
|
||||
//
|
||||
|
||||
import os.log
|
||||
import Combine
|
||||
import CoreData
|
||||
import CoreDataStack
|
||||
|
@ -15,23 +16,28 @@ import MetaTextKit
|
|||
import MastodonMeta
|
||||
import MastodonAsset
|
||||
import MastodonLocalization
|
||||
import MastodonUI
|
||||
|
||||
protocol SuggestionAccountTableViewCellDelegate: AnyObject {
|
||||
func accountButtonPressed(objectID: NSManagedObjectID, cell: SuggestionAccountTableViewCell)
|
||||
func suggestionAccountTableViewCell(_ cell: SuggestionAccountTableViewCell, friendshipDidPressed button: UIButton)
|
||||
}
|
||||
|
||||
final class SuggestionAccountTableViewCell: UITableViewCell {
|
||||
|
||||
let logger = Logger(subsystem: "SuggestionAccountTableViewCell", category: "View")
|
||||
|
||||
var disposeBag = Set<AnyCancellable>()
|
||||
|
||||
weak var delegate: SuggestionAccountTableViewCellDelegate?
|
||||
|
||||
let _imageView: UIImageView = {
|
||||
let imageView = UIImageView()
|
||||
imageView.tintColor = Asset.Colors.Label.primary.color
|
||||
imageView.layer.cornerRadius = 4
|
||||
imageView.clipsToBounds = true
|
||||
return imageView
|
||||
public private(set) lazy var viewModel: ViewModel = {
|
||||
let viewModel = ViewModel()
|
||||
viewModel.bind(cell: self)
|
||||
return viewModel
|
||||
}()
|
||||
|
||||
let avatarButton = AvatarButton()
|
||||
|
||||
let titleLabel = MetaLabel(style: .statusName)
|
||||
|
||||
let subTitleLabel: UILabel = {
|
||||
|
@ -49,12 +55,8 @@ final class SuggestionAccountTableViewCell: UITableViewCell {
|
|||
|
||||
let button: HighlightDimmableButton = {
|
||||
let button = HighlightDimmableButton(type: .custom)
|
||||
if let plusImage = UIImage(systemName: "plus.circle", withConfiguration: UIImage.SymbolConfiguration(pointSize: 22, weight: .regular))?.withRenderingMode(.alwaysTemplate) {
|
||||
button.setImage(plusImage, for: .normal)
|
||||
}
|
||||
if let minusImage = UIImage(systemName: "minus.circle.fill", withConfiguration: UIImage.SymbolConfiguration(pointSize: 22, weight: .regular))?.withRenderingMode(.alwaysTemplate) {
|
||||
button.setImage(minusImage, for: .selected)
|
||||
}
|
||||
let image = UIImage(systemName: "plus.circle", withConfiguration: UIImage.SymbolConfiguration(pointSize: 22, weight: .regular))
|
||||
button.setImage(image, for: .normal)
|
||||
return button
|
||||
}()
|
||||
|
||||
|
@ -66,9 +68,10 @@ final class SuggestionAccountTableViewCell: UITableViewCell {
|
|||
|
||||
override func prepareForReuse() {
|
||||
super.prepareForReuse()
|
||||
_imageView.af.cancelImageRequest()
|
||||
_imageView.image = nil
|
||||
|
||||
disposeBag.removeAll()
|
||||
avatarButton.avatarImageView.prepareForReuse()
|
||||
viewModel.prepareForReuse()
|
||||
}
|
||||
|
||||
override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
|
||||
|
@ -80,9 +83,11 @@ final class SuggestionAccountTableViewCell: UITableViewCell {
|
|||
super.init(coder: coder)
|
||||
configure()
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
extension SuggestionAccountTableViewCell {
|
||||
|
||||
private func configure() {
|
||||
let containerStackView = UIStackView()
|
||||
containerStackView.axis = .horizontal
|
||||
|
@ -99,11 +104,11 @@ extension SuggestionAccountTableViewCell {
|
|||
containerStackView.bottomAnchor.constraint(equalTo: contentView.bottomAnchor),
|
||||
])
|
||||
|
||||
_imageView.translatesAutoresizingMaskIntoConstraints = false
|
||||
containerStackView.addArrangedSubview(_imageView)
|
||||
avatarButton.translatesAutoresizingMaskIntoConstraints = false
|
||||
containerStackView.addArrangedSubview(avatarButton)
|
||||
NSLayoutConstraint.activate([
|
||||
_imageView.widthAnchor.constraint(equalToConstant: 42).priority(.required - 1),
|
||||
_imageView.heightAnchor.constraint(equalToConstant: 42).priority(.required - 1),
|
||||
avatarButton.widthAnchor.constraint(equalToConstant: 42).priority(.required - 1),
|
||||
avatarButton.heightAnchor.constraint(equalToConstant: 42).priority(.required - 1),
|
||||
])
|
||||
|
||||
let textStackView = UIStackView()
|
||||
|
@ -139,56 +144,31 @@ extension SuggestionAccountTableViewCell {
|
|||
buttonContainer.centerXAnchor.constraint(equalTo: button.centerXAnchor),
|
||||
buttonContainer.centerYAnchor.constraint(equalTo: button.centerYAnchor),
|
||||
])
|
||||
|
||||
button.addTarget(self, action: #selector(SuggestionAccountTableViewCell.buttonDidPressed(_:)), for: .touchUpInside)
|
||||
}
|
||||
|
||||
func config(with account: MastodonUser) {
|
||||
if let url = account.avatarImageURL() {
|
||||
_imageView.af.setImage(
|
||||
withURL: url,
|
||||
placeholderImage: UIImage.placeholder(color: .systemFill),
|
||||
imageTransition: .crossDissolve(0.2)
|
||||
)
|
||||
}
|
||||
let mastodonContent = MastodonContent(content: account.displayNameWithFallback, emojis: account.emojis.asDictionary)
|
||||
do {
|
||||
let metaContent = try MastodonMetaContent.convert(document: mastodonContent)
|
||||
titleLabel.configure(content: metaContent)
|
||||
} catch {
|
||||
let metaContent = PlaintextMetaContent(string: account.displayNameWithFallback)
|
||||
titleLabel.configure(content: metaContent)
|
||||
}
|
||||
subTitleLabel.text = "@" + account.acct
|
||||
button.isSelected = isSelected
|
||||
button.publisher(for: .touchUpInside)
|
||||
.sink { [weak self] _ in
|
||||
guard let self = self else { return }
|
||||
self.delegate?.accountButtonPressed(objectID: account.objectID, cell: self)
|
||||
}
|
||||
.store(in: &disposeBag)
|
||||
button.publisher(for: \.isSelected)
|
||||
.sink { [weak self] isSelected in
|
||||
if isSelected {
|
||||
self?.button.tintColor = Asset.Colors.danger.color
|
||||
} else {
|
||||
self?.button.tintColor = Asset.Colors.Label.secondary.color
|
||||
}
|
||||
}
|
||||
.store(in: &disposeBag)
|
||||
activityIndicatorView.publisher(for: \.isHidden)
|
||||
.receive(on: DispatchQueue.main)
|
||||
.sink { [weak self] isHidden in
|
||||
self?.button.isHidden = !isHidden
|
||||
}
|
||||
.store(in: &disposeBag)
|
||||
}
|
||||
|
||||
extension SuggestionAccountTableViewCell {
|
||||
@objc private func buttonDidPressed(_ sender: UIButton) {
|
||||
logger.log(level: .debug, "\((#file as NSString).lastPathComponent, privacy: .public)[\(#line, privacy: .public)], \(#function, privacy: .public)")
|
||||
delegate?.suggestionAccountTableViewCell(self, friendshipDidPressed: sender)
|
||||
}
|
||||
}
|
||||
|
||||
extension SuggestionAccountTableViewCell {
|
||||
|
||||
func startAnimating() {
|
||||
activityIndicatorView.isHidden = false
|
||||
activityIndicatorView.startAnimating()
|
||||
button.isHidden = true
|
||||
}
|
||||
|
||||
func stopAnimating() {
|
||||
activityIndicatorView.stopAnimating()
|
||||
activityIndicatorView.isHidden = true
|
||||
button.isHidden = false
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -203,6 +203,14 @@ extension MastodonUser {
|
|||
])
|
||||
}
|
||||
|
||||
public static func predicate(followingBy userID: MastodonUser.ID) -> NSPredicate {
|
||||
NSPredicate(format: "ANY %K.%K == %@", #keyPath(MastodonUser.followingBy), #keyPath(MastodonUser.id), userID)
|
||||
}
|
||||
|
||||
public static func predicate(followRequestedBy userID: MastodonUser.ID) -> NSPredicate {
|
||||
NSPredicate(format: "ANY %K.%K == %@", #keyPath(MastodonUser.followRequestedBy), #keyPath(MastodonUser.id), userID)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -198,166 +198,6 @@ extension Status {
|
|||
return object
|
||||
}
|
||||
|
||||
// @discardableResult
|
||||
// public static func insert(
|
||||
// into context: NSManagedObjectContext,
|
||||
// property: Property,
|
||||
// author: MastodonUser,
|
||||
// reblog: Status?,
|
||||
// application: Application?,
|
||||
// replyTo: Status?,
|
||||
// poll: Poll?,
|
||||
// mentions: [Mention]?,
|
||||
// mediaAttachments: [Attachment]?,
|
||||
// favouritedBy: MastodonUser?,
|
||||
// rebloggedBy: MastodonUser?,
|
||||
// mutedBy: MastodonUser?,
|
||||
// bookmarkedBy: MastodonUser?,
|
||||
// pinnedBy: MastodonUser?
|
||||
// ) -> Status {
|
||||
// let status: Status = context.insertObject()
|
||||
//
|
||||
// status.identifier = property.identifier
|
||||
// status.domain = property.domain
|
||||
//
|
||||
// status.id = property.id
|
||||
// status.uri = property.uri
|
||||
// status.createdAt = property.createdAt
|
||||
// status.content = property.content
|
||||
//
|
||||
// status.visibility = property.visibility
|
||||
// status.sensitive = property.sensitive
|
||||
// status.spoilerText = property.spoilerText
|
||||
// status.application = application
|
||||
//
|
||||
// status.emojisData = property.emojisData
|
||||
//
|
||||
// status.reblogsCount = property.reblogsCount
|
||||
// status.favouritesCount = property.favouritesCount
|
||||
// status.repliesCount = property.repliesCount
|
||||
//
|
||||
// status.url = property.url
|
||||
// status.inReplyToID = property.inReplyToID
|
||||
// status.inReplyToAccountID = property.inReplyToAccountID
|
||||
//
|
||||
// status.language = property.language
|
||||
// status.text = property.text
|
||||
//
|
||||
// status.author = author
|
||||
// status.reblog = reblog
|
||||
//
|
||||
// status.pinnedBy = pinnedBy
|
||||
// status.poll = poll
|
||||
//
|
||||
// if let mentions = mentions {
|
||||
// status.mutableSetValue(forKey: #keyPath(Status.mentions)).addObjects(from: mentions)
|
||||
// }
|
||||
// if let mediaAttachments = mediaAttachments {
|
||||
// status.mutableSetValue(forKey: #keyPath(Status.mediaAttachments)).addObjects(from: mediaAttachments)
|
||||
// }
|
||||
// if let favouritedBy = favouritedBy {
|
||||
// status.mutableSetValue(forKey: #keyPath(Status.favouritedBy)).add(favouritedBy)
|
||||
// }
|
||||
// if let rebloggedBy = rebloggedBy {
|
||||
// status.mutableSetValue(forKey: #keyPath(Status.rebloggedBy)).add(rebloggedBy)
|
||||
// }
|
||||
// if let mutedBy = mutedBy {
|
||||
// status.mutableSetValue(forKey: #keyPath(Status.mutedBy)).add(mutedBy)
|
||||
// }
|
||||
// if let bookmarkedBy = bookmarkedBy {
|
||||
// status.mutableSetValue(forKey: #keyPath(Status.bookmarkedBy)).add(bookmarkedBy)
|
||||
// }
|
||||
//
|
||||
// status.updatedAt = property.networkDate
|
||||
//
|
||||
// return status
|
||||
// }
|
||||
//
|
||||
// public func update(emojisData: Data?) {
|
||||
// if self.emojisData != emojisData {
|
||||
// self.emojisData = emojisData
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// public func update(reblogsCount: NSNumber) {
|
||||
// if self.reblogsCount.intValue != reblogsCount.intValue {
|
||||
// self.reblogsCount = reblogsCount
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// public func update(favouritesCount: NSNumber) {
|
||||
// if self.favouritesCount.intValue != favouritesCount.intValue {
|
||||
// self.favouritesCount = favouritesCount
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// public func update(repliesCount: NSNumber?) {
|
||||
// guard let count = repliesCount else {
|
||||
// return
|
||||
// }
|
||||
// if self.repliesCount?.intValue != count.intValue {
|
||||
// self.repliesCount = repliesCount
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// public func update(replyTo: Status?) {
|
||||
// if self.replyTo != replyTo {
|
||||
// self.replyTo = replyTo
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// public func update(liked: Bool, by mastodonUser: MastodonUser) {
|
||||
// if liked {
|
||||
// if !(self.favouritedBy ?? Set()).contains(mastodonUser) {
|
||||
// self.mutableSetValue(forKey: #keyPath(Status.favouritedBy)).add(mastodonUser)
|
||||
// }
|
||||
// } else {
|
||||
// if (self.favouritedBy ?? Set()).contains(mastodonUser) {
|
||||
// self.mutableSetValue(forKey: #keyPath(Status.favouritedBy)).remove(mastodonUser)
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// public func update(reblogged: Bool, by mastodonUser: MastodonUser) {
|
||||
// if reblogged {
|
||||
// if !(self.rebloggedBy ?? Set()).contains(mastodonUser) {
|
||||
// self.mutableSetValue(forKey: #keyPath(Status.rebloggedBy)).add(mastodonUser)
|
||||
// }
|
||||
// } else {
|
||||
// if (self.rebloggedBy ?? Set()).contains(mastodonUser) {
|
||||
// self.mutableSetValue(forKey: #keyPath(Status.rebloggedBy)).remove(mastodonUser)
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// public func update(muted: Bool, by mastodonUser: MastodonUser) {
|
||||
// if muted {
|
||||
// if !(self.mutedBy ?? Set()).contains(mastodonUser) {
|
||||
// self.mutableSetValue(forKey: #keyPath(Status.mutedBy)).add(mastodonUser)
|
||||
// }
|
||||
// } else {
|
||||
// if (self.mutedBy ?? Set()).contains(mastodonUser) {
|
||||
// self.mutableSetValue(forKey: #keyPath(Status.mutedBy)).remove(mastodonUser)
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// public func update(bookmarked: Bool, by mastodonUser: MastodonUser) {
|
||||
// if bookmarked {
|
||||
// if !(self.bookmarkedBy ?? Set()).contains(mastodonUser) {
|
||||
// self.mutableSetValue(forKey: #keyPath(Status.bookmarkedBy)).add(mastodonUser)
|
||||
// }
|
||||
// } else {
|
||||
// if (self.bookmarkedBy ?? Set()).contains(mastodonUser) {
|
||||
// self.mutableSetValue(forKey: #keyPath(Status.bookmarkedBy)).remove(mastodonUser)
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// public func didUpdate(at networkDate: Date) {
|
||||
// self.updatedAt = networkDate
|
||||
// }
|
||||
|
||||
}
|
||||
|
||||
extension Status: Managed {
|
||||
|
@ -737,78 +577,3 @@ extension Status {
|
|||
mutableSetValue(forKey: #keyPath(Status.feeds)).add(feed)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//extension Status {
|
||||
// public struct Property {
|
||||
//
|
||||
// public let identifier: ID
|
||||
// public let domain: String
|
||||
//
|
||||
// public let id: String
|
||||
// public let uri: String
|
||||
// public let createdAt: Date
|
||||
// public let content: String
|
||||
//
|
||||
// public let visibility: String?
|
||||
// public let sensitive: Bool
|
||||
// public let spoilerText: String?
|
||||
//
|
||||
// public let emojisData: Data?
|
||||
//
|
||||
// public let reblogsCount: NSNumber
|
||||
// public let favouritesCount: NSNumber
|
||||
// public let repliesCount: NSNumber?
|
||||
//
|
||||
// public let url: String?
|
||||
// public let inReplyToID: Status.ID?
|
||||
// public let inReplyToAccountID: MastodonUser.ID?
|
||||
// public let language: String? // (ISO 639 Part @1 two-letter language code)
|
||||
// public let text: String?
|
||||
//
|
||||
// public let networkDate: Date
|
||||
//
|
||||
// public init(
|
||||
// domain: String,
|
||||
// id: String,
|
||||
// uri: String,
|
||||
// createdAt: Date,
|
||||
// content: String,
|
||||
// visibility: String?,
|
||||
// sensitive: Bool,
|
||||
// spoilerText: String?,
|
||||
// emojisData: Data?,
|
||||
// reblogsCount: NSNumber,
|
||||
// favouritesCount: NSNumber,
|
||||
// repliesCount: NSNumber?,
|
||||
// url: String?,
|
||||
// inReplyToID: Status.ID?,
|
||||
// inReplyToAccountID: MastodonUser.ID?,
|
||||
// language: String?,
|
||||
// text: String?,
|
||||
// networkDate: Date
|
||||
// ) {
|
||||
// self.identifier = id + "@" + domain
|
||||
// self.domain = domain
|
||||
// self.id = id
|
||||
// self.uri = uri
|
||||
// self.createdAt = createdAt
|
||||
// self.content = content
|
||||
// self.visibility = visibility
|
||||
// self.sensitive = sensitive
|
||||
// self.spoilerText = spoilerText
|
||||
// self.emojisData = emojisData
|
||||
// self.reblogsCount = reblogsCount
|
||||
// self.favouritesCount = favouritesCount
|
||||
// self.repliesCount = repliesCount
|
||||
// self.url = url
|
||||
// self.inReplyToID = inReplyToID
|
||||
// self.inReplyToAccountID = inReplyToAccountID
|
||||
// self.language = language
|
||||
// self.text = text
|
||||
// self.networkDate = networkDate
|
||||
// }
|
||||
//
|
||||
// }
|
||||
//}
|
||||
//
|
||||
|
|
Loading…
Reference in New Issue