Skip to content

Conversation

@dfsm
Copy link
Contributor

@dfsm dfsm commented Aug 10, 2025

Implements a new immersive reading experience that automatically hides the navigation bar and toolbar when scrolling down, and shows them when scrolling up.

Features:
• Toggle available in main settings and posts settings
• Velocity-based transitions (0.5 threshold)
• Automatic bar reveal when near top/bottom of content
• Gradient overlay for improved status bar readability
• Seamless light/dark theme integration
• Smooth 0.25s animations with proper layout updates

Files modified:
• AwfulSettings: Added immersionModeEnabled setting
• AwfulSettingsUI: Added settings toggles and localization
• PostsPageView: Core scroll handling and UI hiding logic
• PostsPageViewController: Navigation bar integration
• PostsPageSettingsViewController: In-page settings toggle

  Implements a new immersive reading experience that automatically hides the
  navigation bar and toolbar when scrolling down, and shows them when scrolling up.

  Features:
  • Toggle available in main settings and posts settings
  • Velocity-based transitions (0.5 threshold)
  • Automatic bar reveal when near top/bottom of content
  • Gradient overlay for improved status bar readability
  • Seamless light/dark theme integration
  • Smooth 0.25s animations with proper layout updates

  Files modified:
  • AwfulSettings: Added immersionModeEnabled setting
  • AwfulSettingsUI: Added settings toggles and localization
  • PostsPageView: Core scroll handling and UI hiding logic
  • PostsPageViewController: Navigation bar integration
  • PostsPageSettingsViewController: In-page settings toggle
@dfsm dfsm requested a review from nolanw August 10, 2025 09:48
Copy link
Member

@nolanw nolanw left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nice! got a few nits but overall looking fine

.store(in: &cancellables)

$immersionModeEnabled
.receive(on: RunLoop.main)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This will delay updates while scrolling until after scrolling completes, is that intentional? It kinda makes sense to me so I'm ok with it, but a comment would be good. (Usually receiving on the main run loop is not what people want.)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I double checked with Claude and it seemed pretty sure that this was preferable. So it added a comment as suggested

}
}
return nil
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't get it, why don't we have an outlet or property with the stack view handy?

// Create immersion mode switch
immersionModeSwitch = UISwitch()
immersionModeSwitch.isOn = immersionModeEnabled // Set initial state
immersionModeSwitch.onTintColor = theme["settingsSwitchColor"] // Apply theme color
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should (re)set this in themeDidChange.

scrollViewDelegateMux = ScrollViewDelegateMultiplexer(scrollView: renderView.scrollView)
scrollViewDelegateMux?.addDelegate(self)

// Configure initial gradient
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yep that's what the next line says!

height: gradientHeight)

// Update gradient layer frame to match view bounds
if let gradientLayer = safeAreaGradientView.layer.sublayers?.first as? CAGradientLayer {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is better done as a UIView subclass that overrides layerClass and does something like

var gradientLayer: CAGradientLayer { layer as! CAGradientLayer }

then we don't have to root around for the gradient layer and set its frame. Also then it works with UIKit animation.

gradientLayer.endPoint = CGPoint(x: 0.5, y: 1.0)

safeAreaGradientView.layer.addSublayer(gradientLayer)
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

All of this could go into that UIView subclass, which could also implement themeDidChange.

self.toolbar.alpha = 1.0
self.toolbar.transform = .identity

// Hide safe area gradient
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I recognize these useless comments as very llm coding, which is ok, but I'd love a pass to get rid of them after.

init() {
super.init(frame: .zero)
showsMenuAsPrimaryAction = true
// Enable modern iOS 26 menu styling
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

?

// Update interface style before showing the menu to ensure it uses the correct theme
updateInterfaceStyle()

// Use the original approach that was working, but ensure we get iOS 26 styling
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

?

}

func updateInterfaceStyle() {
// Follow the theme's mode setting for menu appearance
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"Menu appearance" is an excellent candidate for a dedicated theme key.

…tead of "mode".

Changed the way Immersion Mode is activated from velocity-based gesture to 1:1 scroll distance.
Improved safe area gradient using UIView subclass.
@dfsm
Copy link
Contributor Author

dfsm commented Sep 6, 2025

So the approach itself has changed from velocity-based to be more of a 1:1 hide/reveal based on user scroll distance.
I removed unnecessary comments (and some were remnants from my fork, sorry)
I added "menuAppearance" to the Themes.plist and gave every theme a value.
Changed the gradient to a UIView and created a new file for it

@dfsm dfsm closed this Sep 27, 2025
@dfsm dfsm deleted the immersive-mode branch September 27, 2025 08:50
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants