Skip to content

Commit

Permalink
Merge branch 'feature/notifications_onboarding' into feature/ALTAPPS-…
Browse files Browse the repository at this point in the history
…971/ios_notifications_onboarding_screen
  • Loading branch information
ivan-magda authored Sep 22, 2023
2 parents 1803628 + 2dc6f77 commit 3f9beae
Show file tree
Hide file tree
Showing 23 changed files with 450 additions and 16 deletions.
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
Expand Up @@ -36,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 @@ -120,6 +122,7 @@ class MainActivity :
startupViewModel(intent)

observeAuthFlowSuccess()
observeNotificationsOnboardingFlowFinished()

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

Expand Down Expand Up @@ -174,6 +177,17 @@ class MainActivity :
}
}

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 @@ -212,7 +226,7 @@ class MainActivity :
)
)
is AppFeature.Action.ViewAction.NavigateTo.NotificationOnBoardingScreen ->
TODO("Screen is going to be implemented in ALTAPPS-970")
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 3f9beae

Please sign in to comment.