-
Notifications
You must be signed in to change notification settings - Fork 4
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
25157b9
commit 6d4d8f3
Showing
10 changed files
with
452 additions
and
9 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
78 changes: 78 additions & 0 deletions
78
...les/app_ui_kit/src/main/kotlin/kekmech/ru/mpeiapp/demo/screens/shimmers/ShimmersScreen.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,78 @@ | ||
package kekmech.ru.mpeiapp.demo.screens.shimmers | ||
|
||
import androidx.compose.foundation.background | ||
import androidx.compose.foundation.layout.Box | ||
import androidx.compose.foundation.layout.Column | ||
import androidx.compose.foundation.layout.PaddingValues | ||
import androidx.compose.foundation.layout.Row | ||
import androidx.compose.foundation.layout.fillMaxWidth | ||
import androidx.compose.foundation.layout.height | ||
import androidx.compose.foundation.layout.padding | ||
import androidx.compose.foundation.layout.size | ||
import androidx.compose.foundation.layout.wrapContentHeight | ||
import androidx.compose.foundation.shape.RoundedCornerShape | ||
import androidx.compose.runtime.Composable | ||
import androidx.compose.ui.Modifier | ||
import androidx.compose.ui.unit.dp | ||
import com.bumble.appyx.core.modality.BuildContext | ||
import com.bumble.appyx.core.node.Node | ||
import com.bumble.appyx.core.node.node | ||
import kekmech.ru.lib_navigation_api.NavTarget | ||
import kekmech.ru.mpeiapp.demo.ui.UiKitScreen | ||
import kekmech.ru.ui_shimmer.shimmer | ||
import kekmech.ru.ui_theme.theme.MpeixTheme | ||
import kotlinx.parcelize.Parcelize | ||
|
||
@Parcelize | ||
internal class ShimmersScreenNavTarget : NavTarget { | ||
|
||
override fun resolve(buildContext: BuildContext): Node = | ||
node(buildContext) { ShimmersScreen() } | ||
} | ||
|
||
@Composable | ||
private fun ShimmersScreen() { | ||
UiKitScreen(title = "Shimmers") { innerPadding -> | ||
Column(Modifier.padding(innerPadding)) { | ||
ShimmerItem() | ||
ShimmerItem() | ||
ShimmerItem() | ||
ShimmerItem() | ||
ShimmerItem() | ||
} | ||
} | ||
} | ||
|
||
@Composable | ||
private fun ShimmerItem() { | ||
val color = MpeixTheme.palette.surfacePlus3 | ||
val radius = 4.dp | ||
Row( | ||
Modifier | ||
.padding(bottom=8.dp) | ||
.padding(horizontal = 16.dp) | ||
.shimmer() | ||
) { | ||
Box( | ||
Modifier | ||
.padding(end = 8.dp) | ||
.size(64.dp) | ||
.background(color, RoundedCornerShape(radius)) | ||
) | ||
Column { | ||
Box( | ||
Modifier | ||
.fillMaxWidth() | ||
.padding(bottom = 4.dp) | ||
.height(18.dp) | ||
.background(color, RoundedCornerShape(radius)) | ||
) | ||
Box( | ||
Modifier | ||
.fillMaxWidth(fraction = 0.75f) | ||
.height(14.dp) | ||
.background(color, RoundedCornerShape(radius)) | ||
) | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
plugins { | ||
id("mpeix.android.ui") | ||
} | ||
|
||
dependencies { | ||
implementation(project(":ui_theme")) | ||
} |
96 changes: 96 additions & 0 deletions
96
modules/ui/shimmer/src/main/kotlin/kekmech/ru/ui_shimmer/ShimmerArea.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,96 @@ | ||
package kekmech.ru.ui_shimmer | ||
|
||
|
||
import androidx.compose.ui.geometry.Offset | ||
import androidx.compose.ui.geometry.Rect | ||
import androidx.compose.ui.geometry.Size | ||
import kotlin.math.acos | ||
import kotlin.math.cos | ||
import kotlin.math.pow | ||
import kotlin.math.sqrt | ||
|
||
/** | ||
* Describes the area in which the shimmer effect will be drawn. | ||
*/ | ||
internal class ShimmerArea( | ||
private val shimmerWidthPx: Float, | ||
internal val shimmerBounds: Rect, | ||
) { | ||
|
||
private val reducedRotation = ShimmerTokens.Rotation.toRadian() | ||
|
||
private var shimmerSize: Size = Size.Zero | ||
|
||
var translationDistance = 0f | ||
private set | ||
|
||
var pivotPoint = Offset.Unspecified | ||
private set | ||
|
||
var viewBounds = Rect.Zero | ||
set(value) { | ||
if (value == field) return | ||
field = value | ||
computeShimmerBounds() | ||
} | ||
|
||
private fun computeShimmerBounds() { | ||
if (viewBounds.isEmpty) return | ||
|
||
// Pivot point in the view's frame of reference | ||
pivotPoint = -viewBounds.topLeft + shimmerBounds.center | ||
|
||
val newShimmerSize = shimmerBounds.size | ||
if (shimmerSize != newShimmerSize) { | ||
shimmerSize = newShimmerSize | ||
computeTranslationDistance() | ||
} | ||
} | ||
|
||
/** | ||
* Rotating the shimmer results in an effect that will first be visible in one of the corners. | ||
* It will afterwards travel across the view / display until the last visible part of it will | ||
* disappear in the opposite corner. | ||
* | ||
* A simple shimmer going across the device's screen from left to right has to travel until | ||
* it reaches the center of the screen and then the same distance again. Without taking the | ||
* shimmer's own width into account. | ||
* | ||
* If the shimmer is now tilted slightly clockwise around the center of the display, a new | ||
* distance has to be calculated. The required distance is the length of a line, which extends | ||
* from the top left of the display to the rotated shimmer (or center line), hitting it at a | ||
* 90 degree angle. As the height and width of the display (or view) are known, the length of | ||
* the line can be calculated by using basic trigonometric functions. | ||
*/ | ||
private fun computeTranslationDistance() { | ||
val width = shimmerSize.width / 2 | ||
val height = shimmerSize.height / 2 | ||
|
||
val distanceCornerToCenter = sqrt(width.pow(2) + height.pow(2)) | ||
val beta = acos(width / distanceCornerToCenter) | ||
val alpha = beta - reducedRotation | ||
|
||
val distanceCornerToRotatedCenterLine = cos(alpha) * distanceCornerToCenter | ||
translationDistance = distanceCornerToRotatedCenterLine * 2 + shimmerWidthPx | ||
} | ||
|
||
private fun Float.toRadian(): Float = this / 180 * Math.PI.toFloat() | ||
|
||
override fun equals(other: Any?): Boolean { | ||
if (this === other) return true | ||
if (javaClass != other?.javaClass) return false | ||
|
||
other as ShimmerArea | ||
|
||
if (shimmerWidthPx != other.shimmerWidthPx) return false | ||
if (reducedRotation != other.reducedRotation) return false | ||
|
||
return true | ||
} | ||
|
||
override fun hashCode(): Int { | ||
var result = shimmerWidthPx.hashCode() | ||
result = 31 * result + reducedRotation.hashCode() | ||
return result | ||
} | ||
} |
21 changes: 21 additions & 0 deletions
21
modules/ui/shimmer/src/main/kotlin/kekmech/ru/ui_shimmer/ShimmerBounds.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
package kekmech.ru.ui_shimmer | ||
|
||
|
||
import androidx.compose.runtime.Composable | ||
import androidx.compose.runtime.remember | ||
import androidx.compose.ui.geometry.Rect | ||
import androidx.compose.ui.platform.LocalContext | ||
|
||
@Composable | ||
internal fun rememberShimmerBounds(): Rect { | ||
val displayMetrics = LocalContext.current.resources.displayMetrics | ||
return remember(displayMetrics) { | ||
Rect( | ||
left = 0f, | ||
top = 0f, | ||
right = displayMetrics.widthPixels.toFloat(), | ||
bottom = displayMetrics.heightPixels.toFloat() | ||
) | ||
} | ||
} | ||
|
Oops, something went wrong.