@@ -19,17 +19,68 @@ struct SearchResultsView: View {
1919 NavigationView {
2020 ScrollViewReader { proxy in
2121 ScrollView {
22- LazyVStack ( spacing: 12 ) {
23- ForEach ( model. searchResults) { searchResult in
24- SearchResultCard ( result: searchResult)
25- . onTapGesture {
26- model. viewState = . none
27- AppDelegate . instance. open ( route: . post( id: searchResult. postID, . noseen) )
22+ if model. searchResults. isEmpty && !model. searchState. resultInfo. isEmpty {
23+ VStack ( alignment: . leading, spacing: 12 ) {
24+ // Parse and display the search info with proper formatting
25+ let lines = model. searchState. resultInfo
26+ . trimmingCharacters ( in: . whitespacesAndNewlines)
27+ . components ( separatedBy: . newlines)
28+ . map { $0. trimmingCharacters ( in: . whitespaces) }
29+ . filter { !$0. isEmpty }
30+
31+ ForEach ( Array ( lines. enumerated ( ) ) , id: \. offset) { index, line in
32+ if line. starts ( with: " Searched for " ) {
33+ Text ( line)
34+ . font ( . headline)
35+ . foregroundColor ( theme [ color: " listTextColor " ] )
36+ . padding ( . bottom, 4 )
37+ . frame ( maxWidth: . infinity, alignment: . leading)
38+ } else if line == " following criteria: " {
39+ Text ( line)
40+ . font ( . headline)
41+ . foregroundColor ( theme [ color: " listTextColor " ] )
42+ . frame ( maxWidth: . infinity, alignment: . leading)
43+ } else if line. starts ( with: " Text contains " ) || line. starts ( with: " Posted by " ) {
44+ Text ( line)
45+ . font ( . body)
46+ . foregroundColor ( theme [ color: " listTextColor " ] )
47+ . padding ( . vertical, 8 )
48+ . padding ( . leading, 16 )
49+ . frame ( maxWidth: . infinity, alignment: . leading)
50+ } else if line. starts ( with: " There were no results " ) {
51+ Text ( line)
52+ . font ( . body)
53+ . fontWeight ( . medium)
54+ . foregroundColor ( theme [ color: " listTextColor " ] )
55+ . padding ( . top, 8 )
56+ . frame ( maxWidth: . infinity, alignment: . leading)
57+ } else if !line. isEmpty {
58+ Text ( line)
59+ . font ( . body)
60+ . foregroundColor ( theme [ color: " listTextColor " ] )
61+ . frame ( maxWidth: . infinity, alignment: . leading)
2862 }
63+ }
64+ }
65+ . frame ( maxWidth: . infinity, alignment: . leading)
66+ . padding ( )
67+ . background ( theme [ color: " sheetBackgroundColor " ] !)
68+ . cornerRadius ( 12 )
69+ . id ( topID)
70+ . padding ( )
71+ } else {
72+ LazyVStack ( spacing: 12 ) {
73+ ForEach ( model. searchResults) { searchResult in
74+ SearchResultCard ( result: searchResult)
75+ . onTapGesture {
76+ model. viewState = . none
77+ AppDelegate . instance. open ( route: . post( id: searchResult. postID, . noseen) )
78+ }
79+ }
2980 }
81+ . id ( topID)
82+ . padding ( )
3083 }
31- . id ( topID)
32- . padding ( )
3384 }
3485 . background ( theme [ color: " backgroundColor " ] !)
3586 . onChange ( of: model. currentPage) { _ in
@@ -59,9 +110,7 @@ struct SearchResultsView: View {
59110 }
60111
61112 ToolbarItem ( placement: . bottomBar) {
62- if model. totalPages > 1 {
63- paginationControls
64- }
113+ paginationControls
65114 }
66115 }
67116 . background ( NavigationConfigurator ( theme: theme) )
@@ -84,9 +133,11 @@ struct SearchResultsView: View {
84133
85134 Spacer ( )
86135
87- Text ( " Page \( model. currentPage) of \( model. totalPages) " )
136+ Text ( " \( model. currentPage) of \( model. totalPages) " )
88137 . font ( . headline)
89138 . foregroundColor ( theme [ color: " listTextColor " ] )
139+ . frame ( minWidth: 80 )
140+ . lineLimit ( 1 )
90141
91142 Spacer ( )
92143
@@ -404,12 +455,34 @@ struct NavigationConfigurator: UIViewControllerRepresentable {
404455 navAppearance. configureWithOpaqueBackground ( )
405456 navAppearance. backgroundColor = theme [ uicolor: " navigationBarTintColor " ]
406457 navAppearance. shadowColor = . clear
458+
459+ // Ensure the custom back indicator image from assets is used
460+ if let backImage = UIImage ( named: " back " ) {
461+ navAppearance. setBackIndicatorImage ( backImage, transitionMaskImage: backImage)
462+ }
407463
408464 let textColor = theme [ uicolor: " navigationBarTextColor " ] !
409465 navAppearance. titleTextAttributes = [ . foregroundColor: textColor]
466+
467+ // Ensure text-based bar button items adopt theme font (rounded if enabled)
468+ let buttonFont = UIFont . preferredFontForTextStyle ( . body, fontName: nil , sizeAdjustment: 0 , weight: . regular)
469+ let buttonAttrs : [ NSAttributedString . Key : Any ] = [
470+ . foregroundColor: textColor,
471+ . font: buttonFont
472+ ]
473+ navAppearance. buttonAppearance. normal. titleTextAttributes = buttonAttrs
474+ navAppearance. buttonAppearance. highlighted. titleTextAttributes = buttonAttrs
475+ navAppearance. doneButtonAppearance. normal. titleTextAttributes = buttonAttrs
476+ navAppearance. doneButtonAppearance. highlighted. titleTextAttributes = buttonAttrs
477+ navAppearance. backButtonAppearance. normal. titleTextAttributes = buttonAttrs
478+ navAppearance. backButtonAppearance. highlighted. titleTextAttributes = buttonAttrs
410479
411480 navigationController. navigationBar. standardAppearance = navAppearance
412481 navigationController. navigationBar. scrollEdgeAppearance = navAppearance
482+ // Drive the bar style from the current theme so status bar
483+ // icons match the theme while Search is presented.
484+ let isLightBackground = ( theme [ " statusBarBackground " ] == " light " )
485+ navigationController. navigationBar. barStyle = isLightBackground ? . default : . black
413486
414487 // Configure toolbar
415488 let toolbarAppearance = UIToolbarAppearance ( )
@@ -731,6 +804,13 @@ final class SearchPageViewModel: ObservableObject {
731804 self . totalPages = maxPage
732805 } else if let requestedPage = requestedPage {
733806 self . currentPage = requestedPage
807+ // Preserve totalPages if it was already set and we're just navigating
808+ // Only reset to 1 if it was never set (still at initial value)
809+ if self . totalPages == 1 && requestedPage > 1 {
810+ // If we're on page > 1 but totalPages is still 1,
811+ // we know there must be at least requestedPage pages
812+ self . totalPages = requestedPage
813+ }
734814 }
735815 }
736816 }
@@ -864,5 +944,28 @@ final class SearchHostingController: UIHostingController<SearchView> {
864944 @MainActor required dynamic init ? ( coder aDecoder: NSCoder ) {
865945 fatalError ( " init(coder:) has not been implemented " )
866946 }
947+
948+ override func viewDidLoad( ) {
949+ super. viewDidLoad ( )
950+ // Ensure this controller controls status bar appearance so it stays
951+ // consistent with the app's theme while presented
952+ modalPresentationCapturesStatusBarAppearance = true
953+ }
954+
955+ // Keep status bar style in sync with the current theme so opening the
956+ // search view does not change it unexpectedly.
957+ override var preferredStatusBarStyle : UIStatusBarStyle {
958+ let theme = Theme . defaultTheme ( )
959+ return ( theme [ " statusBarBackground " ] == " light " ) ? . darkContent : . lightContent
960+ }
961+
962+ // Force the system to use this hosting controller's status bar style
963+ // instead of deferring to the child SwiftUI navigation controller.
964+ override var childForStatusBarStyle : UIViewController ? { nil }
965+
966+ override func viewWillAppear( _ animated: Bool ) {
967+ super. viewWillAppear ( animated)
968+ setNeedsStatusBarAppearanceUpdate ( )
969+ }
867970}
868971
0 commit comments