mirror of
https://github.com/cranci1/Sora.git
synced 2026-05-14 05:50:41 +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 {
|
} else {
|
||||||
ZStack(alignment: .bottom) {
|
ZStack(alignment: .bottom) {
|
||||||
ZStack {
|
ZStack {
|
||||||
|
|
|
||||||
|
|
@ -632,10 +632,12 @@ struct MediaInfoView: View {
|
||||||
|
|
||||||
@ViewBuilder
|
@ViewBuilder
|
||||||
private var flatEpisodeList: some View {
|
private var flatEpisodeList: some View {
|
||||||
VStack(spacing: 15) {
|
ScrollView {
|
||||||
ForEach(currentEpisodeList.indices.filter { selectedRange.contains($0) }, id: \.self) { i in
|
VStack(spacing: 15) {
|
||||||
let ep = currentEpisodeList[i]
|
ForEach(currentEpisodeList.indices.filter { selectedRange.contains($0) }, id: \.self) { i in
|
||||||
createEpisodeCell(episode: ep, index: i, season: isGroupedBySeasons ? selectedSeason + 1 : 1)
|
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 {
|
private var seasonsEpisodeList: some View {
|
||||||
let seasons = groupedEpisodes()
|
let seasons = groupedEpisodes()
|
||||||
if !seasons.isEmpty, selectedSeason < seasons.count {
|
if !seasons.isEmpty, selectedSeason < seasons.count {
|
||||||
VStack(spacing: 15) {
|
ScrollView {
|
||||||
ForEach(seasons[selectedSeason].indices.filter { selectedRange.contains($0) }, id: \.self) { i in
|
VStack(spacing: 15) {
|
||||||
let ep = seasons[selectedSeason][i]
|
ForEach(seasons[selectedSeason].indices.filter { selectedRange.contains($0) }, id: \.self) { i in
|
||||||
createEpisodeCell(episode: ep, index: i, season: selectedSeason + 1)
|
let ep = seasons[selectedSeason][i]
|
||||||
|
createEpisodeCell(episode: ep, index: i, season: selectedSeason + 1)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} 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("selectedModuleId") private var selectedModuleId: String?
|
||||||
@AppStorage("mediaColumnsPortrait") private var mediaColumnsPortrait: Int = 2
|
@AppStorage("mediaColumnsPortrait") private var mediaColumnsPortrait: Int = 2
|
||||||
@AppStorage("mediaColumnsLandscape") private var mediaColumnsLandscape: Int = 4
|
@AppStorage("mediaColumnsLandscape") private var mediaColumnsLandscape: Int = 4
|
||||||
|
@AppStorage("useNativeTabBar") private var useNativeTabBar: Bool = false
|
||||||
|
|
||||||
@StateObject private var jsController = JSController.shared
|
@StateObject private var jsController = JSController.shared
|
||||||
@EnvironmentObject var moduleManager: ModuleManager
|
@EnvironmentObject var moduleManager: ModuleManager
|
||||||
|
|
@ -74,51 +75,64 @@ struct SearchView: View {
|
||||||
}
|
}
|
||||||
|
|
||||||
private var mainContent: some View {
|
private var mainContent: some View {
|
||||||
VStack(alignment: .leading) {
|
VStack(alignment: .leading) {
|
||||||
HStack {
|
HStack {
|
||||||
Text(LocalizedStringKey("Search"))
|
Text(LocalizedStringKey("Search"))
|
||||||
.font(.largeTitle)
|
.font(.largeTitle)
|
||||||
.fontWeight(.bold)
|
.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(
|
ScrollView(showsIndicators: false) {
|
||||||
selectedModule: selectedModule,
|
SearchContent(
|
||||||
moduleGroups: getModuleLanguageGroups(),
|
selectedModule: selectedModule,
|
||||||
modulesByLanguage: getModulesByLanguage(),
|
searchQuery: searchQuery,
|
||||||
selectedModuleId: selectedModuleId,
|
searchHistory: searchHistory,
|
||||||
onModuleSelected: { moduleId in
|
searchItems: searchItems,
|
||||||
selectedModuleId = moduleId
|
isSearching: isSearching,
|
||||||
}
|
hasNoResults: hasNoResults,
|
||||||
)
|
columns: columns,
|
||||||
}
|
columnsCount: columnsCount,
|
||||||
.padding(.horizontal, 20)
|
cellWidth: cellWidth,
|
||||||
.padding(.top, 20)
|
onHistoryItemSelected: { query in
|
||||||
|
searchQuery = query
|
||||||
ScrollView(showsIndicators: false) {
|
searchDebounceTimer?.invalidate()
|
||||||
SearchContent(
|
|
||||||
selectedModule: selectedModule,
|
UIApplication.shared.sendAction(#selector(UIResponder.resignFirstResponder), to: nil, from: nil, for: nil)
|
||||||
searchQuery: searchQuery,
|
NotificationCenter.default.post(name: .tabBarSearchQueryUpdated, object: nil, userInfo: ["searchQuery": query])
|
||||||
searchHistory: searchHistory,
|
|
||||||
searchItems: searchItems,
|
performSearch()
|
||||||
isSearching: isSearching,
|
},
|
||||||
hasNoResults: hasNoResults,
|
onHistoryItemDeleted: { index in
|
||||||
columns: columns,
|
removeFromHistory(at: index)
|
||||||
columnsCount: columnsCount,
|
},
|
||||||
cellWidth: cellWidth,
|
onClearHistory: clearSearchHistory
|
||||||
onHistoryItemSelected: { query in
|
)
|
||||||
searchQuery = query
|
}
|
||||||
searchDebounceTimer?.invalidate()
|
.scrollViewBottomPadding()
|
||||||
|
.simultaneousGesture(
|
||||||
|
DragGesture().onChanged { _ in
|
||||||
UIApplication.shared.sendAction(#selector(UIResponder.resignFirstResponder), to: nil, from: nil, for: nil)
|
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()
|
.scrollViewBottomPadding()
|
||||||
|
|
@ -128,8 +142,6 @@ struct SearchView: View {
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
.navigationBarHidden(true)
|
|
||||||
}
|
|
||||||
|
|
||||||
var body: some View {
|
var body: some View {
|
||||||
Group {
|
Group {
|
||||||
|
|
@ -348,49 +360,3 @@ struct SearchView: View {
|
||||||
return getModulesByLanguage()[language] ?? []
|
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