Source code for the WriteFreely SwiftUI app for iOS, iPadOS, and macOS
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 

150 lines
6.4 KiB

  1. import SwiftUI
  2. import Combine
  3. struct PostListView: View {
  4. @EnvironmentObject var model: WriteFreelyModel
  5. @Environment(\.managedObjectContext) var managedObjectContext
  6. @State private var postCount: Int = 0
  7. #if os(iOS)
  8. private var frameHeight: CGFloat {
  9. var height: CGFloat = 50
  10. let bottom = UIApplication.shared.windows.first?.safeAreaInsets.bottom ?? 0
  11. height += bottom
  12. return height
  13. }
  14. #endif
  15. var body: some View {
  16. #if os(iOS)
  17. ZStack(alignment: .bottom) {
  18. PostListFilteredView(
  19. collection: model.selectedCollection,
  20. showAllPosts: model.showAllPosts,
  21. postCount: $postCount
  22. )
  23. .navigationTitle(
  24. model.showAllPosts ? "All Posts" : model.selectedCollection?.title ?? (
  25. model.account.server == "https://write.as" ? "Anonymous" : "Drafts"
  26. )
  27. )
  28. .toolbar {
  29. ToolbarItem(placement: .primaryAction) {
  30. // We have to add a Spacer as a sibling view to the Button in some kind of Stack, so that any
  31. // a11y modifiers are applied as expected: bug report filed as FB8956392.
  32. ZStack {
  33. Spacer()
  34. Button(action: {
  35. let managedPost = model.editor.generateNewLocalPost(withFont: model.preferences.font)
  36. withAnimation {
  37. self.model.showAllPosts = false
  38. self.model.selectedPost = managedPost
  39. }
  40. }, label: {
  41. ZStack {
  42. Image("does.not.exist")
  43. .accessibilityHidden(true)
  44. Image(systemName: "square.and.pencil")
  45. .accessibilityHidden(true)
  46. .imageScale(.large) // These modifiers compensate for the resizing
  47. .padding(.vertical, 12) // done to the Image (and the button tap target)
  48. .padding(.leading, 12) // by the SwiftUI layout system from adding a
  49. .padding(.trailing, 8) // Spacer in this ZStack (FB8956392).
  50. }
  51. .frame(maxWidth: .infinity, maxHeight: .infinity)
  52. })
  53. .accessibilityLabel(Text("Compose"))
  54. .accessibilityHint(Text("Compose a new local draft"))
  55. }
  56. }
  57. }
  58. VStack {
  59. HStack(spacing: 0) {
  60. Button(action: {
  61. model.isPresentingSettingsView = true
  62. }, label: {
  63. Image(systemName: "gear")
  64. .padding(.vertical, 4)
  65. .padding(.horizontal, 8)
  66. })
  67. .accessibilityLabel(Text("Settings"))
  68. .accessibilityHint(Text("Open the Settings sheet"))
  69. Spacer()
  70. Text(postCount == 1 ? "\(postCount) post" : "\(postCount) posts")
  71. .foregroundColor(.secondary)
  72. Spacer()
  73. if model.isProcessingRequest {
  74. ProgressView()
  75. .padding(.vertical, 4)
  76. .padding(.horizontal, 8)
  77. } else {
  78. Button(action: {
  79. DispatchQueue.main.async {
  80. model.fetchUserCollections()
  81. model.fetchUserPosts()
  82. }
  83. }, label: {
  84. Image(systemName: "arrow.clockwise")
  85. .padding(.vertical, 4)
  86. .padding(.horizontal, 8)
  87. })
  88. .accessibilityLabel(Text("Refresh Posts"))
  89. .accessibilityHint(Text("Fetch changes from the server"))
  90. .disabled(!model.account.isLoggedIn)
  91. }
  92. }
  93. .padding(.top, 8)
  94. .padding(.horizontal, 8)
  95. Spacer()
  96. }
  97. .frame(height: frameHeight)
  98. .background(Color(UIColor.systemGray5))
  99. .overlay(Divider(), alignment: .top)
  100. }
  101. .ignoresSafeArea()
  102. #else
  103. PostListFilteredView(
  104. collection: model.selectedCollection,
  105. showAllPosts: model.showAllPosts,
  106. postCount: $postCount
  107. )
  108. .toolbar {
  109. ToolbarItemGroup(placement: .primaryAction) {
  110. if model.selectedPost != nil {
  111. ActivePostToolbarView(activePost: model.selectedPost!)
  112. .alert(isPresented: $model.isPresentingNetworkErrorAlert, content: {
  113. Alert(
  114. title: Text("Connection Error"),
  115. message: Text("""
  116. There is no internet connection at the moment. \
  117. Please reconnect or try again later.
  118. """),
  119. dismissButton: .default(Text("OK"), action: {
  120. model.isPresentingNetworkErrorAlert = false
  121. })
  122. )
  123. })
  124. }
  125. }
  126. }
  127. .navigationTitle(
  128. model.showAllPosts ? "All Posts" : model.selectedCollection?.title ?? (
  129. model.account.server == "https://write.as" ? "Anonymous" : "Drafts"
  130. )
  131. )
  132. #endif
  133. }
  134. }
  135. struct PostListView_Previews: PreviewProvider {
  136. static var previews: some View {
  137. let context = LocalStorageManager.persistentContainer.viewContext
  138. let model = WriteFreelyModel()
  139. return PostListView()
  140. .environment(\.managedObjectContext, context)
  141. .environmentObject(model)
  142. }
  143. }