mirror of
https://github.com/Dimillian/IceCubesApp.git
synced 2024-11-29 03:31:02 +00:00
Search users in list edit
This commit is contained in:
parent
ab07fb5906
commit
f2606b4614
3 changed files with 287 additions and 27 deletions
|
@ -1,6 +1,22 @@
|
|||
{
|
||||
"sourceLanguage" : "en",
|
||||
"strings" : {
|
||||
"" : {
|
||||
"localizations" : {
|
||||
"be" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : ""
|
||||
}
|
||||
},
|
||||
"eu" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : ""
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
" ⸱ " : {
|
||||
"localizations" : {
|
||||
"be" : {
|
||||
|
@ -31939,6 +31955,125 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"lists.edit.users-search" : {
|
||||
"extractionState" : "manual",
|
||||
"localizations" : {
|
||||
"be" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "Search users"
|
||||
}
|
||||
},
|
||||
"ca" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "Search users"
|
||||
}
|
||||
},
|
||||
"de" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "Search users"
|
||||
}
|
||||
},
|
||||
"en" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "Search users"
|
||||
}
|
||||
},
|
||||
"en-GB" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "Search users"
|
||||
}
|
||||
},
|
||||
"es" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "Search users"
|
||||
}
|
||||
},
|
||||
"eu" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "Search users"
|
||||
}
|
||||
},
|
||||
"fr" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "Search users"
|
||||
}
|
||||
},
|
||||
"it" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "Search users"
|
||||
}
|
||||
},
|
||||
"ja" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "Search users"
|
||||
}
|
||||
},
|
||||
"ko" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "Search users"
|
||||
}
|
||||
},
|
||||
"nb" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "Search users"
|
||||
}
|
||||
},
|
||||
"nl" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "Search users"
|
||||
}
|
||||
},
|
||||
"pl" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "Search users"
|
||||
}
|
||||
},
|
||||
"pt-BR" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "Search users"
|
||||
}
|
||||
},
|
||||
"tr" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "Search users"
|
||||
}
|
||||
},
|
||||
"uk" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "Search users"
|
||||
}
|
||||
},
|
||||
"zh-Hans" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "Search users"
|
||||
}
|
||||
},
|
||||
"zh-Hant" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "Search users"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"lists.name" : {
|
||||
"extractionState" : "manual",
|
||||
"localizations" : {
|
||||
|
|
|
@ -3,6 +3,7 @@ import EmojiText
|
|||
import Models
|
||||
import Network
|
||||
import SwiftUI
|
||||
import Account
|
||||
|
||||
@MainActor
|
||||
public struct ListEditView: View {
|
||||
|
@ -42,38 +43,28 @@ public struct ListEditView: View {
|
|||
}
|
||||
|
||||
Section("lists.edit.users-in-list") {
|
||||
if viewModel.isLoadingAccounts {
|
||||
HStack {
|
||||
Spacer()
|
||||
ProgressView()
|
||||
Spacer()
|
||||
}
|
||||
} else {
|
||||
ForEach(viewModel.accounts) { account in
|
||||
HStack {
|
||||
AvatarView(account.avatar)
|
||||
VStack(alignment: .leading) {
|
||||
EmojiTextApp(.init(stringValue: account.safeDisplayName),
|
||||
emojis: account.emojis)
|
||||
.emojiSize(Font.scaledBodyFont.emojiSize)
|
||||
.emojiBaselineOffset(Font.scaledBodyFont.emojiBaselineOffset)
|
||||
Text("@\(account.acct)")
|
||||
.foregroundColor(.gray)
|
||||
.font(.scaledFootnote)
|
||||
}
|
||||
}
|
||||
}.onDelete { indexes in
|
||||
if let index = indexes.first {
|
||||
Task {
|
||||
let account = viewModel.accounts[index]
|
||||
await viewModel.delete(account: account)
|
||||
}
|
||||
HStack {
|
||||
TextField("lists.edit.users-search",
|
||||
text: $viewModel.searchUserQuery)
|
||||
if !viewModel.searchUserQuery.isEmpty {
|
||||
Button {
|
||||
viewModel.searchUserQuery = ""
|
||||
} label: {
|
||||
Image(systemName: "xmark.circle")
|
||||
}
|
||||
}
|
||||
}
|
||||
.id("stableId")
|
||||
if !viewModel.searchUserQuery.isEmpty {
|
||||
searchAccountsView
|
||||
} else {
|
||||
listAccountsView
|
||||
}
|
||||
}
|
||||
.listRowBackground(theme.primaryBackgroundColor)
|
||||
.disabled(viewModel.isUpdating)
|
||||
}
|
||||
.scrollDismissesKeyboard(.immediately)
|
||||
.scrollContentBackground(.hidden)
|
||||
.background(theme.secondaryBackgroundColor)
|
||||
.toolbar {
|
||||
|
@ -91,6 +82,98 @@ public struct ListEditView: View {
|
|||
await viewModel.fetchAccounts()
|
||||
}
|
||||
}
|
||||
.task(id: viewModel.searchUserQuery) {
|
||||
do {
|
||||
viewModel.isSearching = true
|
||||
try await Task.sleep(for: .milliseconds(150))
|
||||
await viewModel.searchUsers()
|
||||
} catch {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private var loadingView: some View {
|
||||
HStack {
|
||||
Spacer()
|
||||
ProgressView()
|
||||
Spacer()
|
||||
}
|
||||
.id(UUID())
|
||||
}
|
||||
|
||||
@ViewBuilder
|
||||
private var searchAccountsView: some View {
|
||||
if viewModel.isSearching {
|
||||
loadingView
|
||||
} else {
|
||||
ForEach(viewModel.searchedAccounts) { account in
|
||||
HStack {
|
||||
AvatarView(account.avatar)
|
||||
VStack(alignment: .leading) {
|
||||
EmojiTextApp(.init(stringValue: account.safeDisplayName),
|
||||
emojis: account.emojis)
|
||||
.emojiSize(Font.scaledBodyFont.emojiSize)
|
||||
.emojiBaselineOffset(Font.scaledBodyFont.emojiBaselineOffset)
|
||||
Text("@\(account.acct)")
|
||||
.foregroundColor(.gray)
|
||||
.font(.scaledFootnote)
|
||||
.lineLimit(1)
|
||||
}
|
||||
Spacer()
|
||||
if let relationship = viewModel.searchedRelationships[account.id] {
|
||||
if relationship.following {
|
||||
Toggle("", isOn: .init(get: {
|
||||
viewModel.accounts.contains(where: { $0.id == account.id })
|
||||
}, set: { addedToList in
|
||||
Task {
|
||||
if addedToList {
|
||||
await viewModel.add(account: account)
|
||||
} else {
|
||||
await viewModel.delete(account: account)
|
||||
}
|
||||
}
|
||||
}))
|
||||
} else {
|
||||
FollowButton(viewModel: .init(accountId: account.id,
|
||||
relationship: relationship,
|
||||
shouldDisplayNotify: false,
|
||||
relationshipUpdated: { relationship in
|
||||
viewModel.searchedRelationships[account.id] = relationship
|
||||
}))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ViewBuilder
|
||||
private var listAccountsView: some View {
|
||||
if viewModel.isLoadingAccounts {
|
||||
loadingView
|
||||
} else {
|
||||
ForEach(viewModel.accounts) { account in
|
||||
HStack {
|
||||
AvatarView(account.avatar)
|
||||
VStack(alignment: .leading) {
|
||||
EmojiTextApp(.init(stringValue: account.safeDisplayName),
|
||||
emojis: account.emojis)
|
||||
.emojiSize(Font.scaledBodyFont.emojiSize)
|
||||
.emojiBaselineOffset(Font.scaledBodyFont.emojiBaselineOffset)
|
||||
Text("@\(account.acct)")
|
||||
.foregroundColor(.gray)
|
||||
.font(.scaledFootnote)
|
||||
}
|
||||
}
|
||||
}.onDelete { indexes in
|
||||
if let index = indexes.first {
|
||||
Task {
|
||||
let account = viewModel.accounts[index]
|
||||
await viewModel.delete(account: account)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -20,6 +20,11 @@ import Env
|
|||
|
||||
var isUpdating: Bool = false
|
||||
|
||||
var searchUserQuery: String = ""
|
||||
var searchedAccounts: [Account] = []
|
||||
var searchedRelationships: [String: Relationship] = [:]
|
||||
var isSearching: Bool = false
|
||||
|
||||
init(list: Models.List) {
|
||||
self.list = list
|
||||
self.title = list.title
|
||||
|
@ -58,14 +63,51 @@ import Env
|
|||
}
|
||||
}
|
||||
|
||||
func add(account: Account) async {
|
||||
guard let client else { return }
|
||||
do {
|
||||
isUpdating = true
|
||||
let response = try await client.post(endpoint: Lists.updateAccounts(listId: list.id, accounts: [account.id]))
|
||||
if response?.statusCode == 200 {
|
||||
accounts.append(account)
|
||||
}
|
||||
isUpdating = false
|
||||
} catch {
|
||||
isUpdating = false
|
||||
}
|
||||
}
|
||||
|
||||
func delete(account: Account) async {
|
||||
guard let client else { return }
|
||||
do {
|
||||
isUpdating = true
|
||||
let response = try await client.delete(endpoint: Lists.updateAccounts(listId: list.id, accounts: [account.id]))
|
||||
if response?.statusCode == 200 {
|
||||
accounts.removeAll(where: { $0.id == account.id })
|
||||
}
|
||||
} catch {}
|
||||
isUpdating = false
|
||||
} catch {
|
||||
isUpdating = false
|
||||
}
|
||||
}
|
||||
|
||||
func searchUsers() async {
|
||||
guard let client, !searchUserQuery.isEmpty else { return }
|
||||
do {
|
||||
isSearching = true
|
||||
let results: SearchResults = try await client.get(endpoint: Search.search(query: searchUserQuery,
|
||||
type: nil,
|
||||
offset: nil,
|
||||
following: nil),
|
||||
forceVersion: .v2)
|
||||
let relationships: [Relationship] =
|
||||
try await client.get(endpoint: Accounts.relationships(ids: results.accounts.map(\.id)))
|
||||
searchedRelationships = relationships.reduce(into: [String: Relationship]()) {
|
||||
$0[$1.id] = $1
|
||||
}
|
||||
searchedAccounts = results.accounts
|
||||
isSearching = false
|
||||
} catch { }
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue