Skip to content

Commit

Permalink
Merge branch 'develop' into feature/ALTAPPS-1042/Fill-blanks-with-sel…
Browse files Browse the repository at this point in the history
…ect-improvements
  • Loading branch information
XanderZhu authored Nov 25, 2023
2 parents 195a4d1 + 69ff609 commit 8755922
Show file tree
Hide file tree
Showing 212 changed files with 4,670 additions and 900 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/automerge_into_release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ jobs:
set -e
echo "Getting latest tag without v* prefix..."
current_version_number=$(git describe --tags --abbrev=0 | cut -c 2-)
current_version_number=$(git tag --sort=committerdate | tail -1 | cut -c 2-)
echo "Current version number is $current_version_number"
next_version_number=$(echo $current_version_number | awk -F. -v OFS=. '{$NF++;print}')
Expand Down
2 changes: 1 addition & 1 deletion androidHyperskillApp/Gemfile
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
source "https://rubygems.org"
ruby "3.1.0"

gem "fastlane", "2.216.0"
gem "fastlane", "2.217.0"

eval_gemfile("fastlane/Pluginfile")
46 changes: 21 additions & 25 deletions androidHyperskillApp/Gemfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -8,20 +8,20 @@ GEM
artifactory (3.0.15)
atomos (0.1.3)
aws-eventstream (1.2.0)
aws-partitions (1.826.0)
aws-sdk-core (3.183.0)
aws-partitions (1.853.0)
aws-sdk-core (3.187.0)
aws-eventstream (~> 1, >= 1.0.2)
aws-partitions (~> 1, >= 1.651.0)
aws-sigv4 (~> 1.5)
jmespath (~> 1, >= 1.6.1)
aws-sdk-kms (1.71.0)
aws-sdk-core (~> 3, >= 3.177.0)
aws-sdk-kms (1.72.0)
aws-sdk-core (~> 3, >= 3.184.0)
aws-sigv4 (~> 1.1)
aws-sdk-s3 (1.135.0)
aws-sdk-s3 (1.137.0)
aws-sdk-core (~> 3, >= 3.181.0)
aws-sdk-kms (~> 1)
aws-sigv4 (~> 1.6)
aws-sigv4 (1.6.0)
aws-sigv4 (1.6.1)
aws-eventstream (~> 1, >= 1.0.2)
babosa (1.0.4)
claide (1.1.0)
Expand All @@ -32,11 +32,10 @@ GEM
declarative (0.0.20)
digest-crc (0.6.5)
rake (>= 12.0.0, < 14.0.0)
domain_name (0.5.20190701)
unf (>= 0.0.5, < 1.0.0)
domain_name (0.6.20231109)
dotenv (2.8.1)
emoji_regex (3.2.3)
excon (0.103.0)
excon (0.104.0)
faraday (1.10.3)
faraday-em_http (~> 1.0)
faraday-em_synchrony (~> 1.0)
Expand Down Expand Up @@ -66,7 +65,7 @@ GEM
faraday_middleware (1.2.0)
faraday (~> 1.0)
fastimage (2.2.7)
fastlane (2.216.0)
fastlane (2.217.0)
CFPropertyList (>= 2.3, < 4.0.0)
addressable (>= 2.8, < 3.0.0)
artifactory (~> 3.0)
Expand Down Expand Up @@ -106,12 +105,12 @@ GEM
xcodeproj (>= 1.13.0, < 2.0.0)
xcpretty (~> 0.3.0)
xcpretty-travis-formatter (>= 0.0.3)
fastlane-plugin-firebase_app_distribution (0.7.3)
fastlane-plugin-firebase_app_distribution (0.7.4)
google-apis-firebaseappdistribution_v1 (~> 0.3.0)
gh_inspector (1.1.3)
google-apis-androidpublisher_v3 (0.49.0)
google-apis-androidpublisher_v3 (0.52.0)
google-apis-core (>= 0.11.0, < 2.a)
google-apis-core (0.11.1)
google-apis-core (0.11.2)
addressable (~> 2.5, >= 2.5.1)
googleauth (>= 0.16.2, < 2.a)
httpclient (>= 2.8.1, < 3.a)
Expand All @@ -126,19 +125,19 @@ GEM
google-apis-core (>= 0.11.0, < 2.a)
google-apis-playcustomapp_v1 (0.13.0)
google-apis-core (>= 0.11.0, < 2.a)
google-apis-storage_v1 (0.19.0)
google-apis-core (>= 0.9.0, < 2.a)
google-apis-storage_v1 (0.29.0)
google-apis-core (>= 0.11.0, < 2.a)
google-cloud-core (1.6.0)
google-cloud-env (~> 1.0)
google-cloud-errors (~> 1.0)
google-cloud-env (1.6.0)
faraday (>= 0.17.3, < 3.0)
google-cloud-errors (1.3.1)
google-cloud-storage (1.44.0)
google-cloud-storage (1.45.0)
addressable (~> 2.8)
digest-crc (~> 0.4)
google-apis-iamcredentials_v1 (~> 0.1)
google-apis-storage_v1 (~> 0.19.0)
google-apis-storage_v1 (~> 0.29.0)
google-cloud-core (~> 1.6)
googleauth (>= 0.16.2, < 2.a)
mini_mime (~> 1.0)
Expand All @@ -164,8 +163,8 @@ GEM
optparse (0.1.1)
os (1.1.4)
plist (3.7.0)
public_suffix (5.0.3)
rake (13.0.6)
public_suffix (5.0.4)
rake (13.1.0)
representable (3.2.0)
declarative (< 0.1.0)
trailblazer-option (>= 0.1.1, < 0.2.0)
Expand Down Expand Up @@ -193,13 +192,10 @@ GEM
tty-spinner (0.9.3)
tty-cursor (~> 0.7)
uber (0.1.0)
unf (0.1.4)
unf_ext
unf_ext (0.0.8.2)
unicode-display_width (2.4.2)
unicode-display_width (2.5.0)
webrick (1.8.1)
word_wrap (1.0.0)
xcodeproj (1.22.0)
xcodeproj (1.23.0)
CFPropertyList (>= 2.3.3, < 4.0)
atomos (~> 0.1.3)
claide (>= 1.0.2, < 2.0)
Expand All @@ -217,7 +213,7 @@ PLATFORMS
x86_64-linux

DEPENDENCIES
fastlane (= 2.216.0)
fastlane (= 2.217.0)
fastlane-plugin-firebase_app_distribution

RUBY VERSION
Expand Down
1 change: 1 addition & 0 deletions androidHyperskillApp/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ dependencies {
implementation(libs.android.ui.fragment)
implementation(libs.android.ui.fragment.ktx)
implementation(libs.android.lifecycle.runtime)
implementation(libs.android.browser)

implementation(libs.kotlin.coroutines.core)
implementation(libs.kotlin.coroutines.android)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
package org.hyperskill.app.android.challenge.delegate

import android.app.Activity
import android.content.Context
import android.net.Uri
import android.widget.Toast
import androidx.browser.customtabs.CustomTabsIntent
import androidx.compose.runtime.getValue
import androidx.compose.ui.platform.ComposeView
import androidx.fragment.app.FragmentManager
import androidx.lifecycle.compose.collectAsStateWithLifecycle
import kotlinx.coroutines.flow.MutableStateFlow
import org.hyperskill.app.R
import org.hyperskill.app.android.challenge.ui.ChallengeCard
import org.hyperskill.app.android.core.extensions.openUrl
import org.hyperskill.app.android.core.extensions.setHyperskillColors
import org.hyperskill.app.android.core.view.ui.dialog.CreateMagicLinkLoadingProgressDialogFragment
import org.hyperskill.app.android.core.view.ui.dialog.dismissDialogFragmentIfExists
import org.hyperskill.app.android.core.view.ui.widget.compose.HyperskillTheme
import org.hyperskill.app.challenges.widget.presentation.ChallengeWidgetFeature
import org.hyperskill.app.challenges.widget.view.model.ChallengeWidgetViewState
import org.hyperskill.app.challenges.widget.view.model.isLoadingMagicLink
import ru.nobird.android.view.base.ui.extension.showIfNotExists

class ChallengeCardDelegate {
private val stateFlow: MutableStateFlow<ChallengeWidgetViewState?> = MutableStateFlow(null)

fun setup(
composeView: ComposeView,
onNewMessage: (ChallengeWidgetFeature.Message) -> Unit
) {
composeView.setContent {
HyperskillTheme {
val viewState by stateFlow.collectAsStateWithLifecycle()
viewState?.let { actualViewState ->
ChallengeCard(viewState = actualViewState, onNewMessage = onNewMessage)
}
}
}
}

fun render(
fragmentManager: FragmentManager,
state: ChallengeWidgetViewState
) {
stateFlow.value = state
if (state is ChallengeWidgetViewState.Content && state.isLoadingMagicLink) {
CreateMagicLinkLoadingProgressDialogFragment.newInstance()
.showIfNotExists(fragmentManager, CreateMagicLinkLoadingProgressDialogFragment.TAG)
} else {
fragmentManager.dismissDialogFragmentIfExists(CreateMagicLinkLoadingProgressDialogFragment.TAG)
}
}

fun handleAction(
context: Context,
activity: Activity,
action: ChallengeWidgetFeature.Action.ViewAction
) {
when (action) {
is ChallengeWidgetFeature.Action.ViewAction.OpenUrl -> {
if (action.shouldOpenInApp) {
val intent = CustomTabsIntent.Builder()
.setHyperskillColors(context)
.build()
intent.launchUrl(activity, Uri.parse(action.url))
} else {
context.openUrl(action.url)
}
}
ChallengeWidgetFeature.Action.ViewAction.ShowNetworkError -> {
Toast
.makeText(context, R.string.common_error, Toast.LENGTH_SHORT)
.show()
}
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
package org.hyperskill.app.android.challenge.ui

import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.material.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.tooling.preview.PreviewParameter
import androidx.compose.ui.tooling.preview.PreviewParameterProvider
import org.hyperskill.app.android.core.view.ui.widget.compose.HyperskillButton
import org.hyperskill.app.android.core.view.ui.widget.compose.HyperskillTheme
import org.hyperskill.app.challenges.widget.view.model.ChallengeWidgetViewState.Content.Announcement

@Composable
fun AnnouncementChallengeCard(
state: Announcement,
onReloadClick: () -> Unit,
onDescriptionLinkClick: (String) -> Unit,
modifier: Modifier = Modifier
) {
ChallengeScaffold(modifier) {
ChallengeHeader(
title = state.headerData.title,
dateText = state.headerData.formattedDurationOfTime,
imageRes = org.hyperskill.app.android.R.drawable.img_challenge_announcment,
modifier = Modifier.fillMaxWidth()
)
ChallengeDescription(
description = state.headerData.description,
onLinkClick = onDescriptionLinkClick
)
when (val startIn = state.startsInState) {
Announcement.StartsInState.Deadline -> {
HyperskillButton(
onClick = onReloadClick,
modifier = Modifier.fillMaxWidth()
) {
Text(
text = stringResource(
id = org.hyperskill.app.R.string.challenge_widget_reload_button
)
)
}
}
is Announcement.StartsInState.TimeRemaining -> {
ChallengeTimeText(title = startIn.title, subtitle = startIn.subtitle)
}
}
}
}

private class AnnouncementChallengeCardPreviewProvider : PreviewParameterProvider<Announcement.StartsInState> {
override val values: Sequence<Announcement.StartsInState>
get() = sequenceOf(
Announcement.StartsInState.TimeRemaining(
title = ChallengeCardPreviewValues.TIME_TITLE,
subtitle = ChallengeCardPreviewValues.TIME_SUBTITLE
),
Announcement.StartsInState.Deadline
)
}

@Preview()
@Composable
private fun AnnouncementChallengeCardPreview(
@PreviewParameter(AnnouncementChallengeCardPreviewProvider::class) startsIn: Announcement.StartsInState
) {
HyperskillTheme {
AnnouncementChallengeCard(
state = Announcement(
headerData = ChallengeCardPreviewValues.headerData,
startsInState = startsIn
),
onReloadClick = {},
onDescriptionLinkClick = {}
)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
package org.hyperskill.app.android.challenge.ui

import androidx.compose.foundation.layout.aspectRatio
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.res.stringResource
import org.hyperskill.app.R
import org.hyperskill.app.android.core.view.ui.widget.compose.ShimmerLoading
import org.hyperskill.app.android.core.view.ui.widget.compose.WidgetDataLoadingError
import org.hyperskill.app.challenges.widget.presentation.ChallengeWidgetFeature.Message
import org.hyperskill.app.challenges.widget.view.model.ChallengeWidgetViewState

@Composable
fun ChallengeCard(
viewState: ChallengeWidgetViewState,
onNewMessage: (Message) -> Unit
) {
when (viewState) {
ChallengeWidgetViewState.Idle, ChallengeWidgetViewState.Empty -> {
// no op
}
is ChallengeWidgetViewState.Loading -> {
if (viewState.shouldShowSkeleton) {
ShimmerLoading(
modifier = Modifier
.fillMaxWidth()
.aspectRatio(ratio = 0.5f)
)
}
}
ChallengeWidgetViewState.Error -> {
WidgetDataLoadingError(
onRetryClick = {
onNewMessage(Message.RetryContentLoading)
},
modifier = Modifier.fillMaxWidth(),
title = stringResource(id = R.string.challenge_widget_network_error_text)
)
}
is ChallengeWidgetViewState.Content.Announcement -> {
AnnouncementChallengeCard(
state = viewState,
onReloadClick = {
onNewMessage(Message.DeadlineReachedReloadClicked)
},
onDescriptionLinkClick = {
onNewMessage(Message.LinkInTheDescriptionClicked(it))
}
)
}
is ChallengeWidgetViewState.Content.HappeningNow -> {
HappeningNowChallengeCard(
state = viewState,
onReloadClick = {
onNewMessage(Message.DeadlineReachedReloadClicked)
},
onDescriptionLinkClick = {
onNewMessage(Message.LinkInTheDescriptionClicked(it))
}
)
}
is ChallengeWidgetViewState.Content.Completed -> {
CompletedChallengeCard(
state = viewState,
onCollectRewardClick = {
onNewMessage(Message.CollectRewardClicked)
}
)
}
is ChallengeWidgetViewState.Content.PartiallyCompleted -> {
PartiallyCompletedChallengeCard(
state = viewState,
onCollectRewardClick = {
onNewMessage(Message.CollectRewardClicked)
}
)
}
is ChallengeWidgetViewState.Content.Ended -> {
NotCompletedChallengeCard(state = viewState)
}
}
}
Loading

0 comments on commit 8755922

Please sign in to comment.