Skip to content

Commit

Permalink
Merge remote tracking branch origin/develop
Browse files Browse the repository at this point in the history
  • Loading branch information
ivan-magda committed Sep 22, 2023
2 parents 219872f + 41d58c1 commit 5f51f17
Show file tree
Hide file tree
Showing 94 changed files with 1,571 additions and 189 deletions.
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.215.1"
gem "fastlane", "2.216.0"

eval_gemfile("fastlane/Pluginfile")
12 changes: 6 additions & 6 deletions androidHyperskillApp/Gemfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -8,16 +8,16 @@ GEM
artifactory (3.0.15)
atomos (0.1.3)
aws-eventstream (1.2.0)
aws-partitions (1.824.0)
aws-sdk-core (3.181.1)
aws-partitions (1.826.0)
aws-sdk-core (3.183.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-sigv4 (~> 1.1)
aws-sdk-s3 (1.134.0)
aws-sdk-s3 (1.135.0)
aws-sdk-core (~> 3, >= 3.181.0)
aws-sdk-kms (~> 1)
aws-sigv4 (~> 1.6)
Expand Down Expand Up @@ -66,7 +66,7 @@ GEM
faraday_middleware (1.2.0)
faraday (~> 1.0)
fastimage (2.2.7)
fastlane (2.215.1)
fastlane (2.216.0)
CFPropertyList (>= 2.3, < 4.0.0)
addressable (>= 2.8, < 3.0.0)
artifactory (~> 3.0)
Expand Down Expand Up @@ -142,7 +142,7 @@ GEM
google-cloud-core (~> 1.6)
googleauth (>= 0.16.2, < 2.a)
mini_mime (~> 1.0)
googleauth (1.8.0)
googleauth (1.8.1)
faraday (>= 0.17.3, < 3.a)
jwt (>= 1.4, < 3.0)
multi_json (~> 1.11)
Expand Down Expand Up @@ -217,7 +217,7 @@ PLATFORMS
x86_64-linux

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

RUBY VERSION
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
package org.hyperskill.app.android.core.view.ui.widget.compose

import androidx.compose.foundation.BorderStroke
import androidx.compose.foundation.interaction.MutableInteractionSource
import androidx.compose.foundation.layout.PaddingValues
import androidx.compose.foundation.layout.RowScope
import androidx.compose.material.Button
import androidx.compose.material.ButtonColors
import androidx.compose.material.ButtonDefaults
import androidx.compose.material.ButtonElevation
import androidx.compose.material.MaterialTheme
import androidx.compose.material.ProvideTextStyle
import androidx.compose.material.TextButton
import androidx.compose.runtime.Composable
import androidx.compose.runtime.remember
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.Shape
import androidx.compose.ui.res.colorResource
import androidx.compose.ui.unit.dp
import org.hyperskill.app.R

object HyperskillButtonDefaults {
private val ButtonVerticalPadding = 14.dp
private val ButtonHorizontalPadding = 16.dp

private val TextButtonVerticalPadding = 8.dp

val ContentPadding = PaddingValues(
vertical = ButtonVerticalPadding,
horizontal = ButtonHorizontalPadding
)

val TextButtonContentPadding = PaddingValues(
vertical = TextButtonVerticalPadding,
horizontal = ButtonHorizontalPadding
)

@Composable
fun buttonColors(
backgroundColor: Color = colorResource(id = R.color.button_primary)
): ButtonColors =
ButtonDefaults.buttonColors(
backgroundColor = backgroundColor
)

@Composable
fun textButtonColors(): ButtonColors =
ButtonDefaults.textButtonColors()
}

@Composable
fun HyperskillButton(
onClick: () -> Unit,
modifier: Modifier = Modifier,
enabled: Boolean = true,
interactionSource: MutableInteractionSource = remember { MutableInteractionSource() },
elevation: ButtonElevation? = null,
shape: Shape = MaterialTheme.shapes.small,
border: BorderStroke? = null,
colors: ButtonColors = HyperskillButtonDefaults.buttonColors(),
contentPadding: PaddingValues = HyperskillButtonDefaults.ContentPadding,
content: @Composable RowScope.() -> Unit
) {
Button(
onClick = onClick,
modifier = modifier,
enabled = enabled,
interactionSource = interactionSource,
elevation = elevation,
shape = shape,
border = border,
colors = colors,
contentPadding = contentPadding,
content = content
)
}

@Composable
fun HyperskillTextButton(
onClick: () -> Unit,
modifier: Modifier = Modifier,
enabled: Boolean = true,
interactionSource: MutableInteractionSource = remember { MutableInteractionSource() },
elevation: ButtonElevation? = null,
shape: Shape = MaterialTheme.shapes.small,
border: BorderStroke? = null,
colors: ButtonColors = HyperskillButtonDefaults.textButtonColors(),
contentPadding: PaddingValues = HyperskillButtonDefaults.TextButtonContentPadding,
content: @Composable RowScope.() -> Unit
) {
TextButton(
onClick = onClick,
modifier = modifier,
enabled = enabled,
interactionSource = interactionSource,
elevation = elevation,
shape = shape,
border = border,
colors = colors,
contentPadding = contentPadding,
content = {
ProvideTextStyle(value = MaterialTheme.typography.textButton) {
content()
}
}
)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package org.hyperskill.app.android.core.view.ui.widget.compose

import androidx.compose.material.Typography
import androidx.compose.runtime.Composable
import androidx.compose.ui.res.colorResource
import androidx.compose.ui.text.TextStyle

val Typography.textButton: TextStyle
@Composable
get() = button.copy(
color = colorResource(id = org.hyperskill.app.R.color.button_ghost)
)
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
package org.hyperskill.app.android.main.view.ui.activity

import android.annotation.SuppressLint
import android.content.Intent
import android.content.pm.PackageManager
import android.os.Bundle
import androidx.activity.viewModels
import androidx.appcompat.app.AppCompatActivity
Expand Down Expand Up @@ -34,6 +36,8 @@ import org.hyperskill.app.android.notification.model.ClickedNotificationData
import org.hyperskill.app.android.notification.model.DailyStudyReminderClickedData
import org.hyperskill.app.android.notification.model.DefaultNotificationClickedData
import org.hyperskill.app.android.notification.model.PushNotificationClickedData
import org.hyperskill.app.android.notification_onboarding.fragment.NotificationsOnboardingFragment
import org.hyperskill.app.android.notification_onboarding.navigation.NotificationsOnboardingScreen
import org.hyperskill.app.android.onboarding.navigation.OnboardingScreen
import org.hyperskill.app.android.profile_settings.view.mapper.ThemeMapper
import org.hyperskill.app.android.streak_recovery.view.delegate.StreakRecoveryViewActionDelegate
Expand Down Expand Up @@ -87,6 +91,7 @@ class MainActivity :
)
}

@SuppressLint("InlinedApi")
override fun onCreate(savedInstanceState: Bundle?) {
val splashScreen = installSplashScreen()

Expand Down Expand Up @@ -116,15 +121,8 @@ class MainActivity :

startupViewModel(intent)

lifecycleScope.launch {
router
.observeResult(AuthFragment.AUTH_SUCCESS)
.flowWithLifecycle(lifecycle, Lifecycle.State.STARTED)
.collectLatest {
val profile = (it as? Profile) ?: return@collectLatest
mainViewModel.onNewMessage(AppFeature.Message.UserAuthorized(profile))
}
}
observeAuthFlowSuccess()
observeNotificationsOnboardingFlowFinished()

AppCompatDelegate.setDefaultNightMode(ThemeMapper.getAppCompatDelegate(profileSettings.theme))

Expand Down Expand Up @@ -158,6 +156,38 @@ class MainActivity :
}
}

@SuppressLint("InlinedApi")
private fun observeAuthFlowSuccess() {
lifecycleScope.launch {
router
.observeResult(AuthFragment.AUTH_SUCCESS)
.flowWithLifecycle(lifecycle, Lifecycle.State.STARTED)
.collectLatest {
val profile = (it as? Profile) ?: return@collectLatest
mainViewModel.onNewMessage(
AppFeature.Message.UserAuthorized(
profile = profile,
isNotificationPermissionGranted = ContextCompat.checkSelfPermission(
this@MainActivity,
android.Manifest.permission.POST_NOTIFICATIONS
) == PackageManager.PERMISSION_GRANTED
)
)
}
}
}

private fun observeNotificationsOnboardingFlowFinished() {
lifecycleScope.launch {
router
.observeResult(NotificationsOnboardingFragment.NOTIFICATIONS_ONBOARDING_FINISHED)
.flowWithLifecycle(lifecycle, Lifecycle.State.STARTED)
.collectLatest {
mainViewModel.onNewMessage(AppFeature.Message.NotificationOnboardingCompleted)
}
}
}

override fun onNewIntent(intent: Intent?) {
super.onNewIntent(intent)
if (intent != null) {
Expand Down Expand Up @@ -195,6 +225,8 @@ class MainActivity :
TrackSelectionListParams(isNewUserMode = true)
)
)
is AppFeature.Action.ViewAction.NavigateTo.NotificationOnBoardingScreen ->
router.newRootScreen(NotificationsOnboardingScreen)
is AppFeature.Action.ViewAction.StreakRecoveryViewAction ->
StreakRecoveryViewActionDelegate.handleViewAction(
fragmentManager = supportFragmentManager,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
package org.hyperskill.app.android.notification_onboarding.fragment

import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.compose.ui.platform.ComposeView
import androidx.fragment.app.Fragment
import androidx.fragment.app.viewModels
import androidx.lifecycle.ViewModelProvider
import com.google.accompanist.themeadapter.material.MdcTheme
import org.hyperskill.app.android.HyperskillApp
import org.hyperskill.app.android.core.view.ui.navigation.requireAppRouter
import org.hyperskill.app.android.notification.permission.NotificationPermissionDelegate
import org.hyperskill.app.android.notification_onboarding.ui.NotificationsOnboardingScreen
import org.hyperskill.app.core.view.handleActions
import org.hyperskill.app.notifications_onboarding.presentation.NotificationsOnboardingFeature.Action.ViewAction
import org.hyperskill.app.notifications_onboarding.presentation.NotificationsOnboardingFeature.Message
import org.hyperskill.app.notifications_onboarding.presentation.NotificationsOnboardingViewModel

class NotificationsOnboardingFragment : Fragment() {

companion object {
const val NOTIFICATIONS_ONBOARDING_FINISHED = "NOTIFICATIONS_ONBOARDING_FINISHED"
fun newInstance(): NotificationsOnboardingFragment =
NotificationsOnboardingFragment()
}

private var viewModelFactory: ViewModelProvider.Factory? = null
private val notificationsOnboardingViewModel: NotificationsOnboardingViewModel by viewModels {
requireNotNull(viewModelFactory)
}

private val notificationPermissionDelegate: NotificationPermissionDelegate =
NotificationPermissionDelegate(this)

override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
injectComponent()
notificationsOnboardingViewModel.handleActions(this, block = ::onAction)
}

private fun injectComponent() {
val notificationOnboardingComponent =
HyperskillApp.graph().buildPlatformNotificationOnboardingComponent()
viewModelFactory = notificationOnboardingComponent.reduxViewModelFactory
}

override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View =
ComposeView(requireContext()).apply {
setContent {
MdcTheme(
setTextColors = true,
setDefaultFontFamily = true
) {
NotificationsOnboardingScreen(notificationsOnboardingViewModel)
}
}
}

override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
notificationsOnboardingViewModel.onNewMessage(Message.ViewedEventMessage)
}

private fun onAction(action: ViewAction) {
when (action) {
ViewAction.CompleteNotificationOnboarding -> {
requireAppRouter().sendResult(NOTIFICATIONS_ONBOARDING_FINISHED, Any())
}
ViewAction.RequestNotificationPermission -> {
notificationPermissionDelegate.requestNotificationPermission { result ->
val isPermissionGranted = when (result) {
NotificationPermissionDelegate.Result.GRANTED -> true
NotificationPermissionDelegate.Result.DENIED,
NotificationPermissionDelegate.Result.DONT_ASK -> false
}
notificationsOnboardingViewModel.onNewMessage(
Message.NotificationPermissionRequestResult(isPermissionGranted)
)
}
}
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package org.hyperskill.app.android.notification_onboarding.navigation

import androidx.fragment.app.Fragment
import androidx.fragment.app.FragmentFactory
import com.github.terrakok.cicerone.androidx.FragmentScreen
import org.hyperskill.app.android.notification_onboarding.fragment.NotificationsOnboardingFragment

object NotificationsOnboardingScreen : FragmentScreen {
override fun createFragment(factory: FragmentFactory): Fragment =
NotificationsOnboardingFragment.newInstance()
}
Loading

0 comments on commit 5f51f17

Please sign in to comment.