patch search

This commit is contained in:
cheykrym 2025-10-07 06:05:38 +03:00
parent 7ce0fb3cd3
commit f6ca117b8e
4 changed files with 150 additions and 76 deletions

View File

@ -395,7 +395,7 @@
ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
CODE_SIGN_ENTITLEMENTS = yobble/yobble.entitlements;
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 4;
CURRENT_PROJECT_VERSION = 5;
DEVELOPMENT_TEAM = V22H44W47J;
ENABLE_HARDENED_RUNTIME = YES;
ENABLE_PREVIEWS = YES;
@ -435,7 +435,7 @@
ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
CODE_SIGN_ENTITLEMENTS = yobble/yobble.entitlements;
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 4;
CURRENT_PROJECT_VERSION = 5;
DEVELOPMENT_TEAM = V22H44W47J;
ENABLE_HARDENED_RUNTIME = YES;
ENABLE_PREVIEWS = YES;

View File

@ -26,6 +26,18 @@ struct SearchProfile: Decodable {
}
extension UserSearchResult {
var officialFullName: String? {
trimmed(fullName) ?? trimmed(profile?.fullName)
}
var preferredCustomName: String? {
trimmed(customName) ?? trimmed(profile?.customName)
}
var loginHandle: String {
"@\(login)"
}
var displayName: String {
if let official = officialFullName {
return official
@ -42,50 +54,6 @@ extension UserSearchResult {
return loginHandle
}
var secondaryText: String? {
// Отдельное поле для совместимости с существующими вызовами
// if let official = officialFullName, official != displayName {
// return official
// }
if let profileLogin = trimmed(profile?.login), profileLogin != login {
return "@\(profileLogin)"
}
return nil
}
var officialFullName: String? {
trimmed(fullName) ?? trimmed(profile?.fullName)
}
var preferredCustomName: String? {
trimmed(customName) ?? trimmed(profile?.customName)
}
var loginHandle: String {
"@\(login)"
}
var secondaryLabelForSearch: String? {
if let official = officialFullName {
// if let custom = preferredCustomName, custom != official {
// return custom
// }
if official != loginHandle {
return loginHandle
}
}
if let secondary = secondaryText, secondary != displayName {
return secondary
}
if displayName != loginHandle {
return loginHandle
}
return nil
}
var avatarInitial: String {
let source = officialFullName
?? preferredCustomName

View File

@ -29,6 +29,9 @@
},
"Chat ID:" : {
},
"Companion ID" : {
"comment" : "Search placeholder companion title"
},
"Companion ID:" : {
@ -338,6 +341,9 @@
}
}
},
"Здесь появится информация о собеседнике и существующих чатах." : {
"comment" : "Search placeholder description"
},
"Идеи" : {
"extractionState" : "stale",
"localizations" : {
@ -1082,6 +1088,9 @@
}
}
},
"Профиль в разработке" : {
"comment" : "Search placeholder title"
},
"Публичная информация" : {
},
@ -1204,6 +1213,9 @@
}
}
},
"Скопировать" : {
"comment" : "Search placeholder copy"
},
"Скоро появится мини-игра, где можно заработать очки для кастомизации профиля. Следите за обновлениями!" : {
"comment" : "Concept tab placeholder description"
},

View File

@ -23,6 +23,7 @@ struct ChatsTab: View {
@State private var isGlobalSearchLoading: Bool = false
@State private var globalSearchError: String?
@State private var globalSearchTask: Task<Void, Never>? = nil
@State private var selectedSearchUserId: UUID?
private let searchRevealDistance: CGFloat = 90
@ -361,6 +362,9 @@ struct ChatsTab: View {
}
private func globalSearchRow(for user: UserSearchResult) -> some View {
Button {
selectedSearchUserId = user.userId
} label: {
HStack(spacing: 12) {
Circle()
.fill(user.isOfficial ? Color.accentColor.opacity(0.85) : Color.accentColor.opacity(0.15))
@ -386,7 +390,7 @@ struct ChatsTab: View {
}
}
if let secondary = user.secondaryLabelForSearch {
if let secondary = secondaryLine(for: user) {
Text(secondary)
.font(.footnote)
.foregroundColor(.secondary)
@ -397,7 +401,19 @@ struct ChatsTab: View {
.frame(maxWidth: .infinity, alignment: .leading)
}
.padding(.vertical, 8)
}
.buttonStyle(.plain)
.listRowInsets(EdgeInsets(top: 8, leading: 16, bottom: 8, trailing: 16))
.background(
NavigationLink(
destination: SearchResultPlaceholderView(userId: user.userId),
tag: user.userId,
selection: $selectedSearchUserId
) {
EmptyView()
}
.hidden()
)
}
}
@ -423,6 +439,7 @@ private extension ChatsTab {
globalSearchResults = []
globalSearchError = nil
isGlobalSearchLoading = false
selectedSearchUserId = nil
return
}
@ -441,6 +458,7 @@ private extension ChatsTab {
isGlobalSearchLoading = false
globalSearchError = nil
globalSearchTask = nil
selectedSearchUserId = nil
}
} catch is CancellationError {
// Ignore cancellation
@ -451,6 +469,7 @@ private extension ChatsTab {
isGlobalSearchLoading = false
globalSearchError = friendlyErrorMessage(for: error)
globalSearchTask = nil
selectedSearchUserId = nil
}
}
}
@ -462,8 +481,37 @@ private extension ChatsTab {
globalSearchResults = []
globalSearchError = nil
isGlobalSearchLoading = false
selectedSearchUserId = nil
}
func secondaryLine(for user: UserSearchResult) -> String? {
if let official = user.officialFullName {
if let custom = user.preferredCustomName, custom != official {
return "\(user.loginHandle) (\(custom))"
}
// if official != user.loginHandle {
// return user.loginHandle
// }
}
else if let custom = user.preferredCustomName, custom != user.displayName {
return custom
}
if let profileLogin = user.profile?.login?.trimmingCharacters(in: .whitespacesAndNewlines), !profileLogin.isEmpty {
let handle = "@\(profileLogin)"
if handle != user.loginHandle {
return handle
}
}
if user.displayName != user.loginHandle {
return user.loginHandle
}
return nil
}
func friendlyErrorMessage(for error: Error) -> String {
if let searchError = error as? SearchServiceError {
return searchError.errorDescription ?? NSLocalizedString("Не удалось выполнить поиск.", comment: "Search error fallback")
@ -500,6 +548,52 @@ private struct ScrollDismissesKeyboardModifier: ViewModifier {
}
}
private struct SearchResultPlaceholderView: View {
let userId: UUID
var body: some View {
VStack(spacing: 16) {
Text(NSLocalizedString("Профиль в разработке", comment: "Search placeholder title"))
.font(.headline)
VStack(alignment: .leading, spacing: 8) {
Text(NSLocalizedString("Companion ID", comment: "Search placeholder companion title"))
.font(.subheadline)
.foregroundColor(.secondary)
Text(userId.uuidString)
.font(.body.monospaced())
.contextMenu {
Button(action: {
#if canImport(UIKit)
UIPasteboard.general.string = userId.uuidString
#endif
}) {
Label(NSLocalizedString("Скопировать", comment: "Search placeholder copy"), systemImage: "doc.on.doc")
}
}
}
.frame(maxWidth: .infinity, alignment: .leading)
.padding()
.background(
RoundedRectangle(cornerRadius: 12)
.fill(Color(UIColor.secondarySystemBackground))
)
Text(NSLocalizedString("Здесь появится информация о собеседнике и существующих чатах.", comment: "Search placeholder description"))
.font(.footnote)
.foregroundColor(.secondary)
.multilineTextAlignment(.center)
.padding(.horizontal)
Spacer()
}
.padding(.top, 40)
.padding(.horizontal, 24)
.frame(maxWidth: .infinity, maxHeight: .infinity, alignment: .top)
.background(Color(UIColor.systemBackground))
}
}
private struct ChatRowView: View {
let chat: PrivateChatListItem
let currentUserId: String?