damus

nostr ios client
git clone git://jb55.com/damus
Log | Files | Refs | README | LICENSE

SearchHeaderView.swift (4889B)


      1 //
      2 //  SearchIconView.swift
      3 //  damus
      4 //
      5 //  Created by William Casarin on 2023-07-12.
      6 //
      7 
      8 import SwiftUI
      9 
     10 struct SearchHeaderView: View {
     11     let state: DamusState
     12     let described: DescribedSearch
     13     @State var is_following: Bool
     14 
     15     init(state: DamusState, described: DescribedSearch) {
     16         self.state = state
     17         self.described = described
     18 
     19         let is_following = (described.is_hashtag.map {
     20             ht in is_following_hashtag(contacts: state.contacts.event, hashtag: ht)
     21         }) ?? false
     22 
     23         self._is_following = State(wrappedValue: is_following)
     24     }
     25 
     26     var Icon: some View {
     27         ZStack {
     28             switch described {
     29                 case .hashtag:
     30                     SingleCharacterAvatar(character: "#")
     31                 case .unknown:
     32                     SystemIconAvatar(system_name: "magnifyingglass")
     33             }
     34         }
     35     }
     36 
     37     var SearchText: Text {
     38         Text(described.description)
     39     }
     40 
     41     var body: some View {
     42         HStack(alignment: .center, spacing: 30) {
     43             Icon
     44 
     45             VStack(alignment: .leading, spacing: 10.0) {
     46                 SearchText
     47                     .foregroundStyle(DamusLogoGradient.gradient)
     48                     .font(.title.bold())
     49 
     50                 if state.is_privkey_user, case .hashtag(let ht) = described {
     51                     if is_following {
     52                         HashtagUnfollowButton(damus_state: state, hashtag: ht, is_following: $is_following)
     53                     } else {
     54                         HashtagFollowButton(damus_state: state, hashtag: ht, is_following: $is_following)
     55                     }
     56                 }
     57             }
     58         }
     59         .onReceive(handle_notify(.followed)) { ref in
     60             guard hashtag_matches_search(desc: self.described, ref: ref) else { return }
     61             self.is_following = true
     62         }
     63         .onReceive(handle_notify(.unfollowed)) { ref in
     64             guard hashtag_matches_search(desc: self.described, ref: ref) else { return }
     65             self.is_following = false
     66         }
     67     }
     68 }
     69 
     70 struct SystemIconAvatar: View {
     71     let system_name: String
     72     
     73     var body: some View {
     74         NonImageAvatar {
     75             Image(systemName: system_name)
     76                 .font(.title.bold())
     77         }
     78     }
     79 }
     80 
     81 struct SingleCharacterAvatar: View {
     82     let character: String
     83     
     84     var body: some View {
     85         NonImageAvatar {
     86             Text(character)
     87                 .font(.largeTitle.bold())
     88                 .mask(Text(character)
     89                     .font(.largeTitle.bold()))
     90         }
     91     }
     92 }
     93 
     94 struct NonImageAvatar<Content: View>: View {
     95     let content: Content
     96     
     97     init(@ViewBuilder content: () -> Content) {
     98         self.content = content()
     99     }
    100     
    101     var body: some View {
    102         ZStack {
    103             Circle()
    104                 .fill(DamusColors.lightBackgroundPink)
    105                 .frame(width: 54, height: 54)
    106             
    107             content
    108                 .foregroundStyle(PinkGradient)
    109         }
    110     }
    111 }
    112 
    113 struct HashtagUnfollowButton: View {
    114     let damus_state: DamusState
    115     let hashtag: String
    116     @Binding var is_following: Bool
    117     
    118     var body: some View {
    119         return Button(action: { unfollow(hashtag) }) {
    120             Text("Unfollow hashtag", comment: "Button to unfollow a given hashtag.")
    121                 .font(.footnote.bold())
    122         }
    123         .buttonStyle(GradientButtonStyle(padding: 10))
    124     }
    125         
    126     func unfollow(_ hashtag: String) {
    127         is_following = false
    128         handle_unfollow(state: damus_state, unfollow: FollowRef.hashtag(hashtag))
    129     }
    130 }
    131 
    132 struct HashtagFollowButton: View {
    133     let damus_state: DamusState
    134     let hashtag: String
    135     @Binding var is_following: Bool
    136     
    137     var body: some View {
    138         return Button(action: { follow(hashtag) }) {
    139             Text("Follow hashtag", comment: "Button to follow a given hashtag.")
    140                 .font(.footnote.bold())
    141         }
    142         .buttonStyle(GradientButtonStyle(padding: 10))
    143     }
    144     
    145     func follow(_ hashtag: String) {
    146         is_following = true
    147         handle_follow(state: damus_state, follow: .hashtag(hashtag))
    148     }
    149 }
    150 
    151 func hashtag_matches_search(desc: DescribedSearch, ref: FollowRef) -> Bool {
    152     guard case .hashtag(let follow_ht) = ref,
    153           case .hashtag(let search_ht) = desc,
    154           follow_ht == search_ht
    155     else {
    156         return false
    157     }
    158 
    159     return true
    160 }
    161 
    162 func is_following_hashtag(contacts: NostrEvent?, hashtag: String) -> Bool {
    163     guard let contacts else { return false }
    164     return is_already_following(contacts: contacts, follow: .hashtag(hashtag))
    165 }
    166 
    167 
    168 struct SearchHeaderView_Previews: PreviewProvider {
    169     static var previews: some View {
    170         VStack(alignment: .leading) {
    171             SearchHeaderView(state: test_damus_state, described: .hashtag("damus"))
    172 
    173             SearchHeaderView(state: test_damus_state, described: .unknown)
    174         }
    175     }
    176 }