mirror of
https://github.com/omnivore-app/omnivore.git
synced 2026-03-11 08:54:26 +00:00
Merge pull request #220 from omnivore-app/feature/ipad-panels
iPad panels
This commit is contained in:
commit
da8678a207
8 changed files with 165 additions and 115 deletions
|
|
@ -66,6 +66,7 @@ struct GridCardNavigationLink: View {
|
|||
viewModel.itemAppeared(item: item, searchQuery: searchQuery, dataService: dataService)
|
||||
}
|
||||
}
|
||||
.aspectRatio(2.1, contentMode: .fill)
|
||||
.scaleEffect(scale)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -186,6 +186,7 @@ struct LinkItemDetailView: View {
|
|||
}
|
||||
}
|
||||
|
||||
@available(macOS 12.0, *)
|
||||
@available(iOS 15.0, *)
|
||||
var navBar: some View {
|
||||
HStack(alignment: .center) {
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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 }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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) }
|
||||
}
|
||||
|
|
|
|||
15
apple/OmnivoreKit/Sources/Views/Images/Images.xcassets/_dots-three.imageset/Contents.json
vendored
Normal file
15
apple/OmnivoreKit/Sources/Views/Images/Images.xcassets/_dots-three.imageset/Contents.json
vendored
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
{
|
||||
"images" : [
|
||||
{
|
||||
"filename" : "dots-three.svg",
|
||||
"idiom" : "universal"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
},
|
||||
"properties" : {
|
||||
"template-rendering-intent" : "template"
|
||||
}
|
||||
}
|
||||
8
apple/OmnivoreKit/Sources/Views/Images/Images.xcassets/_dots-three.imageset/dots-three.svg
vendored
Normal file
8
apple/OmnivoreKit/Sources/Views/Images/Images.xcassets/_dots-three.imageset/dots-three.svg
vendored
Normal 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 |
Loading…
Reference in a new issue