@@ -29,6 +29,7 @@ struct FeedDetailPage: StateView, KeyboardReadable, InstanceIdentifiable {
2929 }
3030 @State var hideTitleViews = true
3131 @State var isKeyboardVisiable = false
32+ @State private var isLoadingMore = false
3233 @FocusState private var replyIsFocused : Bool
3334 var initData : FeedInfo . Item ? = nil
3435 var id : String
@@ -68,37 +69,15 @@ struct FeedDetailPage: StateView, KeyboardReadable, InstanceIdentifiable {
6869
6970 @ViewBuilder
7071 private var contentView : some View {
71- VStack ( spacing: 0 ) {
72- VStack ( spacing: 0 ) {
73- AuthorInfoView ( initData: initData, data: state. model. headerInfo)
74- if !isContentEmpty {
75- NewsContentView ( state. model. contentInfo, rendered: $rendered)
76- . padding ( . horizontal, 10 )
77- }
78- replayListView
79- . padding ( . top, 8 )
80- }
81- . background ( showProgressView ? . clear : Color . itemBg)
82- . updatable ( autoRefresh: showProgressView, hasMoreData: state. hasMoreData) {
83- await run ( action: FeedDetailActions . FetchData. Start ( id: instanceId, feedId: initData? . id) )
84- } loadMore: {
85- await run ( action: FeedDetailActions . LoadMore. Start ( id: instanceId, feedId: initData? . id, willLoadPage: state. willLoadPage) )
86- } onScroll: { scrollY in
87- withAnimation {
88- hideTitleViews = !( scrollY <= - 100 )
89- }
90- }
91- . onTapGesture {
92- replyIsFocused = false
93- }
72+ VStack ( spacing: 0 ) {
73+ listContentView
9474 replyBar
9575 }
9676 . safeAreaInset ( edge: . top, spacing: 0 ) {
9777 navBar
9878 }
9979 . ignoresSafeArea ( . container)
10080 . navigationBarHidden ( true )
101-
10281 . onChange ( of: state. ignored) { ignored in
10382 if ignored {
10483 dismiss ( )
@@ -120,6 +99,75 @@ struct FeedDetailPage: StateView, KeyboardReadable, InstanceIdentifiable {
12099 }
121100 }
122101
102+ @ViewBuilder
103+ private var listContentView : some View {
104+ List {
105+ // Header Section
106+ AuthorInfoView ( initData: initData, data: state. model. headerInfo)
107+ . listRowInsets ( EdgeInsets ( ) )
108+ . listRowSeparator ( . hidden)
109+ . listRowBackground ( Color . itemBg)
110+
111+ // Content Section
112+ if !isContentEmpty {
113+ NewsContentView ( state. model. contentInfo, rendered: $rendered)
114+ . padding ( . horizontal, 10 )
115+ . listRowInsets ( EdgeInsets ( ) )
116+ . listRowSeparator ( . hidden)
117+ . listRowBackground ( Color . itemBg)
118+ }
119+
120+ // Reply Section
121+ ForEach ( state. model. replyInfo. items) { item in
122+ ReplyItemView ( info: item)
123+ . listRowInsets ( EdgeInsets ( ) )
124+ . listRowSeparator ( . hidden)
125+ . listRowBackground ( Color . itemBg)
126+ }
127+
128+ // Load More Indicator
129+ if state. hasMoreData {
130+ HStack {
131+ Spacer ( )
132+ if isLoadingMore {
133+ ProgressView ( )
134+ }
135+ Spacer ( )
136+ }
137+ . frame ( height: 50 )
138+ . listRowInsets ( EdgeInsets ( ) )
139+ . listRowSeparator ( . hidden)
140+ . listRowBackground ( Color . itemBg)
141+ . onAppear {
142+ guard !isLoadingMore else { return }
143+ isLoadingMore = true
144+ Task {
145+ await run ( action: FeedDetailActions . LoadMore. Start ( id: instanceId, feedId: initData? . id, willLoadPage: state. willLoadPage) )
146+ await MainActor . run {
147+ isLoadingMore = false
148+ }
149+ }
150+ }
151+ }
152+ }
153+ . listStyle ( . plain)
154+ . scrollContentBackground ( . hidden)
155+ . background ( Color . itemBg)
156+ . environment ( \. defaultMinListRowHeight, 1 )
157+ . refreshable {
158+ await run ( action: FeedDetailActions . FetchData. Start ( id: instanceId, feedId: initData? . id) )
159+ }
160+ . overlay {
161+ if showProgressView {
162+ ProgressView ( )
163+ . scaleEffect ( 1.5 )
164+ }
165+ }
166+ . onTapGesture {
167+ replyIsFocused = false
168+ }
169+ }
170+
123171 private var replyBar : some View {
124172 VStack ( spacing: 0 ) {
125173 Divider ( )
@@ -260,14 +308,4 @@ struct FeedDetailPage: StateView, KeyboardReadable, InstanceIdentifiable {
260308 }
261309 . visualBlur ( )
262310 }
263-
264- @ViewBuilder
265- private var replayListView : some View {
266- LazyVStack ( spacing: 0 ) {
267- ForEach ( state. model. replyInfo. items) { item in
268- ReplyItemView ( info: item)
269- }
270- }
271- }
272-
273311}
0 commit comments