HomeFragment.kt 10.1 KB
Newer Older
lita_kornilova's avatar
lita_kornilova committed
1
2
package org.dpppt.android.app.home

3
import android.animation.LayoutTransition
4
5
import android.content.Intent
import android.net.Uri
lita_kornilova's avatar
lita_kornilova committed
6
7
8
9
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
10
11
import android.view.animation.Animation
import android.view.animation.AnimationUtils
12
import androidx.core.content.ContextCompat
lita_kornilova's avatar
lita_kornilova committed
13
14
import androidx.core.view.isVisible
import androidx.fragment.app.viewModels
Lita Kornilova's avatar
Lita Kornilova committed
15
import androidx.navigation.NavDirections
16
import androidx.navigation.fragment.findNavController
lita_kornilova's avatar
lita_kornilova committed
17
import mobi.lab.mvvm.MvvmFragment
18
import org.dpppt.android.app.BuildConfig
lita_kornilova's avatar
lita_kornilova committed
19
import org.dpppt.android.app.R
20
import org.dpppt.android.app.common.util.DateUtils
21
import org.dpppt.android.app.common.util.FragmentBindingHolder
22
import org.dpppt.android.app.common.util.ViewBindingHolder
23
24
25
import org.dpppt.android.app.common.util.ViewModelFactory
import org.dpppt.android.app.common.util.exhaustive
import org.dpppt.android.app.common.util.setTextWithBoldSpans
Lita Kornilova's avatar
Lita Kornilova committed
26
import org.dpppt.android.app.databinding.FragmentHomeBinding
lita_kornilova's avatar
lita_kornilova committed
27
import org.dpppt.android.app.di.Injector
28
import org.dpppt.android.app.domain.entity.AppTracingStatus
29
import org.dpppt.android.app.domain.entity.enums.SettingsScrollDestination
30
import org.dpppt.android.app.main.model.InfectedStatus
Aleks Krause's avatar
Aleks Krause committed
31
import org.dpppt.android.app.util.startActivitySafely
lita_kornilova's avatar
lita_kornilova committed
32
33
34
import org.dpppt.android.app.viewmodel.TracingViewModel
import javax.inject.Inject

Lita Kornilova's avatar
Lita Kornilova committed
35
class HomeFragment : MvvmFragment(R.layout.fragment_home), ViewBindingHolder<FragmentHomeBinding> by FragmentBindingHolder() {
36

lita_kornilova's avatar
lita_kornilova committed
37
38
39
40
41
    @Inject
    lateinit var factory: ViewModelFactory

    override val viewModel: HomeViewModel by viewModels { factory }

42
    private val tracingViewModel: TracingViewModel by viewModels { factory }
lita_kornilova's avatar
lita_kornilova committed
43
44
45
46
47

    init {
        Injector.inject(this)
    }

48
    override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View {
Lita Kornilova's avatar
Lita Kornilova committed
49
        return createBinding(FragmentHomeBinding.inflate(inflater), this)
lita_kornilova's avatar
lita_kornilova committed
50
51
52
53
54
    }

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)
        initViewModel()
55
        requireBinding {
56
            initSwipeRefresh()
57
            myDataCard.setOnClickListener { viewModel.myDataClicked() }
58
            gaenNotWorkingCard.setOnClickListener { viewModel.settingsClicked() }
59
60
            settingsButton.setOnClickListener { viewModel.settingsClicked() }
            learnMoreView.setOnClickListener { viewModel.learnMoreClicked() }
61
62
63
64
65
66
67
            infectionAbroadCard.setOnClickListener { viewModel.gotSickAbroadClicked() }
            moreInfoButton.setOnClickListener { viewModel.contactsClicked() }
            if (BuildConfig.DEBUG) {
                mainButtonDebug.setOnClickListener { viewModel.debugButtonClicked() }
            } else {
                mainButtonDebug.isVisible = false
            }
68
        }
lita_kornilova's avatar
lita_kornilova committed
69
70
    }

71
72
73
74
75
    override fun onResume() {
        super.onResume()
        viewModel.start(tracingViewModel.appStatusLiveData)
    }

76
    private fun initViewModel() {
77
        viewModel.infectedStatus.onEachNotNull(::showInfectedStatus)
78
        viewModel.tracing.onEachNotNull(::showTracingStatusInfo)
79
        viewModel.action.onEachEvent(::handleAction)
80
81
    }

82
83
    private fun handleAction(action: HomeViewModel.Action) {
        when (action) {
Lita Kornilova's avatar
Lita Kornilova committed
84
85
86
87
            is HomeViewModel.Action.NavigateToConfirmInfectionDate -> navigateAndResetStatusBarColor(HomeFragmentDirections.confirmInfectionDate())
            is HomeViewModel.Action.NavigateToContacts -> navigateAndResetStatusBarColor(HomeFragmentDirections.contacts())
            is HomeViewModel.Action.NavigateToDebug -> navigateAndResetStatusBarColor(HomeFragmentDirections.debug())
            is HomeViewModel.Action.NavigateToMyData -> navigateAndResetStatusBarColor(HomeFragmentDirections.myData())
88
            is HomeViewModel.Action.NavigateToSettings ->
Lita Kornilova's avatar
Lita Kornilova committed
89
                navigateAndResetStatusBarColor(HomeFragmentDirections.settings(SettingsScrollDestination.None))
Aleks Krause's avatar
Aleks Krause committed
90
91
            is HomeViewModel.Action.OpenCovidInstructionsUrl -> startActivitySafely(Intent(Intent.ACTION_VIEW).setData(Uri.parse(action.url)))
            is HomeViewModel.Action.OpenLearnMoreUrl -> startActivitySafely(Intent(Intent.ACTION_VIEW).setData(Uri.parse(action.url)))
92
            is HomeViewModel.Action.OpenGotSickAbroadInstructionsUrl -> startActivitySafely(Intent(Intent.ACTION_VIEW).setData(Uri.parse(action.url)))
93
            is HomeViewModel.Action.StartLoadingAnimation -> requireBinding().startLoadingAnimation(action.infectedStatus)
94
95
96
        }.exhaustive
    }

Lita Kornilova's avatar
Lita Kornilova committed
97
98
99
100
101
102
    private fun FragmentHomeBinding.initSwipeRefresh() {
        swipeContainer.setColorSchemeResources(R.color.primary)
        swipeContainer.setOnRefreshListener {
            swipeContainer.isRefreshing = false
            viewModel.onRefresh()
        }
Michelle Mueller's avatar
Michelle Mueller committed
103
104
    }

105
    private fun showTracingStatusInfo(tracingStatus: AppTracingStatus) {
106
        requireBinding().gaenNotWorkingCard.isVisible = tracingStatus is AppTracingStatus.DisabledUnexpectedly
lita_kornilova's avatar
lita_kornilova committed
107
108
    }

Lita Kornilova's avatar
Lita Kornilova committed
109
    private fun FragmentHomeBinding.setInfectionCardsToNotInfected() {
110
        // Home card visible and in the correct state
111
        infectionAtHomeCard.setState(CardView.State.notInfectedAtHome(requireContext()))
112
113
114
        infectionAtHomeCard.setOnClickListener { viewModel.confirmInfectionClicked() }
        infectionAtHomeCard.setDescriptionOnClickListener(null)
        // Abroad card visible and in the base state
115
116
117
        infectionAbroadCard.visibility = View.VISIBLE
        infectionAbroadCard.setState(CardView.State.notInfectedAbroad(requireContext()))
        infectionAbroadCard.setOnClickListener { viewModel.gotSickAbroadClicked() }
118
119
        // My data is collapsed
        myDataCard.setState(CardView.State.myDataCardCollapsed(requireContext()))
120
121
    }

Lita Kornilova's avatar
Lita Kornilova committed
122
    private fun FragmentHomeBinding.setInfectionCardsToInfected() {
123
124
125
126
127
        // Home card visible and in the correct state
        infectionAtHomeCard.setState(CardView.State.infected(requireContext()))
        infectionAtHomeCard.setOnClickListener(null)
        infectionAtHomeCard.setDescriptionOnClickListener { viewModel.covidInstructionsClicked() }
        // Abroad card not visible
128
        infectionAbroadCard.visibility = View.GONE
129
130
        // My data is expanded
        myDataCard.setState(CardView.State.myDataCardExpandedWithDetectionSuspendedInfo(requireContext()))
131
    }
132
133
134
135
136
137
138

    private fun showInfectedStatus(infectedStatus: InfectedStatus) = with(requireBinding()) {
        if (infectedStatus == InfectedStatus.Infected) {
            setInfectionCardsToInfected()
        } else {
            setInfectionCardsToNotInfected()
        }
139
140
141
        parentView.layoutTransition = LayoutTransition().apply {
            enableTransitionType(LayoutTransition.CHANGING)
        }
142
143
144
        setupHeaderColor(infectedStatus)
        setupHeaderText(infectedStatus)
        setupHeaderImage(infectedStatus)
145
146
        infectionDetailsViews.isVisible = infectedStatus is InfectedStatus.HasContacts
        if (infectedStatus is InfectedStatus.HasContacts) setupInfectionStateHadContactsDescription(infectedStatus)
147
148
    }

Lita Kornilova's avatar
Lita Kornilova committed
149
    private fun FragmentHomeBinding.setupHeaderText(infectedStatus: InfectedStatus) {
150
151
        val text = when (infectedStatus) {
            is InfectedStatus.Infected -> getString(R.string.home_infection_status_infected)
152
            is InfectedStatus.HasContacts -> resources.getQuantityString(
153
154
155
156
                R.plurals.home_infection_status_had_contacts,
                infectedStatus.num,
                infectedStatus.num
            )
157
            is InfectedStatus.None -> getString(R.string.home_infection_status_healthy)
158
159
160
161
        }.exhaustive
        infectionStatusText.text = text
    }

Lita Kornilova's avatar
Lita Kornilova committed
162
    private fun FragmentHomeBinding.setupHeaderImage(infectedStatus: InfectedStatus) {
163
        val imageResource = if (infectedStatus is InfectedStatus.HasContacts) R.drawable.ic_virus else R.drawable.ic_checkmark
164
165
166
        infectionStatusImage.setImageResource(imageResource)
    }

Lita Kornilova's avatar
Lita Kornilova committed
167
    private fun FragmentHomeBinding.setupHeaderColor(infectedStatus: InfectedStatus) {
168
169
        val colorRes = when (infectedStatus) {
            is InfectedStatus.Infected -> R.color.dark_green
170
            is InfectedStatus.HasContacts -> R.color.pink
171
172
173
174
175
176
177
178
            is InfectedStatus.None -> R.color.primary
        }.exhaustive
        val color = ContextCompat.getColor(requireContext(), colorRes)
        colorView.setBackgroundColor(color)
        homeToolbar.setBackgroundColor(color)
        requireActivity().window.statusBarColor = color
    }

179
    private fun FragmentHomeBinding.setupInfectionStateHadContactsDescription(infectedStatus: InfectedStatus.HasContacts) {
180
181
182
183
184
185
186
187
188
189
        val formattedDate = DateUtils.getFormattedLocalDate(infectedStatus.stayHomeUntilDate)
        infectionStatusDescription.setTextWithBoldSpans(
            getString(
                R.string.home_infection_status_had_contacts_description,
                formattedDate
            ),
            formattedDate
        )
    }

Lita Kornilova's avatar
Lita Kornilova committed
190
    private fun FragmentHomeBinding.startLoadingAnimation(infectedStatus: InfectedStatus) {
191
192
193
194
195
196
197
198
        infectionStatusText.text = getString(R.string.home_infection_status_loading)
        infectionDetailsViews.isVisible = false
        // this should be replaced with a new animation according to COVAPP-445
        val scaleUpAnimation = AnimationUtils.loadAnimation(activity, R.anim.scale_up).apply {
            setAnimationListener(object : Animation.AnimationListener {
                override fun onAnimationStart(animation: Animation?) = Unit

                override fun onAnimationEnd(animation: Animation?) {
199
                    if (infectedStatus is InfectedStatus.HasContacts) {
200
201
202
203
204
205
206
207
208
209
                        infectionDetailsViews.isVisible = true
                    }
                    setupHeaderText(infectedStatus)
                }

                override fun onAnimationRepeat(animation: Animation?) = Unit
            })
        }
        loadingView.startAnimation(AnimationUtils.loadAnimation(activity, R.anim.rotate))
        infectionStatusImage.startAnimation(scaleUpAnimation)
210
    }
Lita Kornilova's avatar
Lita Kornilova committed
211
212
213
214
215

    private fun navigateAndResetStatusBarColor(directions: NavDirections) {
        requireActivity().window.statusBarColor = ContextCompat.getColor(requireContext(), R.color.primary)
        findNavController().navigate(directions)
    }
lita_kornilova's avatar
lita_kornilova committed
216
}