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 }