More work on grid nav
This commit is contained in:
@ -39,16 +39,18 @@ struct FeedCardNavigationLink: View {
|
||||
@ObservedObject var viewModel: HomeFeedViewModel
|
||||
|
||||
var body: some View {
|
||||
NavigationLink(destination: LinkItemDetailView(
|
||||
linkedItemObjectID: item.objectID,
|
||||
isPDF: item.isPDF
|
||||
), label: {
|
||||
ZStack {
|
||||
LibraryItemCard(item: item, viewer: dataService.currentViewer)
|
||||
.padding(.top, 15)
|
||||
})
|
||||
.onAppear {
|
||||
Task { await viewModel.itemAppeared(item: item, dataService: dataService) }
|
||||
}
|
||||
NavigationLink(destination: LinkItemDetailView(
|
||||
linkedItemObjectID: item.objectID,
|
||||
isPDF: item.isPDF
|
||||
), label: {
|
||||
EmptyView()
|
||||
}).opacity(0)
|
||||
}
|
||||
.onAppear {
|
||||
Task { await viewModel.itemAppeared(item: item, dataService: dataService) }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -84,7 +84,7 @@ struct AnimatingCellHeight: AnimatableModifier {
|
||||
FilterSelectorView(viewModel: viewModel)
|
||||
}
|
||||
}
|
||||
.navigationBarTitleDisplayMode(.inline)
|
||||
// .navigationBarTitleDisplayMode(.inline)
|
||||
.toolbar {
|
||||
ToolbarItem(placement: .barLeading) {
|
||||
VStack(alignment: .leading) {
|
||||
@ -93,7 +93,7 @@ struct AnimatingCellHeight: AnimatableModifier {
|
||||
Text(title)
|
||||
.font(Font.system(size: isListScrolled ? 10 : 18, weight: .semibold))
|
||||
|
||||
if isListScrolled {
|
||||
if prefersListLayout, isListScrolled {
|
||||
Text(listTitle)
|
||||
.font(Font.system(size: 15, weight: .regular))
|
||||
.foregroundColor(Color.appGrayText)
|
||||
@ -244,7 +244,7 @@ struct AnimatingCellHeight: AnimatableModifier {
|
||||
if prefersListLayout || !enableGrid {
|
||||
HomeFeedListView(listTitle: $listTitle, isListScrolled: $isListScrolled, prefersListLayout: $prefersListLayout, viewModel: viewModel)
|
||||
} else {
|
||||
HomeFeedGridView(viewModel: viewModel)
|
||||
HomeFeedGridView(viewModel: viewModel, isListScrolled: $isListScrolled)
|
||||
}
|
||||
}.sheet(isPresented: $viewModel.showLabelsSheet) {
|
||||
FilterByLabelsView(
|
||||
@ -309,7 +309,8 @@ struct AnimatingCellHeight: AnimatableModifier {
|
||||
},
|
||||
label: {
|
||||
TextChipButton.makeMenuButton(
|
||||
title: LinkedItemFilter(rawValue: viewModel.appliedFilter)?.displayName ?? "Filter"
|
||||
title: LinkedItemFilter(rawValue: viewModel.appliedFilter)?.displayName ?? "Filter",
|
||||
color: .systemGray6
|
||||
)
|
||||
}
|
||||
)
|
||||
@ -322,13 +323,12 @@ struct AnimatingCellHeight: AnimatableModifier {
|
||||
},
|
||||
label: {
|
||||
TextChipButton.makeMenuButton(
|
||||
title: LinkedItemSort(rawValue: viewModel.appliedSort)?.displayName ?? "Sort"
|
||||
title: LinkedItemSort(rawValue: viewModel.appliedSort)?.displayName ?? "Sort",
|
||||
color: .systemGray6
|
||||
)
|
||||
}
|
||||
)
|
||||
TextChipButton.makeAddLabelButton {
|
||||
viewModel.showLabelsSheet = true
|
||||
}
|
||||
TextChipButton.makeAddLabelButton(color: .systemGray6, onTap: { viewModel.showLabelsSheet = true })
|
||||
ForEach(viewModel.selectedLabels, id: \.self) { label in
|
||||
TextChipButton.makeRemovableLabelButton(feedItemLabel: label, negated: false) {
|
||||
viewModel.selectedLabels.removeAll { $0.id == label.id }
|
||||
@ -633,6 +633,7 @@ struct AnimatingCellHeight: AnimatableModifier {
|
||||
@State var isContextMenuOpen = false
|
||||
|
||||
@ObservedObject var viewModel: HomeFeedViewModel
|
||||
@Binding var isListScrolled: Bool
|
||||
|
||||
func contextMenuActionHandler(item: LinkedItem, action: GridCardAction) {
|
||||
switch action {
|
||||
@ -670,7 +671,8 @@ struct AnimatingCellHeight: AnimatableModifier {
|
||||
},
|
||||
label: {
|
||||
TextChipButton.makeMenuButton(
|
||||
title: LinkedItemFilter(rawValue: viewModel.appliedFilter)?.displayName ?? "Filter"
|
||||
title: LinkedItemFilter(rawValue: viewModel.appliedFilter)?.displayName ?? "Filter",
|
||||
color: .systemGray6
|
||||
)
|
||||
}
|
||||
)
|
||||
@ -683,13 +685,12 @@ struct AnimatingCellHeight: AnimatableModifier {
|
||||
},
|
||||
label: {
|
||||
TextChipButton.makeMenuButton(
|
||||
title: LinkedItemSort(rawValue: viewModel.appliedSort)?.displayName ?? "Sort"
|
||||
title: LinkedItemSort(rawValue: viewModel.appliedSort)?.displayName ?? "Sort",
|
||||
color: .systemGray6
|
||||
)
|
||||
}
|
||||
)
|
||||
TextChipButton.makeAddLabelButton {
|
||||
viewModel.showLabelsSheet = true
|
||||
}
|
||||
TextChipButton.makeAddLabelButton(color: .systemGray6, onTap: { viewModel.showLabelsSheet = true })
|
||||
ForEach(viewModel.selectedLabels, id: \.self) { label in
|
||||
TextChipButton.makeRemovableLabelButton(feedItemLabel: label, negated: false) {
|
||||
viewModel.selectedLabels.removeAll { $0.id == label.id }
|
||||
@ -706,15 +707,32 @@ struct AnimatingCellHeight: AnimatableModifier {
|
||||
}
|
||||
.listRowSeparator(.hidden)
|
||||
}
|
||||
.dynamicTypeSize(.small ... .accessibility1)
|
||||
}
|
||||
|
||||
var body: some View {
|
||||
ZStack {
|
||||
ScrollView {
|
||||
filtersHeader
|
||||
.padding(.leading, 16)
|
||||
.padding(.bottom, 25)
|
||||
VStack(alignment: .leading) {
|
||||
if viewModel.showLoadingBar {
|
||||
ShimmeringLoader()
|
||||
} else {
|
||||
Spacer(minLength: 2)
|
||||
}
|
||||
|
||||
filtersHeader
|
||||
.onAppear {
|
||||
withAnimation {
|
||||
isListScrolled = false
|
||||
}
|
||||
}
|
||||
.onDisappear {
|
||||
withAnimation {
|
||||
isListScrolled = true
|
||||
}
|
||||
}
|
||||
.padding(.horizontal, 20)
|
||||
.frame(maxHeight: 35)
|
||||
|
||||
ScrollView {
|
||||
LazyVGrid(columns: [GridItem(.adaptive(minimum: 325, maximum: 400), spacing: 16)], alignment: .center, spacing: 30) {
|
||||
ForEach(viewModel.items) { item in
|
||||
GridCardNavigationLink(
|
||||
@ -723,9 +741,6 @@ struct AnimatingCellHeight: AnimatableModifier {
|
||||
isContextMenuOpen: $isContextMenuOpen,
|
||||
viewModel: viewModel
|
||||
)
|
||||
// .contextMenu {
|
||||
// libraryItemMenu(dataService: dataService, viewModel: viewModel, item: item)
|
||||
// }
|
||||
}
|
||||
Spacer()
|
||||
}
|
||||
@ -751,7 +766,11 @@ struct AnimatingCellHeight: AnimatableModifier {
|
||||
LoadingSection()
|
||||
}
|
||||
}
|
||||
.background(Color(.systemGroupedBackground))
|
||||
|
||||
Spacer()
|
||||
}
|
||||
.frame(maxHeight: .infinity)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -54,7 +54,5 @@ struct LibraryListView: View {
|
||||
}
|
||||
}
|
||||
// }
|
||||
.navigationViewStyle(.stack)
|
||||
.navigationBarTitleDisplayMode(.inline)
|
||||
}
|
||||
}
|
||||
|
||||
@ -19,6 +19,8 @@ import Views
|
||||
return AnyView(splitView)
|
||||
} else {
|
||||
return AnyView(LibraryTabView())
|
||||
// .navigationViewStyle(.stack)
|
||||
// .navigationBarTitleDisplayMode(.inline)
|
||||
}
|
||||
#else
|
||||
return AnyView(splitView)
|
||||
@ -44,6 +46,7 @@ import Views
|
||||
// Second column is the Primary Nav Stack
|
||||
PrimaryContentCategory.feed.destinationView
|
||||
}
|
||||
.navigationBarTitleDisplayMode(.inline)
|
||||
.accentColor(.appGrayTextContrast)
|
||||
.introspectSplitViewController {
|
||||
$0.preferredSplitBehavior = .tile
|
||||
|
||||
@ -45,6 +45,8 @@ struct WebReaderContainerView: View {
|
||||
@StateObject var viewModel = WebReaderViewModel()
|
||||
@Environment(\.dismiss) var dismiss
|
||||
|
||||
@AppStorage(UserDefaultKey.prefersHideStatusBarInReader.rawValue) var prefersHideStatusBarInReader = false
|
||||
|
||||
func webViewActionHandler(message: WKScriptMessage, replyHandler: WKScriptMessageReplyHandler?) {
|
||||
if let replyHandler = replyHandler {
|
||||
viewModel.webViewActionWithReplyHandler(
|
||||
@ -425,6 +427,7 @@ struct WebReaderContainerView: View {
|
||||
showHighlightAnnotationModal: $showHighlightAnnotationModal
|
||||
)
|
||||
.background(ThemeManager.currentBgColor)
|
||||
.statusBar(hidden: prefersHideStatusBarInReader)
|
||||
.onAppear {
|
||||
if item.isUnread {
|
||||
dataService.updateLinkReadingProgress(itemID: item.unwrappedID, readingProgress: 0.1, anchorIndex: 0)
|
||||
|
||||
@ -33,4 +33,5 @@ public enum UserDefaultKey: String {
|
||||
case userWordsPerMinute
|
||||
case hideFeatureSection
|
||||
case justifyText
|
||||
case prefersHideStatusBarInReader
|
||||
}
|
||||
|
||||
@ -5,9 +5,9 @@
|
||||
"color-space" : "srgb",
|
||||
"components" : {
|
||||
"alpha" : "1.000",
|
||||
"blue" : "0xF9",
|
||||
"green" : "0xF9",
|
||||
"red" : "0xF9"
|
||||
"blue" : "0xF5",
|
||||
"green" : "0xF5",
|
||||
"red" : "0xF5"
|
||||
}
|
||||
},
|
||||
"idiom" : "universal"
|
||||
|
||||
@ -0,0 +1,38 @@
|
||||
{
|
||||
"colors" : [
|
||||
{
|
||||
"color" : {
|
||||
"color-space" : "srgb",
|
||||
"components" : {
|
||||
"alpha" : "1.000",
|
||||
"blue" : "0xF7",
|
||||
"green" : "0xF2",
|
||||
"red" : "0xF2"
|
||||
}
|
||||
},
|
||||
"idiom" : "universal"
|
||||
},
|
||||
{
|
||||
"appearances" : [
|
||||
{
|
||||
"appearance" : "luminosity",
|
||||
"value" : "dark"
|
||||
}
|
||||
],
|
||||
"color" : {
|
||||
"color-space" : "srgb",
|
||||
"components" : {
|
||||
"alpha" : "1.000",
|
||||
"blue" : "0xF7",
|
||||
"green" : "0xF2",
|
||||
"red" : "0xF2"
|
||||
}
|
||||
},
|
||||
"idiom" : "universal"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
}
|
||||
}
|
||||
@ -36,7 +36,8 @@ public struct LibraryItemCard: View {
|
||||
labels
|
||||
}
|
||||
}
|
||||
.padding(.bottom, 5)
|
||||
.padding(5)
|
||||
.padding(.top, 10)
|
||||
.draggableItem(item: item)
|
||||
.dynamicTypeSize(.xSmall ... .accessibility1)
|
||||
}
|
||||
@ -156,12 +157,12 @@ public struct LibraryItemCard: View {
|
||||
image
|
||||
.resizable()
|
||||
.aspectRatio(contentMode: .fill)
|
||||
.frame(width: 60, height: 60)
|
||||
.frame(width: 50, height: 50)
|
||||
.cornerRadius(5)
|
||||
.padding(.top, 2)
|
||||
} else {
|
||||
Color.systemBackground
|
||||
.frame(width: 60, height: 60)
|
||||
.frame(width: 50, height: 50)
|
||||
.cornerRadius(5)
|
||||
.padding(.top, 2)
|
||||
}
|
||||
@ -170,6 +171,7 @@ public struct LibraryItemCard: View {
|
||||
fallbackImage
|
||||
}
|
||||
}
|
||||
.padding(.top, 15)
|
||||
.cornerRadius(5)
|
||||
}
|
||||
|
||||
@ -183,7 +185,7 @@ public struct LibraryItemCard: View {
|
||||
.frame(maxWidth: .infinity, maxHeight: .infinity)
|
||||
.background(Gradient.randomColor(str: item.unwrappedTitle, offset: 0))
|
||||
.background(LinearGradient(gradient: Gradient(fromStr: item.unwrappedTitle)!, startPoint: .top, endPoint: .bottom))
|
||||
.frame(width: 74 * 0.666, height: 74)
|
||||
.frame(width: 50, height: 50)
|
||||
}
|
||||
|
||||
var bylineStr: String {
|
||||
|
||||
@ -28,7 +28,7 @@ public struct LibraryItemLabelView: View {
|
||||
.cornerRadius(5)
|
||||
.overlay(
|
||||
RoundedRectangle(cornerRadius: 5)
|
||||
.stroke(Color.isDarkMode ? Color.themeLabelBackground : Color.themeLabelOutline, lineWidth: 1)
|
||||
.stroke(Color.isDarkMode ? Color.themeLabelBackground : Color.themeLabelBackground, lineWidth: 1)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@ -90,6 +90,7 @@ public enum WebFont: String, CaseIterable {
|
||||
@AppStorage(UserDefaultKey.preferredWebFont.rawValue) var preferredFont = WebFont.inter.rawValue
|
||||
@AppStorage(UserDefaultKey.prefersHighContrastWebFont.rawValue) var prefersHighContrastText = true
|
||||
@AppStorage(UserDefaultKey.justifyText.rawValue) var justifyText = false
|
||||
@AppStorage(UserDefaultKey.prefersHideStatusBarInReader.rawValue) var prefersHideStatusBar = false
|
||||
|
||||
public init(
|
||||
updateReaderPreferences: @escaping () -> Void,
|
||||
@ -151,6 +152,13 @@ public enum WebFont: String, CaseIterable {
|
||||
updateReaderPreferences()
|
||||
}
|
||||
|
||||
Toggle("Hide Status Bar", isOn: $prefersHideStatusBar)
|
||||
.frame(height: 40)
|
||||
.padding(.trailing, 6)
|
||||
.onChange(of: prefersHideStatusBar) { _ in
|
||||
updateReaderPreferences()
|
||||
}
|
||||
|
||||
Spacer()
|
||||
}
|
||||
.padding(.horizontal, 30)
|
||||
|
||||
@ -92,12 +92,12 @@ public struct TextChip: View {
|
||||
}
|
||||
|
||||
public struct TextChipButton: View {
|
||||
public static func makeAddLabelButton(onTap: @escaping () -> Void) -> TextChipButton {
|
||||
TextChipButton(title: LocalText.labelsGeneric, color: .systemGray6, actionType: .show, negated: false, onTap: onTap)
|
||||
public static func makeAddLabelButton(color: Color, onTap: @escaping () -> Void) -> TextChipButton {
|
||||
TextChipButton(title: LocalText.labelsGeneric, color: color, actionType: .show, negated: false, onTap: onTap)
|
||||
}
|
||||
|
||||
public static func makeMenuButton(title: String) -> TextChipButton {
|
||||
TextChipButton(title: title, color: .systemGray6, actionType: .show, negated: false, onTap: {})
|
||||
public static func makeMenuButton(title: String, color: Color) -> TextChipButton {
|
||||
TextChipButton(title: title, color: color, actionType: .show, negated: false, onTap: {})
|
||||
}
|
||||
|
||||
public static func makeSearchFilterButton(title: String, onTap: @escaping () -> Void) -> TextChipButton {
|
||||
|
||||
Reference in New Issue
Block a user