mirror of
https://github.com/omnivore-app/omnivore.git
synced 2026-03-11 08:54:26 +00:00
Handle grid cards
This commit is contained in:
parent
dfaf61cf8c
commit
dcdb01171c
13 changed files with 190 additions and 187 deletions
|
|
@ -13,38 +13,47 @@ class SlideAnimatedTransitioning: NSObject {}
|
|||
extension SlideAnimatedTransitioning: UIViewControllerAnimatedTransitioning {
|
||||
func animateTransition(using transitionContext: UIViewControllerContextTransitioning) {
|
||||
let containerView = transitionContext.containerView
|
||||
let fromView = transitionContext.viewController(forKey: UITransitionContextViewControllerKey.from)!.view
|
||||
let toView = transitionContext.viewController(forKey: UITransitionContextViewControllerKey.to)!.view
|
||||
guard
|
||||
let fromVC = transitionContext.viewController(forKey: UITransitionContextViewControllerKey.from),
|
||||
let toVC = transitionContext.viewController(forKey: UITransitionContextViewControllerKey.to)
|
||||
else {
|
||||
return
|
||||
}
|
||||
|
||||
let width = containerView.frame.width
|
||||
|
||||
var offsetLeft = fromView?.frame
|
||||
var offsetLeft = fromVC.view?.frame
|
||||
offsetLeft?.origin.x = width
|
||||
|
||||
var offscreenRight = toView?.frame
|
||||
var offscreenRight = fromVC.view?.frame
|
||||
offscreenRight?.origin.x = -width / 3.33
|
||||
|
||||
toView?.frame = offscreenRight!
|
||||
toVC.view?.frame = offscreenRight!
|
||||
|
||||
fromView?.layer.shadowRadius = 5.0
|
||||
fromView?.layer.shadowOpacity = 1.0
|
||||
toView?.layer.opacity = 0.9
|
||||
fromVC.view?.layer.shadowRadius = 5.0
|
||||
fromVC.view?.layer.shadowOpacity = 1.0
|
||||
toVC.view?.layer.opacity = 0.9
|
||||
|
||||
containerView.insertSubview(toView!, belowSubview: fromView!)
|
||||
transitionContext.containerView.addSubview(toVC.view)
|
||||
transitionContext.containerView.addSubview(fromVC.view)
|
||||
|
||||
// containerView.insertSubview(toView!, belowSubview: fromView!)
|
||||
print("CONTAINER VIEW: ", containerView)
|
||||
|
||||
UIView.animate(withDuration: transitionDuration(using: transitionContext), delay: 0, options: .curveLinear, animations: {
|
||||
toView?.frame = (fromView?.frame)!
|
||||
fromView?.frame = offsetLeft!
|
||||
toVC.view?.frame = (fromVC.view?.frame)!
|
||||
fromVC.view?.frame = offsetLeft!
|
||||
|
||||
toView?.layer.opacity = 1.0
|
||||
fromView?.layer.shadowOpacity = 0.1
|
||||
toVC.view?.layer.opacity = 1.0
|
||||
fromVC.view?.layer.shadowOpacity = 0.1
|
||||
|
||||
}, completion: { _ in
|
||||
toView?.layer.opacity = 1.0
|
||||
toView?.layer.shadowOpacity = 0
|
||||
fromView?.layer.opacity = 1.0
|
||||
fromView?.layer.shadowOpacity = 0
|
||||
toVC.view?.layer.opacity = 1.0
|
||||
toVC.view?.layer.shadowOpacity = 0
|
||||
fromVC.view?.layer.opacity = 1.0
|
||||
fromVC.view?.layer.shadowOpacity = 0
|
||||
|
||||
fromVC.view.removeFromSuperview()
|
||||
// when cancelling or completing the animation, ios simulator seems to sometimes flash black backgrounds during the animation. on devices, this doesn't seem to happen though.
|
||||
// containerView.backgroundColor = [UIColor whiteColor];
|
||||
transitionContext.completeTransition(!transitionContext.transitionWasCancelled)
|
||||
|
|
|
|||
|
|
@ -66,28 +66,16 @@ struct GridCardNavigationLink: View {
|
|||
@ObservedObject var viewModel: HomeFeedViewModel
|
||||
|
||||
var body: some View {
|
||||
ZStack {
|
||||
Button {
|
||||
if isContextMenuOpen {
|
||||
isContextMenuOpen = false
|
||||
} else {
|
||||
// viewModel.selectedItem = item
|
||||
// viewModel.linkIsActive = true
|
||||
}
|
||||
} label: {
|
||||
NavigationLink(destination: EmptyView()) {
|
||||
EmptyView()
|
||||
}
|
||||
.opacity(0)
|
||||
.buttonStyle(PlainButtonStyle())
|
||||
.onAppear {
|
||||
Task { await viewModel.itemAppeared(item: item, dataService: dataService) }
|
||||
}
|
||||
GridCard(item: item, isContextMenuOpen: $isContextMenuOpen, actionHandler: actionHandler)
|
||||
}
|
||||
NavigationLink(destination: LinkItemDetailView(
|
||||
linkedItemObjectID: item.objectID,
|
||||
isPDF: item.isPDF
|
||||
)) {
|
||||
GridCard(item: item, isContextMenuOpen: $isContextMenuOpen, actionHandler: actionHandler)
|
||||
}
|
||||
.aspectRatio(1.8, contentMode: .fill)
|
||||
.scaleEffect(scale)
|
||||
.onAppear {
|
||||
Task { await viewModel.itemAppeared(item: item, dataService: dataService) }
|
||||
}
|
||||
.aspectRatio(1.0, contentMode: .fill)
|
||||
.background(
|
||||
Color.secondarySystemGroupedBackground
|
||||
.onTapGesture {
|
||||
|
|
|
|||
|
|
@ -20,7 +20,10 @@ struct LibraryFeatureCardNavigationLink: View {
|
|||
@State var showFeatureActions = false
|
||||
|
||||
var body: some View {
|
||||
NavigationLink(destination: EmptyView()) {
|
||||
NavigationLink(destination: LinkItemDetailView(
|
||||
linkedItemObjectID: item.objectID,
|
||||
isPDF: item.isPDF
|
||||
)) {
|
||||
LibraryFeatureCard(item: item, viewer: dataService.currentViewer)
|
||||
}
|
||||
.confirmationDialog("", isPresented: $showFeatureActions) {
|
||||
|
|
|
|||
|
|
@ -159,8 +159,8 @@ struct AnimatingCellHeight: AnimatableModifier {
|
|||
guard let objectID = dataService.persist(jsonArticle: jsonArticle) else { return }
|
||||
guard let linkedItem = dataService.viewContext.object(with: objectID) as? LinkedItem else { return }
|
||||
viewModel.pushFeedItem(item: linkedItem)
|
||||
// viewModel.selectedItem = linkedItem
|
||||
// viewModel.linkIsActive = true
|
||||
viewModel.selectedItem = linkedItem
|
||||
viewModel.linkIsActive = true
|
||||
}
|
||||
.onOpenURL { url in
|
||||
viewModel.linkRequest = nil
|
||||
|
|
@ -228,6 +228,19 @@ struct AnimatingCellHeight: AnimatableModifier {
|
|||
|
||||
var body: some View {
|
||||
VStack(spacing: 0) {
|
||||
if let linkRequest = viewModel.linkRequest {
|
||||
NavigationLink(
|
||||
destination: WebReaderLoadingContainer(requestID: linkRequest.serverID),
|
||||
tag: linkRequest,
|
||||
selection: $viewModel.linkRequest
|
||||
) {
|
||||
EmptyView()
|
||||
}
|
||||
}
|
||||
NavigationLink(destination: LinkDestination(selectedItem: viewModel.selectedItem), isActive: $viewModel.linkIsActive) {
|
||||
EmptyView()
|
||||
}
|
||||
|
||||
if prefersListLayout || !enableGrid {
|
||||
HomeFeedListView(listTitle: $listTitle, isListScrolled: $isListScrolled, prefersListLayout: $prefersListLayout, viewModel: viewModel)
|
||||
} else {
|
||||
|
|
@ -702,7 +715,7 @@ struct AnimatingCellHeight: AnimatableModifier {
|
|||
.padding(.leading, 16)
|
||||
.padding(.bottom, 25)
|
||||
|
||||
LazyVGrid(columns: [GridItem(.adaptive(minimum: 325), spacing: 16)], alignment: .leading, spacing: 16) {
|
||||
LazyVGrid(columns: [GridItem(.adaptive(minimum: 325, maximum: 400), spacing: 16)], alignment: .center, spacing: 30) {
|
||||
ForEach(viewModel.items) { item in
|
||||
GridCardNavigationLink(
|
||||
item: item,
|
||||
|
|
@ -710,9 +723,9 @@ struct AnimatingCellHeight: AnimatableModifier {
|
|||
isContextMenuOpen: $isContextMenuOpen,
|
||||
viewModel: viewModel
|
||||
)
|
||||
.contextMenu {
|
||||
libraryItemMenu(dataService: dataService, viewModel: viewModel, item: item)
|
||||
}
|
||||
// .contextMenu {
|
||||
// libraryItemMenu(dataService: dataService, viewModel: viewModel, item: item)
|
||||
// }
|
||||
}
|
||||
Spacer()
|
||||
}
|
||||
|
|
|
|||
|
|
@ -27,7 +27,7 @@ import Views
|
|||
@Published var appliedSort = LinkedItemSort.newest.rawValue
|
||||
|
||||
@Published var selectedLinkItem: NSManagedObjectID? // used by mac app only
|
||||
// @Published var selectedItem: LinkedItem?
|
||||
@Published var selectedItem: LinkedItem?
|
||||
@Published var linkIsActive = false
|
||||
|
||||
@Published var showLabelsSheet = false
|
||||
|
|
|
|||
|
|
@ -43,50 +43,14 @@ struct LibraryTabView: View {
|
|||
)
|
||||
|
||||
var body: some View {
|
||||
NavigationView {
|
||||
// ZStack {
|
||||
// NavigationLink(
|
||||
// destination: LinkDestination(selectedItem: libraryViewModel.selectedItem),
|
||||
// isActive: $libraryViewModel.linkIsActive
|
||||
// ) {
|
||||
// EmptyView()
|
||||
// }
|
||||
// TabView(selection: $selection) {
|
||||
// BriefingView(
|
||||
// articleId: "98e017a3-79d5-4049-97bc-ff170153792a"
|
||||
// )
|
||||
// .tabItem {
|
||||
// Label {
|
||||
// Text("Your Briefing")
|
||||
// } icon: {
|
||||
// Image.tabBriefing.padding(.trailing, 5)
|
||||
// }
|
||||
// }.tag(0)
|
||||
|
||||
HomeView(viewModel: libraryViewModel)
|
||||
// .tabItem {
|
||||
// Label {
|
||||
// Text("Library")
|
||||
// } icon: {
|
||||
// Image.tabLibrary
|
||||
// }
|
||||
// }.tag(1)
|
||||
|
||||
// HomeView(viewModel: highlightsViewModel)
|
||||
// .tabItem {
|
||||
// Label {
|
||||
// Text("Highlights")
|
||||
// } icon: {
|
||||
// Image.tabHighlights
|
||||
// }
|
||||
// }.tag(2)
|
||||
// }
|
||||
if #available(iOS 16.0, *) {
|
||||
NavigationView {
|
||||
HomeView(viewModel: libraryViewModel)
|
||||
.navigationBarHidden(false)
|
||||
}
|
||||
} else {
|
||||
// Fallback on earlier versions
|
||||
EmptyView()
|
||||
}
|
||||
// }.introspectNavigationController { controller in
|
||||
// print("INTROSPECTING CONTROLLER: ", controller.transitionCoordinator)
|
||||
// controller.transitionCoordinator?.notifyWhenInteractionChanges { context in
|
||||
// print("interaction changed: ", context)
|
||||
// }
|
||||
// }
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -89,15 +89,15 @@ struct LinkItemDetailView: View {
|
|||
pdfContainerView
|
||||
} else if let item = viewModel.item {
|
||||
WebReaderContainerView(item: item, pop: { dismiss() })
|
||||
.navigationBarHidden(true)
|
||||
.lazyPop(pop: {
|
||||
dismiss()
|
||||
}, isEnabled: $isEnabled)
|
||||
}
|
||||
}
|
||||
.task {
|
||||
await viewModel.loadItem(linkedItemObjectID: linkedItemObjectID, dataService: dataService)
|
||||
}
|
||||
.navigationBarHidden(true)
|
||||
.lazyPop(pop: {
|
||||
dismiss()
|
||||
}, isEnabled: $isEnabled)
|
||||
}
|
||||
|
||||
@ViewBuilder private var pdfContainerView: some View {
|
||||
|
|
@ -117,30 +117,3 @@ struct LinkItemDetailView: View {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// #if os(iOS)
|
||||
// // Enable swipe to go back behavior if nav bar is hidden
|
||||
// extension UINavigationController: UIGestureRecognizerDelegate, UINavigationControllerDelegate {
|
||||
// override open func viewDidLoad() {
|
||||
// super.viewDidLoad()
|
||||
// print("INIT: ", viewControllers)
|
||||
// delegate = self
|
||||
// interactivePopGestureRecognizer?.delegate = nil
|
||||
// }
|
||||
////
|
||||
//// public func gestureRecognizerShouldBegin(_ gesture: UIGestureRecognizer) -> Bool {
|
||||
//// print("SHOULD BEGIN: ", viewControllers, gesture)
|
||||
//// return viewControllers.count > 1
|
||||
//// }
|
||||
////
|
||||
//// public func navigationController(_ navigationController: UINavigationController, willShow _: UIViewController, animated _: Bool) {
|
||||
//// navigationController.transitionCoordinator?.notifyWhenInteractionChanges { context in
|
||||
//// print("DID SHOW CONTEXT: ", context.percentComplete, navigationController.viewControllers)
|
||||
//// navigationController.interactivePopGestureRecognizer?.delegate = nil
|
||||
//// navigationController.popToRootViewController(animated: false)
|
||||
//// // interactivePopGestureRecognizer.
|
||||
//// }
|
||||
//// }
|
||||
// }
|
||||
// #endif
|
||||
|
|
|
|||
|
|
@ -49,22 +49,22 @@ struct InnerRootView: View {
|
|||
|
||||
@ViewBuilder private var innerBody: some View {
|
||||
if authenticator.isLoggedIn {
|
||||
GeometryReader { geo in
|
||||
PrimaryContentView()
|
||||
#if os(iOS)
|
||||
.miniPlayer()
|
||||
.formSheet(isPresented: $viewModel.showNewFeaturePrimer,
|
||||
modalSize: CGSize(width: geo.size.width * 0.66, height: geo.size.width * 0.66)) {
|
||||
FeaturePrimer.recommendationsPrimer
|
||||
}
|
||||
.onAppear {
|
||||
DispatchQueue.main.asyncAfter(deadline: .now() + .milliseconds(300)) {
|
||||
viewModel.showNewFeaturePrimer = viewModel.shouldShowNewFeaturePrimer
|
||||
viewModel.shouldShowNewFeaturePrimer = false
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
// GeometryReader { geo in
|
||||
PrimaryContentView()
|
||||
// #if os(iOS)
|
||||
// .miniPlayer()
|
||||
// .formSheet(isPresented: $viewModel.showNewFeaturePrimer,
|
||||
// modalSize: CGSize(width: geo.size.width * 0.66, height: geo.size.width * 0.66)) {
|
||||
// FeaturePrimer.recommendationsPrimer
|
||||
// }
|
||||
// .onAppear {
|
||||
// DispatchQueue.main.asyncAfter(deadline: .now() + .milliseconds(300)) {
|
||||
// viewModel.showNewFeaturePrimer = viewModel.shouldShowNewFeaturePrimer
|
||||
// viewModel.shouldShowNewFeaturePrimer = false
|
||||
// }
|
||||
// }
|
||||
// #endif
|
||||
// }
|
||||
} else {
|
||||
WelcomeView()
|
||||
.accessibilityElement()
|
||||
|
|
|
|||
|
|
@ -121,7 +121,11 @@ class SwipeRightToPopViewController<Content>: UIHostingController<Content>, UINa
|
|||
from _: UIViewController,
|
||||
to _: UIViewController) -> UIViewControllerAnimatedTransitioning?
|
||||
{
|
||||
SlideAnimatedTransitioning()
|
||||
if #available(iOS 17.0, *) {
|
||||
return nil
|
||||
} else {
|
||||
return SlideAnimatedTransitioning()
|
||||
}
|
||||
}
|
||||
|
||||
func navigationController(_: UINavigationController,
|
||||
|
|
@ -129,7 +133,7 @@ class SwipeRightToPopViewController<Content>: UIHostingController<Content>, UINa
|
|||
-> UIViewControllerInteractiveTransitioning?
|
||||
{
|
||||
parentNavigationControllerToUse?.delegate = nil
|
||||
// navigationController.delegate = nil
|
||||
// navigationController.delegate = nil
|
||||
|
||||
if panGestureRecognizer.state == .began {
|
||||
percentDrivenInteractiveTransition = UIPercentDrivenInteractiveTransition()
|
||||
|
|
|
|||
|
|
@ -34,8 +34,11 @@ import Views
|
|||
public struct WebReaderLoadingContainer: View {
|
||||
let requestID: String
|
||||
|
||||
@Environment(\.dismiss) private var dismiss
|
||||
@EnvironmentObject var dataService: DataService
|
||||
@EnvironmentObject var audioController: AudioController
|
||||
|
||||
@State var lazyPopIsEnabled = true
|
||||
@StateObject var viewModel = WebReaderLoadingContainerViewModel()
|
||||
|
||||
public var body: some View {
|
||||
|
|
@ -53,9 +56,11 @@ public struct WebReaderLoadingContainer: View {
|
|||
}
|
||||
#endif
|
||||
} else {
|
||||
WebReaderContainerView(item: item, pop: {})
|
||||
WebReaderContainerView(item: item, pop: { dismiss() })
|
||||
#if os(iOS)
|
||||
.navigationViewStyle(.stack)
|
||||
.navigationBarHidden(true)
|
||||
.lazyPop(pop: { dismiss() }, isEnabled: $lazyPopIsEnabled)
|
||||
#endif
|
||||
.accentColor(.appGrayTextContrast)
|
||||
.task { viewModel.trackReadEvent() }
|
||||
|
|
|
|||
|
|
@ -69,20 +69,67 @@ public struct GridCard: View {
|
|||
}
|
||||
}
|
||||
|
||||
var imageBox: some View {
|
||||
GeometryReader { geo in
|
||||
|
||||
ZStack(alignment: .bottomLeading) {
|
||||
if let imageURL = item.imageURL {
|
||||
AsyncImage(url: imageURL) { phase in
|
||||
switch phase {
|
||||
case .empty:
|
||||
Color.systemBackground
|
||||
.frame(maxWidth: .infinity, maxHeight: geo.size.height)
|
||||
case let .success(image):
|
||||
image.resizable()
|
||||
.resizable()
|
||||
.scaledToFill()
|
||||
.frame(maxWidth: .infinity, maxHeight: geo.size.height)
|
||||
.clipped()
|
||||
case .failure:
|
||||
fallbackImage
|
||||
|
||||
@unknown default:
|
||||
// Since the AsyncImagePhase enum isn't frozen,
|
||||
// we need to add this currently unused fallback
|
||||
// to handle any new cases that might be added
|
||||
// in the future:
|
||||
Color.systemBackground
|
||||
.frame(maxWidth: .infinity, maxHeight: geo.size.height)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
fallbackImage
|
||||
}
|
||||
Color(hex: "#D9D9D9")?.opacity(0.65).frame(width: geo.size.width, height: 5)
|
||||
Color(hex: "#FFD234").frame(width: geo.size.width * (item.readingProgress / 100), height: 5)
|
||||
}
|
||||
}
|
||||
.cornerRadius(5)
|
||||
}
|
||||
|
||||
var fallbackImage: some View {
|
||||
GeometryReader { geo in
|
||||
HStack {
|
||||
Text(item.unwrappedTitle.prefix(1))
|
||||
.font(Font.system(size: 128, weight: .bold))
|
||||
.offset(CGSize(width: -48, height: 12))
|
||||
.frame(alignment: .bottomLeading)
|
||||
.foregroundColor(Gradient.randomColor(str: item.unwrappedTitle, offset: 1))
|
||||
}
|
||||
.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: geo.size.width, height: geo.size.height)
|
||||
}
|
||||
}
|
||||
|
||||
public var body: some View {
|
||||
GeometryReader { geo in
|
||||
VStack(alignment: .leading, spacing: 0) {
|
||||
// Progress Bar
|
||||
Group {
|
||||
ProgressView(value: min(abs(item.readingProgress) / 100, 1))
|
||||
.tint(.appYellow48)
|
||||
.frame(maxWidth: .infinity, alignment: .leading)
|
||||
.padding(.bottom, 16)
|
||||
}
|
||||
// .onTapGesture { tapHandler() }
|
||||
|
||||
VStack {
|
||||
// Title, Subtitle, Menu Button
|
||||
imageBox
|
||||
.frame(height: geo.size.height / 2.0)
|
||||
|
||||
VStack(alignment: .leading, spacing: 4) {
|
||||
HStack {
|
||||
Text(item.unwrappedTitle)
|
||||
|
|
@ -111,8 +158,9 @@ public struct GridCard: View {
|
|||
// .onTapGesture { tapHandler() }
|
||||
}
|
||||
.frame(height: 30)
|
||||
.padding(.horizontal)
|
||||
.padding(.bottom, 16)
|
||||
.padding(.horizontal, 10)
|
||||
.padding(.bottom, 10)
|
||||
.padding(.top, 10)
|
||||
|
||||
// Link description and image
|
||||
HStack(alignment: .top) {
|
||||
|
|
@ -123,27 +171,8 @@ public struct GridCard: View {
|
|||
.multilineTextAlignment(.leading)
|
||||
|
||||
Spacer()
|
||||
|
||||
if let imageURL = item.imageURL {
|
||||
AsyncImage(url: imageURL) { phase in
|
||||
if let image = phase.image {
|
||||
image
|
||||
.resizable()
|
||||
.aspectRatio(contentMode: .fill)
|
||||
.frame(width: geo.size.width / 3, height: (geo.size.width * 2) / 9)
|
||||
.cornerRadius(3)
|
||||
} else if phase.error != nil {
|
||||
EmptyView()
|
||||
} else {
|
||||
Color.appButtonBackground
|
||||
.frame(width: geo.size.width / 3, height: (geo.size.width * 2) / 9)
|
||||
.cornerRadius(3)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
.padding(.horizontal)
|
||||
// .onTapGesture { tapHandler() }
|
||||
.padding(.horizontal, 10)
|
||||
|
||||
// Category Labels
|
||||
if item.hasLabels {
|
||||
|
|
@ -154,7 +183,7 @@ public struct GridCard: View {
|
|||
}
|
||||
Spacer()
|
||||
}
|
||||
.padding(.horizontal)
|
||||
.padding(.horizontal, 10)
|
||||
}
|
||||
// .onTapGesture { tapHandler() }
|
||||
}
|
||||
|
|
@ -165,7 +194,6 @@ public struct GridCard: View {
|
|||
}
|
||||
.padding(.horizontal, 0)
|
||||
.padding(.top, 0)
|
||||
.padding(.bottom, 8)
|
||||
}
|
||||
.contextMenu { contextMenuView }
|
||||
}
|
||||
|
|
|
|||
|
|
@ -149,7 +149,7 @@ public struct LibraryItemCard: View {
|
|||
}
|
||||
|
||||
var imageBox: some View {
|
||||
Group {
|
||||
ZStack(alignment: .bottomLeading) {
|
||||
if let imageURL = item.imageURL {
|
||||
AsyncImage(url: imageURL) { phase in
|
||||
if let image = phase.image {
|
||||
|
|
@ -166,8 +166,24 @@ public struct LibraryItemCard: View {
|
|||
.padding(.top, 2)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
fallbackImage
|
||||
}
|
||||
}
|
||||
.cornerRadius(5)
|
||||
}
|
||||
|
||||
var fallbackImage: some View {
|
||||
HStack {
|
||||
Text(item.unwrappedTitle.prefix(1))
|
||||
.font(Font.system(size: 32, weight: .bold))
|
||||
.frame(alignment: .bottomLeading)
|
||||
.foregroundColor(Gradient.randomColor(str: item.unwrappedTitle, offset: 1))
|
||||
}
|
||||
.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)
|
||||
}
|
||||
|
||||
var bylineStr: String {
|
||||
|
|
|
|||
|
|
@ -1,12 +1,12 @@
|
|||
#if os(iOS)
|
||||
|
||||
import UIKit
|
||||
|
||||
extension UINavigationController {
|
||||
// Remove back button text
|
||||
override open func viewWillLayoutSubviews() {
|
||||
navigationBar.topItem?.backButtonDisplayMode = .minimal
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
// #if os(iOS)
|
||||
//
|
||||
// import UIKit
|
||||
//
|
||||
// extension UINavigationController {
|
||||
// // Remove back button text
|
||||
// override open func viewWillLayoutSubviews() {
|
||||
// navigationBar.topItem?.backButtonDisplayMode = .minimal
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// #endif
|
||||
|
|
|
|||
Loading…
Reference in a new issue