mirror of
https://github.com/omnivore-app/omnivore.git
synced 2026-03-11 08:54:26 +00:00
update grid spacing
This commit is contained in:
parent
d89b17800e
commit
508763b061
4 changed files with 109 additions and 93 deletions
|
|
@ -54,6 +54,14 @@ struct GridCardNavigationLink: View {
|
|||
|
||||
@ObservedObject var viewModel: HomeFeedViewModel
|
||||
|
||||
func tapAction() {
|
||||
scale = 0.95
|
||||
DispatchQueue.main.asyncAfter(deadline: .now() + .milliseconds(150)) {
|
||||
scale = 1.0
|
||||
viewModel.selectedLinkItem = item.objectID
|
||||
}
|
||||
}
|
||||
|
||||
var body: some View {
|
||||
let destination = LinkItemDetailView(
|
||||
viewModel: LinkItemDetailViewModel(
|
||||
|
|
@ -77,13 +85,7 @@ struct GridCardNavigationLink: View {
|
|||
EmptyView()
|
||||
}
|
||||
GridCard(item: item, isContextMenuOpen: $isContextMenuOpen, actionHandler: actionHandler, tapAction: {
|
||||
withAnimation {
|
||||
scale = 0.95
|
||||
DispatchQueue.main.asyncAfter(deadline: .now() + .milliseconds(150)) {
|
||||
scale = 1.0
|
||||
viewModel.selectedLinkItem = item.objectID
|
||||
}
|
||||
}
|
||||
withAnimation { tapAction() }
|
||||
})
|
||||
.onAppear {
|
||||
Task { await viewModel.itemAppeared(item: item, dataService: dataService) }
|
||||
|
|
@ -91,5 +93,18 @@ struct GridCardNavigationLink: View {
|
|||
}
|
||||
.aspectRatio(1.8, contentMode: .fill)
|
||||
.scaleEffect(scale)
|
||||
.background(
|
||||
Color.secondarySystemGroupedBackground
|
||||
.onTapGesture {
|
||||
if isContextMenuOpen {
|
||||
isContextMenuOpen = false
|
||||
} else {
|
||||
withAnimation {
|
||||
tapAction()
|
||||
}
|
||||
}
|
||||
}
|
||||
)
|
||||
.cornerRadius(6)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -338,7 +338,7 @@ import Views
|
|||
|
||||
var body: some View {
|
||||
ScrollView {
|
||||
LazyVGrid(columns: [GridItem(.adaptive(minimum: 325), spacing: 24)], spacing: 24) {
|
||||
LazyVGrid(columns: [GridItem(.adaptive(minimum: 325), spacing: 16)], spacing: 16) {
|
||||
ForEach(viewModel.items) { item in
|
||||
GridCardNavigationLink(
|
||||
item: item,
|
||||
|
|
|
|||
|
|
@ -34,6 +34,10 @@ public extension LinkedItem {
|
|||
var unwrappedSavedAt: Date { savedAt ?? Date() }
|
||||
var unwrappedCreatedAt: Date { createdAt ?? Date() }
|
||||
|
||||
var hasLabels: Bool {
|
||||
(labels?.count ?? 0) > 0
|
||||
}
|
||||
|
||||
var isRead: Bool {
|
||||
readingProgress >= 0.98
|
||||
}
|
||||
|
|
|
|||
|
|
@ -75,100 +75,97 @@ public struct GridCard: View {
|
|||
}
|
||||
.onTapGesture { tapHandler() }
|
||||
|
||||
// Title, Subtitle, Menu Button
|
||||
VStack(alignment: .leading, spacing: 4) {
|
||||
HStack {
|
||||
Text(item.unwrappedTitle)
|
||||
.font(.appHeadline)
|
||||
VStack {
|
||||
// Title, Subtitle, Menu Button
|
||||
VStack(alignment: .leading, spacing: 4) {
|
||||
HStack {
|
||||
Text(item.unwrappedTitle)
|
||||
.font(.appHeadline)
|
||||
.foregroundColor(.appGrayTextContrast)
|
||||
.lineLimit(1)
|
||||
.onTapGesture { tapHandler() }
|
||||
Spacer()
|
||||
|
||||
Menu(
|
||||
content: { contextMenuView },
|
||||
label: { Image(systemName: "ellipsis").padding() }
|
||||
)
|
||||
.frame(width: 16, height: 16, alignment: .center)
|
||||
.onTapGesture { isContextMenuOpen = true }
|
||||
}
|
||||
|
||||
HStack {
|
||||
if let author = item.author {
|
||||
Text("by \(author)")
|
||||
.font(.appCaptionTwo)
|
||||
.foregroundColor(.appGrayText)
|
||||
.lineLimit(1)
|
||||
}
|
||||
|
||||
if let publisherDisplayName = item.publisherDisplayName {
|
||||
Text(publisherDisplayName)
|
||||
.font(.appCaptionTwo)
|
||||
.foregroundColor(.appGrayText)
|
||||
.lineLimit(1)
|
||||
}
|
||||
|
||||
Spacer()
|
||||
}
|
||||
.onTapGesture { tapHandler() }
|
||||
}
|
||||
.frame(height: 30)
|
||||
.padding(.horizontal)
|
||||
.padding(.bottom, 16)
|
||||
|
||||
// Link description and image
|
||||
HStack(alignment: .top) {
|
||||
Text(item.descriptionText ?? item.unwrappedTitle)
|
||||
.font(.appSubheadline)
|
||||
.foregroundColor(.appGrayTextContrast)
|
||||
.lineLimit(1)
|
||||
.onTapGesture { tapHandler() }
|
||||
Spacer()
|
||||
|
||||
Menu(
|
||||
content: { contextMenuView },
|
||||
label: { Image(systemName: "ellipsis").padding() }
|
||||
)
|
||||
.frame(width: 16, height: 16, alignment: .center)
|
||||
.onTapGesture { isContextMenuOpen = true }
|
||||
}
|
||||
|
||||
HStack {
|
||||
if let author = item.author {
|
||||
Text("by \(author)")
|
||||
.font(.appCaptionTwo)
|
||||
.foregroundColor(.appGrayText)
|
||||
.lineLimit(1)
|
||||
}
|
||||
|
||||
if let publisherDisplayName = item.publisherDisplayName {
|
||||
Text(publisherDisplayName)
|
||||
.font(.appCaptionTwo)
|
||||
.foregroundColor(.appGrayText)
|
||||
.lineLimit(1)
|
||||
}
|
||||
.lineLimit(nil)
|
||||
.multilineTextAlignment(.leading)
|
||||
|
||||
Spacer()
|
||||
}
|
||||
.onTapGesture { tapHandler() }
|
||||
}
|
||||
.frame(height: 30)
|
||||
.padding(.horizontal)
|
||||
.padding(.bottom, 12)
|
||||
|
||||
// Link description and image
|
||||
HStack(alignment: .top) {
|
||||
Text(item.descriptionText ?? item.unwrappedTitle)
|
||||
.font(.appSubheadline)
|
||||
.foregroundColor(.appGrayTextContrast)
|
||||
.lineLimit(nil)
|
||||
.multilineTextAlignment(.leading)
|
||||
.frame(height: (geo.size.width * 2) / 9, alignment: .top)
|
||||
|
||||
Spacer()
|
||||
|
||||
if let imageURL = item.imageURL {
|
||||
AsyncLoadingImage(url: imageURL) { imageStatus in
|
||||
if case let AsyncImageStatus.loaded(image) = imageStatus {
|
||||
image
|
||||
.resizable()
|
||||
.aspectRatio(contentMode: .fill)
|
||||
.frame(width: geo.size.width / 3, height: (geo.size.width * 2) / 9)
|
||||
.cornerRadius(3)
|
||||
} else if case AsyncImageStatus.loading = imageStatus {
|
||||
Color.appButtonBackground
|
||||
.frame(width: geo.size.width / 3, height: (geo.size.width * 2) / 9)
|
||||
.cornerRadius(3)
|
||||
} else {
|
||||
EmptyView()
|
||||
if let imageURL = item.imageURL {
|
||||
AsyncLoadingImage(url: imageURL) { imageStatus in
|
||||
if case let AsyncImageStatus.loaded(image) = imageStatus {
|
||||
image
|
||||
.resizable()
|
||||
.aspectRatio(contentMode: .fill)
|
||||
.frame(width: geo.size.width / 3, height: (geo.size.width * 2) / 9)
|
||||
.cornerRadius(3)
|
||||
} else if case AsyncImageStatus.loading = imageStatus {
|
||||
Color.appButtonBackground
|
||||
.frame(width: geo.size.width / 3, height: (geo.size.width * 2) / 9)
|
||||
.cornerRadius(3)
|
||||
} else {
|
||||
EmptyView()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
.padding(.horizontal)
|
||||
.onTapGesture { tapHandler() }
|
||||
|
||||
// Category Labels
|
||||
ScrollView(.horizontal, showsIndicators: false) {
|
||||
HStack {
|
||||
ForEach(item.sortedLabels, id: \.self) {
|
||||
TextChip(feedItemLabel: $0)
|
||||
}
|
||||
// Add an empty chip to the end so that we create a Spacer equivalent
|
||||
// in the case where there are no labels set on the item
|
||||
TextChip(text: "", color: Color.secondarySystemGroupedBackground)
|
||||
Spacer()
|
||||
}
|
||||
.padding(.horizontal)
|
||||
}
|
||||
.frame(height: 40)
|
||||
.onTapGesture { tapHandler() }
|
||||
}
|
||||
.background(
|
||||
Color.secondarySystemGroupedBackground
|
||||
.onTapGesture { tapHandler() }
|
||||
)
|
||||
.cornerRadius(6)
|
||||
|
||||
// Category Labels
|
||||
if item.hasLabels {
|
||||
ScrollView(.horizontal, showsIndicators: false) {
|
||||
HStack {
|
||||
ForEach(item.sortedLabels, id: \.self) {
|
||||
TextChip(feedItemLabel: $0)
|
||||
}
|
||||
Spacer()
|
||||
}
|
||||
.padding(.horizontal)
|
||||
}
|
||||
.onTapGesture { tapHandler() }
|
||||
}
|
||||
}
|
||||
.padding(.horizontal, 0)
|
||||
.padding(.top, 0)
|
||||
.padding(.bottom, 8)
|
||||
}
|
||||
.contextMenu { contextMenuView }
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue