Merge pull request #220 from omnivore-app/feature/ipad-panels

iPad panels
This commit is contained in:
Satindar Dhillon 2022-03-10 15:17:24 -08:00 committed by GitHub
commit da8678a207
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
8 changed files with 165 additions and 115 deletions

View file

@ -66,6 +66,7 @@ struct GridCardNavigationLink: View {
viewModel.itemAppeared(item: item, searchQuery: searchQuery, dataService: dataService)
}
}
.aspectRatio(2.1, contentMode: .fill)
.scaleEffect(scale)
}
}

View file

@ -24,8 +24,8 @@ struct HomeView: View {
}
.accentColor(.appGrayTextContrast)
} else {
GeometryReader { geo in
HomeFeedContainerView(isCompact: geo.size.width < 500, viewModel: viewModel)
GeometryReader { _ in
HomeFeedContainerView(isCompact: UIDevice.isIPhone, viewModel: viewModel)
}
}
#elseif os(macOS)

View file

@ -186,6 +186,7 @@ struct LinkItemDetailView: View {
}
}
@available(macOS 12.0, *)
@available(iOS 15.0, *)
var navBar: some View {
HStack(alignment: .center) {

View file

@ -4,40 +4,60 @@ import SwiftUI
import Views
public struct PrimaryContentView: View {
let categories = [
PrimaryContentCategory.feed,
PrimaryContentCategory.profile
]
public var body: some View {
#if os(iOS)
if UIDevice.isIPad {
regularView
splitView
} else {
HomeView()
}
#elseif os(macOS)
regularView
splitView
#endif
}
// ipad and mac view container
private var regularView: some View {
let categories = [
PrimaryContentCategory.feed,
PrimaryContentCategory.profile
]
#if os(macOS)
private var splitView: some View {
NavigationView {
// The first column is the sidebar.
PrimaryContentSidebar(categories: categories)
.navigationTitle("Categories")
return NavigationView {
// The first column is the sidebar.
PrimaryContentSidebar(categories: categories)
.navigationTitle("Categories")
// Second column is the Primary Nav Stack
PrimaryContentCategory.feed.destinationView
// Second column is the Primary Nav Stack
PrimaryContentCategory.feed.destinationView
// Add a third column for macOS only
#if os(macOS)
// Third column is the detail view
Text("Select a link from the feed")
#endif
}
.accentColor(.appGrayTextContrast)
}
.accentColor(.appGrayTextContrast)
}
#endif
#if os(iOS)
private var splitView: some View {
NavigationView {
// The first column is the sidebar.
PrimaryContentSidebar(categories: categories)
// Second column is the Primary Nav Stack
PrimaryContentCategory.feed.destinationView
}
.accentColor(.appGrayTextContrast)
.introspectSplitViewController {
$0.preferredSplitBehavior = .tile
$0.preferredPrimaryColumnWidth = 200
if #available(iOS 14.5, *) {
$0.presentsWithGesture = false
$0.displayModeButtonVisibility = .always
}
}
}
#endif
}
struct PrimaryContentSidebar: View {

View file

@ -59,108 +59,112 @@ public struct GridCard: View {
}
public var body: some View {
VStack(alignment: .leading, spacing: 16) {
// Progress Bar
Group {
// Remove os check when dropping macOS 11
#if os(iOS)
if #available(iOS 15.0, *) {
ProgressView(value: min(abs(item.readingProgress) / 100, 1))
.tint(.appYellow48)
.frame(maxWidth: .infinity, alignment: .leading)
} else {
GeometryReader { geo in
VStack(alignment: .leading, spacing: 16) {
// Progress Bar
Group {
// Remove os check when dropping macOS 11
#if os(iOS)
if #available(iOS 15.0, *) {
ProgressView(value: min(abs(item.readingProgress) / 100, 1))
.tint(.appYellow48)
.frame(maxWidth: .infinity, alignment: .leading)
} else {
ProgressView(value: max(abs(item.readingProgress) / 100, 1))
.frame(maxWidth: .infinity, alignment: .leading)
}
#else
ProgressView(value: max(abs(item.readingProgress) / 100, 1))
.frame(maxWidth: .infinity, alignment: .leading)
}
#else
ProgressView(value: max(abs(item.readingProgress) / 100, 1))
.frame(maxWidth: .infinity, alignment: .leading)
#endif
}
.onTapGesture { tapHandler() }
// Title, Subtitle, Menu Button
VStack(alignment: .leading, spacing: 4) {
HStack {
Text(item.title)
.font(.appHeadline)
.foregroundColor(.appGrayTextContrast)
.lineLimit(1)
.onTapGesture { tapHandler() }
Spacer()
Menu(
content: { contextMenuView },
label: { Image.profile }
)
.onTapGesture { isContextMenuOpen = true }
}
HStack {
if let author = item.author {
Text("by \(author)")
.font(.appCaptionTwo)
.foregroundColor(.appGrayText)
.lineLimit(1)
}
if let publisherURL = item.publisherHostname {
Text(publisherURL)
.font(.appCaptionTwo)
.foregroundColor(.appGrayText)
.underline()
.lineLimit(1)
}
Spacer()
#endif
}
.onTapGesture { tapHandler() }
}
.frame(height: 30)
.padding(.horizontal)
// Link description and image
HStack(alignment: .top) {
Text(item.description ?? item.title)
.font(.appFootnote)
.foregroundColor(.appGrayTextContrast)
.lineLimit(nil)
.multilineTextAlignment(.leading)
Spacer()
if let imageURL = item.imageURL {
AsyncImage(url: imageURL, isResizable: true)
.aspectRatio(1, contentMode: .fill)
.frame(width: 135, height: 90)
.cornerRadius(3)
}
}
.frame(height: 95)
.padding(.horizontal)
.onTapGesture { tapHandler() }
// Category Labels
if FeatureFlag.showFeedItemTags {
ScrollView(.horizontal, showsIndicators: false) {
// Title, Subtitle, Menu Button
VStack(alignment: .leading, spacing: 4) {
HStack {
TextChip(text: "label", color: .red)
TextChip(text: "longer label", color: .blue)
Text(item.title)
.font(.appHeadline)
.foregroundColor(.appGrayTextContrast)
.lineLimit(1)
.onTapGesture { tapHandler() }
Spacer()
Menu(
content: { contextMenuView },
label: { Image.dotsThree }
)
.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 publisherURL = item.publisherHostname {
Text(publisherURL)
.font(.appCaptionTwo)
.foregroundColor(.appGrayText)
.underline()
.lineLimit(1)
}
Spacer()
}
.frame(height: 30)
.padding(.horizontal)
.padding(.bottom, 8)
.onTapGesture { tapHandler() }
}
} else {
Spacer(minLength: 8)
}
}
.background(
Color.secondarySystemGroupedBackground
.frame(height: 30)
.padding(.horizontal)
// Link description and image
HStack(alignment: .top) {
Text(item.description ?? item.title)
.font(.appSubheadline)
.foregroundColor(.appGrayTextContrast)
.lineLimit(nil)
.multilineTextAlignment(.leading)
.frame(height: (geo.size.width * 2) / 9, alignment: .top)
Spacer()
if let imageURL = item.imageURL {
AsyncImage(url: imageURL, isResizable: true)
.aspectRatio(contentMode: .fill)
.frame(width: geo.size.width / 3, height: (geo.size.width * 2) / 9)
.cornerRadius(3)
}
}
.padding(.horizontal)
.padding(.bottom, 5)
.onTapGesture { tapHandler() }
)
.cornerRadius(6)
.contextMenu { contextMenuView }
// Category Labels
if FeatureFlag.showFeedItemTags {
ScrollView(.horizontal, showsIndicators: false) {
HStack {
TextChip(text: "label", color: .red)
TextChip(text: "longer label", color: .blue)
Spacer()
}
.frame(height: 30)
.padding(.horizontal)
.padding(.bottom, 8)
}
} else {
Spacer(minLength: 8)
}
}
.background(
Color.secondarySystemGroupedBackground
.onTapGesture { tapHandler() }
)
.cornerRadius(6)
.contextMenu { contextMenuView }
}
}
}

View file

@ -17,4 +17,5 @@ public extension Image {
static var profileTab: Image { Image("_profileTab", bundle: .module) }
static var profile: Image { Image("_profile", bundle: .module) }
static var profileTabSelected: Image { Image("_profileTabSelected", bundle: .module) }
static var dotsThree: Image { Image("_dots-three", bundle: .module) }
}

View file

@ -0,0 +1,15 @@
{
"images" : [
{
"filename" : "dots-three.svg",
"idiom" : "universal"
}
],
"info" : {
"author" : "xcode",
"version" : 1
},
"properties" : {
"template-rendering-intent" : "template"
}
}

View file

@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="26" height="26" viewBox="0 0 26 26" version="1.1">
<g id="surface1">
<path style=" stroke:none;fill-rule:nonzero;fill:rgb(0%,0%,0%);fill-opacity:1;" d="M 14.21875 13 C 14.21875 13.671875 13.671875 14.21875 13 14.21875 C 12.328125 14.21875 11.78125 13.671875 11.78125 13 C 11.78125 12.328125 12.328125 11.78125 13 11.78125 C 13.671875 11.78125 14.21875 12.328125 14.21875 13 Z M 14.21875 13 "/>
<path style=" stroke:none;fill-rule:nonzero;fill:rgb(0%,0%,0%);fill-opacity:1;" d="M 20.71875 13 C 20.71875 13.671875 20.171875 14.21875 19.5 14.21875 C 18.828125 14.21875 18.28125 13.671875 18.28125 13 C 18.28125 12.328125 18.828125 11.78125 19.5 11.78125 C 20.171875 11.78125 20.71875 12.328125 20.71875 13 Z M 20.71875 13 "/>
<path style=" stroke:none;fill-rule:nonzero;fill:rgb(0%,0%,0%);fill-opacity:1;" d="M 7.71875 13 C 7.71875 13.671875 7.171875 14.21875 6.5 14.21875 C 5.828125 14.21875 5.28125 13.671875 5.28125 13 C 5.28125 12.328125 5.828125 11.78125 6.5 11.78125 C 7.171875 11.78125 7.71875 12.328125 7.71875 13 Z M 7.71875 13 "/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.2 KiB