- Fixed the grid view not changing with the theme.
- Fixed a gap at the top of the story view.
- Fixed a crash in some situations due to not loading the view.
- Fixed grid layout glitch returning to the grid view from the stories view.
- Swipe left on grid card to mark read; swipe right to mark unread.
- Added support for disabling mark read on scroll.
This commit is contained in:
David Sinclair 2023-06-15 21:53:00 -07:00
parent 73dbc805d8
commit a2341690b4
7 changed files with 89 additions and 24 deletions

View file

@ -397,18 +397,27 @@ class DetailViewController: BaseViewController {
} }
} }
adjustTopConstraint() coordinator.animate { context in
self.adjustTopConstraint()
}
} }
private func adjustTopConstraint() { private func adjustTopConstraint() {
guard let scene = view.window?.windowScene else {
return
}
if !isPhone { if !isPhone {
if view.window?.windowScene?.traitCollection.horizontalSizeClass == .compact { if scene.traitCollection.horizontalSizeClass == .compact {
topContainerTopConstraint.constant = -50 topContainerTopConstraint.constant = -50
} else { } else {
topContainerTopConstraint.constant = 0 topContainerTopConstraint.constant = 0
} }
} else if let controller = storyPagesViewController, !controller.isNavigationBarHidden { } else if let controller = storyPagesViewController, !controller.isNavigationBarHidden {
topContainerTopConstraint.constant = -44 let navigationHeight = navigationController?.navigationBar.frame.height ?? 0
let adjustment: CGFloat = view.safeAreaInsets.top > 25 ? 5 : 0
topContainerTopConstraint.constant = -(navigationHeight - adjustment)
} else { } else {
topContainerTopConstraint.constant = 0 topContainerTopConstraint.constant = 0
} }

View file

@ -53,6 +53,9 @@ struct CardView: View {
} }
} }
.opacity(story.isRead ? 0.7 : 1) .opacity(story.isRead ? 0.7 : 1)
// .overlay( RoundedRectangle(cornerRadius: 10)
// .opacity(story.isRead ? 0.2 : 0)
// .animation(.spring()) )
.if(cache.isGrid || story.isSelected) { view in .if(cache.isGrid || story.isSelected) { view in
view.clipShape(RoundedRectangle(cornerRadius: 10)) view.clipShape(RoundedRectangle(cornerRadius: 10))
} }

View file

@ -13,12 +13,14 @@ protocol FeedDetailInteraction {
var storyHeight: CGFloat { get } var storyHeight: CGFloat { get }
var hasNoMoreStories: Bool { get } var hasNoMoreStories: Bool { get }
var isPremiumRestriction: Bool { get } var isPremiumRestriction: Bool { get }
var isMarkReadOnScroll: Bool { get }
func pullToRefresh() func pullToRefresh()
func visible(story: Story) func visible(story: Story)
func tapped(story: Story) func tapped(story: Story)
func reading(story: Story) func reading(story: Story)
func read(story: Story) func read(story: Story)
func unread(story: Story)
func hid(story: Story) func hid(story: Story)
} }
@ -63,23 +65,40 @@ struct FeedDetailGridView: View {
ScrollView { ScrollView {
ScrollViewReader { scroller in ScrollViewReader { scroller in
LazyVGrid(columns: columns, spacing: cache.isGrid ? 20 : 0) { LazyVGrid(columns: columns, spacing: cache.isGrid ? 20 : 0) {
Section { if cache.isPhone {
ForEach(cache.before, id: \.id) { story in Section(footer: makeLoadingView()) {
makeCardView(for: story, reader: reader) ForEach(cache.before, id: \.id) { story in
makeCardView(for: story, reader: reader)
}
if let story = cache.selected {
makeCardView(for: story, reader: reader)
.id(story.id)
}
ForEach(cache.after, id: \.id) { story in
makeCardView(for: story, reader: reader)
}
} }
} } else {
Section {
if cache.isGrid && !cache.isPhone { ForEach(cache.before, id: \.id) { story in
EmptyView() makeCardView(for: story, reader: reader)
.id(storyViewID) }
} else if let story = cache.selected { }
makeCardView(for: story, reader: reader)
.id(story.id) if cache.isGrid && !cache.isPhone {
} EmptyView()
.id(storyViewID)
Section(header: makeStoryView(), footer: makeLoadingView()) { } else if let story = cache.selected {
ForEach(cache.after, id: \.id) { story in
makeCardView(for: story, reader: reader) makeCardView(for: story, reader: reader)
.id(story.id)
}
Section(header: makeStoryView(), footer: makeLoadingView()) {
ForEach(cache.after, id: \.id) { story in
makeCardView(for: story, reader: reader)
}
} }
} }
} }
@ -134,10 +153,12 @@ struct FeedDetailGridView: View {
.onPreferenceChange(CardKey.self) { .onPreferenceChange(CardKey.self) {
print("pref change for '\(story.title)': \($0)") print("pref change for '\(story.title)': \($0)")
if let value = $0.first, value.frame.minY < -(value.frame.size.height / 2) { if feedDetailInteraction.isMarkReadOnScroll, let value = $0.first, value.frame.minY < -(value.frame.size.height / 2) {
print("pref '\(story.title)': scrolled off the top") print("pref '\(story.title)': scrolled off the top")
feedDetailInteraction.read(story: story) // withAnimation(Animation.spring().delay(2)) {
feedDetailInteraction.read(story: story)
// }
} }
} }
.onAppear { .onAppear {
@ -146,6 +167,19 @@ struct FeedDetailGridView: View {
.if(cache.isGrid) { view in .if(cache.isGrid) { view in
view.frame(height: cardHeight) view.frame(height: cardHeight)
} }
.gesture(DragGesture(minimumDistance: 50.0, coordinateSpace: .local)
.onEnded { value in
switch(value.translation.width, value.translation.height) {
case (...0, -30...30):
feedDetailInteraction.read(story: story)
case (0..., -30...30):
feedDetailInteraction.unread(story: story)
// case (-100...100, ...0): print("up swipe")
// case (-100...100, 0...): print("down swipe")
default: break
}
}
)
} }
@ViewBuilder @ViewBuilder

View file

@ -58,6 +58,7 @@
//@property (nonatomic, readonly) NSIndexPath *selectedIndexPath; //@property (nonatomic, readonly) NSIndexPath *selectedIndexPath;
@property (nonatomic) CGFloat storyHeight; @property (nonatomic) CGFloat storyHeight;
@property (nonatomic, readonly) BOOL canPullToRefresh; @property (nonatomic, readonly) BOOL canPullToRefresh;
@property (nonatomic, readonly) BOOL isMarkReadOnScroll;
@property (nonatomic, readonly) BOOL isLegacyTable; @property (nonatomic, readonly) BOOL isLegacyTable;
@property (nonatomic, readwrite) BOOL pageFetching; @property (nonatomic, readwrite) BOOL pageFetching;

View file

@ -55,7 +55,6 @@ typedef NS_ENUM(NSUInteger, FeedSection)
@property (nonatomic) NSInteger oldLocation; @property (nonatomic) NSInteger oldLocation;
@property (nonatomic) NSUInteger scrollingMarkReadRow; @property (nonatomic) NSUInteger scrollingMarkReadRow;
@property (nonatomic, readonly) BOOL isMarkReadOnScroll;
@property (readwrite) BOOL inPullToRefresh_; @property (readwrite) BOOL inPullToRefresh_;
@property (nonatomic, strong) NSString *restoringFolder; @property (nonatomic, strong) NSString *restoringFolder;
@property (nonatomic, strong) NSString *restoringFeedID; @property (nonatomic, strong) NSString *restoringFeedID;
@ -3073,7 +3072,8 @@ didEndSwipingSwipingWithState:(MCSwipeTableViewCellState)state
self.view.backgroundColor = UIColorFromRGB(0xf4f4f4); self.view.backgroundColor = UIColorFromRGB(0xf4f4f4);
self.storyTitlesTable.backgroundColor = UIColorFromRGB(0xf4f4f4); self.storyTitlesTable.backgroundColor = UIColorFromRGB(0xf4f4f4);
self.storyTitlesTable.separatorColor = UIColorFromRGB(0xE9E8E4); self.storyTitlesTable.separatorColor = UIColorFromRGB(0xE9E8E4);
[self.storyTitlesTable reloadData];
[self reload];
} }
#pragma mark - #pragma mark -

View file

@ -129,6 +129,9 @@ class FeedDetailViewController: FeedDetailObjCViewController {
// //
// feedCollectionView.setNeedsLayout() // feedCollectionView.setNeedsLayout()
// Make sure the view has loaded.
_ = view
storyTitlesTable.isHidden = !isLegacyTable storyTitlesTable.isHidden = !isLegacyTable
gridViewController.view.isHidden = isLegacyTable gridViewController.view.isHidden = isLegacyTable
@ -413,6 +416,21 @@ extension FeedDetailViewController: FeedDetailInteraction {
} }
} }
func unread(story: Story) {
let dict = story.dictionary
if !storiesCollection.isStoryUnread(dict) {
print("marking as unread '\(story.title)'")
storiesCollection.markStoryUnread(dict)
storiesCollection.syncStory(asRead: dict)
story.load()
deferredReload()
}
}
func hid(story: Story) { func hid(story: Story) {
print("hiding \(story.title)") print("hiding \(story.title)")

View file

@ -3,7 +3,7 @@
<device id="ipad11_0rounded" orientation="landscape" layout="fullscreen" appearance="light"/> <device id="ipad11_0rounded" orientation="landscape" layout="fullscreen" appearance="light"/>
<dependencies> <dependencies>
<deployment identifier="iOS"/> <deployment identifier="iOS"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="21678"/> <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="21679"/>
<capability name="Safe area layout guides" minToolsVersion="9.0"/> <capability name="Safe area layout guides" minToolsVersion="9.0"/>
<capability name="System colors in document resources" minToolsVersion="11.0"/> <capability name="System colors in document resources" minToolsVersion="11.0"/>
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/> <capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
@ -349,7 +349,7 @@
</connections> </connections>
</tableView> </tableView>
<view hidden="YES" opaque="NO" contentMode="scaleToFill" insetsLayoutMarginsFromSafeArea="NO" translatesAutoresizingMaskIntoConstraints="NO" id="ZLP-oU-XR7"> <view hidden="YES" opaque="NO" contentMode="scaleToFill" insetsLayoutMarginsFromSafeArea="NO" translatesAutoresizingMaskIntoConstraints="NO" id="ZLP-oU-XR7">
<rect key="frame" x="0.0" y="279.5" width="375" height="181"/> <rect key="frame" x="0.0" y="212.5" width="375" height="181"/>
<subviews> <subviews>
<imageView userInteractionEnabled="NO" alpha="0.40000000596046448" contentMode="scaleToFill" image="big_world.png" translatesAutoresizingMaskIntoConstraints="NO" id="Lzk-2I-zT1"> <imageView userInteractionEnabled="NO" alpha="0.40000000596046448" contentMode="scaleToFill" image="big_world.png" translatesAutoresizingMaskIntoConstraints="NO" id="Lzk-2I-zT1">
<rect key="frame" x="155.5" y="24" width="64" height="64"/> <rect key="frame" x="155.5" y="24" width="64" height="64"/>