Skip to content

Commit

Permalink
Pro tem tab reselection (mlemgroup#769)
Browse files Browse the repository at this point in the history
  • Loading branch information
EricBAndrews authored Nov 21, 2023
1 parent baa54a8 commit 35cdbfe
Show file tree
Hide file tree
Showing 11 changed files with 111 additions and 129 deletions.
12 changes: 8 additions & 4 deletions Mlem.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -375,6 +375,8 @@
CD4368DB2AE247B700BD8BD1 /* MentionTracker.swift in Sources */ = {isa = PBXBuildFile; fileRef = CD4368DA2AE247B700BD8BD1 /* MentionTracker.swift */; };
CD4368DD2AE24E1A00BD8BD1 /* InboxView+Logic.swift in Sources */ = {isa = PBXBuildFile; fileRef = CD4368DC2AE24E1A00BD8BD1 /* InboxView+Logic.swift */; };
CD45BCEE2A75CA7200A2899C /* Thumbnail Image View.swift in Sources */ = {isa = PBXBuildFile; fileRef = CD45BCED2A75CA7200A2899C /* Thumbnail Image View.swift */; };
CD46C1F62B0D0A5700065953 /* FancyTabBarReselectionEnvironmentKey.swift in Sources */ = {isa = PBXBuildFile; fileRef = CD46C1F52B0D0A5700065953 /* FancyTabBarReselectionEnvironmentKey.swift */; };
CD46C1F82B0D0A8A00065953 /* View+TabReselectionConsumer.swift in Sources */ = {isa = PBXBuildFile; fileRef = CD46C1F72B0D0A8A00065953 /* View+TabReselectionConsumer.swift */; };
CD4DBC032A6F803C001A1E61 /* ReplyToPost.swift in Sources */ = {isa = PBXBuildFile; fileRef = CD4DBC022A6F803C001A1E61 /* ReplyToPost.swift */; };
CD4E98A12A69BE980026C4D9 /* AlternativeIconCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = CD4E98A02A69BE980026C4D9 /* AlternativeIconCell.swift */; };
CD4E98A32A69BEDC0026C4D9 /* IconSettingsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = CD4E98A22A69BEDC0026C4D9 /* IconSettingsView.swift */; };
Expand Down Expand Up @@ -498,7 +500,6 @@
E49E01F42ABD99D300E42BB3 /* Routable.swift in Sources */ = {isa = PBXBuildFile; fileRef = E49E01F32ABD99D300E42BB3 /* Routable.swift */; };
E49F0E762A90395400BC4EE3 /* NavigationPath+Helpers.swift in Sources */ = {isa = PBXBuildFile; fileRef = E49F0E752A90395400BC4EE3 /* NavigationPath+Helpers.swift */; };
E4D4DBA02A7C7B9D00C4F3DE /* Comments.swift in Sources */ = {isa = PBXBuildFile; fileRef = E4D4DB9F2A7C7B9D00C4F3DE /* Comments.swift */; };
E4D4DBA22A7F233200C4F3DE /* FancyTabNavigationSelectionHashValueEnvironmentKey.swift in Sources */ = {isa = PBXBuildFile; fileRef = E4D4DBA12A7F233200C4F3DE /* FancyTabNavigationSelectionHashValueEnvironmentKey.swift */; };
E4DDB4322A81819300B3A7E0 /* Double.swift in Sources */ = {isa = PBXBuildFile; fileRef = E4DDB4312A81819300B3A7E0 /* Double.swift */; };
E4DDB4342A819C8000B3A7E0 /* QuickLookView.swift in Sources */ = {isa = PBXBuildFile; fileRef = E4DDB4332A819C8000B3A7E0 /* QuickLookView.swift */; };
E4F0B56F2ABD00A000BC3E4A /* PresentationBackgroundInteraction.swift in Sources */ = {isa = PBXBuildFile; fileRef = E4F0B56E2ABD00A000BC3E4A /* PresentationBackgroundInteraction.swift */; };
Expand Down Expand Up @@ -888,6 +889,8 @@
CD4368DA2AE247B700BD8BD1 /* MentionTracker.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MentionTracker.swift; sourceTree = "<group>"; };
CD4368DC2AE24E1A00BD8BD1 /* InboxView+Logic.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "InboxView+Logic.swift"; sourceTree = "<group>"; };
CD45BCED2A75CA7200A2899C /* Thumbnail Image View.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Thumbnail Image View.swift"; sourceTree = "<group>"; };
CD46C1F52B0D0A5700065953 /* FancyTabBarReselectionEnvironmentKey.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FancyTabBarReselectionEnvironmentKey.swift; sourceTree = "<group>"; };
CD46C1F72B0D0A8A00065953 /* View+TabReselectionConsumer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "View+TabReselectionConsumer.swift"; sourceTree = "<group>"; };
CD4DBC022A6F803C001A1E61 /* ReplyToPost.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReplyToPost.swift; sourceTree = "<group>"; };
CD4E98A02A69BE980026C4D9 /* AlternativeIconCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = AlternativeIconCell.swift; path = Mlem/Extensions/AlternativeIconCell.swift; sourceTree = SOURCE_ROOT; };
CD4E98A22A69BEDC0026C4D9 /* IconSettingsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = IconSettingsView.swift; path = Mlem/Extensions/IconSettingsView.swift; sourceTree = SOURCE_ROOT; };
Expand Down Expand Up @@ -1011,7 +1014,6 @@
E49E01F32ABD99D300E42BB3 /* Routable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Routable.swift; sourceTree = "<group>"; };
E49F0E752A90395400BC4EE3 /* NavigationPath+Helpers.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "NavigationPath+Helpers.swift"; sourceTree = "<group>"; };
E4D4DB9F2A7C7B9D00C4F3DE /* Comments.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Comments.swift; sourceTree = "<group>"; };
E4D4DBA12A7F233200C4F3DE /* FancyTabNavigationSelectionHashValueEnvironmentKey.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FancyTabNavigationSelectionHashValueEnvironmentKey.swift; sourceTree = "<group>"; };
E4DDB4312A81819300B3A7E0 /* Double.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Double.swift; sourceTree = "<group>"; };
E4DDB4332A819C8000B3A7E0 /* QuickLookView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = QuickLookView.swift; sourceTree = "<group>"; };
E4F0B56E2ABD00A000BC3E4A /* PresentationBackgroundInteraction.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PresentationBackgroundInteraction.swift; sourceTree = "<group>"; };
Expand Down Expand Up @@ -2158,6 +2160,7 @@
isa = PBXGroup;
children = (
CD18243F2AA8E24100D9BEB5 /* View+DestructiveConfirmation.swift */,
CD46C1F72B0D0A8A00065953 /* View+TabReselectionConsumer.swift */,
);
path = "View Modifiers";
sourceTree = "<group>";
Expand Down Expand Up @@ -2411,12 +2414,12 @@
CDDCF6422A66343D003DA3AC /* FancyTabBar.swift */,
CDDCF6442A66375E003DA3AC /* FancyTabItemViewModifier.swift */,
CDDCF6462A663849003DA3AC /* FancyTabBarSelectionEnvironmentKey.swift */,
E4D4DBA12A7F233200C4F3DE /* FancyTabNavigationSelectionHashValueEnvironmentKey.swift */,
CDDCF6482A6641F0003DA3AC /* FancyTabItemLabelBuilder.swift */,
CDDCF64E2A672C0A003DA3AC /* FancyTabBarLabel.swift */,
CDDCF6502A677E1B003DA3AC /* FancyTabItemPreferenceKeys.swift */,
CDDCF6562A678298003DA3AC /* FancyTabBarSelection.swift */,
CD863FB92A6AEB5900A31ED9 /* TabSafeScrollView.swift */,
CD46C1F52B0D0A5700065953 /* FancyTabBarReselectionEnvironmentKey.swift */,
);
path = "Custom Tab Bar";
sourceTree = "<group>";
Expand Down Expand Up @@ -2871,7 +2874,6 @@
03EC92992AC0BF8A007BBE7E /* APIClient+Pictrs.swift in Sources */,
6372186C2A3A2AAD008C4816 /* SaveComment.swift in Sources */,
CD4368B62AE23F4700BD8BD1 /* ParentTracker.swift in Sources */,
E4D4DBA22A7F233200C4F3DE /* FancyTabNavigationSelectionHashValueEnvironmentKey.swift in Sources */,
6DD8677A2A5083A200BEB00F /* Community Sidebar Link.swift in Sources */,
03C898032AC04F61005F3403 /* RecentSearchesView.swift in Sources */,
50811B382A920545006BA3F2 /* APICommunityModeratorView+Mock.swift in Sources */,
Expand Down Expand Up @@ -2913,6 +2915,7 @@
504106CD2A744D7F000AAEF8 /* CommentRepository+Dependency.swift in Sources */,
6372186F2A3A2AAD008C4816 /* SearchRequest.swift in Sources */,
03EC92952AC064AE007BBE7E /* SearchHomeView.swift in Sources */,
CD46C1F62B0D0A5700065953 /* FancyTabBarReselectionEnvironmentKey.swift in Sources */,
50811B362A920519006BA3F2 /* APISite+Mock.swift in Sources */,
503422562AAB784000EFE88D /* Environment+AppFlow.swift in Sources */,
CDDCF6512A677E1B003DA3AC /* FancyTabItemPreferenceKeys.swift in Sources */,
Expand Down Expand Up @@ -2986,6 +2989,7 @@
B14E93C02A45CA3400D6DA93 /* Post Link.swift in Sources */,
CD2BD6782A79F55800ECFF89 /* ImageSize.swift in Sources */,
50785F712A98C4F600117245 /* SiteInformationTracker.swift in Sources */,
CD46C1F82B0D0A8A00065953 /* View+TabReselectionConsumer.swift in Sources */,
6DEB0FFD2A4F891B007CAB99 /* User Moderator Link.swift in Sources */,
6D405AFF2A43E66600C65F9C /* UserLabelView.swift in Sources */,
CD391F9A2A537EF900E213B5 /* CommentBodyView.swift in Sources */,
Expand Down
42 changes: 16 additions & 26 deletions Mlem/Custom Tab Bar/FancyTabBar.swift
Original file line number Diff line number Diff line change
Expand Up @@ -15,29 +15,27 @@ struct FancyTabBar<Selection: FancyTabBarSelection, Content: View>: View {
@AppStorage("hasTranslucentInsets") var hasTranslucentInsets: Bool = true

@Binding private var selection: Selection
/// Keeps track of tab "re-selected" state.
@Binding private var navigationSelection: NavigationSelection
@State private var __tempNavigationSelection: Int = -1
/// We only toggle this to trigger an `onChange` event.
@State private var __navigationSelectionSignal: Bool = false
@State var tabReselectionHashValue: Int?

private let content: () -> Content

@State private var tabItemKeys: [Selection] = []
@State private var tabItems: [Selection: FancyTabItemLabelBuilder<Selection>] = [:]

var dragUpGestureCallback: (() -> Void)?
var doubleTapCallback: ((Selection) -> Void)?

init(
selection: Binding<Selection>,
navigationSelection: Binding<NavigationSelection>,
dragUpGestureCallback: (() -> Void)? = nil,
doubleTapCallback: ((Selection) -> Void)? = nil,
@ViewBuilder content: @escaping () -> Content
) {
self._selection = selection
self._navigationSelection = navigationSelection
self.content = content
self.dragUpGestureCallback = dragUpGestureCallback
self.doubleTapCallback = doubleTapCallback
}

var body: some View {
Expand All @@ -53,13 +51,19 @@ struct FancyTabBar<Selection: FancyTabBarSelection, Content: View>: View {
.ignoresSafeArea(.keyboard, edges: .bottom)
}
.environment(\.tabSelectionHashValue, selection.hashValue)
.environment(\.tabNavigationSelectionHashValue, navigationSelection.hashValue)
.environment(\.tabReselectionHashValue, tabReselectionHashValue)
.onPreferenceChange(FancyTabItemPreferenceKey<Selection>.self) {
tabItemKeys = $0
}
.onPreferenceChange(FancyTabItemLabelBuilderPreferenceKey<Selection>.self) {
tabItems = $0
}
.onChange(of: tabReselectionHashValue) { newValue in
// resets the reselection value to nil after the change is published
if newValue != nil {
tabReselectionHashValue = nil
}
}
}

private func getAccessibilityLabel(tab: Selection) -> String {
Expand Down Expand Up @@ -92,30 +96,16 @@ struct FancyTabBar<Selection: FancyTabBarSelection, Content: View>: View {
.contentShape(Rectangle())
// high priority to prevent conflict with long press/drag
.highPriorityGesture(
TapGesture()
.onEnded {
/// Emit "re-selected tab" event, if user tapped on tab that's already selected.
if key.hashValue == selection.hashValue {
/// Set to placeholder value.
/// Previous implementation used `DispatchQueue.asyncAfter` to set this to its actual value, but that caused bugs when performing UI changes on scroll views. [2023.08]
navigationSelection = TabSelection._tabBarNavigation
/// Keep track of new selection for use in `onChange` handler.
__tempNavigationSelection = key.index
/// Trigger `onChange` event.
__navigationSelectionSignal.toggle()
}

TapGesture().onEnded {
if selection == key {
tabReselectionHashValue = selection.hashValue
} else {
selection = key
}
}
)
}
}
/// Workaround for issue where setting `navigationSelection` inside a `Dispatch.asyncAfter` block caused issues when performing programmatic scrolling. [2023.08]
.onChange(of: __navigationSelectionSignal) { _ in
if let newTabSelection = TabSelection(index: __tempNavigationSelection) {
navigationSelection = newTabSelection
}
}
.gesture(
DragGesture()
.onChanged { gesture in
Expand Down
19 changes: 19 additions & 0 deletions Mlem/Custom Tab Bar/FancyTabBarReselectionEnvironmentKey.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
//
// FancyTabBarReselectionEnvironmentKey.swift
// Mlem
//
// Created by Eric Andrews on 2023-11-02.
//
import Foundation
import SwiftUI

struct FancyTabBarReselectionEnvironmentKey: EnvironmentKey {
static var defaultValue: Int? { nil }
}

extension EnvironmentValues {
var tabReselectionHashValue: Int? {
get { self[FancyTabBarReselectionEnvironmentKey.self] }
set { self[FancyTabBarReselectionEnvironmentKey.self] = newValue }
}
}

This file was deleted.

30 changes: 30 additions & 0 deletions Mlem/Extensions/View Modifiers/View+TabReselectionConsumer.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
//
// View+TabReselectionConsumer.swift
// Mlem
//
// Created by Eric Andrews on 2023-11-04.
//
import Foundation
import SwiftUI

struct ReselectConsumer: ViewModifier {
@Environment(\.tabReselectionHashValue) private var tabReselectionHashValue

let tab: TabSelection
let action: () -> Void

func body(content: Content) -> some View {
content
.onChange(of: tabReselectionHashValue) { newValue in
if newValue == tab.hashValue {
action()
}
}
}
}

extension View {
func reselectAction(tab: TabSelection, action: @escaping () -> Void) -> some View {
modifier(ReselectConsumer(tab: tab, action: action))
}
}
13 changes: 1 addition & 12 deletions Mlem/Views/Tabs/Feeds/Feed Root.swift
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,13 @@
// Created by tht7 on 30/06/2023.
//

import SwiftUI
import Dependencies
import SwiftUI

struct FeedRoot: View {
@EnvironmentObject var appState: AppState
@Environment(\.scenePhase) var phase
@Environment(\.tabSelectionHashValue) private var selectedTagHashValue
@Environment(\.tabNavigationSelectionHashValue) private var selectedNavigationTabHashValue

@AppStorage("defaultFeed") var defaultFeed: FeedType = .subscribed

Expand Down Expand Up @@ -75,16 +74,6 @@ struct FeedRoot: View {
}
}
}
.onChange(of: selectedTagHashValue) { newValue in
if newValue == TabSelection.feeds.hashValue {
print("switched to Feed tab")
}
}
.onChange(of: selectedNavigationTabHashValue) { newValue in
if newValue == TabSelection.feeds.hashValue {
print("re-selected \(TabSelection.feeds) tab")
}
}
}
}

Expand Down
44 changes: 29 additions & 15 deletions Mlem/Views/Tabs/Feeds/Feed View.swift
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import Dependencies
import Foundation
import SwiftUI

// swiftlint:disable type_body_length
struct FeedView: View {
// MARK: Environment and settings

Expand Down Expand Up @@ -146,26 +147,37 @@ struct FeedView: View {

@ViewBuilder
private var contentView: some View {
ScrollView {
if !postTracker.items.isEmpty {
LazyVStack(spacing: 0) {
// note: using .uid here because .id causes swipe actions to break--state changes still seem to properly trigger rerenders this way 🤔
ForEach(postTracker.items, id: \.uid) { post in
feedPost(for: post)
ScrollViewReader { scrollProxy in
ScrollView {
if !postTracker.items.isEmpty {
LazyVStack(spacing: 0) {
EmptyView().id("top")

// note: using .uid here because .id causes swipe actions to break--state changes still seem to properly trigger rerenders this way 🤔
ForEach(postTracker.items, id: \.uid) { post in
feedPost(for: post)
}

// TODO: update to use proper LoadingState
EndOfFeedView(loadingState: isLoading && postTracker.page > 1 ? .loading : .done, viewType: .hobbit)
}

// TODO: update to use proper LoadingState
EndOfFeedView(loadingState: isLoading && postTracker.page > 1 ? .loading : .done, viewType: .hobbit)
}
}
}
.frame(maxWidth: .infinity)
.overlay {
if postTracker.items.isEmpty {
noPostsView()
.frame(maxWidth: .infinity)
.overlay {
if postTracker.items.isEmpty {
noPostsView()
}
}
.reselectAction(tab: TabSelection.feeds) {
// TODO: SwiftUI doesn't seem to natively support customizing this animation
// https://stackoverflow.com/questions/62535553/swiftui-customize-animation-for-scrollto-using-scrollviewreader
withAnimation {
scrollProxy.scrollTo("top")
}
}
.fancyTabScrollCompatible()
}
.fancyTabScrollCompatible()
}

@ViewBuilder
Expand Down Expand Up @@ -306,3 +318,5 @@ struct FeedView: View {
}
}
}

// swiftlint:enable type_body_length
14 changes: 2 additions & 12 deletions Mlem/Views/Tabs/Inbox/Inbox View.swift
Original file line number Diff line number Diff line change
Expand Up @@ -32,9 +32,6 @@ struct InboxView: View {
@EnvironmentObject var appState: AppState
@EnvironmentObject var editorTracker: EditorTracker
@EnvironmentObject var unreadTracker: UnreadTracker

@Environment(\.tabSelectionHashValue) private var selectedTagHashValue
@Environment(\.tabNavigationSelectionHashValue) private var selectedNavigationTabHashValue

@AppStorage("internetSpeed") var internetSpeed: InternetSpeed = .fast

Expand Down Expand Up @@ -121,15 +118,8 @@ struct InboxView: View {
await handleShouldFilterReadChange(newShouldFilterRead: newValue)
}
}
.onChange(of: selectedTagHashValue) { newValue in
if newValue == TabSelection.inbox.hashValue {
print("switched to inbox tab")
}
}
.onChange(of: selectedNavigationTabHashValue) { newValue in
if newValue == TabSelection.inbox.hashValue {
print("re-selected \(TabSelection.inbox) tab")
}
.reselectAction(tab: TabSelection.inbox) {
print("re-selected inbox")
}
}
}
Expand Down
Loading

0 comments on commit 35cdbfe

Please sign in to comment.