Implement new account deletion and auth flows

Signed-off-by: denis0001-dev <denis0001.dev@ya.ru>
This commit is contained in:
2026-06-24 17:16:34 +03:00
Unverified
parent 712e4a9ed4
commit 306458bcd8
41 changed files with 3823 additions and 1596 deletions
@@ -0,0 +1,20 @@
package com.pr0gramm3r101.utils
import androidx.compose.foundation.layout.ExperimentalLayoutApi
import androidx.compose.foundation.layout.WindowInsets
import androidx.compose.foundation.layout.ime
import androidx.compose.foundation.layout.imeAnimationSource
import androidx.compose.foundation.layout.imeAnimationTarget
import androidx.compose.runtime.Composable
import androidx.compose.ui.platform.LocalDensity
@OptIn(ExperimentalLayoutApi::class)
@Composable
actual fun rememberImeMotion(): ImeMotion {
val density = LocalDensity.current
return ImeMotion(
currentBottomPx = WindowInsets.ime.getBottom(density),
sourceBottomPx = WindowInsets.imeAnimationSource.getBottom(density),
targetBottomPx = WindowInsets.imeAnimationTarget.getBottom(density),
)
}
@@ -0,0 +1,79 @@
package com.pr0gramm3r101.utils
import androidx.compose.runtime.Composable
import androidx.compose.runtime.Immutable
/**
* IME inset motion for the current frame.
*
* On Android, [sourceBottomPx] / [targetBottomPx] come from
* [androidx.compose.foundation.layout.WindowInsets.imeAnimationSource] and
* [androidx.compose.foundation.layout.WindowInsets.imeAnimationTarget].
*/
@Immutable
data class ImeMotion(
val currentBottomPx: Int,
val sourceBottomPx: Int,
val targetBottomPx: Int,
) {
val isAnimating: Boolean
get() = sourceBottomPx != targetBottomPx
val isOpeningAnimation: Boolean
get() = isAnimating && targetBottomPx > sourceBottomPx
val isClosingAnimation: Boolean
get() = isAnimating && targetBottomPx < sourceBottomPx
/** Open animation that started from a fully hidden keyboard. */
val isOpeningFromClosed: Boolean
get() = isOpeningAnimation && sourceBottomPx == 0
}
/** Keyboard phase used to decide when bring-into-view may run. */
enum class ImeKeyboardPhase {
/** IME inset is zero. */
Hidden,
/** Keyboard animating up from fully hidden — follow with bring-into-view. */
OpeningFromHidden,
/** Keyboard visible and not in an inset animation. */
Open,
/** Keyboard animating down (inset shrinking). */
Closing,
/** Keyboard animating back up after a cancelled / partial dismiss. */
ReopeningPartial,
}
/**
* @param settledImeBottomPx last IME bottom when no inset animation was in progress.
* @param previousReportedImeBottomPx IME bottom on the prior processed frame.
*/
fun ImeMotion.keyboardPhase(
settledImeBottomPx: Int,
previousReportedImeBottomPx: Int,
): ImeKeyboardPhase {
when {
isOpeningFromClosed -> return ImeKeyboardPhase.OpeningFromHidden
isOpeningAnimation && sourceBottomPx > 0 && settledImeBottomPx > 0 ->
return ImeKeyboardPhase.ReopeningPartial
isClosingAnimation -> return ImeKeyboardPhase.Closing
// iOS / fallback: inset growing from zero without animation metadata.
previousReportedImeBottomPx <= 0 && currentBottomPx > 0 &&
(previousReportedImeBottomPx < 0 || currentBottomPx > previousReportedImeBottomPx) ->
return ImeKeyboardPhase.OpeningFromHidden
// iOS / fallback: inset shrinking frame-by-frame.
previousReportedImeBottomPx > 0 && currentBottomPx in 1..<previousReportedImeBottomPx ->
return ImeKeyboardPhase.Closing
currentBottomPx > 0 -> return ImeKeyboardPhase.Open
else -> return ImeKeyboardPhase.Hidden
}
}
@Composable
expect fun rememberImeMotion(): ImeMotion
@@ -0,0 +1,41 @@
package com.pr0gramm3r101.utils
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.runtime.Stable
import androidx.compose.ui.unit.Density
import androidx.compose.ui.unit.Dp
/**
* Fixed [Dp] gaps between children, plus extra height before the last child so it sits at the
* bottom when content is shorter than the viewport.
*/
@Stable
class LastAnchoredBottomArrangement(
private val space: Dp,
) : Arrangement.Vertical {
override val spacing get() = space
override fun Density.arrange(
totalSize: Int,
sizes: IntArray,
outPositions: IntArray,
) {
val spacePx = space.roundToPx()
when (sizes.size) {
0 -> return
1 -> {
outPositions[0] = (totalSize - sizes[0]).coerceAtLeast(0)
return
}
}
var y = 0
for (i in 0 until sizes.size - 1) {
outPositions[i] = y
y += sizes[i] + spacePx
}
outPositions[sizes.size - 1] =
y + (totalSize - sizes.sum() - (spacePx * (sizes.size - 1))).coerceAtLeast(0)
}
}
@@ -0,0 +1,17 @@
package com.pr0gramm3r101.utils
import androidx.compose.foundation.layout.WindowInsets
import androidx.compose.foundation.layout.ime
import androidx.compose.runtime.Composable
import androidx.compose.ui.platform.LocalDensity
@Composable
actual fun rememberImeMotion(): ImeMotion {
val density = LocalDensity.current
val currentBottomPx = WindowInsets.ime.getBottom(density)
return ImeMotion(
currentBottomPx = currentBottomPx,
sourceBottomPx = currentBottomPx,
targetBottomPx = currentBottomPx,
)
}