Skip to content

Smooth mode switching - #679

Open
RankoR wants to merge 8 commits into
GrapheneOS:mainfrom
RankoR-GOS:smooth-mode-switching
Open

Smooth mode switching#679
RankoR wants to merge 8 commits into
GrapheneOS:mainfrom
RankoR-GOS:smooth-mode-switching

Conversation

@RankoR

@RankoR RankoR commented Aug 3, 2026

Copy link
Copy Markdown
Contributor

No description provided.

@RankoR
RankoR marked this pull request as ready for review August 3, 2026 15:19
@RankoR
RankoR requested a review from inthewaves August 3, 2026 15:27
@thestinger
thestinger force-pushed the main branch 5 times, most recently from 25fd41a to db39c2d Compare August 4, 2026 00:35
@RankoR
RankoR requested a review from m4pl August 4, 2026 07:08
Comment on lines +77 to +80
val centers = (0 until tabParent.childCount).map {
val tabView = tabParent.getChildAt(it)
tabView.left + tabView.width / 2 - width / 2
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Could this use the children extension?

Suggested change
val centers = (0 until tabParent.childCount).map {
val tabView = tabParent.getChildAt(it)
tabView.left + tabView.width / 2 - width / 2
}
val centers = tabParent.children.take(tabCount).map {
it.left + it.width / 2 - width / 2
}.toList()

Separately, would it be worth iterating tabCount instead of childCount? Everything downstream compares the result against tabCount.

Comment on lines 115 to 122
val target = tabCenters.getOrNull(tab.position)
val duration = if (target == null) 0L else settleDuration(abs(target - scrollX))

// snapPoints is empty until the first layout pass, and goes stale when the tab set is
// rebuilt, so an index taken from it may no longer name a tab.
if (snapPoints.isEmpty() || snapPoints.last() == 0) {
if (target == null || duration == 0L || !ValueAnimator.areAnimatorsEnabled()) {
target?.let { scrollTo(it, 0) }
onSettled?.run()
return
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Small thing: target == null gets tested twice.

Suggested change
val target = tabCenters.getOrNull(tab.position)
val duration = if (target == null) 0L else settleDuration(abs(target - scrollX))
// snapPoints is empty until the first layout pass, and goes stale when the tab set is
// rebuilt, so an index taken from it may no longer name a tab.
if (snapPoints.isEmpty() || snapPoints.last() == 0) {
if (target == null || duration == 0L || !ValueAnimator.areAnimatorsEnabled()) {
target?.let { scrollTo(it, 0) }
onSettled?.run()
return
}
val target = tabCenters.getOrNull(tab.position) ?: run {
onSettled?.run()
return
}
val duration = settleDuration(abs(target - scrollX))
if (duration == 0L || !ValueAnimator.areAnimatorsEnabled()) {
scrollTo(target, 0)
onSettled?.run()
return
}

val selectedWidth = selectedChild.width

return selectedChild.left + selectedWidth - width / 2
private fun fractionalTabPosition(x: Int): Float {

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

nit: tabCenters.lastIndex in both spots reads a little better, and the empty case then falls out on its own.

// is already visible and to dismiss it if the permission gets granted.
private var cameraPermissionDialog: AlertDialog? = null
private var audioPermissionDialog: AlertDialog? = null
@Volatile

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

nit: missing blank line before @Volatile.

if (frameCopyPending || hasFreshPrefetch()) return
if (previewView.width == 0 || previewView.height == 0) return

val surfaceView = previewView.getChildAt(0) as? SurfaceView ?: return

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Could we log once when the cast misses?

@RankoR
RankoR requested a review from sdsantos August 4, 2026 17:59

@sdsantos sdsantos left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Found a bug when changing tabs. If you click on a tab to change, and they quickly tap back on the tab you were before, the camera surface is stuck on the blurred preview and never shows the live camera, until you click on another tab.

camera_switch_stuck.mp4


override fun onScrollChanged(x: Int, y: Int, oldX: Int, oldY: Int) {
super.onScrollChanged(x, y, oldX, oldY)
fun goToTab(tab: Tab, onSettled: Runnable? = null) {

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Looks like nothing is using that onSettled.

@RankoR
RankoR requested review from m4pl and sdsantos August 9, 2026 12:13
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