Empty states for grid, filter divider on headers shouldnt show on iPad
This commit is contained in:
@ -77,6 +77,50 @@ struct FiltersHeader: View {
|
||||
}
|
||||
}
|
||||
|
||||
struct EmptyState: View {
|
||||
@ObservedObject var viewModel: HomeFeedViewModel
|
||||
|
||||
var body: some View {
|
||||
if viewModel.currentFolder == "following" {
|
||||
return AnyView(
|
||||
VStack(alignment: .center, spacing: 20) {
|
||||
Text("You don't have any Feed items.")
|
||||
.font(Font.system(size: 18, weight: .bold))
|
||||
|
||||
Text("Add an RSS/Atom feed")
|
||||
.foregroundColor(Color.blue)
|
||||
.onTapGesture {
|
||||
viewModel.showAddFeedView = true
|
||||
}
|
||||
|
||||
Text("Hide the Following tab")
|
||||
.foregroundColor(Color.blue)
|
||||
.onTapGesture {
|
||||
viewModel.showHideFollowingAlert = true
|
||||
}
|
||||
}
|
||||
.frame(minHeight: 400)
|
||||
.frame(maxWidth: .infinity)
|
||||
.padding()
|
||||
)
|
||||
} else {
|
||||
return AnyView(Group {
|
||||
Spacer()
|
||||
|
||||
VStack(alignment: .center, spacing: 20) {
|
||||
Text("No results found for this query")
|
||||
.font(Font.system(size: 18, weight: .bold))
|
||||
}
|
||||
.frame(minHeight: 400)
|
||||
.frame(maxWidth: .infinity)
|
||||
.padding()
|
||||
|
||||
Spacer()
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct AnimatingCellHeight: AnimatableModifier {
|
||||
var height: CGFloat = 0
|
||||
|
||||
@ -391,7 +435,6 @@ struct AnimatingCellHeight: AnimatableModifier {
|
||||
isListScrolled: $isListScrolled,
|
||||
prefersListLayout: $prefersListLayout,
|
||||
isEditMode: $isEditMode,
|
||||
showAddFeedView: $showAddFeedView,
|
||||
selection: $selection,
|
||||
viewModel: viewModel,
|
||||
showFeatureCards: showFeatureCards
|
||||
@ -445,9 +488,7 @@ struct AnimatingCellHeight: AnimatableModifier {
|
||||
@Binding var isListScrolled: Bool
|
||||
@Binding var prefersListLayout: Bool
|
||||
@Binding var isEditMode: EditMode
|
||||
@Binding var showAddFeedView: Bool
|
||||
@State private var showHideFeatureAlert = false
|
||||
@State private var showHideFollowingAlert = false
|
||||
|
||||
@Binding var selection: Set<String>
|
||||
@ObservedObject var viewModel: HomeFeedViewModel
|
||||
@ -463,7 +504,7 @@ struct AnimatingCellHeight: AnimatableModifier {
|
||||
.overlay(Rectangle()
|
||||
.padding(.leading, 15)
|
||||
.frame(width: nil, height: 0.5, alignment: .bottom)
|
||||
.foregroundColor(isListScrolled ? Color(hex: "#3D3D3D") : Color.systemBackground), alignment: .bottom)
|
||||
.foregroundColor(isListScrolled && UIDevice.isIPhone ? Color(hex: "#3D3D3D") : Color.systemBackground), alignment: .bottom)
|
||||
.dynamicTypeSize(.small ... .accessibility1)
|
||||
}
|
||||
|
||||
@ -616,46 +657,6 @@ struct AnimatingCellHeight: AnimatableModifier {
|
||||
}.redacted(reason: .placeholder)
|
||||
}
|
||||
|
||||
var emptyState: some View {
|
||||
if viewModel.currentFolder == "following" {
|
||||
return AnyView(
|
||||
VStack(alignment: .center, spacing: 20) {
|
||||
Text("You don't have any Feed items.")
|
||||
.font(Font.system(size: 18, weight: .bold))
|
||||
|
||||
Text("Add an RSS/Atom feed")
|
||||
.foregroundColor(Color.blue)
|
||||
.onTapGesture {
|
||||
showAddFeedView = true
|
||||
}
|
||||
|
||||
Text("Hide the Following tab")
|
||||
.foregroundColor(Color.blue)
|
||||
.onTapGesture {
|
||||
showHideFollowingAlert = true
|
||||
}
|
||||
}
|
||||
.frame(minHeight: 400)
|
||||
.frame(maxWidth: .infinity)
|
||||
.padding()
|
||||
)
|
||||
} else {
|
||||
return AnyView(Group {
|
||||
Spacer()
|
||||
|
||||
VStack(alignment: .center, spacing: 20) {
|
||||
Text("No results found for this query")
|
||||
.font(Font.system(size: 18, weight: .bold))
|
||||
}
|
||||
.frame(minHeight: 400)
|
||||
.frame(maxWidth: .infinity)
|
||||
.padding()
|
||||
|
||||
Spacer()
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
var listItems: some View {
|
||||
ForEach(Array(viewModel.fetcher.items.enumerated()), id: \.1.unwrappedID) { idx, item in
|
||||
let horizontalInset = CGFloat(UIDevice.isIPad ? 20 : 10)
|
||||
@ -746,7 +747,7 @@ struct AnimatingCellHeight: AnimatableModifier {
|
||||
if viewModel.showLoadingBar {
|
||||
redactedItems
|
||||
} else if viewModel.fetcher.items.isEmpty {
|
||||
emptyState
|
||||
EmptyState(viewModel: viewModel)
|
||||
.listRowSeparator(.hidden, edges: .all)
|
||||
} else {
|
||||
listItems
|
||||
@ -782,11 +783,11 @@ struct AnimatingCellHeight: AnimatableModifier {
|
||||
Button(LocalText.cancelGeneric, role: .cancel) { self.showHideFeatureAlert = false }
|
||||
}
|
||||
.alert("The Following tab will be hidden. You can add it back from the filter settings in your profile.",
|
||||
isPresented: $showHideFollowingAlert) {
|
||||
isPresented: $viewModel.showHideFollowingAlert) {
|
||||
Button("OK", role: .destructive) {
|
||||
viewModel.hideFollowingTab = true
|
||||
}
|
||||
Button(LocalText.cancelGeneric, role: .cancel) { self.showHideFollowingAlert = false }
|
||||
Button(LocalText.cancelGeneric, role: .cancel) { viewModel.showHideFollowingAlert = false }
|
||||
}
|
||||
.introspectNavigationController { nav in
|
||||
nav.navigationBar.shadowImage = UIImage()
|
||||
@ -874,6 +875,11 @@ struct AnimatingCellHeight: AnimatableModifier {
|
||||
|
||||
var filtersHeader: some View {
|
||||
FiltersHeader(viewModel: viewModel)
|
||||
.overlay(Rectangle()
|
||||
.padding(.leading, 15)
|
||||
.frame(width: nil, height: 0.5, alignment: .bottom)
|
||||
.foregroundColor(isListScrolled && UIDevice.isIPhone ? Color(hex: "#3D3D3D") : Color.systemBackground), alignment: .bottom)
|
||||
.dynamicTypeSize(.small ... .accessibility1)
|
||||
}
|
||||
|
||||
func menuItems(for item: Models.LibraryItem) -> some View {
|
||||
@ -907,18 +913,22 @@ struct AnimatingCellHeight: AnimatableModifier {
|
||||
.cornerRadius(6)
|
||||
}.redacted(reason: .placeholder)
|
||||
} else {
|
||||
ForEach(Array(viewModel.fetcher.items.enumerated()), id: \.1.id) { idx, item in
|
||||
LibraryItemGridCardNavigationLink(
|
||||
item: item,
|
||||
viewModel: viewModel
|
||||
)
|
||||
.contextMenu {
|
||||
menuItems(for: item)
|
||||
}
|
||||
.onAppear {
|
||||
if idx >= viewModel.fetcher.items.count - 5 {
|
||||
Task {
|
||||
await viewModel.loadMore(dataService: dataService)
|
||||
if viewModel.fetcher.items.isEmpty {
|
||||
EmptyState(viewModel: viewModel)
|
||||
} else {
|
||||
ForEach(Array(viewModel.fetcher.items.enumerated()), id: \.1.id) { idx, item in
|
||||
LibraryItemGridCardNavigationLink(
|
||||
item: item,
|
||||
viewModel: viewModel
|
||||
)
|
||||
.contextMenu {
|
||||
menuItems(for: item)
|
||||
}
|
||||
.onAppear {
|
||||
if idx >= viewModel.fetcher.items.count - 5 {
|
||||
Task {
|
||||
await viewModel.loadMore(dataService: dataService)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -23,6 +23,8 @@ import Views
|
||||
|
||||
@Published var showLabelsSheet = false
|
||||
@Published var showSnackbar = false
|
||||
@Published var showAddFeedView = false
|
||||
@Published var showHideFollowingAlert = false
|
||||
@Published var snackbarOperation: SnackbarOperation?
|
||||
|
||||
@Published var filters = [InternalFilter]()
|
||||
|
||||
@ -20,83 +20,78 @@ import SwiftUI
|
||||
@AppStorage("followingMenuState") var followingMenuState = "open"
|
||||
|
||||
var innerBody: some View {
|
||||
ZStack {
|
||||
// NavigationLink("", destination: HomeView(viewModel: inboxViewModel), isActive: $inboxActive)
|
||||
// NavigationLink("", destination: HomeView(viewModel: followingViewModel), isActive: $followingActive)
|
||||
List {
|
||||
Section {
|
||||
Button(action: { inboxMenuState = inboxMenuState == "open" ? "closed" : "open" }, label: {
|
||||
HStack {
|
||||
Image.tabLibrary
|
||||
Text("Library")
|
||||
Spacer()
|
||||
|
||||
List {
|
||||
Section {
|
||||
Button(action: { inboxMenuState = inboxMenuState == "open" ? "closed" : "open" }, label: {
|
||||
HStack {
|
||||
Image.tabLibrary
|
||||
Text("Library")
|
||||
Spacer()
|
||||
|
||||
if inboxMenuState == "open" {
|
||||
Image(systemName: "chevron.down")
|
||||
} else {
|
||||
Image(systemName: "chevron.right")
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
if inboxMenuState == "open" {
|
||||
ForEach(viewModel.filters.filter { $0.folder == "inbox" }, id: \.self) { filter in
|
||||
Button(action: {
|
||||
viewModel.appliedFilter = filter
|
||||
selectedFilter = filter
|
||||
followingActive = false
|
||||
inboxActive = true
|
||||
}, label: {
|
||||
HStack {
|
||||
Spacer().frame(width: 35)
|
||||
Text(filter.name)
|
||||
.lineLimit(1)
|
||||
}
|
||||
})
|
||||
.listRowBackground(
|
||||
selectedFilter == filter && inboxActive
|
||||
? Color.systemBackground.cornerRadius(8) : Color.clear.cornerRadius(8)
|
||||
)
|
||||
if inboxMenuState == "open" {
|
||||
Image(systemName: "chevron.down")
|
||||
} else {
|
||||
Image(systemName: "chevron.right")
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
Section {
|
||||
Button(action: { followingMenuState = followingMenuState == "open" ? "closed" : "open" }, label: {
|
||||
HStack {
|
||||
Image.tabFollowing
|
||||
Text("Following")
|
||||
Spacer()
|
||||
|
||||
if followingMenuState == "open" {
|
||||
Image(systemName: "chevron.down")
|
||||
} else {
|
||||
Image(systemName: "chevron.right")
|
||||
if inboxMenuState == "open" {
|
||||
ForEach(viewModel.filters.filter { $0.folder == "inbox" }, id: \.self) { filter in
|
||||
Button(action: {
|
||||
viewModel.appliedFilter = filter
|
||||
selectedFilter = filter
|
||||
followingActive = false
|
||||
inboxActive = true
|
||||
}, label: {
|
||||
HStack {
|
||||
Spacer().frame(width: 35)
|
||||
Text(filter.name)
|
||||
.lineLimit(1)
|
||||
}
|
||||
}
|
||||
})
|
||||
})
|
||||
.listRowBackground(
|
||||
selectedFilter == filter && inboxActive
|
||||
? Color.systemBackground.cornerRadius(8) : Color.clear.cornerRadius(8)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if followingMenuState == "open" {
|
||||
ForEach(viewModel.filters.filter { $0.folder == "following" }, id: \.self) { filter in
|
||||
Button(action: {
|
||||
viewModel.appliedFilter = filter
|
||||
selectedFilter = filter
|
||||
inboxActive = false
|
||||
followingActive = true
|
||||
}, label: {
|
||||
HStack {
|
||||
Spacer().frame(width: 35)
|
||||
Text(filter.name)
|
||||
.lineLimit(1)
|
||||
}
|
||||
})
|
||||
.listRowBackground(
|
||||
selectedFilter == filter && followingActive
|
||||
? Color.systemBackground.cornerRadius(8) : Color.clear.cornerRadius(8)
|
||||
)
|
||||
Section {
|
||||
Button(action: { followingMenuState = followingMenuState == "open" ? "closed" : "open" }, label: {
|
||||
HStack {
|
||||
Image.tabFollowing
|
||||
Text("Following")
|
||||
Spacer()
|
||||
|
||||
if followingMenuState == "open" {
|
||||
Image(systemName: "chevron.down")
|
||||
} else {
|
||||
Image(systemName: "chevron.right")
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
if followingMenuState == "open" {
|
||||
ForEach(viewModel.filters.filter { $0.folder == "following" }, id: \.self) { filter in
|
||||
Button(action: {
|
||||
viewModel.appliedFilter = filter
|
||||
selectedFilter = filter
|
||||
inboxActive = false
|
||||
followingActive = true
|
||||
}, label: {
|
||||
HStack {
|
||||
Spacer().frame(width: 35)
|
||||
Text(filter.name)
|
||||
.lineLimit(1)
|
||||
}
|
||||
})
|
||||
.listRowBackground(
|
||||
selectedFilter == filter && followingActive
|
||||
? Color.systemBackground.cornerRadius(8) : Color.clear.cornerRadius(8)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
.listStyle(.sidebar)
|
||||
|
||||
Reference in New Issue
Block a user