damus

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

PostingTimelineView.swift (5172B)


      1 //
      2 //  PostingTimelineView.swift
      3 //  damus
      4 //
      5 //  Created by eric on 7/15/24.
      6 //
      7 
      8 import SwiftUI
      9 
     10 struct PostingTimelineView: View {
     11     
     12     let damus_state: DamusState
     13     var home: HomeModel
     14     @State var search: String = ""
     15     @State var results: [NostrEvent] = []
     16     @State var initialOffset: CGFloat?
     17     @State var offset: CGFloat?
     18     @State var showSearch: Bool = true
     19     @Binding var isSideBarOpened: Bool
     20     @Binding var active_sheet: Sheets?
     21     @FocusState private var isSearchFocused: Bool
     22     @State private var contentOffset: CGFloat = 0
     23     @State private var indicatorWidth: CGFloat = 0
     24     @State private var indicatorPosition: CGFloat = 0
     25     @State var headerHeight: CGFloat = 0
     26     @Binding var headerOffset: CGFloat
     27     @SceneStorage("PostingTimelineView.filter_state") var filter_state : FilterState = .posts_and_replies
     28 
     29     func content_filter(_ fstate: FilterState) -> ((NostrEvent) -> Bool) {
     30         var filters = ContentFilters.defaults(damus_state: damus_state)
     31         filters.append(fstate.filter)
     32         return ContentFilters(filters: filters).filter
     33     }
     34     
     35     func contentTimelineView(filter: (@escaping (NostrEvent) -> Bool)) -> some View {
     36         TimelineView<AnyView>(events: home.events, loading: .constant(false), headerHeight: $headerHeight, headerOffset: $headerOffset, damus: damus_state, show_friend_icon: false, filter: filter)
     37     }
     38     
     39     func HeaderView()->some View {
     40         VStack {
     41             VStack(spacing: 0) {
     42                 // This is needed for the Dynamic Island
     43                 HStack {}
     44                 .frame(height: getSafeAreaTop())
     45                 
     46                 HStack(alignment: .top) {
     47                     TopbarSideMenuButton(damus_state: damus_state, isSideBarOpened: $isSideBarOpened)
     48                     
     49                     Spacer()
     50                     
     51                     Image("damus-home")
     52                         .resizable()
     53                         .frame(width:30,height:30)
     54                         .shadow(color: DamusColors.purple, radius: 2)
     55                         .opacity(isSideBarOpened ? 0 : 1)
     56                         .animation(isSideBarOpened ? .none : .default, value: isSideBarOpened)
     57                         .onTapGesture {
     58                             isSideBarOpened.toggle()
     59                         }
     60                         .padding(.leading)
     61                     
     62                     Spacer()
     63                     
     64                     HStack(alignment: .center) {
     65                         SignalView(state: damus_state, signal: home.signal)
     66                     }
     67                 }
     68                 .frame(maxWidth: .infinity, alignment: .trailing)
     69             }
     70             .padding(.horizontal, 20)
     71             
     72             VStack(spacing: 0) {
     73                 CustomPicker(tabs: [
     74                     (NSLocalizedString("Notes", comment: "Label for filter for seeing only notes (instead of notes and replies)."), FilterState.posts),
     75                     (NSLocalizedString("Notes & Replies", comment: "Label for filter for seeing notes and replies (instead of only notes)."), FilterState.posts_and_replies)
     76                 ],
     77                              selection: $filter_state)
     78                 
     79                 Divider()
     80                     .frame(height: 1)
     81             }
     82         }
     83         .background {
     84             DamusColors.adaptableWhite
     85                 .ignoresSafeArea()
     86         }
     87     }
     88 
     89     var body: some View {
     90         VStack {
     91             ZStack {
     92                 TabView(selection: $filter_state) {
     93                     contentTimelineView(filter: content_filter(.posts))
     94                         .tag(FilterState.posts)
     95                         .id(FilterState.posts)
     96                     contentTimelineView(filter: content_filter(.posts_and_replies))
     97                         .tag(FilterState.posts_and_replies)
     98                         .id(FilterState.posts_and_replies)
     99                 }
    100                 .tabViewStyle(.page(indexDisplayMode: .never))
    101                 
    102                 if damus_state.keypair.privkey != nil {
    103                     PostButtonContainer(is_left_handed: damus_state.settings.left_handed) {
    104                         self.active_sheet = .post(.posting(.none))
    105                     }
    106                     .padding(.bottom, tabHeight + getSafeAreaBottom())
    107                     .opacity(0.35 + abs(1.25 - (abs(headerOffset/100.0))))
    108                 }
    109             }
    110         }
    111         .overlay(alignment: .top) {
    112             HeaderView()
    113                 .anchorPreference(key: HeaderBoundsKey.self, value: .bounds){$0}
    114                 .overlayPreferenceValue(HeaderBoundsKey.self) { value in
    115                     GeometryReader{ proxy in
    116                         if let anchor = value{
    117                             Color.clear
    118                                 .onAppear {
    119                                     headerHeight = proxy[anchor].height
    120                                 }
    121                         }
    122                     }
    123                 }
    124                 .offset(y: -headerOffset < headerHeight ? headerOffset : (headerOffset < 0 ? headerOffset : 0))
    125                 .opacity(1.0 - (abs(headerOffset/100.0)))
    126         }
    127     }
    128 }