Skip to content

Commit

Permalink
Merge pull request #340 from Planetable/keyboard-navigation-search
Browse files Browse the repository at this point in the history
Add basic keyboard navigation to search view
  • Loading branch information
livid authored Apr 16, 2024
2 parents e01f194 + 3321544 commit 6c62b61
Show file tree
Hide file tree
Showing 3 changed files with 122 additions and 23 deletions.
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
{
"originHash" : "2d350f39146062b36abb00c558bb2f952938a1a96238113e0d424870f7d32ad3",
"pins" : [
{
"identity" : "bigint",
Expand Down Expand Up @@ -262,5 +261,5 @@
}
}
],
"version" : 3
"version" : 2
}
140 changes: 120 additions & 20 deletions Planet/Search/SearchView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ struct SearchView: View {
@EnvironmentObject var planetStore: PlanetStore

@State private var result: [SearchResult] = []
@State private var focusedResult: SearchResult?

@Environment(\.dismiss) private var dismiss

Expand Down Expand Up @@ -45,11 +46,23 @@ struct SearchView: View {
Divider()
ScrollViewReader { proxy in
VStack(spacing: 0) {
searchResult()
}.id("top")
.onChange(of: result.count) { _ in
proxy.scrollTo("top", anchor: .top)
// searchResult()
if result.count > 0 {
searchResultView()
} else {
List {
}.padding(0)
}
}
.id("top")
.onChange(of: result.count) { _ in
proxy.scrollTo("top", anchor: .top)
}
.onChange(of: focusedResult) { _ in
if let id = focusedResult?.articleID {
proxy.scrollTo(id)
}
}
}
Divider()
statusView()
Expand Down Expand Up @@ -82,6 +95,7 @@ struct SearchView: View {
else {
self.search()
}
focusedResult = nil
}
}

Expand Down Expand Up @@ -120,6 +134,82 @@ struct SearchView: View {
}.padding(0)
}
}

@ViewBuilder
private func searchResultView() -> some View {
ZStack {
List {
ForEach(result, id: \.self) { item in
searchResultRow(item)
.id(item.articleID)
.onTapGesture {
goToArticle(item)
}
}
}
.padding(0)
.listStyle(PlainListStyle())
// arrow key navigation hack
VStack {
Spacer()
HStack {
Spacer()
Button {
// highlight first search result when return key event was sent to search field.
if focusedResult == nil && result.count > 0 {
focusedResult = result.first
return
}
guard let item = focusedResult else { return }
goToArticle(item)
} label: {
Text("")
}
.keyboardShortcut(.return, modifiers: [])
Button {
goToPreviousSearchResult()
} label: {
Text("")
}
.keyboardShortcut(.upArrow, modifiers: [])
Button {
goToNextSearchResult()
} label: {
Text("")
}
.keyboardShortcut(.downArrow, modifiers: [])
Spacer()
}
}
.opacity(0)
}
}

private func goToNextSearchResult() {
guard result.count > 0 else { return }
if let currentFocusedResult = focusedResult {
if let index = result.firstIndex(of: currentFocusedResult) {
if index + 1 < result.count {
focusedResult = result[index + 1]
}
}
} else {
focusedResult = result.first
}
}

private func goToPreviousSearchResult() {
guard result.count > 0 else { return }
if let currentFocusedResult = focusedResult {
if let index = result.firstIndex(of: currentFocusedResult) {
if index > 0 {
focusedResult = result[index - 1]
}
}
} else {
focusedResult = result.last
}
}

@ViewBuilder
func planetAvatarView(result: SearchResult, size: CGFloat) -> some View {
Expand Down Expand Up @@ -182,29 +272,39 @@ struct SearchView: View {

@ViewBuilder
private func searchResultRow(_ item: SearchResult) -> some View {
HStack(spacing: 10) {
planetAvatarView(result: item, size: 32)
VStack(alignment: .leading, spacing: 5) {
HStack(spacing: 10) {
Text(item.title)
.lineLimit(1)
.font(.headline)
ZStack {
HStack(spacing: 10) {
planetAvatarView(result: item, size: 32)
VStack(alignment: .leading, spacing: 5) {
HStack(spacing: 10) {
Text(item.title)
.lineLimit(1)
.font(.headline)

Spacer()
Spacer()

Text(item.planetName)
.font(.subheadline)
Text(item.planetName)
.font(.subheadline)
.lineLimit(1)
.foregroundColor(.secondary)
}
Text(item.preview)
.lineLimit(1)
.foregroundColor(.secondary)
}
Text(item.preview)
.lineLimit(1)
.foregroundColor(.secondary)
.padding(.vertical, 5)
.padding(.horizontal, 4)
}
.padding(.vertical, 5)
.padding(.horizontal, 0)
}.padding(0)
.padding(0)
.padding(.leading, 2)
.contentShape(Rectangle())
.overlay {
RoundedRectangle(cornerRadius: 8)
.stroke(Color.accentColor, lineWidth: 2)
.opacity(focusedResult == item ? 1.0 : 0)
.padding(.horizontal, 2)
}
}
}

@ViewBuilder
Expand Down
2 changes: 1 addition & 1 deletion Planet/versioning.xcconfig
Original file line number Diff line number Diff line change
@@ -1 +1 @@
CURRENT_PROJECT_VERSION = 1972
CURRENT_PROJECT_VERSION = 1973

0 comments on commit 6c62b61

Please sign in to comment.