-
-
Notifications
You must be signed in to change notification settings - Fork 2k
Expand file tree
/
Copy pathFileActionsViewModel.kt
More file actions
150 lines (131 loc) · 5.49 KB
/
Copy pathFileActionsViewModel.kt
File metadata and controls
150 lines (131 loc) · 5.49 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
/*
* Nextcloud - Android Client
*
* SPDX-FileCopyrightText: 2022 Álvaro Brey <alvaro@alvarobrey.com>
* SPDX-FileCopyrightText: 2022 Nextcloud GmbH
* SPDX-License-Identifier: AGPL-3.0-or-later OR GPL-2.0-only
*/
package com.nextcloud.ui.fileactions
import android.os.Bundle
import androidx.annotation.IdRes
import androidx.annotation.VisibleForTesting
import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import com.nextcloud.client.account.CurrentAccountProvider
import com.nextcloud.client.logger.Logger
import com.nextcloud.utils.TimeConstants
import com.owncloud.android.datamodel.OCFile
import com.owncloud.android.files.FileMenuFilter
import com.owncloud.android.lib.resources.files.model.FileLockType
import com.owncloud.android.ui.activity.ComponentsGetter
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import javax.inject.Inject
class FileActionsViewModel @Inject constructor(
private val currentAccountProvider: CurrentAccountProvider,
private val filterFactory: FileMenuFilter.Factory,
private val logger: Logger
) : ViewModel() {
data class LockInfo(val lockType: FileLockType, val lockedBy: String, val lockedUntil: Long?)
sealed interface UiState {
object Loading : UiState
object Error : UiState
data class LoadedForSingleFile(
val actions: List<FileAction>,
val titleFile: OCFile?,
val lockInfo: LockInfo? = null
) : UiState
data class LoadedForMultipleFiles(val actions: List<FileAction>, val fileCount: Int) : UiState
}
private val _uiState: MutableLiveData<UiState> = MutableLiveData(UiState.Loading)
val uiState: LiveData<UiState>
get() = _uiState
private val _clickActionId: MutableLiveData<Int?> = MutableLiveData(null)
val clickActionId: LiveData<Int?>
@IdRes
get() = _clickActionId
fun load(arguments: Bundle, componentsGetter: ComponentsGetter) {
val files: List<OCFile>? = arguments.getParcelableArrayList(ARG_FILES)
val numberOfAllFiles: Int = arguments.getInt(ARG_ALL_FILES_COUNT, 1)
val isOverflow = arguments.getBoolean(ARG_IS_OVERFLOW, false)
val additionalFilter: IntArray? = arguments.getIntArray(ARG_ADDITIONAL_FILTER)
val inSingleFileFragment = arguments.getBoolean(ARG_IN_SINGLE_FILE_FRAGMENT)
if (files.isNullOrEmpty()) {
logger.d(TAG, "No valid files argument for loading actions")
_uiState.postValue(UiState.Error)
} else {
load(componentsGetter, files.toList(), numberOfAllFiles, isOverflow, additionalFilter, inSingleFileFragment)
}
}
private fun load(
componentsGetter: ComponentsGetter,
files: Collection<OCFile>,
numberOfAllFiles: Int?,
isOverflow: Boolean?,
additionalFilter: IntArray?,
inSingleFileFragment: Boolean = false
) {
viewModelScope.launch(Dispatchers.IO) {
val toHide = getHiddenActions(componentsGetter, numberOfAllFiles, files, isOverflow, inSingleFileFragment)
val availableActions = getActionsToShow(additionalFilter, toHide, files)
updateStateLoaded(files, availableActions)
}
}
private fun getHiddenActions(
componentsGetter: ComponentsGetter,
numberOfAllFiles: Int?,
files: Collection<OCFile>,
isOverflow: Boolean?,
inSingleFileFragment: Boolean
): List<Int> = filterFactory.newInstance(
numberOfAllFiles ?: 1,
files.toList(),
componentsGetter,
isOverflow ?: false,
currentAccountProvider.user
)
.getToHide(inSingleFileFragment)
private fun getActionsToShow(additionalFilter: IntArray?, toHide: List<Int>, files: Collection<OCFile>) =
FileAction.getActions(files)
.filter { additionalFilter == null || it.id !in additionalFilter }
.filter { it.id !in toHide }
private fun updateStateLoaded(files: Collection<OCFile>, availableActions: List<FileAction>) {
val state: UiState = when (files.size) {
1 -> {
val file = files.first()
UiState.LoadedForSingleFile(availableActions, file, getLockInfo(file))
}
else -> UiState.LoadedForMultipleFiles(availableActions, files.size)
}
_uiState.postValue(state)
}
private fun getLockInfo(file: OCFile): LockInfo? {
val lockType = file.lockType
val username = file.lockOwnerDisplayName ?: file.lockOwnerId
return if (file.isLocked && lockType != null && username != null) {
LockInfo(lockType, username, getLockedUntil(file))
} else {
null
}
}
@VisibleForTesting
internal fun getLockedUntil(file: OCFile): Long? = if (file.lockTimestamp == 0L || file.lockTimeout <= 0L) {
null
} else {
(file.lockTimestamp + file.lockTimeout) * TimeConstants.MILLIS_PER_SECOND
}
fun onClick(action: FileAction) {
_clickActionId.value = action.id
}
companion object {
const val ARG_ALL_FILES_COUNT = "ALL_FILES_COUNT"
const val ARG_FILES = "FILES"
const val ARG_IS_OVERFLOW = "OVERFLOW"
const val ARG_ADDITIONAL_FILTER = "ADDITIONAL_FILTER"
const val ARG_IN_SINGLE_FILE_FRAGMENT = "IN_SINGLE_FILE_FRAGMENT"
const val ARG_ENDPOINTS = "ENDPOINTS"
private val TAG = FileActionsViewModel::class.simpleName!!
}
}