@@ -44,6 +44,7 @@ struct FeedDetailPage: StateView, KeyboardReadable, InstanceIdentifiable {
4444 @State var isKeyboardVisiable = false
4545 @State private var isLoadingMore = false
4646 @State private var contentReady = false
47+ @State private var repliesReady = false
4748 @FocusState private var replyIsFocused : Bool
4849 var initData : FeedInfo . Item ? = nil
4950 var id : String
@@ -206,8 +207,12 @@ struct FeedDetailPage: StateView, KeyboardReadable, InstanceIdentifiable {
206207 // Content Section
207208 if !isContentEmpty {
208209 NewsContentView ( state. model. contentInfo) {
209- withAnimation {
210- contentReady = true
210+ contentReady = true
211+ // Show replies after a short delay for smoother transition
212+ DispatchQueue . main. asyncAfter ( deadline: . now( ) + 0.15 ) {
213+ withAnimation ( . easeInOut( duration: 0.2 ) ) {
214+ repliesReady = true
215+ }
211216 }
212217 }
213218 . padding ( . horizontal, 10 )
@@ -216,31 +221,31 @@ struct FeedDetailPage: StateView, KeyboardReadable, InstanceIdentifiable {
216221 . listRowBackground ( Color . itemBg)
217222 }
218223
219- // Show postscripts and replies only after content is ready
220- if contentReady || isContentEmpty {
221- // Postscripts Section (附言)
222- ForEach ( state. model. postscripts) { postscript in
223- PostscriptItemView ( postscript: postscript)
224- . listRowInsets ( EdgeInsets ( ) )
225- . listRowSeparator ( . hidden)
226- . listRowBackground ( Color . itemBg)
227- }
224+ // Postscripts Section (附言) - always in layout, fade in when ready
225+ ForEach ( state. model. postscripts) { postscript in
226+ PostscriptItemView ( postscript: postscript)
227+ . listRowInsets ( EdgeInsets ( ) )
228+ . listRowSeparator ( . hidden)
229+ . listRowBackground ( Color . itemBg)
230+ . opacity ( contentReady || isContentEmpty ? 1 : 0 )
231+ }
228232
229- // Reply Section Header with Sort Toggle
230- if !state. model. replyInfo. items. isEmpty {
231- replySectionHeader
232- . listRowInsets ( EdgeInsets ( ) )
233- . listRowSeparator ( . hidden)
234- . listRowBackground ( Color . itemBg)
235- }
233+ // Reply Section Header with Sort Toggle
234+ if !state. model. replyInfo. items. isEmpty {
235+ replySectionHeader
236+ . listRowInsets ( EdgeInsets ( ) )
237+ . listRowSeparator ( . hidden)
238+ . listRowBackground ( Color . itemBg)
239+ . opacity ( repliesReady || isContentEmpty ? 1 : 0 )
240+ }
236241
237- // Reply Section
238- ForEach ( sortedReplies, id: \. floor) { item in
239- ReplyItemView ( info: item, topicId: id)
240- . listRowInsets ( EdgeInsets ( ) )
241- . listRowSeparator ( . hidden)
242- . listRowBackground ( Color . itemBg)
243- }
242+ // Reply Section - always in layout, fade in when ready
243+ ForEach ( sortedReplies, id: \. floor) { item in
244+ ReplyItemView ( info: item, topicId: id)
245+ . listRowInsets ( EdgeInsets ( ) )
246+ . listRowSeparator ( . hidden)
247+ . listRowBackground ( Color . itemBg)
248+ . opacity ( repliesReady || isContentEmpty ? 1 : 0 )
244249 }
245250
246251 // Load More Indicator
@@ -272,6 +277,8 @@ struct FeedDetailPage: StateView, KeyboardReadable, InstanceIdentifiable {
272277 . scrollContentBackground ( . hidden)
273278 . background ( Color . itemBg)
274279 . environment ( \. defaultMinListRowHeight, 1 )
280+ . animation ( . easeIn( duration: 0.15 ) , value: contentReady)
281+ . animation ( . easeIn( duration: 0.15 ) , value: repliesReady)
275282 . refreshable {
276283 await run ( action: FeedDetailActions . FetchData. Start ( id: instanceId, feedId: initData? . id) )
277284 }
0 commit comments