Add disclaimer fragment

This commit is contained in:
Kirill Kamakin
2021-11-20 18:43:33 +03:00
parent 071ce453e2
commit 4b817ba404
10 changed files with 331 additions and 3 deletions

View File

@@ -0,0 +1,76 @@
package gq.kirmanak.mealient.ui.disclaimer
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.fragment.app.Fragment
import androidx.fragment.app.viewModels
import androidx.navigation.fragment.findNavController
import dagger.hilt.android.AndroidEntryPoint
import gq.kirmanak.mealient.R
import gq.kirmanak.mealient.databinding.FragmentDisclaimerBinding
import timber.log.Timber
@AndroidEntryPoint
class DisclaimerFragment : Fragment() {
private var _binding: FragmentDisclaimerBinding? = null
private val binding: FragmentDisclaimerBinding
get() = checkNotNull(_binding) { "Binding requested when fragment is off screen" }
private val viewModel by viewModels<DisclaimerViewModel>()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
Timber.v("onCreate() called with: savedInstanceState = $savedInstanceState")
listenToAcceptStatus()
}
private fun listenToAcceptStatus() {
Timber.v("listenToAcceptStatus() called")
viewModel.isAccepted.observe(this) {
Timber.d("listenToAcceptStatus: new status = $it")
if (it) navigateToAuth()
}
viewModel.checkIsAccepted()
}
private fun navigateToAuth() {
Timber.v("navigateToAuth() called")
findNavController().navigate(DisclaimerFragmentDirections.actionDisclaimerFragmentToAuthenticationFragment())
}
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View {
Timber.v("onCreateView() called with: inflater = $inflater, container = $container, savedInstanceState = $savedInstanceState")
_binding = FragmentDisclaimerBinding.inflate(inflater, container, false)
return binding.root
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
Timber.v("onViewCreated() called with: view = $view, savedInstanceState = $savedInstanceState")
binding.okay.setOnClickListener {
Timber.v("onViewCreated: okay clicked")
viewModel.acceptDisclaimer()
}
viewModel.okayCountDown.observe(viewLifecycleOwner) {
Timber.d("onViewCreated: new count $it")
binding.okay.text = if (it > 0) {
getString(R.string.fragment_disclaimer_button_okay_timer, it)
} else {
getString(R.string.fragment_disclaimer_button_okay)
}
binding.okay.isClickable = it == 0
}
viewModel.startCountDown()
}
override fun onDestroyView() {
super.onDestroyView()
Timber.v("onDestroyView() called")
_binding = null
}
}

View File

@@ -0,0 +1,15 @@
package gq.kirmanak.mealient.ui.disclaimer
import dagger.Binds
import dagger.Module
import dagger.hilt.InstallIn
import dagger.hilt.components.SingletonComponent
import gq.kirmanak.mealient.data.disclaimer.DisclaimerStorage
import gq.kirmanak.mealient.data.disclaimer.DisclaimerStorageImpl
@Module
@InstallIn(SingletonComponent::class)
interface DisclaimerModule {
@Binds
fun provideDisclaimerStorage(disclaimerStorageImpl: DisclaimerStorageImpl): DisclaimerStorage
}

View File

@@ -0,0 +1,73 @@
package gq.kirmanak.mealient.ui.disclaimer
import androidx.annotation.VisibleForTesting
import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import dagger.hilt.android.lifecycle.HiltViewModel
import gq.kirmanak.mealient.data.disclaimer.DisclaimerStorage
import kotlinx.coroutines.delay
import kotlinx.coroutines.flow.flow
import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.onEach
import kotlinx.coroutines.flow.take
import kotlinx.coroutines.launch
import timber.log.Timber
import java.util.concurrent.TimeUnit
import javax.inject.Inject
@HiltViewModel
class DisclaimerViewModel @Inject constructor(
private val disclaimerStorage: DisclaimerStorage
) : ViewModel() {
private val _isAccepted = MutableLiveData(false)
val isAccepted: LiveData<Boolean> = _isAccepted
private val _okayCountDown = MutableLiveData(FULL_COUNT_DOWN_SEC)
val okayCountDown: LiveData<Int> = _okayCountDown
fun checkIsAccepted() {
Timber.v("checkIsAccepted() called")
viewModelScope.launch {
_isAccepted.value = disclaimerStorage.isDisclaimerAccepted()
}
}
fun acceptDisclaimer() {
Timber.v("acceptDisclaimer() called")
disclaimerStorage.acceptDisclaimer()
_isAccepted.value = true
}
fun startCountDown() {
Timber.v("startCountDown() called")
tickerFlow(COUNT_DOWN_TICK_PERIOD_SEC.toLong(), TimeUnit.SECONDS)
.take(FULL_COUNT_DOWN_SEC - COUNT_DOWN_TICK_PERIOD_SEC + 1)
.onEach { _okayCountDown.value = FULL_COUNT_DOWN_SEC - it }
.launchIn(viewModelScope)
}
/**
* Sends an event every [period] of [timeUnit]. For example, if period = 3 and timeUnit = SECOND
* then this will send an event every 3 seconds. Additionally to the event, it sends counter
* of how many ticks there were. It doesn't depend on period or timeUnit parameters, it just
* counts how many events it sent starting from 1.
*/
@VisibleForTesting
fun tickerFlow(period: Long, timeUnit: TimeUnit) = flow {
Timber.v("tickerFlow() called with: period = $period, timeUnit = $timeUnit")
val periodMillis = timeUnit.toMillis(period)
var counter = 0
while (true) {
delay(periodMillis)
counter++
emit(counter)
}
}
companion object {
private const val FULL_COUNT_DOWN_SEC = 5
private const val COUNT_DOWN_TICK_PERIOD_SEC = 1
}
}