@@ -60,13 +60,19 @@ class FileListAdapter(
6060 var files = mutableListOf<Any >()
6161 private var account: Account ? = AccountUtils .getCurrentOpenCloudAccount(context)
6262 private var fileListOption: FileListOption = FileListOption .ALL_FILES
63+ private val disallowTouchesWithOtherWindows =
64+ PreferenceUtils .shouldDisallowTouchesWithOtherVisibleWindows(context)
65+
66+ init {
67+ setHasStableIds(true )
68+ }
6369
6470 fun updateFileList (filesToAdd : List <OCFileWithSyncInfo >, fileListOption : FileListOption ) {
6571
6672 val listWithFooter = mutableListOf<Any >()
6773 listWithFooter.addAll(filesToAdd)
6874
69- if (listWithFooter.isNotEmpty()) {
75+ if (listWithFooter.isNotEmpty() && ! isPickerMode ) {
7076 listWithFooter.add(OCFooterFile (manageListOfFilesAndGenerateText(filesToAdd)))
7177 }
7278
@@ -85,13 +91,22 @@ class FileListAdapter(
8591 diffResult.dispatchUpdatesTo(this )
8692 }
8793
94+ override fun getItemId (position : Int ): Long {
95+ val item = files.getOrNull(position)
96+ return when (item) {
97+ is OCFileWithSyncInfo -> item.file.id ? : item.file.remotePath.hashCode().toLong()
98+ is OCFooterFile -> Long .MIN_VALUE + position
99+ else -> position.toLong()
100+ }
101+ }
102+
88103 override fun onCreateViewHolder (parent : ViewGroup , viewType : Int ): RecyclerView .ViewHolder =
89104 when (viewType) {
90105 ViewType .LIST_ITEM .ordinal -> {
91106 val binding = ItemFileListBinding .inflate(LayoutInflater .from(parent.context), parent, false )
92107 binding.root.apply {
93108 tag = ViewType .LIST_ITEM
94- filterTouchesWhenObscured = PreferenceUtils .shouldDisallowTouchesWithOtherVisibleWindows(context)
109+ filterTouchesWhenObscured = disallowTouchesWithOtherWindows
95110 }
96111 ListViewHolder (binding)
97112 }
@@ -100,7 +115,7 @@ class FileListAdapter(
100115 val binding = GridItemBinding .inflate(LayoutInflater .from(parent.context), parent, false )
101116 binding.root.apply {
102117 tag = ViewType .GRID_IMAGE
103- filterTouchesWhenObscured = PreferenceUtils .shouldDisallowTouchesWithOtherVisibleWindows(context)
118+ filterTouchesWhenObscured = disallowTouchesWithOtherWindows
104119 }
105120 GridImageViewHolder (binding)
106121 }
@@ -109,7 +124,7 @@ class FileListAdapter(
109124 val binding = GridItemBinding .inflate(LayoutInflater .from(parent.context), parent, false )
110125 binding.root.apply {
111126 tag = ViewType .GRID_ITEM
112- filterTouchesWhenObscured = PreferenceUtils .shouldDisallowTouchesWithOtherVisibleWindows(context)
127+ filterTouchesWhenObscured = disallowTouchesWithOtherWindows
113128 }
114129 GridViewHolder (binding)
115130 }
@@ -118,17 +133,19 @@ class FileListAdapter(
118133 val binding = ListFooterBinding .inflate(LayoutInflater .from(parent.context), parent, false )
119134 binding.root.apply {
120135 tag = ViewType .FOOTER
121- filterTouchesWhenObscured = PreferenceUtils .shouldDisallowTouchesWithOtherVisibleWindows(context)
136+ filterTouchesWhenObscured = disallowTouchesWithOtherWindows
122137 }
123138 FooterViewHolder (binding)
124139 }
125140 }
126141
127142 override fun getItemCount (): Int = files.size
128143
129- override fun getItemId ( position : Int ): Long = position.toLong()
144+ private fun hasFooter ( ): Boolean = files.lastOrNull() is OCFooterFile
130145
131- private fun isFooter (position : Int ) = position == files.size.minus(1 )
146+ private fun isFooter (position : Int ) = files.getOrNull(position) is OCFooterFile
147+
148+ private fun selectableItemCount (): Int = files.size - if (hasFooter()) 1 else 0
132149
133150 override fun getItemViewType (position : Int ): Int =
134151
@@ -166,33 +183,44 @@ class FileListAdapter(
166183
167184 fun selectAll () {
168185 // Last item on list is the footer, so that element must be excluded from selection
169- selectAll(totalItems = files.size - 1 )
186+ selectAll(totalItems = selectableItemCount() )
170187 }
171188
172189 fun selectInverse () {
173190 // Last item on list is the footer, so that element must be excluded from selection
174- toggleSelectionInBulk(totalItems = files.size - 1 )
191+ toggleSelectionInBulk(totalItems = selectableItemCount() )
175192 }
176193
177194 override fun onBindViewHolder (holder : RecyclerView .ViewHolder , position : Int ) {
178195
179196 val viewType = getItemViewType(position)
180197
198+ AccountUtils .getCurrentOpenCloudAccount(context)?.let { currentAccount ->
199+ if (currentAccount != account) {
200+ account = currentAccount
201+ }
202+ } ? : run {
203+ if (account != null ) {
204+ account = null
205+ }
206+ }
207+
181208 if (viewType != ViewType .FOOTER .ordinal) { // Is Item
182209
210+ val hasActiveSelection = selectedItemCount > 0
183211 val fileWithSyncInfo = files[position] as OCFileWithSyncInfo
184212 val file = fileWithSyncInfo.file
185213 val name = file.fileName
186214 val fileIcon = holder.itemView.findViewById<ImageView >(R .id.thumbnail).apply {
187215 tag = file.id
188216 }
189- val thumbnail: Bitmap ? = file.remoteId?. let { ThumbnailsCacheManager .getBitmapFromDiskCache(file.remoteId) }
217+ val thumbnail: Bitmap ? = ThumbnailsCacheManager .getBitmapFromDiskCache(file)
190218
191219 holder.itemView.findViewById<LinearLayout >(R .id.ListItemLayout )?.apply {
192220 contentDescription = " LinearLayout-$name "
193221
194222 // Allow or disallow touches with other visible windows
195- filterTouchesWhenObscured = PreferenceUtils .shouldDisallowTouchesWithOtherVisibleWindows(context)
223+ filterTouchesWhenObscured = disallowTouchesWithOtherWindows
196224 }
197225
198226 holder.itemView.findViewById<LinearLayout >(R .id.share_icons_layout).isVisible =
@@ -201,26 +229,35 @@ class FileListAdapter(
201229 holder.itemView.findViewById<ImageView >(R .id.shared_via_users_icon).isVisible =
202230 file.sharedWithSharee == true || file.isSharedWithMe
203231
204- setSpecificViewHolder(viewType, holder, fileWithSyncInfo, thumbnail)
232+ setSpecificViewHolder(viewType, holder, fileWithSyncInfo, thumbnail, hasActiveSelection )
205233
206234 setIconPinAccordingToFilesLocalState(holder.itemView.findViewById(R .id.localFileIndicator), fileWithSyncInfo)
207235
208236 holder.itemView.setOnClickListener {
237+ val adapterPosition = holder.bindingAdapterPosition
238+ if (adapterPosition == RecyclerView .NO_POSITION ) {
239+ return @setOnClickListener
240+ }
241+ val currentItem = files.getOrNull(adapterPosition) as ? OCFileWithSyncInfo ? : return @setOnClickListener
209242 listener.onItemClick(
210- ocFileWithSyncInfo = fileWithSyncInfo ,
211- position = position
243+ ocFileWithSyncInfo = currentItem ,
244+ position = adapterPosition
212245 )
213246 }
214247
215248 holder.itemView.setOnLongClickListener {
249+ val adapterPosition = holder.bindingAdapterPosition
250+ if (adapterPosition == RecyclerView .NO_POSITION ) {
251+ return @setOnLongClickListener false
252+ }
216253 listener.onLongItemClick(
217- position = position
254+ position = adapterPosition
218255 )
219256 }
220257 holder.itemView.setBackgroundColor(Color .WHITE )
221258
222259 val checkBoxV = holder.itemView.findViewById<ImageView >(R .id.custom_checkbox).apply {
223- isVisible = getCheckedItems().isNotEmpty()
260+ isVisible = hasActiveSelection
224261 }
225262
226263 if (isSelected(position)) {
@@ -234,27 +271,36 @@ class FileListAdapter(
234271 if (file.isFolder) {
235272 // Folder
236273 fileIcon.setImageResource(R .drawable.ic_menu_archive)
274+ fileIcon.setBackgroundColor(Color .TRANSPARENT )
237275 } else {
238276 // Set file icon depending on its mimetype. Ask for thumbnail later.
239277 fileIcon.setImageResource(MimetypeIconUtil .getFileTypeIconId(file.mimeType, file.fileName))
240278
241279 if (thumbnail != null ) {
242280 fileIcon.setImageBitmap(thumbnail)
243281 }
244- if (file.needsToUpdateThumbnail && ThumbnailsCacheManager .cancelPotentialThumbnailWork(file, fileIcon)) {
245- // generate new Thumbnail
246- val task = ThumbnailsCacheManager .ThumbnailGenerationTask (fileIcon, account)
247- val asyncDrawable = ThumbnailsCacheManager .AsyncThumbnailDrawable (context.resources, thumbnail, task)
248-
249- // If drawable is not visible, do not update it.
250- if (asyncDrawable.minimumHeight > 0 && asyncDrawable.minimumWidth > 0 ) {
251- fileIcon.setImageDrawable(asyncDrawable)
282+
283+ if (file.needsToUpdateThumbnail) {
284+ val canStartTask = ThumbnailsCacheManager .cancelPotentialThumbnailWork(file, fileIcon)
285+ val activeAccount = account
286+ if (activeAccount != null && canStartTask) {
287+ // generate new Thumbnail
288+ val task = ThumbnailsCacheManager .ThumbnailGenerationTask (fileIcon, activeAccount)
289+ val placeholder = thumbnail ? : ThumbnailsCacheManager .mDefaultImg
290+ val asyncDrawable = ThumbnailsCacheManager .AsyncThumbnailDrawable (context.resources, placeholder, task)
291+
292+ // If drawable is not visible, do not update it.
293+ if (asyncDrawable.minimumHeight > 0 && asyncDrawable.minimumWidth > 0 ) {
294+ fileIcon.setImageDrawable(asyncDrawable)
295+ }
296+ ThumbnailsCacheManager .executeThumbnailTask(task, file)
252297 }
253- task.execute(file)
254298 }
255299
256- if (file.mimeType == " image/png" ) {
300+ if (file.mimeType.equals( " image/png" , ignoreCase = true ) ) {
257301 fileIcon.setBackgroundColor(ContextCompat .getColor(context, R .color.background_color))
302+ } else {
303+ fileIcon.setBackgroundColor(Color .TRANSPARENT )
258304 }
259305 }
260306
@@ -270,18 +316,24 @@ class FileListAdapter(
270316 }
271317 }
272318
273- private fun setSpecificViewHolder (viewType : Int , holder : RecyclerView .ViewHolder , fileWithSyncInfo : OCFileWithSyncInfo , thumbnail : Bitmap ? ) {
319+ private fun setSpecificViewHolder (
320+ viewType : Int ,
321+ holder : RecyclerView .ViewHolder ,
322+ fileWithSyncInfo : OCFileWithSyncInfo ,
323+ thumbnail : Bitmap ? ,
324+ hasActiveSelection : Boolean ,
325+ ) {
274326 val file = fileWithSyncInfo.file
275327
276328 when (viewType) {
277329 ViewType .LIST_ITEM .ordinal -> {
278330 val view = holder as ListViewHolder
279331 view.binding.let {
280- it.fileListConstraintLayout.filterTouchesWhenObscured = PreferenceUtils .shouldDisallowTouchesWithOtherVisibleWindows(context)
332+ it.fileListConstraintLayout.filterTouchesWhenObscured = disallowTouchesWithOtherWindows
281333 it.Filename .text = file.fileName
282334 it.fileListSize.text = DisplayUtils .bytesToHumanReadable(file.length, context, true )
283335 it.fileListLastMod.text = DisplayUtils .getRelativeTimestamp(context, file.modificationTimestamp)
284- it.threeDotMenu.isVisible = getCheckedItems().isEmpty()
336+ it.threeDotMenu.isVisible = ! hasActiveSelection
285337 it.threeDotMenu.contentDescription = context.getString(R .string.content_description_file_operations, file.fileName)
286338 if (fileListOption.isAvailableOffline() || (fileListOption.isSharedByLink() && fileWithSyncInfo.space == null )) {
287339 it.spacePathLine.path.apply {
@@ -321,7 +373,10 @@ class FileListAdapter(
321373 val layoutParams = fileIcon.layoutParams as ViewGroup .MarginLayoutParams
322374
323375 if (thumbnail == null ) {
324- view.binding.Filename .text = file.fileName
376+ view.binding.Filename .apply {
377+ text = file.fileName
378+ isVisible = true
379+ }
325380 // Reset layout params values default
326381 manageGridLayoutParams(
327382 layoutParams = layoutParams,
@@ -330,6 +385,10 @@ class FileListAdapter(
330385 width = context.resources.getDimensionPixelSize(R .dimen.item_file_grid_width),
331386 )
332387 } else {
388+ view.binding.Filename .apply {
389+ text = " "
390+ isVisible = false
391+ }
333392 manageGridLayoutParams(
334393 layoutParams = layoutParams,
335394 marginVertical = context.resources.getDimensionPixelSize(R .dimen.item_file_image_grid_margin),
0 commit comments