1 /*
2  * Copyright (C) 2024 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.android.healthconnect.controller.exportimport.api
18 
19 import android.health.connect.Constants.DEFAULT_INT
20 import android.health.connect.exportimport.ScheduledExportSettings
21 import android.net.Uri
22 import androidx.lifecycle.LiveData
23 import androidx.lifecycle.MutableLiveData
24 import androidx.lifecycle.ViewModel
25 import androidx.lifecycle.viewModelScope
26 import dagger.hilt.android.lifecycle.HiltViewModel
27 import javax.inject.Inject
28 import kotlinx.coroutines.launch
29 
30 /** View model for Export settings fragments. */
31 @HiltViewModel
32 class ExportSettingsViewModel
33 @Inject
34 constructor(
35     private val loadExportSettingsUseCase: ILoadExportSettingsUseCase,
36     private val updateExportSettingsUseCase: IUpdateExportSettingsUseCase,
37     private val queryDocumentProvidersUseCase: IQueryDocumentProvidersUseCase,
38 ) : ViewModel() {
39     private val _storedExportSettings = MutableLiveData<ExportSettings>()
40     private val _selectedExportFrequency = MutableLiveData<ExportFrequency>()
41     private val _previousExportFrequency = MutableLiveData<ExportFrequency?>()
42     private val _documentProviders = MutableLiveData<DocumentProviders>()
43     private val _selectedDocumentProvider = MutableLiveData<DocumentProviderInfo?>()
44     private val _selectedDocumentProviderRoot = MutableLiveData<DocumentProviderRoot?>()
45     private val _selectedRootsForDocumentProviders =
46         MutableLiveData<MutableMap<String, DocumentProviderRoot?>>()
47 
48     /** Holds the export settings that is stored in the Health Connect service. */
49     val storedExportSettings: LiveData<ExportSettings>
50         get() = _storedExportSettings
51 
52     /** Holds the previous export frequency that is stored. */
53     val previousExportFrequency: LiveData<ExportFrequency?>
54         get() = _previousExportFrequency
55 
56     /** Holds the user selected export frequency. */
57     val selectedExportFrequency: LiveData<ExportFrequency?>
58         get() = _selectedExportFrequency
59 
60     /** Holds the supported document providers. */
61     val documentProviders: LiveData<DocumentProviders>
62         get() = _documentProviders
63 
64     /** Holds the user selected document provider. */
65     val selectedDocumentProvider: LiveData<DocumentProviderInfo?>
66         get() = _selectedDocumentProvider
67 
68     /** Holds the user selected document provider. */
69     val selectedDocumentProviderRoot: LiveData<DocumentProviderRoot?>
70         get() = _selectedDocumentProviderRoot
71 
72     /**
73      * Holds the user stored document providers.
74      *
75      * This is needed for remembering the user selected account when switching between providers.
76      */
77     val selectedRootsForDocumentProviders: LiveData<MutableMap<String, DocumentProviderRoot?>>
78         get() = _selectedRootsForDocumentProviders
79 
80     init {
81         loadExportSettings()
82         loadDocumentProviders()
83         _selectedExportFrequency.value = ExportFrequency.EXPORT_FREQUENCY_NEVER
84         _selectedRootsForDocumentProviders.value = mutableMapOf()
85     }
86 
87     /** Triggers a load of export settings. */
loadExportSettingsnull88     fun loadExportSettings() {
89         _storedExportSettings.postValue(ExportSettings.Loading)
90         viewModelScope.launch {
91             when (val result = loadExportSettingsUseCase.invoke()) {
92                 is ExportImportUseCaseResult.Success -> {
93                     _storedExportSettings.postValue(ExportSettings.WithData(result.data))
94                 }
95                 is ExportImportUseCaseResult.Failed -> {
96                     _storedExportSettings.postValue(ExportSettings.LoadingFailed)
97                 }
98             }
99         }
100     }
101 
102     /** Triggers a query of the document providers. */
loadDocumentProvidersnull103     fun loadDocumentProviders() {
104         _documentProviders.postValue(DocumentProviders.Loading)
105         viewModelScope.launch {
106             when (val result = queryDocumentProvidersUseCase.invoke()) {
107                 is ExportImportUseCaseResult.Success -> {
108                     _documentProviders.postValue(DocumentProviders.WithData(result.data))
109                 }
110                 is ExportImportUseCaseResult.Failed -> {
111                     _documentProviders.postValue(DocumentProviders.LoadingFailed)
112                 }
113             }
114         }
115     }
116 
117     /** Updates the previous frequency of scheduled exports of Health Connect data. */
updatePreviousExportFrequencynull118     fun updatePreviousExportFrequency(frequency: ExportFrequency) {
119         if (frequency != ExportFrequency.EXPORT_FREQUENCY_NEVER) {
120             _previousExportFrequency.value = frequency
121         }
122     }
123 
124     /** Updates the uri to write to in scheduled exports of Health Connect data. */
updateExportUrinull125     fun updateExportUri(uri: Uri) {
126         val settings = ScheduledExportSettings.Builder().setUri(uri).build()
127         updateExportSettings(settings)
128     }
129 
130     /**
131      * Updates the uri and the selected frequency to write to in scheduled exports of Health Connect
132      * data.
133      */
updateExportUriWithSelectedFrequencynull134     fun updateExportUriWithSelectedFrequency(uri: Uri) {
135         val settings =
136             ScheduledExportSettings.Builder()
137                 .setPeriodInDays(
138                     _selectedExportFrequency.value?.periodInDays
139                         ?: ExportFrequency.EXPORT_FREQUENCY_NEVER.periodInDays
140                 )
141                 .setUri(uri)
142                 .build()
143         updateExportSettings(settings)
144     }
145 
146     /** Updates the frequency of scheduled exports of Health Connect data. */
updateExportFrequencynull147     fun updateExportFrequency(frequency: ExportFrequency) {
148         val settings =
149             ScheduledExportSettings.Builder().setPeriodInDays(frequency.periodInDays).build()
150         updateExportSettings(settings)
151     }
152 
153     /** Updates the stored frequency of scheduled exports of Health Connect data. */
updateSelectedFrequencynull154     fun updateSelectedFrequency(frequency: ExportFrequency) {
155         _selectedExportFrequency.value = frequency
156     }
157 
158     /** Updates the selected document provider. */
updateSelectedDocumentProvidernull159     fun updateSelectedDocumentProvider(
160         documentProvider: DocumentProviderInfo,
161         documentProviderRoot: DocumentProviderRoot,
162     ) {
163         _selectedDocumentProvider.value = documentProvider
164         _selectedDocumentProviderRoot.value = documentProviderRoot
165         _selectedRootsForDocumentProviders.value?.set(documentProvider.title, documentProviderRoot)
166     }
167 
updateExportSettingsnull168     private fun updateExportSettings(settings: ScheduledExportSettings) {
169         viewModelScope.launch {
170             when (updateExportSettingsUseCase.invoke(settings)) {
171                 is ExportImportUseCaseResult.Success -> {
172                     if (settings.periodInDays != DEFAULT_INT) {
173                         val frequency = fromPeriodInDays(settings.periodInDays)
174                         _storedExportSettings.postValue(ExportSettings.WithData(frequency))
175                     }
176                 }
177                 is ExportImportUseCaseResult.Failed -> {
178                     _storedExportSettings.postValue(ExportSettings.LoadingFailed)
179                 }
180             }
181         }
182     }
183 }
184