ReadKeep/readeck/UI/Search/SearchBookmarksView.swift
Ilyas Hallak c13fc107b1 fix: Card width consistency and layout loading in search
- Fixed natural layout width using screen bounds instead of infinity
- Added card layout settings loading in SearchBookmarksView
- Consistent card width across all views prevents overflow
2025-09-05 21:58:24 +02:00

133 lines
5.0 KiB
Swift

import SwiftUI
struct SearchBookmarksView: View {
@State private var viewModel = SearchBookmarksViewModel()
@FocusState private var searchFieldIsFocused: Bool
@State private var selectedBookmarkId: String?
@Binding var selectedBookmark: Bookmark?
@Namespace private var namespace
@State private var isFirstAppearance = true
@State private var cardLayoutStyle: CardLayoutStyle = .magazine
var body: some View {
VStack(spacing: 0) {
HStack {
Image(systemName: "magnifyingglass")
.foregroundColor(.gray)
TextField("Search...", text: $viewModel.searchQuery)
.focused($searchFieldIsFocused)
.textFieldStyle(PlainTextFieldStyle())
.autocapitalization(.none)
.disableAutocorrection(true)
if !viewModel.searchQuery.isEmpty {
Button(action: {
viewModel.searchQuery = ""
searchFieldIsFocused = true
}) {
Image(systemName: "xmark.circle.fill")
.foregroundColor(.gray)
}
.buttonStyle(.plain)
}
}
.padding(10)
.background(Color(.systemGray6))
.cornerRadius(12)
.padding([.horizontal, .top])
if viewModel.isLoading {
ProgressView("Searching...")
.padding()
}
if let error = viewModel.errorMessage {
Text(error)
.foregroundColor(.red)
.padding()
}
if let bookmarks = viewModel.bookmarks?.bookmarks, !bookmarks.isEmpty {
List(bookmarks) { bookmark in
Button(action: {
if UIDevice.isPhone {
selectedBookmarkId = bookmark.id
} else {
if selectedBookmark?.id == bookmark.id {
selectedBookmark = nil
DispatchQueue.main.async {
selectedBookmark = bookmark
}
} else {
selectedBookmark = bookmark
}
}
}) {
BookmarkCardView(
bookmark: bookmark,
currentState: .all,
layout: cardLayoutStyle,
onArchive: {_ in },
onDelete: {_ in },
onToggleFavorite: {_ in }
)
}
.buttonStyle(PlainButtonStyle())
.listRowInsets(EdgeInsets(
top: cardLayoutStyle == .compact ? 8 : 12,
leading: 16,
bottom: cardLayoutStyle == .compact ? 8 : 12,
trailing: 16
))
.listRowSeparator(.hidden)
.listRowBackground(Color(R.color.bookmark_list_bg))
}
.listStyle(.plain)
.background(Color(R.color.bookmark_list_bg))
.scrollContentBackground(.hidden)
.simultaneousGesture(
DragGesture()
.onChanged { _ in
searchFieldIsFocused = false
}
)
} else if !viewModel.isLoading && viewModel.bookmarks != nil {
ContentUnavailableView("No results", systemImage: "magnifyingglass", description: Text("No bookmarks found."))
.padding()
}
Spacer()
}
.background(Color(R.color.bookmark_list_bg))
.navigationTitle("Search")
.navigationDestination(
item: Binding<String?>(
get: { selectedBookmarkId },
set: { selectedBookmarkId = $0 }
)
) { bookmarkId in
BookmarkDetailView(bookmarkId: bookmarkId)
}
.onAppear {
if isFirstAppearance {
searchFieldIsFocused = true
isFirstAppearance = false
}
loadCardLayoutStyle()
}
.onReceive(NotificationCenter.default.publisher(for: .cardLayoutChanged)) { notification in
if let layout = notification.object as? CardLayoutStyle {
cardLayoutStyle = layout
}
}
}
private func loadCardLayoutStyle() {
Task {
let loadCardLayoutUseCase = DefaultUseCaseFactory.shared.makeLoadCardLayoutUseCase()
let layout = await loadCardLayoutUseCase.execute()
await MainActor.run {
cardLayoutStyle = layout
}
}
}
}