Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ALTAPPS-1277: Shared, Android new first session onboarding #1080

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
39 commits
Select commit Hold shift + click to select a range
d7d3a76
Rename WelcomeOnboardingFeature to LegacyWelcomeOnboardingFeature
XanderZhu Jun 12, 2024
8aae7d7
Fix iOS build
XanderZhu Jun 12, 2024
4a85f11
Rename welcome_onboarding package to legacy_welcome_onboarding
XanderZhu Jun 12, 2024
a31c56c
Add appFeature copy without child LegacyWelcomeOnboardingFeature; Use…
XanderZhu Jun 12, 2024
3a055e8
Use LegacyMainComponent on iOS
XanderZhu Jun 12, 2024
b2a93f3
Implement new WelcomeOnboardingFeature frame
XanderZhu Jun 12, 2024
2cd933f
Merge branch 'develop' into feature/ALTAPPS-1277/Shared-android-new-f…
XanderZhu Jun 12, 2024
7f5cc7e
Implement WelcomeOnboardingEntryPoint
XanderZhu Jun 13, 2024
f132998
Fix detekt
XanderZhu Jun 13, 2024
1562e1a
Navigate user to study plan after auth if track is selected & notific…
XanderZhu Jun 13, 2024
4909a1c
Rename WelcomeOnboardingStartingScreen to WelcomeOnboardingEntryPoint
XanderZhu Jun 13, 2024
c98d3ff
Rename UsersQuestionnaireOnboardingFeature to LegacyUsersQuestionnair…
XanderZhu Jun 13, 2024
8c5d006
Pass params to WelcomeOnboardingFeature
XanderZhu Jun 13, 2024
2d70743
Implement welcome questionnaire
XanderZhu Jun 13, 2024
2532cb6
Implement language selection
XanderZhu Jun 13, 2024
d949c12
Implement track screen
XanderZhu Jun 14, 2024
49c2d3e
Implement track selection
XanderZhu Jun 14, 2024
7efd693
Refactor packages
XanderZhu Jun 14, 2024
4074a79
Add WelcomeOnboardingFeature to new onboarding flow
XanderZhu Jun 17, 2024
dbeb117
Implement nextLearningActivity fetch
XanderZhu Jun 17, 2024
27bbada
Implement WelcomeOnboardingFinishFragment
XanderZhu Jun 17, 2024
cca2f6e
Implement WelcomeOnboarding completion
XanderZhu Jun 17, 2024
25f10a7
Implement WelcomeOnboardingFinishComponent
XanderZhu Jun 17, 2024
df7d486
Implement WelcomeOnboarding flow launch for user with selected track
XanderZhu Jun 17, 2024
4b6365d
Merge branch 'develop' into feature/ALTAPPS-1277/Shared-android-new-f…
XanderZhu Jun 17, 2024
6a714ae
Show NextLearningActivityLoading
XanderZhu Jun 17, 2024
3edab71
Cleanup
XanderZhu Jun 17, 2024
a2ab508
Cleanup
XanderZhu Jun 18, 2024
9addeae
Add analytic events
XanderZhu Jun 18, 2024
99573fb
Fix NotificationOnboarding condition after track selection
XanderZhu Jun 18, 2024
63855fd
Fix detekt & ktlint
XanderZhu Jun 18, 2024
72adb0e
Refactor shared packages
XanderZhu Jun 18, 2024
d558130
Merge branch 'develop' into feature/ALTAPPS-1277/Shared-android-new-f…
XanderZhu Jun 18, 2024
116ba16
Fix ktlint
XanderZhu Jun 18, 2024
af39ef7
Fix iOS build
XanderZhu Jun 18, 2024
5feb6d8
Merge branch 'develop' into feature/ALTAPPS-1277/Shared-android-new-f…
XanderZhu Jun 18, 2024
7dd374a
Use new analytic logging approach
XanderZhu Jun 18, 2024
c2bdaf0
iOS: Fix build
ivan-magda Jun 19, 2024
65c4161
Apply suggestions from code review
ivan-magda Jun 19, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import androidx.compose.ui.res.colorResource
import androidx.compose.ui.text.SpanStyle
import androidx.compose.ui.tooling.preview.Preview
import org.hyperskill.app.R
import org.hyperskill.app.android.core.view.ui.widget.compose.HtmlText
import org.hyperskill.app.android.core.view.ui.widget.compose.ClickableHtmlText
import org.hyperskill.app.android.core.view.ui.widget.compose.HyperskillTheme

@Composable
Expand All @@ -16,7 +16,7 @@ fun ChallengeDescription(
onLinkClick: (String) -> Unit,
modifier: Modifier = Modifier
) {
HtmlText(
ClickableHtmlText(
text = description,
modifier = modifier,
baseSpanStyle = SpanStyle(color = colorResource(id = R.color.color_on_surface_alpha_60)),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,26 @@ private const val URL_TAG = "url"

@Composable
fun HtmlText(
text: String,
baseSpanStyle: SpanStyle? = null,
content: @Composable (AnnotatedString) -> Unit
) {
val annotatedString = remember(text) {
HtmlCompat
.fromHtml(
text.replace("\n", "<br>"),
HtmlCompat.FROM_HTML_MODE_COMPACT
)
.toAnnotatedString(
baseSpanStyle = baseSpanStyle,
underlineLinks = false
)
}
content(annotatedString)
}

@Composable
fun ClickableHtmlText(
text: String,
modifier: Modifier = Modifier,
baseSpanStyle: SpanStyle? = null,
Expand All @@ -35,15 +55,19 @@ fun HtmlText(
style: TextStyle = LocalTextStyle.current,
onUrlClick: ((url: String) -> Unit)? = null
) {
val spannedText = remember(text) {
HtmlCompat.fromHtml(text.replace("\n", "<br>"), HtmlCompat.FROM_HTML_MODE_COMPACT)
val annotatedString = remember(text) {
HtmlCompat
.fromHtml(
text.replace("\n", "<br>"),
HtmlCompat.FROM_HTML_MODE_COMPACT
)
.toAnnotatedString(
baseSpanStyle = baseSpanStyle,
linkColor = if (isHighlightLink) linkColor else Color.Unspecified,
underlineLinks = false
)
}
val uriHandler = LocalUriHandler.current
val annotatedString = spannedText.toAnnotatedString(
baseSpanStyle = baseSpanStyle,
linkColor = if (isHighlightLink) linkColor else Color.Unspecified,
underlineLinks = false
)
ClickableText(
modifier = modifier,
text = annotatedString,
Expand All @@ -62,7 +86,7 @@ fun HtmlText(
fun Spanned.toAnnotatedString(
baseSpanStyle: SpanStyle?,
underlineLinks: Boolean,
linkColor: Color
linkColor: Color = Color.Blue
): AnnotatedString =
buildAnnotatedString {
val spanned = this@toAnnotatedString
Expand Down Expand Up @@ -101,7 +125,7 @@ fun Spanned.toAnnotatedString(
@Preview
@Composable
private fun LinksHtmlTextPreview() {
HtmlText(
ClickableHtmlText(
/*ktlint-disable*/
text = "<b>Some text</b> \n<a href=\"https://developer.android.com/jetpack/androidx/releases/compose\" target=\"_blank\">" +
"link text</a>, the rest of the text"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ object HyperskillButtonDefaults {
): ButtonColors =
ButtonDefaults.buttonColors(
backgroundColor = backgroundColor,
disabledBackgroundColor = backgroundColor.copy(alpha = 0.38f),
contentColor = contentColor
)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,9 @@ import org.hyperskill.app.android.R

@Composable
fun HyperskillCard(
contentPadding: PaddingValues,
modifier: Modifier = Modifier,
cornerRadius: Dp = dimensionResource(id = R.dimen.corner_radius),
contentPadding: PaddingValues? = null,
interactionSource: MutableInteractionSource = remember { MutableInteractionSource() },
onClick: (() -> Unit)? = null,
content: @Composable BoxScope.() -> Unit
Expand All @@ -42,7 +42,11 @@ fun HyperskillCard(
it
}
}
.padding(contentPadding),
.apply {
if (contentPadding != null) {
padding(contentPadding)
}
},
content = content
)
}
Original file line number Diff line number Diff line change
@@ -1,9 +1,13 @@
package org.hyperskill.app.android.core.view.ui.widget.compose

import androidx.compose.animation.core.AnimationSpec
import androidx.compose.animation.core.DurationBasedAnimationSpec
import androidx.compose.animation.core.Easing
import androidx.compose.animation.core.FastOutSlowInEasing
import androidx.compose.animation.core.RepeatMode
import androidx.compose.animation.core.animateFloat
import androidx.compose.animation.core.animateFloatAsState
import androidx.compose.animation.core.infiniteRepeatable
import androidx.compose.animation.core.rememberInfiniteTransition
import androidx.compose.animation.core.tween
import androidx.compose.runtime.Stable
import androidx.compose.runtime.getValue
Expand All @@ -16,16 +20,25 @@ import androidx.compose.ui.geometry.Offset
import androidx.compose.ui.graphics.Brush
import androidx.compose.ui.graphics.Color

private const val INITIAL_VALUE = -2f
private const val TARGET_VALUE = 2f

private val DefaultColors: List<Color> = listOf(
Color.Transparent,
Color.White.copy(alpha = 0.7f),
Color.Transparent
)

/**
* Applies shimmer animation to the target Composable.
* Animation is playing one time.
* To start animation call [ShimmerState.runShimmerAnimation] on the [ShimmerState] instance.
* To start animation call [ShimmerShotState.runShimmerAnimation] on the [ShimmerShotState] instance.
*/
fun Modifier.shimmerShot(shimmerState: ShimmerState): Modifier =
fun Modifier.shimmerShot(shimmerState: ShimmerShotState): Modifier =
composed {
val startOffsetX by animateFloatAsState(
targetValue = shimmerState.targetValue,
animationSpec = shimmerState.startOffsetXAnimationSpec,
animationSpec = shimmerState.animationSpec,
label = "shimmer"
)
drawWithContent {
Expand All @@ -43,26 +56,65 @@ fun Modifier.shimmerShot(shimmerState: ShimmerState): Modifier =
}
}

fun Modifier.shimmer(
isLoading: Boolean,
colors: List<Color> = DefaultColors,
durationMillis: Int = 2000,
easing: Easing = FastOutSlowInEasing
): Modifier =
if (isLoading) {
shimmer(colors, durationMillis, easing)
} else {
this
}

private fun Modifier.shimmer(
colors: List<Color>,
durationMillis: Int,
easing: Easing
): Modifier =
composed {
val transition = rememberInfiniteTransition(label = "")

val translateAnimation = transition.animateFloat(
initialValue = INITIAL_VALUE,
targetValue = TARGET_VALUE,
animationSpec = infiniteRepeatable(
animation = tween(
durationMillis = durationMillis,
easing = easing
),
repeatMode = RepeatMode.Restart,
),
label = "Shimmer loading animation",
)

drawWithContent {
val width = size.width
val height = size.height
val offset = translateAnimation.value * width

drawContent()
val brush = Brush.linearGradient(
colors = colors,
start = Offset(offset, 0f),
end = Offset(offset + width, height)
)
drawRect(brush)
}
}

@Stable
class ShimmerState(
val colors: List<Color> = listOf(
Color.Transparent,
Color.White.copy(alpha = 0.7f),
Color.Transparent
),
class ShimmerShotState(
val colors: List<Color> = DefaultColors,
durationMillis: Int = 1200,
easing: Easing = FastOutSlowInEasing
) {

companion object {
private const val INITIAL_VALUE = -2f
private const val TARGET_VALUE = 2f
}

var targetValue: Float by mutableStateOf(INITIAL_VALUE)
private set

val startOffsetXAnimationSpec: AnimationSpec<Float> = tween(
val animationSpec: DurationBasedAnimationSpec<Float> = tween(
durationMillis = durationMillis,
easing = easing
)
Expand Down
Loading
Loading