diff --git a/androidHyperskillApp/src/main/AndroidManifest.xml b/androidHyperskillApp/src/main/AndroidManifest.xml
index 1d19647511..6a8ed9fbf0 100644
--- a/androidHyperskillApp/src/main/AndroidManifest.xml
+++ b/androidHyperskillApp/src/main/AndroidManifest.xml
@@ -64,5 +64,15 @@
android:name="firebase_analytics_collection_enabled"
android:value="false" />
+
+
+
+
\ No newline at end of file
diff --git a/androidHyperskillApp/src/main/java/org/hyperskill/app/android/core/extensions/ShareUtils.kt b/androidHyperskillApp/src/main/java/org/hyperskill/app/android/core/extensions/ShareUtils.kt
new file mode 100644
index 0000000000..ecfc0a1f0e
--- /dev/null
+++ b/androidHyperskillApp/src/main/java/org/hyperskill/app/android/core/extensions/ShareUtils.kt
@@ -0,0 +1,58 @@
+package org.hyperskill.app.android.core.extensions
+
+import android.content.ClipData
+import android.content.Context
+import android.content.Intent
+import android.graphics.Bitmap
+import android.graphics.BitmapFactory
+import android.net.Uri
+import androidx.annotation.DrawableRes
+import androidx.core.content.FileProvider
+import java.io.File
+import java.io.FileOutputStream
+import org.hyperskill.app.android.BuildConfig
+import org.hyperskill.app.android.HyperskillApp
+
+object ShareUtils {
+ fun getShareDrawableIntent(
+ context: Context,
+ @DrawableRes drawableRes: Int,
+ text: String,
+ title: String
+ ): Intent {
+ val shareIntent = Intent().apply {
+ val bitmap = BitmapFactory.decodeResource(context.resources, drawableRes)
+
+ val originImageUri = getUriForBitmap(context, bitmap, "$drawableRes.png")
+
+ action = Intent.ACTION_SEND
+ putExtra(Intent.EXTRA_STREAM, originImageUri)
+ addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
+ putExtra(Intent.EXTRA_TEXT, text)
+ clipData = ClipData.newRawUri(null, originImageUri)
+ type = "image/*"
+ }
+ return Intent.createChooser(
+ shareIntent,
+ title
+ )
+ }
+
+ private fun getUriForBitmap(
+ context: Context,
+ bitmap: Bitmap,
+ name: String
+ ): Uri {
+ val file = File(context.cacheDir, name).apply {
+ createNewFile()
+ }
+ FileOutputStream(file).use { stream ->
+ bitmap.compress(Bitmap.CompressFormat.PNG, 100, stream)
+ }
+ return FileProvider.getUriForFile(
+ HyperskillApp.getAppContext(),
+ "${BuildConfig.APPLICATION_ID}.provider",
+ file
+ )
+ }
+}
\ No newline at end of file
diff --git a/androidHyperskillApp/src/main/java/org/hyperskill/app/android/share_streak/fragment/ShareStreakDialogFragment.kt b/androidHyperskillApp/src/main/java/org/hyperskill/app/android/share_streak/fragment/ShareStreakDialogFragment.kt
new file mode 100644
index 0000000000..4dcaf9675c
--- /dev/null
+++ b/androidHyperskillApp/src/main/java/org/hyperskill/app/android/share_streak/fragment/ShareStreakDialogFragment.kt
@@ -0,0 +1,96 @@
+package org.hyperskill.app.android.share_streak.fragment
+
+import android.app.Dialog
+import android.content.DialogInterface
+import android.os.Bundle
+import android.view.LayoutInflater
+import android.view.View
+import android.view.ViewGroup
+import androidx.annotation.DrawableRes
+import by.kirich1409.viewbindingdelegate.viewBinding
+import coil.load
+import coil.transform.RoundedCornersTransformation
+import com.google.android.material.bottomsheet.BottomSheetBehavior
+import com.google.android.material.bottomsheet.BottomSheetDialog
+import com.google.android.material.bottomsheet.BottomSheetDialogFragment
+import org.hyperskill.app.android.R
+import org.hyperskill.app.android.databinding.FragmentShareStreakBinding
+import org.hyperskill.app.android.view.base.ui.extension.wrapWithTheme
+import ru.nobird.android.view.base.ui.extension.argument
+
+class ShareStreakDialogFragment : BottomSheetDialogFragment() {
+
+ companion object {
+ const val TAG = "ShareStreakBottomSheetTag"
+
+ fun newInstance(
+ streak: Int,
+ @DrawableRes imageRes: Int
+ ): ShareStreakDialogFragment =
+ ShareStreakDialogFragment().apply {
+ this.streak = streak
+ this.imageRes = imageRes
+ }
+ }
+
+ private var streak: Int by argument()
+ @get:DrawableRes
+ private var imageRes: Int by argument()
+
+ private val binding: FragmentShareStreakBinding by viewBinding(FragmentShareStreakBinding::bind)
+
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+ setStyle(STYLE_NORMAL, R.style.TopCornersRoundedBottomSheetDialog)
+ }
+
+ override fun onCreateDialog(savedInstanceState: Bundle?): Dialog =
+ BottomSheetDialog(requireContext(), theme).also { dialog ->
+ dialog.setOnShowListener {
+ dialog.behavior.state = BottomSheetBehavior.STATE_EXPANDED
+ if (savedInstanceState == null) {
+ (parentFragment as? Callback)?.onShareStreakBottomSheetShown(streak)
+ }
+ }
+ }
+
+ override fun onDismiss(dialog: DialogInterface) {
+ (parentFragment as? Callback)?.onShareStreakBottomSheetDismissed(streak)
+ }
+
+ override fun onCreateView(
+ inflater: LayoutInflater,
+ container: ViewGroup?,
+ savedInstanceState: Bundle?
+ ): View? =
+ inflater.wrapWithTheme(requireActivity())
+ .inflate(R.layout.fragment_share_streak, container, false)
+
+ override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
+ with(binding) {
+ shareStreakImage.load(imageRes) {
+ transformations(
+ RoundedCornersTransformation(
+ requireContext().resources.getDimension(R.dimen.corner_radius)
+ )
+ )
+ }
+ shareStreakShareButton.setOnClickListener {
+ (parentFragment as? Callback)?.onShareClick(streak)
+ }
+ shareStreakRefuseButton.setOnClickListener {
+ (parentFragment as? Callback)?.onRefuseStreakSharingClick(streak)
+ }
+ }
+ }
+
+ interface Callback {
+ fun onShareStreakBottomSheetShown(streak: Int)
+
+ fun onShareStreakBottomSheetDismissed(streak: Int)
+
+ fun onShareClick(streak: Int)
+
+ fun onRefuseStreakSharingClick(streak: Int)
+ }
+}
\ No newline at end of file
diff --git a/androidHyperskillApp/src/main/java/org/hyperskill/app/android/stage_implementation/view/fragment/StageStepWrapperFragment.kt b/androidHyperskillApp/src/main/java/org/hyperskill/app/android/stage_implementation/view/fragment/StageStepWrapperFragment.kt
index 0ba43cac06..8ee6c4b0db 100644
--- a/androidHyperskillApp/src/main/java/org/hyperskill/app/android/stage_implementation/view/fragment/StageStepWrapperFragment.kt
+++ b/androidHyperskillApp/src/main/java/org/hyperskill/app/android/stage_implementation/view/fragment/StageStepWrapperFragment.kt
@@ -12,6 +12,7 @@ import org.hyperskill.app.android.core.view.ui.fragment.setChildFragment
import org.hyperskill.app.android.core.view.ui.navigation.requireRouter
import org.hyperskill.app.android.databinding.FragmentStageStepWrapperBinding
import org.hyperskill.app.android.main.view.ui.navigation.MainScreenRouter
+import org.hyperskill.app.android.share_streak.fragment.ShareStreakDialogFragment
import org.hyperskill.app.android.step.view.delegate.StepDelegate
import org.hyperskill.app.android.step.view.fragment.StepFragment
import org.hyperskill.app.android.step.view.model.StepCompletionHost
@@ -41,7 +42,8 @@ class StageStepWrapperFragment :
Fragment(R.layout.fragment_stage_step_wrapper),
ReduxView,
StepCompletionHost,
- RequestDailyStudyReminderDialogFragment.Callback {
+ RequestDailyStudyReminderDialogFragment.Callback,
+ ShareStreakDialogFragment.Callback {
companion object {
private const val STEP_DESCRIPTION_FRAGMENT_TAG = "step_content"
@@ -162,4 +164,20 @@ class StageStepWrapperFragment :
override fun onPermissionResult(isGranted: Boolean) {
stepDelegate?.onPermissionResult(isGranted)
}
+
+ override fun onShareStreakBottomSheetShown(streak: Int) {
+ stepViewModel.onShareStreakBottomSheetShown(streak)
+ }
+
+ override fun onShareStreakBottomSheetDismissed(streak: Int) {
+ stepViewModel.onShareStreakBottomSheetDismissed(streak)
+ }
+
+ override fun onShareClick(streak: Int) {
+ stepViewModel.onShareClick(streak)
+ }
+
+ override fun onRefuseStreakSharingClick(streak: Int) {
+ stepViewModel.onRefuseStreakSharingClick(streak)
+ }
}
\ No newline at end of file
diff --git a/androidHyperskillApp/src/main/java/org/hyperskill/app/android/step/view/delegate/StepDelegate.kt b/androidHyperskillApp/src/main/java/org/hyperskill/app/android/step/view/delegate/StepDelegate.kt
index c4ce1018ff..082585f39a 100644
--- a/androidHyperskillApp/src/main/java/org/hyperskill/app/android/step/view/delegate/StepDelegate.kt
+++ b/androidHyperskillApp/src/main/java/org/hyperskill/app/android/step/view/delegate/StepDelegate.kt
@@ -1,7 +1,13 @@
package org.hyperskill.app.android.step.view.delegate
+import android.content.ActivityNotFoundException
+import android.content.Context
+import android.util.Log
+import androidx.annotation.DrawableRes
import androidx.core.app.NotificationManagerCompat
import androidx.fragment.app.Fragment
+import org.hyperskill.app.R
+import org.hyperskill.app.android.core.extensions.ShareUtils
import org.hyperskill.app.android.core.extensions.checkNotificationChannelAvailability
import org.hyperskill.app.android.core.view.ui.navigation.requireRouter
import org.hyperskill.app.android.databinding.ErrorNoConnectionWithButtonBinding
@@ -11,6 +17,7 @@ import org.hyperskill.app.android.main.view.ui.navigation.Tabs
import org.hyperskill.app.android.main.view.ui.navigation.switch
import org.hyperskill.app.android.notification.model.HyperskillNotificationChannel
import org.hyperskill.app.android.notification.permission.NotificationPermissionDelegate
+import org.hyperskill.app.android.share_streak.fragment.ShareStreakDialogFragment
import org.hyperskill.app.android.step.view.dialog.TopicPracticeCompletedBottomSheet
import org.hyperskill.app.android.step.view.screen.StepScreen
import org.hyperskill.app.android.step_quiz.view.dialog.CompletedStepOfTheDayDialogFragment
@@ -25,7 +32,8 @@ class StepDelegate(
private val onRequestDailyStudyRemindersPermissionResult: (Boolean) -> Unit
) : RequestDailyStudyReminderDialogFragment.Callback
where TFragment : Fragment,
- TFragment : RequestDailyStudyReminderDialogFragment.Callback {
+ TFragment : RequestDailyStudyReminderDialogFragment.Callback,
+ TFragment : ShareStreakDialogFragment.Callback {
private val notificationPermissionDelegate: NotificationPermissionDelegate =
NotificationPermissionDelegate(fragment, ::onNotificationPermissionResult)
@@ -78,15 +86,22 @@ class StepDelegate(
}
is StepCompletionFeature.Action.ViewAction.ShowProblemOfDaySolvedModal -> {
CompletedStepOfTheDayDialogFragment
- .newInstance(earnedGemsText = stepCompletionAction.earnedGemsText)
+ .newInstance(
+ earnedGemsText = stepCompletionAction.earnedGemsText,
+ shareStreakData = stepCompletionAction.shareStreakData
+ )
.showIfNotExists(fragment.childFragmentManager, CompletedStepOfTheDayDialogFragment.TAG)
}
is StepCompletionFeature.Action.ViewAction.ShowShareStreakModal -> {
- // TODO: ALTAPPS-1028 Show share streak modal
+ ShareStreakDialogFragment
+ .newInstance(
+ streak = stepCompletionAction.streak,
+ imageRes = getShareStreakDrawableRes(stepCompletionAction.streak)
+ )
+ .showIfNotExists(fragment.childFragmentManager, ShareStreakDialogFragment.TAG)
}
is StepCompletionFeature.Action.ViewAction.ShowShareStreakSystemModal -> {
- // TODO: ALTAPPS-1028 Show system share streak modal (after "Share your streak" button clicked)
- // on the problem of day solved modal
+ shareStreak(stepCompletionAction.streak)
}
}
}
@@ -121,4 +136,36 @@ class StepDelegate(
.checkNotificationChannelAvailability(context, HyperskillNotificationChannel.DailyReminder)
}
}
+
+ @DrawableRes
+ private fun getShareStreakDrawableRes(streak: Int): Int =
+ when (streak) {
+ 1 -> org.hyperskill.app.android.R.drawable.img_share_streak_day_1
+ 5 -> org.hyperskill.app.android.R.drawable.img_share_streak_day_5
+ 10 -> org.hyperskill.app.android.R.drawable.img_share_streak_day_10
+ 25 -> org.hyperskill.app.android.R.drawable.img_share_streak_day_25
+ 50 -> org.hyperskill.app.android.R.drawable.img_share_streak_day_50
+ 100 -> org.hyperskill.app.android.R.drawable.img_share_streak_day_100
+ else -> org.hyperskill.app.android.R.drawable.img_share_streak_day_1
+ }
+
+ private fun getShareStreakText(context: Context): String {
+ val title = context.getString(R.string.share_streak_sharing_text)
+ val link = context.getString(R.string.share_streak_sharing_url)
+ return "$title\n$link"
+ }
+
+ private fun shareStreak(streak: Int) {
+ val shareIntent = ShareUtils.getShareDrawableIntent(
+ fragment.requireContext(),
+ getShareStreakDrawableRes(streak),
+ text = getShareStreakText(fragment.requireContext()),
+ title = fragment.requireContext().getString(R.string.share_streak_modal_title)
+ )
+ try {
+ fragment.startActivity(shareIntent)
+ } catch (e: ActivityNotFoundException) {
+ Log.e("StepDelegate", "Unable to share streak. Activity not found!")
+ }
+ }
}
\ No newline at end of file
diff --git a/androidHyperskillApp/src/main/java/org/hyperskill/app/android/step/view/fragment/StepFragment.kt b/androidHyperskillApp/src/main/java/org/hyperskill/app/android/step/view/fragment/StepFragment.kt
index bb8f4679b3..71709b3a35 100644
--- a/androidHyperskillApp/src/main/java/org/hyperskill/app/android/step/view/fragment/StepFragment.kt
+++ b/androidHyperskillApp/src/main/java/org/hyperskill/app/android/step/view/fragment/StepFragment.kt
@@ -11,6 +11,7 @@ import org.hyperskill.app.android.core.extensions.argument
import org.hyperskill.app.android.core.view.ui.fragment.setChildFragment
import org.hyperskill.app.android.databinding.FragmentStepBinding
import org.hyperskill.app.android.main.view.ui.navigation.MainScreenRouter
+import org.hyperskill.app.android.share_streak.fragment.ShareStreakDialogFragment
import org.hyperskill.app.android.step.view.delegate.StepDelegate
import org.hyperskill.app.android.step.view.model.StepCompletionHost
import org.hyperskill.app.android.step.view.model.StepCompletionView
@@ -30,7 +31,8 @@ class StepFragment :
Fragment(R.layout.fragment_step),
ReduxView,
StepCompletionHost,
- RequestDailyStudyReminderDialogFragment.Callback {
+ RequestDailyStudyReminderDialogFragment.Callback,
+ ShareStreakDialogFragment.Callback {
companion object {
private const val STEP_TAG = "step"
@@ -101,6 +103,16 @@ class StepFragment :
}
}
+ private fun initStepContainer(data: StepFeature.State.Data) {
+ setChildFragment(R.id.stepContainer, STEP_TAG) {
+ if (data.step.type == Step.Type.PRACTICE) {
+ StepPracticeFragment.newInstance(data.step, stepRoute)
+ } else {
+ StepTheoryFragment.newInstance(data.step, stepRoute, data.isPracticingAvailable)
+ }
+ }
+ }
+
override fun onDestroyView() {
super.onDestroyView()
viewStateDelegate = null
@@ -121,13 +133,19 @@ class StepFragment :
stepDelegate?.onPermissionResult(isGranted)
}
- private fun initStepContainer(data: StepFeature.State.Data) {
- setChildFragment(R.id.stepContainer, STEP_TAG) {
- if (data.step.type == Step.Type.PRACTICE) {
- StepPracticeFragment.newInstance(data.step, stepRoute)
- } else {
- StepTheoryFragment.newInstance(data.step, stepRoute, data.isPracticingAvailable)
- }
- }
+ override fun onShareStreakBottomSheetShown(streak: Int) {
+ stepViewModel.onShareStreakBottomSheetShown(streak)
+ }
+
+ override fun onShareStreakBottomSheetDismissed(streak: Int) {
+ stepViewModel.onShareStreakBottomSheetDismissed(streak)
+ }
+
+ override fun onRefuseStreakSharingClick(streak: Int) {
+ stepViewModel.onRefuseStreakSharingClick(streak)
+ }
+
+ override fun onShareClick(streak: Int) {
+ stepViewModel.onShareClick(streak)
}
}
\ No newline at end of file
diff --git a/androidHyperskillApp/src/main/java/org/hyperskill/app/android/step_quiz/view/dialog/CompletedStepOfTheDayDialogFragment.kt b/androidHyperskillApp/src/main/java/org/hyperskill/app/android/step_quiz/view/dialog/CompletedStepOfTheDayDialogFragment.kt
index 5cc929a3a7..3273625254 100644
--- a/androidHyperskillApp/src/main/java/org/hyperskill/app/android/step_quiz/view/dialog/CompletedStepOfTheDayDialogFragment.kt
+++ b/androidHyperskillApp/src/main/java/org/hyperskill/app/android/step_quiz/view/dialog/CompletedStepOfTheDayDialogFragment.kt
@@ -7,12 +7,14 @@ import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.appcompat.view.ContextThemeWrapper
+import androidx.core.view.isVisible
import androidx.fragment.app.viewModels
import by.kirich1409.viewbindingdelegate.viewBinding
import com.google.android.material.bottomsheet.BottomSheetBehavior
import com.google.android.material.bottomsheet.BottomSheetDialog
import com.google.android.material.bottomsheet.BottomSheetDialogFragment
import org.hyperskill.app.android.R
+import org.hyperskill.app.android.core.extensions.argument
import org.hyperskill.app.android.databinding.FragmentCompletedDailyStepBinding
import org.hyperskill.app.step.presentation.StepFeature
import org.hyperskill.app.step.presentation.StepViewModel
@@ -23,9 +25,13 @@ class CompletedStepOfTheDayDialogFragment : BottomSheetDialogFragment() {
companion object {
const val TAG = "CompletedStepOfTheDayDialogFragment"
- fun newInstance(earnedGemsText: String): CompletedStepOfTheDayDialogFragment =
+ fun newInstance(
+ earnedGemsText: String,
+ shareStreakData: StepCompletionFeature.ShareStreakData
+ ): CompletedStepOfTheDayDialogFragment =
CompletedStepOfTheDayDialogFragment().apply {
this.earnedGemsText = earnedGemsText
+ this.shareStreakData = shareStreakData
}
}
@@ -36,6 +42,10 @@ class CompletedStepOfTheDayDialogFragment : BottomSheetDialogFragment() {
private var earnedGemsText: String by argument()
+ private var shareStreakData: StepCompletionFeature.ShareStreakData by argument(
+ StepCompletionFeature.ShareStreakData.serializer()
+ )
+
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setStyle(STYLE_NORMAL, R.style.TopCornersRoundedBottomSheetDialog)
@@ -71,6 +81,12 @@ class CompletedStepOfTheDayDialogFragment : BottomSheetDialogFragment() {
super.onViewCreated(view, savedInstanceState)
with(viewBinding) {
completedDailyStepEarnedGemsTextView.text = earnedGemsText
+
+ completedDailyStepStreakTextView.isVisible =
+ shareStreakData is StepCompletionFeature.ShareStreakData.Content
+ completedDailyStepStreakTextView.text =
+ (shareStreakData as? StepCompletionFeature.ShareStreakData.Content)?.streakText
+
completedDailyStepGoBackButton.setOnClickListener {
stepViewModel.onNewMessage(
StepFeature.Message.StepCompletionMessage(
@@ -79,6 +95,18 @@ class CompletedStepOfTheDayDialogFragment : BottomSheetDialogFragment() {
)
dismiss()
}
+
+ completedDailyStepShareStreakButton.isVisible =
+ shareStreakData is StepCompletionFeature.ShareStreakData.Content
+ (shareStreakData as? StepCompletionFeature.ShareStreakData.Content)?.streak?.let { streak ->
+ completedDailyStepShareStreakButton.setOnClickListener {
+ stepViewModel.onNewMessage(
+ StepFeature.Message.StepCompletionMessage(
+ StepCompletionFeature.Message.ProblemOfDaySolvedModalShareStreakClicked(streak)
+ )
+ )
+ }
+ }
}
}
diff --git a/androidHyperskillApp/src/main/res/drawable/ic_streak.xml b/androidHyperskillApp/src/main/res/drawable/ic_streak.xml
new file mode 100644
index 0000000000..8e8b626be4
--- /dev/null
+++ b/androidHyperskillApp/src/main/res/drawable/ic_streak.xml
@@ -0,0 +1,18 @@
+
+
+
+
+
diff --git a/androidHyperskillApp/src/main/res/drawable/img_share_streak_day_1.png b/androidHyperskillApp/src/main/res/drawable/img_share_streak_day_1.png
new file mode 100644
index 0000000000..29099f7ef4
Binary files /dev/null and b/androidHyperskillApp/src/main/res/drawable/img_share_streak_day_1.png differ
diff --git a/androidHyperskillApp/src/main/res/drawable/img_share_streak_day_10.png b/androidHyperskillApp/src/main/res/drawable/img_share_streak_day_10.png
new file mode 100644
index 0000000000..8cde9d572e
Binary files /dev/null and b/androidHyperskillApp/src/main/res/drawable/img_share_streak_day_10.png differ
diff --git a/androidHyperskillApp/src/main/res/drawable/img_share_streak_day_100.png b/androidHyperskillApp/src/main/res/drawable/img_share_streak_day_100.png
new file mode 100644
index 0000000000..9755bae702
Binary files /dev/null and b/androidHyperskillApp/src/main/res/drawable/img_share_streak_day_100.png differ
diff --git a/androidHyperskillApp/src/main/res/drawable/img_share_streak_day_25.png b/androidHyperskillApp/src/main/res/drawable/img_share_streak_day_25.png
new file mode 100644
index 0000000000..f2337f29a3
Binary files /dev/null and b/androidHyperskillApp/src/main/res/drawable/img_share_streak_day_25.png differ
diff --git a/androidHyperskillApp/src/main/res/drawable/img_share_streak_day_5.png b/androidHyperskillApp/src/main/res/drawable/img_share_streak_day_5.png
new file mode 100644
index 0000000000..7e4376db1e
Binary files /dev/null and b/androidHyperskillApp/src/main/res/drawable/img_share_streak_day_5.png differ
diff --git a/androidHyperskillApp/src/main/res/drawable/img_share_streak_day_50.png b/androidHyperskillApp/src/main/res/drawable/img_share_streak_day_50.png
new file mode 100644
index 0000000000..aef1046d61
Binary files /dev/null and b/androidHyperskillApp/src/main/res/drawable/img_share_streak_day_50.png differ
diff --git a/androidHyperskillApp/src/main/res/layout/fragment_completed_daily_step.xml b/androidHyperskillApp/src/main/res/layout/fragment_completed_daily_step.xml
index a4d4323ccc..be5964b456 100644
--- a/androidHyperskillApp/src/main/res/layout/fragment_completed_daily_step.xml
+++ b/androidHyperskillApp/src/main/res/layout/fragment_completed_daily_step.xml
@@ -5,6 +5,7 @@
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="wrap_content"
+ android:paddingBottom="20dp"
>
@@ -51,7 +52,7 @@
android:textAppearance="@style/TextAppearance.AppCompat.Body1"
android:text="@string/step_quiz_problem_of_day_solved_modal_text"
android:layout_marginTop="20dp"
- android:layout_marginHorizontal="20dp"
+ android:layout_marginHorizontal="16dp"
app:layout_constraintTop_toBottomOf="@+id/completedDailyStepTitleTextView"
/>
@@ -68,10 +69,29 @@
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/completedDailyStepDescriptionTextView"
android:layout_marginTop="24dp"
- android:layout_marginStart="20dp"
+ android:layout_marginStart="16dp"
tools:text="300"
/>
+
+
+
+
\ No newline at end of file
diff --git a/androidHyperskillApp/src/main/res/layout/fragment_share_streak.xml b/androidHyperskillApp/src/main/res/layout/fragment_share_streak.xml
new file mode 100644
index 0000000000..7d8d9f1f26
--- /dev/null
+++ b/androidHyperskillApp/src/main/res/layout/fragment_share_streak.xml
@@ -0,0 +1,60 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/androidHyperskillApp/src/main/res/xml/provider_paths.xml b/androidHyperskillApp/src/main/res/xml/provider_paths.xml
new file mode 100644
index 0000000000..ae73680b42
--- /dev/null
+++ b/androidHyperskillApp/src/main/res/xml/provider_paths.xml
@@ -0,0 +1,4 @@
+
+
+
+
\ No newline at end of file
diff --git a/gradle/app.versions.toml b/gradle/app.versions.toml
index 0bbe9a07e8..b6c0498b5f 100644
--- a/gradle/app.versions.toml
+++ b/gradle/app.versions.toml
@@ -2,5 +2,5 @@
minSdk = '24'
targetSdk = '33'
compileSdk = '33'
-versionName = '1.41'
-versionCode = '233'
\ No newline at end of file
+versionName = '1.42'
+versionCode = '236'
\ No newline at end of file
diff --git a/iosHyperskillApp/NotificationServiceExtension/Info.plist b/iosHyperskillApp/NotificationServiceExtension/Info.plist
index 6f906799ef..24c7fa57ab 100644
--- a/iosHyperskillApp/NotificationServiceExtension/Info.plist
+++ b/iosHyperskillApp/NotificationServiceExtension/Info.plist
@@ -9,9 +9,9 @@
CFBundleIdentifier
$(PRODUCT_BUNDLE_IDENTIFIER)
CFBundleVersion
- 234
+ 236
CFBundleShortVersionString
- 1.41
+ 1.42
CFBundlePackageType
$(PRODUCT_BUNDLE_PACKAGE_TYPE)
CFBundleExecutable
diff --git a/iosHyperskillApp/iosHyperskillApp.xcodeproj/project.pbxproj b/iosHyperskillApp/iosHyperskillApp.xcodeproj/project.pbxproj
index 4a95104204..3b311db39b 100644
--- a/iosHyperskillApp/iosHyperskillApp.xcodeproj/project.pbxproj
+++ b/iosHyperskillApp/iosHyperskillApp.xcodeproj/project.pbxproj
@@ -4673,7 +4673,7 @@
buildSettings = {
CLANG_CXX_LANGUAGE_STANDARD = "gnu++20";
CODE_SIGN_STYLE = Automatic;
- CURRENT_PROJECT_VERSION = 234;
+ CURRENT_PROJECT_VERSION = 236;
DEBUG_INFORMATION_FORMAT = dwarf;
DEVELOPMENT_TEAM = 3DWS674B2M;
GENERATE_INFOPLIST_FILE = NO;
@@ -4694,7 +4694,7 @@
buildSettings = {
CLANG_CXX_LANGUAGE_STANDARD = "gnu++20";
CODE_SIGN_STYLE = Automatic;
- CURRENT_PROJECT_VERSION = 234;
+ CURRENT_PROJECT_VERSION = 236;
DEVELOPMENT_TEAM = 3DWS674B2M;
GENERATE_INFOPLIST_FILE = NO;
INFOPLIST_FILE = iosHyperskillAppUITests/Info.plist;
@@ -4715,7 +4715,7 @@
BUNDLE_LOADER = "$(TEST_HOST)";
CLANG_CXX_LANGUAGE_STANDARD = "gnu++17";
CODE_SIGN_STYLE = Automatic;
- CURRENT_PROJECT_VERSION = 234;
+ CURRENT_PROJECT_VERSION = 236;
DEBUG_INFORMATION_FORMAT = dwarf;
DEVELOPMENT_TEAM = 3DWS674B2M;
INFOPLIST_FILE = iosHyperskillAppTests/Info.plist;
@@ -4736,7 +4736,7 @@
BUNDLE_LOADER = "$(TEST_HOST)";
CLANG_CXX_LANGUAGE_STANDARD = "gnu++17";
CODE_SIGN_STYLE = Automatic;
- CURRENT_PROJECT_VERSION = 234;
+ CURRENT_PROJECT_VERSION = 236;
DEVELOPMENT_TEAM = 3DWS674B2M;
INFOPLIST_FILE = iosHyperskillAppTests/Info.plist;
IPHONEOS_DEPLOYMENT_TARGET = 14.0;
@@ -4757,7 +4757,7 @@
CODE_SIGN_ENTITLEMENTS = NotificationServiceExtension/NotificationServiceExtension.entitlements;
CODE_SIGN_IDENTITY = "iPhone Developer";
CODE_SIGN_STYLE = Automatic;
- CURRENT_PROJECT_VERSION = 234;
+ CURRENT_PROJECT_VERSION = 236;
DEBUG_INFORMATION_FORMAT = dwarf;
DEVELOPMENT_TEAM = 3DWS674B2M;
INFOPLIST_FILE = NotificationServiceExtension/Info.plist;
@@ -4785,7 +4785,7 @@
CODE_SIGN_ENTITLEMENTS = NotificationServiceExtension/NotificationServiceExtension.entitlements;
CODE_SIGN_IDENTITY = "iPhone Developer";
CODE_SIGN_STYLE = Automatic;
- CURRENT_PROJECT_VERSION = 234;
+ CURRENT_PROJECT_VERSION = 236;
DEVELOPMENT_TEAM = 3DWS674B2M;
INFOPLIST_FILE = NotificationServiceExtension/Info.plist;
IPHONEOS_DEPLOYMENT_TARGET = 14.0;
@@ -4930,7 +4930,7 @@
CODE_SIGN_ENTITLEMENTS = iosHyperskillApp/iosHyperskillApp.entitlements;
CODE_SIGN_IDENTITY = "iPhone Developer";
CODE_SIGN_STYLE = Automatic;
- CURRENT_PROJECT_VERSION = 234;
+ CURRENT_PROJECT_VERSION = 236;
DEVELOPMENT_ASSET_PATHS = "\"iosHyperskillApp/Preview Content\"";
DEVELOPMENT_TEAM = 3DWS674B2M;
ENABLE_PREVIEWS = YES;
@@ -4966,7 +4966,7 @@
CODE_SIGN_ENTITLEMENTS = iosHyperskillApp/iosHyperskillApp.entitlements;
CODE_SIGN_IDENTITY = "iPhone Developer";
CODE_SIGN_STYLE = Automatic;
- CURRENT_PROJECT_VERSION = 234;
+ CURRENT_PROJECT_VERSION = 236;
DEVELOPMENT_ASSET_PATHS = "\"iosHyperskillApp/Preview Content\"";
DEVELOPMENT_TEAM = 3DWS674B2M;
ENABLE_PREVIEWS = YES;
diff --git a/iosHyperskillApp/iosHyperskillApp/Info.plist b/iosHyperskillApp/iosHyperskillApp/Info.plist
index ee5abcfe29..459bb92a4c 100644
--- a/iosHyperskillApp/iosHyperskillApp/Info.plist
+++ b/iosHyperskillApp/iosHyperskillApp/Info.plist
@@ -23,7 +23,7 @@
CFBundlePackageType
$(PRODUCT_BUNDLE_PACKAGE_TYPE)
CFBundleShortVersionString
- 1.41
+ 1.42
CFBundleURLTypes
@@ -36,7 +36,7 @@
CFBundleVersion
- 234
+ 236
FirebaseAppDelegateProxyEnabled
FirebaseMessagingAutoInitEnabled
diff --git a/iosHyperskillApp/iosHyperskillAppTests/Info.plist b/iosHyperskillApp/iosHyperskillAppTests/Info.plist
index 2de64564ff..e7e159dc56 100644
--- a/iosHyperskillApp/iosHyperskillAppTests/Info.plist
+++ b/iosHyperskillApp/iosHyperskillAppTests/Info.plist
@@ -13,8 +13,8 @@
CFBundlePackageType
BNDL
CFBundleShortVersionString
- 1.41
+ 1.42
CFBundleVersion
- 234
+ 236
diff --git a/iosHyperskillApp/iosHyperskillAppUITests/Info.plist b/iosHyperskillApp/iosHyperskillAppUITests/Info.plist
index 34c5aef57c..f20229aae3 100644
--- a/iosHyperskillApp/iosHyperskillAppUITests/Info.plist
+++ b/iosHyperskillApp/iosHyperskillAppUITests/Info.plist
@@ -13,8 +13,8 @@
CFBundlePackageType
$(PRODUCT_BUNDLE_PACKAGE_TYPE)
CFBundleShortVersionString
- 1.41
+ 1.42
CFBundleVersion
- 234
+ 236
diff --git a/shared/src/androidMain/kotlin/org/hyperskill/app/step/presentation/StepViewModel.kt b/shared/src/androidMain/kotlin/org/hyperskill/app/step/presentation/StepViewModel.kt
index 95201d6e81..b6cf2d02c1 100644
--- a/shared/src/androidMain/kotlin/org/hyperskill/app/step/presentation/StepViewModel.kt
+++ b/shared/src/androidMain/kotlin/org/hyperskill/app/step/presentation/StepViewModel.kt
@@ -1,5 +1,6 @@
package org.hyperskill.app.step.presentation
+import org.hyperskill.app.step_completion.presentation.StepCompletionFeature
import ru.nobird.android.view.redux.viewmodel.ReduxViewModel
import ru.nobird.app.presentation.redux.container.ReduxViewContainer
@@ -9,4 +10,36 @@ class StepViewModel(
init {
onNewMessage(StepFeature.Message.Initialize())
}
+
+ fun onShareStreakBottomSheetShown(streak: Int) {
+ onNewMessage(
+ StepFeature.Message.StepCompletionMessage(
+ StepCompletionFeature.Message.ShareStreakModalShownEventMessage(streak)
+ )
+ )
+ }
+
+ fun onShareStreakBottomSheetDismissed(streak: Int) {
+ onNewMessage(
+ StepFeature.Message.StepCompletionMessage(
+ StepCompletionFeature.Message.ShareStreakModalHiddenEventMessage(streak)
+ )
+ )
+ }
+
+ fun onShareClick(streak: Int) {
+ onNewMessage(
+ StepFeature.Message.StepCompletionMessage(
+ StepCompletionFeature.Message.ShareStreakModalShareClicked(streak)
+ )
+ )
+ }
+
+ fun onRefuseStreakSharingClick(streak: Int) {
+ onNewMessage(
+ StepFeature.Message.StepCompletionMessage(
+ StepCompletionFeature.Message.ShareStreakModalNoThanksClickedEventMessage(streak)
+ )
+ )
+ }
}
\ No newline at end of file
diff --git a/shared/src/commonMain/kotlin/org/hyperskill/app/step_completion/presentation/StepCompletionFeature.kt b/shared/src/commonMain/kotlin/org/hyperskill/app/step_completion/presentation/StepCompletionFeature.kt
index ded4bb998c..51132340cc 100644
--- a/shared/src/commonMain/kotlin/org/hyperskill/app/step_completion/presentation/StepCompletionFeature.kt
+++ b/shared/src/commonMain/kotlin/org/hyperskill/app/step_completion/presentation/StepCompletionFeature.kt
@@ -1,5 +1,6 @@
package org.hyperskill.app.step_completion.presentation
+import kotlinx.serialization.Serializable
import org.hyperskill.app.analytic.domain.model.AnalyticEvent
import org.hyperskill.app.learning_activities.domain.model.LearningActivity
import org.hyperskill.app.step.domain.model.Step
@@ -53,8 +54,11 @@ interface StepCompletionFeature {
* @see Message.ProblemOfDaySolved
* @see Action.ViewAction.ShowProblemOfDaySolvedModal
*/
+ @Serializable
sealed interface ShareStreakData {
+ @Serializable
object Empty : ShareStreakData
+ @Serializable
data class Content(val streakText: String, val streak: Int) : ShareStreakData
}