Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 9 additions & 2 deletions app/src/main/java/com/infomaniak/drive/ui/menu/GalleryAdapter.kt
Original file line number Diff line number Diff line change
Expand Up @@ -143,8 +143,15 @@ class GalleryAdapter(
updateMultiSelect?.invoke()
}

fun insertDuplicatedImages(prefix: List<Any>) {
itemList.addAll(0, prefix)
fun setDisplayList(displayList: List<Any>) {
itemList.clear()
itemList.addAll(displayList)
notifyDataSetChanged()
}

fun insertDuplicatedImages(prefix: List<Any>, offset: Int) {
itemList.addAll(offset, prefix)
notifyItemRangeInserted(offset, prefix.size)
}

fun clearGallery() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -274,6 +274,13 @@ class GalleryFragment : MultiSelectFragment(
}
}

val currentPeriod get() = galleryViewModel.period

fun onPeriodSelected(newPeriod: GalleryPeriod) {
val displayList = galleryViewModel.updatePeriod(newPeriod) ?: return
galleryAdapter.setDisplayList(displayList)
}

fun onRefreshGallery() {
if (isResumed) {
galleryViewModel.clearGallery()
Expand Down Expand Up @@ -342,15 +349,8 @@ class GalleryFragment : MultiSelectFragment(
override fun onAllIndividualActionsFinished(type: BulkOperationType) {

if (type == BulkOperationType.COPY) {
val oldTotal = galleryAdapter.itemList.size
val oldFirstItem = galleryAdapter.itemList.firstOrNull()

galleryAdapter.insertDuplicatedImages(galleryViewModel.prependDuplicatedImages(oldFirstItem))
val newTotal = galleryAdapter.itemList.count()
val newFirstItem = galleryAdapter.itemList.firstOrNull()

val positionStart = if (oldFirstItem != newFirstItem) 0 else 1
galleryAdapter.notifyItemRangeInserted(positionStart, newTotal - oldTotal)
val (prefix, offset) = galleryViewModel.prependDuplicatedImages(galleryAdapter.itemList.firstOrNull())
galleryAdapter.insertDuplicatedImages(prefix, offset)
}
}

Expand Down
27 changes: 27 additions & 0 deletions app/src/main/java/com/infomaniak/drive/ui/menu/GalleryPeriod.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
/*
* Infomaniak kDrive - Android
* Copyright (C) 2026 Infomaniak Network SA
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.infomaniak.drive.ui.menu

import androidx.annotation.StringRes
import com.infomaniak.drive.R

enum class GalleryPeriod(@StringRes val translation: Int, val pattern: String) {
DAY(R.string.sortDay, "d MMMM yyyy"),
MONTH(R.string.sortMonth, "MMMM yyyy"),
YEAR(R.string.sortYear, "yyyy"),
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
/*
* Infomaniak kDrive - Android
* Copyright (C) 2026 Infomaniak Network SA
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.infomaniak.drive.ui.menu

import android.view.LayoutInflater
import android.view.ViewGroup
import androidx.core.view.isVisible
import androidx.recyclerview.widget.RecyclerView.Adapter
import androidx.recyclerview.widget.RecyclerView.ViewHolder
import com.infomaniak.drive.databinding.ItemSelectBottomSheetBinding
import com.infomaniak.drive.ui.menu.GalleryPeriodBottomSheetAdapter.GalleryPeriodViewHolder

class GalleryPeriodBottomSheetAdapter(
private val selectedPeriod: GalleryPeriod,
private val onItemClicked: (period: GalleryPeriod) -> Unit,
) : Adapter<GalleryPeriodViewHolder>() {

private val periods = GalleryPeriod.entries

override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): GalleryPeriodViewHolder {
return GalleryPeriodViewHolder(ItemSelectBottomSheetBinding.inflate(LayoutInflater.from(parent.context), parent, false))
}

override fun onBindViewHolder(holder: GalleryPeriodViewHolder, position: Int) = with(holder.binding) {
periods[position].let { period ->
itemSelectText.setText(period.translation)
itemSelectActiveIcon.isVisible = selectedPeriod == period
root.setOnClickListener { onItemClicked(period) }
}
}

override fun getItemCount() = periods.size

class GalleryPeriodViewHolder(val binding: ItemSelectBottomSheetBinding) : ViewHolder(binding.root)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
/*
* Infomaniak kDrive - Android
* Copyright (C) 2026 Infomaniak Network SA
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.infomaniak.drive.ui.menu

import android.os.Bundle
import android.view.View
import androidx.navigation.fragment.navArgs
import com.infomaniak.core.legacy.utils.setBackNavigationResult
import com.infomaniak.drive.R
import com.infomaniak.drive.views.SelectBottomSheetDialog

class GalleryPeriodBottomSheetDialog : SelectBottomSheetDialog() {

private val navigationArgs: GalleryPeriodBottomSheetDialogArgs by navArgs()

override fun onViewCreated(view: View, savedInstanceState: Bundle?) = with(binding) {
super.onViewCreated(view, savedInstanceState)

selectTitle.setText(R.string.sortTitle)

selectRecyclerView.adapter = GalleryPeriodBottomSheetAdapter(
selectedPeriod = navigationArgs.period,
onItemClicked = { period -> setBackNavigationResult(GALLERY_PERIOD_KEY, period) },
)
}

companion object {
const val GALLERY_PERIOD_KEY = "gallery_period"
}
}
44 changes: 30 additions & 14 deletions app/src/main/java/com/infomaniak/drive/ui/menu/GalleryViewModel.kt
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,9 @@ class GalleryViewModel : ViewModel() {
val galleryList = arrayListOf<File>()
val duplicatedList = arrayListOf<File>()

var period: GalleryPeriod = GalleryPeriod.MONTH
private set

private var getGalleryJob: Job? = null

private var currentCursor: String? = null
Expand Down Expand Up @@ -69,35 +72,48 @@ class GalleryViewModel : ViewModel() {

val displayList = arrayListOf<Any>()
for (file in newFiles) {
val month = file.getMonth()
if (lastSectionTitle != month) {
displayList.add(month)
lastSectionTitle = month
val sectionTitle = file.getSectionTitle()
if (lastSectionTitle != sectionTitle) {
displayList.add(sectionTitle)
lastSectionTitle = sectionTitle
}
displayList.add(file)
}

return displayList
}

fun updatePeriod(newPeriod: GalleryPeriod): List<Any>? {
if (newPeriod == period) return null

period = newPeriod

val files = ArrayList(galleryList)
galleryList.clear()
lastSectionTitle = ""

fun prependDuplicatedImages(currentTopTitle: Any?): List<Any> {
return formatList(files)
}

fun prependDuplicatedImages(currentTopTitle: Any?): Pair<List<Any>, Int> {
val prefix = arrayListOf<Any>()
var newestSectionTitle = currentTopTitle

for (file in duplicatedList) {
galleryList.add(0, file)
galleryList.addAll(0, duplicatedList)

val month = file.getMonth()
if (newestSectionTitle != month) {
prefix.add(month)
newestSectionTitle = month
for (file in duplicatedList) {
val sectionTitle = file.getSectionTitle()
if (newestSectionTitle != sectionTitle) {
prefix.add(sectionTitle)
newestSectionTitle = sectionTitle
}
prefix.add(file)
}

duplicatedList.clear()

return prefix
val offset = if (prefix.firstOrNull() is String) 0 else 1
return prefix to offset
}

fun removeFileFromGallery(fileId: Int) {
Expand All @@ -109,8 +125,8 @@ class GalleryViewModel : ViewModel() {
lastSectionTitle = ""
}

fun File.getMonth(): String {
return getLastModifiedAt().format("MMMM yyyy").capitalizeFirstChar()
private fun File.getSectionTitle(): String {
return getLastModifiedAt().format(period.pattern).capitalizeFirstChar()
}

private fun loadLastGallery(
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
/*
* Infomaniak kDrive - Android
* Copyright (C) 2022-2024 Infomaniak Network SA
* Copyright (C) 2022-2026 Infomaniak Network SA
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
Expand All @@ -25,7 +25,9 @@ import androidx.core.view.isGone
import androidx.core.view.marginBottom
import androidx.core.view.marginTop
import androidx.fragment.app.Fragment
import com.infomaniak.core.legacy.utils.getBackNavigationResult
import com.infomaniak.core.legacy.utils.safeBinding
import com.infomaniak.core.legacy.utils.safeNavigate
import com.infomaniak.core.legacy.utils.toPx
import com.infomaniak.drive.R
import com.infomaniak.drive.databinding.FragmentMenuGalleryBinding
Expand Down Expand Up @@ -65,6 +67,23 @@ class MenuGalleryFragment : Fragment() {

swipeRefreshLayout.setOnRefreshListener(galleryFragment::onRefreshGallery)

toolbar.setOnMenuItemClickListener { menuItem ->
if (menuItem.itemId == R.id.selectGalleryPeriod) {
safeNavigate(
MenuGalleryFragmentDirections.actionMenuGalleryFragmentToGalleryPeriodBottomSheetDialog(
galleryFragment.currentPeriod,
)
)
true
} else {
false
}
}

getBackNavigationResult<GalleryPeriod>(GalleryPeriodBottomSheetDialog.GALLERY_PERIOD_KEY) {
galleryFragment.onPeriodSelected(it)
}

multiSelectLayout.apply {
selectAllButton.isGone = true
setMultiSelectClickListeners(galleryFragment)
Expand Down
1 change: 1 addition & 0 deletions app/src/main/res/layout/fragment_menu_gallery.xml
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
app:layout_collapseMode="pin"
app:menu="@menu/gallery_menu"
app:navigationIcon="@null" />

</com.google.android.material.appbar.CollapsingToolbarLayout>
Expand Down
27 changes: 27 additions & 0 deletions app/src/main/res/menu/gallery_menu.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
<?xml version="1.0" encoding="utf-8"?><!--
~ Infomaniak kDrive - Android
~ Copyright (C) 2026 Infomaniak Network SA
~
~ This program is free software: you can redistribute it and/or modify
~ it under the terms of the GNU General Public License as published by
~ the Free Software Foundation, either version 3 of the License, or
~ (at your option) any later version.
~
~ This program is distributed in the hope that it will be useful,
~ but WITHOUT ANY WARRANTY; without even the implied warranty of
~ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
~ GNU General Public License for more details.
~
~ You should have received a copy of the GNU General Public License
~ along with this program. If not, see <http://www.gnu.org/licenses/>.
-->
<menu xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">

<item
android:id="@+id/selectGalleryPeriod"
android:icon="@drawable/ic_filter"
android:title="@string/sortTitle"
app:showAsAction="always" />

</menu>
17 changes: 16 additions & 1 deletion app/src/main/res/navigation/main_navigation.xml
Original file line number Diff line number Diff line change
Expand Up @@ -1175,7 +1175,22 @@
android:id="@+id/menuGalleryFragment"
android:name="com.infomaniak.drive.ui.menu.MenuGalleryFragment"
android:label="MenuGalleryFragment"
tools:layout="@layout/fragment_menu_gallery" />
tools:layout="@layout/fragment_menu_gallery">
<action
android:id="@+id/action_menuGalleryFragment_to_galleryPeriodBottomSheetDialog"
app:destination="@id/galleryPeriodBottomSheetDialog" />
</fragment>

<dialog
android:id="@+id/galleryPeriodBottomSheetDialog"
android:name="com.infomaniak.drive.ui.menu.GalleryPeriodBottomSheetDialog"
android:label="GalleryPeriodBottomSheetDialog"
tools:layout="@layout/fragment_bottom_sheet_select">
<argument
android:name="period"
android:defaultValue="MONTH"
app:argType="com.infomaniak.drive.ui.menu.GalleryPeriod" />
</dialog>

<fragment
android:id="@+id/rootFilesFragment"
Expand Down
Loading