mirror of
https://github.com/cranci1/Sora.git
synced 2026-01-11 20:10:24 +00:00
Fix for native navigation (#233)
Co-authored-by: cranci <100066266+cranci1@users.noreply.github.com>
This commit is contained in:
parent
8b2f9c08cd
commit
122e248d9c
4 changed files with 112 additions and 99 deletions
|
|
@ -52,7 +52,7 @@ struct ContentView: View {
|
|||
}
|
||||
}
|
||||
}
|
||||
.searchable(text: $searchQuery)
|
||||
//.searchable(text: $searchQuery)
|
||||
} else {
|
||||
ZStack(alignment: .bottom) {
|
||||
ZStack {
|
||||
|
|
|
|||
|
|
@ -632,10 +632,12 @@ struct MediaInfoView: View {
|
|||
|
||||
@ViewBuilder
|
||||
private var flatEpisodeList: some View {
|
||||
VStack(spacing: 15) {
|
||||
ForEach(currentEpisodeList.indices.filter { selectedRange.contains($0) }, id: \.self) { i in
|
||||
let ep = currentEpisodeList[i]
|
||||
createEpisodeCell(episode: ep, index: i, season: isGroupedBySeasons ? selectedSeason + 1 : 1)
|
||||
ScrollView {
|
||||
VStack(spacing: 15) {
|
||||
ForEach(currentEpisodeList.indices.filter { selectedRange.contains($0) }, id: \.self) { i in
|
||||
let ep = currentEpisodeList[i]
|
||||
createEpisodeCell(episode: ep, index: i, season: isGroupedBySeasons ? selectedSeason + 1 : 1)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -644,10 +646,12 @@ struct MediaInfoView: View {
|
|||
private var seasonsEpisodeList: some View {
|
||||
let seasons = groupedEpisodes()
|
||||
if !seasons.isEmpty, selectedSeason < seasons.count {
|
||||
VStack(spacing: 15) {
|
||||
ForEach(seasons[selectedSeason].indices.filter { selectedRange.contains($0) }, id: \.self) { i in
|
||||
let ep = seasons[selectedSeason][i]
|
||||
createEpisodeCell(episode: ep, index: i, season: selectedSeason + 1)
|
||||
ScrollView {
|
||||
VStack(spacing: 15) {
|
||||
ForEach(seasons[selectedSeason].indices.filter { selectedRange.contains($0) }, id: \.self) { i in
|
||||
let ep = seasons[selectedSeason][i]
|
||||
createEpisodeCell(episode: ep, index: i, season: selectedSeason + 1)
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
|
|
|
|||
|
|
@ -69,3 +69,46 @@ struct SearchHistoryRow: View {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct SearchBar: View {
|
||||
@Binding var text: String
|
||||
@Binding var isSearching: Bool
|
||||
@FocusState private var isFocused: Bool
|
||||
|
||||
var body: some View {
|
||||
HStack {
|
||||
HStack {
|
||||
Image(systemName: "magnifyingglass")
|
||||
.foregroundColor(.gray)
|
||||
|
||||
TextField("Search", text: $text)
|
||||
.focused($isFocused)
|
||||
.submitLabel(.search)
|
||||
.autocorrectionDisabled(true)
|
||||
.autocapitalization(.none)
|
||||
.disableAutocorrection(true)
|
||||
.textInputAutocapitalization(.never)
|
||||
.onChange(of: text) { _ in
|
||||
// This triggers search while typing
|
||||
NotificationCenter.default.post(name: .tabBarSearchQueryUpdated, object: nil, userInfo: ["searchQuery": text])
|
||||
}
|
||||
.onSubmit {
|
||||
UIApplication.shared.sendAction(#selector(UIResponder.resignFirstResponder), to: nil, from: nil, for: nil)
|
||||
}
|
||||
|
||||
if !text.isEmpty {
|
||||
Button(action: {
|
||||
text = ""
|
||||
isFocused = false
|
||||
}) {
|
||||
Image(systemName: "xmark.circle.fill")
|
||||
.foregroundColor(.gray)
|
||||
}
|
||||
}
|
||||
}
|
||||
.padding(8)
|
||||
.background(Color(.systemGray6))
|
||||
.cornerRadius(10)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -20,6 +20,7 @@ struct SearchView: View {
|
|||
@AppStorage("selectedModuleId") private var selectedModuleId: String?
|
||||
@AppStorage("mediaColumnsPortrait") private var mediaColumnsPortrait: Int = 2
|
||||
@AppStorage("mediaColumnsLandscape") private var mediaColumnsLandscape: Int = 4
|
||||
@AppStorage("useNativeTabBar") private var useNativeTabBar: Bool = false
|
||||
|
||||
@StateObject private var jsController = JSController.shared
|
||||
@EnvironmentObject var moduleManager: ModuleManager
|
||||
|
|
@ -74,51 +75,64 @@ struct SearchView: View {
|
|||
}
|
||||
|
||||
private var mainContent: some View {
|
||||
VStack(alignment: .leading) {
|
||||
HStack {
|
||||
Text(LocalizedStringKey("Search"))
|
||||
.font(.largeTitle)
|
||||
.fontWeight(.bold)
|
||||
VStack(alignment: .leading) {
|
||||
HStack {
|
||||
Text(LocalizedStringKey("Search"))
|
||||
.font(.largeTitle)
|
||||
.fontWeight(.bold)
|
||||
|
||||
Spacer()
|
||||
|
||||
ModuleSelectorMenu(
|
||||
selectedModule: selectedModule,
|
||||
moduleGroups: getModuleLanguageGroups(),
|
||||
modulesByLanguage: getModulesByLanguage(),
|
||||
selectedModuleId: selectedModuleId,
|
||||
onModuleSelected: { moduleId in
|
||||
selectedModuleId = moduleId
|
||||
}
|
||||
)
|
||||
}
|
||||
.padding(.horizontal, 20)
|
||||
.padding(.top, 20)
|
||||
|
||||
Spacer()
|
||||
if useNativeTabBar {
|
||||
SearchBar(text: $searchQuery, isSearching: $isSearching)
|
||||
.padding(.horizontal, 20)
|
||||
.padding(.top, 10)
|
||||
}
|
||||
|
||||
ModuleSelectorMenu(
|
||||
selectedModule: selectedModule,
|
||||
moduleGroups: getModuleLanguageGroups(),
|
||||
modulesByLanguage: getModulesByLanguage(),
|
||||
selectedModuleId: selectedModuleId,
|
||||
onModuleSelected: { moduleId in
|
||||
selectedModuleId = moduleId
|
||||
}
|
||||
)
|
||||
}
|
||||
.padding(.horizontal, 20)
|
||||
.padding(.top, 20)
|
||||
|
||||
ScrollView(showsIndicators: false) {
|
||||
SearchContent(
|
||||
selectedModule: selectedModule,
|
||||
searchQuery: searchQuery,
|
||||
searchHistory: searchHistory,
|
||||
searchItems: searchItems,
|
||||
isSearching: isSearching,
|
||||
hasNoResults: hasNoResults,
|
||||
columns: columns,
|
||||
columnsCount: columnsCount,
|
||||
cellWidth: cellWidth,
|
||||
onHistoryItemSelected: { query in
|
||||
searchQuery = query
|
||||
searchDebounceTimer?.invalidate()
|
||||
|
||||
ScrollView(showsIndicators: false) {
|
||||
SearchContent(
|
||||
selectedModule: selectedModule,
|
||||
searchQuery: searchQuery,
|
||||
searchHistory: searchHistory,
|
||||
searchItems: searchItems,
|
||||
isSearching: isSearching,
|
||||
hasNoResults: hasNoResults,
|
||||
columns: columns,
|
||||
columnsCount: columnsCount,
|
||||
cellWidth: cellWidth,
|
||||
onHistoryItemSelected: { query in
|
||||
searchQuery = query
|
||||
searchDebounceTimer?.invalidate()
|
||||
|
||||
UIApplication.shared.sendAction(#selector(UIResponder.resignFirstResponder), to: nil, from: nil, for: nil)
|
||||
NotificationCenter.default.post(name: .tabBarSearchQueryUpdated, object: nil, userInfo: ["searchQuery": query])
|
||||
|
||||
performSearch()
|
||||
},
|
||||
onHistoryItemDeleted: { index in
|
||||
removeFromHistory(at: index)
|
||||
},
|
||||
onClearHistory: clearSearchHistory
|
||||
)
|
||||
}
|
||||
.scrollViewBottomPadding()
|
||||
.simultaneousGesture(
|
||||
DragGesture().onChanged { _ in
|
||||
UIApplication.shared.sendAction(#selector(UIResponder.resignFirstResponder), to: nil, from: nil, for: nil)
|
||||
NotificationCenter.default.post(name: .tabBarSearchQueryUpdated, object: nil, userInfo: ["searchQuery": query])
|
||||
|
||||
performSearch()
|
||||
},
|
||||
onHistoryItemDeleted: { index in
|
||||
removeFromHistory(at: index)
|
||||
},
|
||||
onClearHistory: clearSearchHistory
|
||||
}
|
||||
)
|
||||
}
|
||||
.scrollViewBottomPadding()
|
||||
|
|
@ -128,8 +142,6 @@ struct SearchView: View {
|
|||
}
|
||||
)
|
||||
}
|
||||
.navigationBarHidden(true)
|
||||
}
|
||||
|
||||
var body: some View {
|
||||
Group {
|
||||
|
|
@ -348,49 +360,3 @@ struct SearchView: View {
|
|||
return getModulesByLanguage()[language] ?? []
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
struct SearchBar: View {
|
||||
@State private var debounceTimer: Timer?
|
||||
@Binding var text: String
|
||||
@Binding var isFocused: Bool
|
||||
var onSearchButtonClicked: () -> Void
|
||||
|
||||
var body: some View {
|
||||
HStack {
|
||||
TextField(LocalizedStringKey("Search..."), text: $text, onEditingChanged: { isEditing in
|
||||
isFocused = isEditing
|
||||
}, onCommit: onSearchButtonClicked)
|
||||
.padding(7)
|
||||
.padding(.horizontal, 25)
|
||||
.background(Color(.systemGray6))
|
||||
.cornerRadius(8)
|
||||
.onChange(of: text) { newValue in
|
||||
debounceTimer?.invalidate()
|
||||
if !newValue.isEmpty {
|
||||
debounceTimer = Timer.scheduledTimer(withTimeInterval: 1.0, repeats: false) { _ in
|
||||
onSearchButtonClicked()
|
||||
}
|
||||
}
|
||||
}
|
||||
.overlay(
|
||||
HStack {
|
||||
Image(systemName: "magnifyingglass")
|
||||
.foregroundColor(.secondary)
|
||||
.frame(minWidth: 0, maxWidth: .infinity, alignment: .leading)
|
||||
.padding(.leading, 8)
|
||||
|
||||
if !text.isEmpty {
|
||||
Button(action: {
|
||||
self.text = ""
|
||||
}) {
|
||||
Image(systemName: "multiply.circle.fill")
|
||||
.foregroundColor(.secondary)
|
||||
.padding(.trailing, 8)
|
||||
}
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue