Skip to content

Commit b6ef335

Browse files
authored
Merge pull request #4665 from owncloud/feature/spaces_in_horizontal_with_menu
[FEATURE REQUEST] Set space cells in horizontal with menu
2 parents d3749b3 + d1a3933 commit b6ef335

File tree

11 files changed

+173
-21
lines changed

11 files changed

+173
-21
lines changed

CHANGELOG.md

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ ownCloud admins and users.
4040
## Summary
4141

4242
* Change - SBOM workflow runs on dependabot PRs: [#4664](https://github.com/owncloud/android/pull/4664)
43+
* Enhancement - New layout for spaces list: [#4604](https://github.com/owncloud/android/issues/4604)
4344
* Enhancement - Add account ID to the user information: [#4605](https://github.com/owncloud/android/issues/4605)
4445

4546
## Details
@@ -52,6 +53,15 @@ ownCloud admins and users.
5253
https://github.com/owncloud/android/pull/4664
5354
https://github.com/owncloud/android/pull/4666
5455

56+
* Enhancement - New layout for spaces list: [#4604](https://github.com/owncloud/android/issues/4604)
57+
58+
A three-dot button has been added to each space card, allowing a bottom sheet
59+
dialog to be opened when clicked. In addition, the spaces layout has been
60+
changed to horizontal.
61+
62+
https://github.com/owncloud/android/issues/4604
63+
https://github.com/owncloud/android/pull/4665
64+
5565
* Enhancement - Add account ID to the user information: [#4605](https://github.com/owncloud/android/issues/4605)
5666

5767
The account ID has been added to the Account Manager only for Infinite Scale

changelog/unreleased/4665

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
Enhancement: New layout for spaces list
2+
3+
A three-dot button has been added to each space card, allowing a bottom sheet dialog to
4+
be opened when clicked. In addition, the spaces layout has been changed to horizontal.
5+
6+
https://github.com/owncloud/android/issues/4604
7+
https://github.com/owncloud/android/pull/4665

owncloudApp/src/main/java/com/owncloud/android/presentation/releasenotes/ReleaseNotesViewModel.kt

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,11 @@ class ReleaseNotesViewModel(
5858
subtitle = R.string.release_notes_4_6_1_subtitle_shares_space_docs_provider,
5959
type = ReleaseNoteType.ENHANCEMENT
6060
),
61+
ReleaseNote(
62+
title = R.string.release_notes_4_7_0_title_new_layout_for_spaces,
63+
subtitle = R.string.release_notes_4_7_0_subtitle_new_layout_for_spaces,
64+
type = ReleaseNoteType.ENHANCEMENT
65+
),
6166
ReleaseNote(
6267
title = R.string.release_notes_bugfixes_title,
6368
subtitle = R.string.release_notes_bugfixes_subtitle,

owncloudApp/src/main/java/com/owncloud/android/presentation/spaces/SpacesListAdapter.kt

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,9 @@
44
* @author Juan Carlos Garrote Gascón
55
* @author Manuel Plazas Palacio
66
* @author Aitor Balleteros Pavón
7+
* @author Jorge Aguado Recio
78
*
8-
* Copyright (C) 2024 ownCloud GmbH.
9+
* Copyright (C) 2025 ownCloud GmbH.
910
*
1011
* This program is free software: you can redistribute it and/or modify
1112
* it under the terms of the GNU General Public License version 2,
@@ -59,6 +60,10 @@ class SpacesListAdapter(
5960
listener.onItemClick(space)
6061
}
6162
spacesListItemCard.setAccessibilityRole(className = Button::class.java)
63+
spacesListItemName.contentDescription = holder.itemView.context.getString(R.string.content_description_space_name, space.name)
64+
spacesThreeDotMenu.contentDescription = holder.itemView.context.getString(R.string.content_description_space_three_dot_menu, space.name)
65+
spacesListItemSubtitle.contentDescription = holder.itemView.context.getString(R.string.content_description_space_subtitle,
66+
space.description)
6267

6368
if (space.isPersonal && !isMultiPersonal) {
6469
spacesListItemName.text = holder.itemView.context.getString(R.string.bottom_nav_personal)
@@ -88,6 +93,10 @@ class SpacesListAdapter(
8893
}
8994
}
9095
}
96+
97+
spacesThreeDotMenu.setOnClickListener {
98+
listener.onThreeDotButtonClick(space)
99+
}
91100
}
92101
}
93102

@@ -106,6 +115,7 @@ class SpacesListAdapter(
106115

107116
interface SpacesListAdapterListener {
108117
fun onItemClick(ocSpace: OCSpace)
118+
fun onThreeDotButtonClick(ocSpace: OCSpace)
109119
}
110120

111121
class SpacesViewHolder(val binding: SpacesListItemBinding) : RecyclerView.ViewHolder(binding.root)

owncloudApp/src/main/java/com/owncloud/android/presentation/spaces/SpacesListFragment.kt

Lines changed: 54 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222

2323
package com.owncloud.android.presentation.spaces
2424

25+
import android.content.res.Configuration
2526
import android.os.Bundle
2627
import android.view.LayoutInflater
2728
import android.view.Menu
@@ -34,7 +35,10 @@ import androidx.core.view.isVisible
3435
import androidx.fragment.app.Fragment
3536
import androidx.fragment.app.setFragmentResult
3637
import androidx.recyclerview.widget.GridLayoutManager
38+
import com.google.android.material.bottomsheet.BottomSheetBehavior
39+
import com.google.android.material.bottomsheet.BottomSheetDialog
3740
import com.owncloud.android.R
41+
import com.owncloud.android.databinding.FileOptionsBottomSheetFragmentBinding
3842
import com.owncloud.android.databinding.SpacesListFragmentBinding
3943
import com.owncloud.android.domain.files.model.FileListOption
4044
import com.owncloud.android.domain.spaces.model.OCSpace
@@ -44,6 +48,7 @@ import com.owncloud.android.extensions.toDrawableRes
4448
import com.owncloud.android.extensions.toSubtitleStringRes
4549
import com.owncloud.android.extensions.toTitleStringRes
4650
import com.owncloud.android.presentation.capabilities.CapabilityViewModel
51+
import com.owncloud.android.utils.DisplayUtils
4752
import com.owncloud.android.presentation.common.UIResult
4853
import org.koin.androidx.viewmodel.ext.android.viewModel
4954
import org.koin.core.parameter.parametersOf
@@ -84,11 +89,14 @@ class SpacesListFragment : SpacesListAdapter.SpacesListAdapterListener, Fragment
8489
subscribeToViewModels()
8590
}
8691

92+
override fun onConfigurationChanged(newConfig: Configuration) {
93+
super.onConfigurationChanged(newConfig)
94+
setSpacesLayout(newConfig)
95+
}
96+
8797
private fun initViews() {
8898
setHasOptionsMenu(true)
89-
90-
val spacesListLayoutManager = GridLayoutManager(requireContext(), 2)
91-
binding.recyclerSpacesList.layoutManager = spacesListLayoutManager
99+
setSpacesLayout(resources.configuration)
92100
spacesListAdapter = SpacesListAdapter(this)
93101
binding.recyclerSpacesList.adapter = spacesListAdapter
94102

@@ -151,10 +159,53 @@ class SpacesListFragment : SpacesListAdapter.SpacesListAdapterListener, Fragment
151159
}
152160
}
153161

162+
private fun setSpacesLayout(config: Configuration) {
163+
val layoutColumns = if (config.orientation == Configuration.ORIENTATION_LANDSCAPE) 2 else 1
164+
val spacesListLayoutManager = GridLayoutManager(requireContext(), layoutColumns)
165+
binding.recyclerSpacesList.layoutManager = spacesListLayoutManager
166+
}
167+
154168
override fun onItemClick(ocSpace: OCSpace) {
155169
spacesListViewModel.getRootFileForSpace(ocSpace)
156170
}
157171

172+
override fun onThreeDotButtonClick(ocSpace: OCSpace) {
173+
val spaceOptionsBottomSheetBinding = FileOptionsBottomSheetFragmentBinding.inflate(layoutInflater)
174+
val dialog = BottomSheetDialog(requireContext())
175+
dialog.setContentView(spaceOptionsBottomSheetBinding.root)
176+
177+
val fileOptionsBottomSheetSingleFileBehavior: BottomSheetBehavior<*> = BottomSheetBehavior.from(
178+
spaceOptionsBottomSheetBinding.root.parent as View)
179+
val closeBottomSheetButton = spaceOptionsBottomSheetBinding.closeBottomSheet
180+
closeBottomSheetButton.setOnClickListener {
181+
dialog.dismiss()
182+
}
183+
184+
val thumbnailBottomSheet = spaceOptionsBottomSheetBinding.thumbnailBottomSheet
185+
thumbnailBottomSheet.setImageResource(R.drawable.ic_menu_space)
186+
187+
val spaceNameBottomSheet = spaceOptionsBottomSheetBinding.fileNameBottomSheet
188+
spaceNameBottomSheet.text = ocSpace.name
189+
190+
val spaceSizeBottomSheet = spaceOptionsBottomSheetBinding.fileSizeBottomSheet
191+
spaceSizeBottomSheet.text = DisplayUtils.bytesToHumanReadable(ocSpace.quota?.used ?: 0L, requireContext(), true)
192+
193+
val spaceSeparatorBottomSheet = spaceOptionsBottomSheetBinding.fileSeparatorBottomSheet
194+
spaceSeparatorBottomSheet.visibility = View.GONE
195+
196+
fileOptionsBottomSheetSingleFileBehavior.addBottomSheetCallback(object : BottomSheetBehavior.BottomSheetCallback() {
197+
override fun onStateChanged(bottomSheet: View, newState: Int) {
198+
if (newState == BottomSheetBehavior.STATE_DRAGGING) {
199+
fileOptionsBottomSheetSingleFileBehavior.state = BottomSheetBehavior.STATE_EXPANDED
200+
}
201+
}
202+
override fun onSlide(bottomSheet: View, slideOffset: Float) {}
203+
})
204+
205+
dialog.setOnShowListener { fileOptionsBottomSheetSingleFileBehavior.peekHeight = spaceOptionsBottomSheetBinding.root.measuredHeight }
206+
dialog.show()
207+
}
208+
158209
override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) {
159210
super.onCreateOptionsMenu(menu, inflater)
160211
(menu.findItem(R.id.action_search).actionView as SearchView).run {
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
<vector android:height="48dp" android:viewportHeight="24"
2+
android:viewportWidth="24" android:width="48dp" xmlns:android="http://schemas.android.com/apk/res/android">
3+
<path android:fillColor="#55739a" android:pathData="M22,12.999L22,20a1,1 0,0 1,-1 1h-8v-8.001h9zM11,12.999L11,21L3,21a1,1 0,0 1,-1 -1v-7.001h9zM11,3v7.999L2,10.999L2,4a1,1 0,0 1,1 -1h8zM21,3a1,1 0,0 1,1 1v6.999h-9L13,3h8z"/>
4+
</vector>

owncloudApp/src/main/res/layout/spaces_list_item.xml

Lines changed: 40 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,9 @@
22
~ ownCloud Android client application
33
~
44
~ @author Juan Carlos Garrote Gascón
5-
~ Copyright (C) 2023 ownCloud GmbH.
5+
~ @author Jorge Aguado Recio
6+
~
7+
~ Copyright (C) 2025 ownCloud GmbH.
68
~
79
~ This program is free software: you can redistribute it and/or modify
810
~ it under the terms of the GNU General Public License version 2,
@@ -24,7 +26,10 @@
2426
android:id="@+id/spaces_list_item_layout"
2527
android:layout_width="match_parent"
2628
android:layout_height="wrap_content"
27-
android:layout_margin="8dp"
29+
android:layout_marginStart="@dimen/spaces_margin_horizontal"
30+
android:layout_marginEnd="@dimen/spaces_margin_horizontal"
31+
android:layout_marginTop="@dimen/spaces_margin_vertical"
32+
android:layout_marginBottom="@dimen/spaces_margin_vertical"
2833
android:orientation="vertical">
2934

3035
<androidx.cardview.widget.CardView
@@ -46,23 +51,45 @@
4651
android:layout_width="match_parent"
4752
android:layout_height="@dimen/spaces_thumbnail_height"
4853
android:scaleType="centerCrop"
49-
android:src="@drawable/ic_spaces" />
54+
android:src="@drawable/ic_spaces"
55+
android:contentDescription="@string/content_description_space_image"/>
5056

5157
<View
5258
android:layout_width="match_parent"
5359
android:layout_height="1dp"
5460
android:background="@color/actionbar_start_color" />
5561

56-
<TextView
57-
android:id="@+id/spaces_list_item_name"
58-
android:layout_width="wrap_content"
59-
android:layout_height="wrap_content"
60-
android:layout_margin="@dimen/standard_half_margin"
61-
android:singleLine="true"
62-
android:textColor="@color/textColor"
63-
android:textSize="18sp"
64-
android:textStyle="bold"
65-
tools:text="Name" />
62+
<LinearLayout
63+
android:layout_width="match_parent"
64+
android:layout_height="match_parent"
65+
android:orientation="horizontal">
66+
67+
<TextView
68+
android:id="@+id/spaces_list_item_name"
69+
android:layout_width="0dp"
70+
android:layout_height="wrap_content"
71+
android:layout_weight="1"
72+
android:layout_margin="@dimen/standard_half_margin"
73+
android:singleLine="true"
74+
android:textColor="@color/textColor"
75+
android:textSize="18sp"
76+
android:textStyle="bold"
77+
tools:text="Name" />
78+
79+
<ImageView
80+
android:id="@+id/spaces_three_dot_menu"
81+
android:layout_width="@dimen/icon_button_size"
82+
android:layout_height="@dimen/icon_button_size"
83+
android:scaleType="center"
84+
android:src="@drawable/ic_three_dot_menu"
85+
android:clickable="true"
86+
android:focusable="true"
87+
android:background="?android:attr/selectableItemBackground"
88+
app:layout_constraintEnd_toEndOf="parent"
89+
app:layout_constraintTop_toTopOf="parent"
90+
app:layout_constraintBottom_toBottomOf="parent"/>
91+
92+
</LinearLayout>
6693

6794
<TextView
6895
android:id="@+id/spaces_list_item_subtitle"

owncloudApp/src/main/res/values-h740dp/dims.xml

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,9 @@
33
44
@author David Crespo Ríos
55
@author Juan Carlos Garrote Gascón
6+
@author Jorge Aguado Recio
67
7-
Copyright (C) 2023 ownCloud GmbH.
8+
Copyright (C) 2025 ownCloud GmbH.
89
910
This program is free software: you can redistribute it and/or modify
1011
it under the terms of the GNU General Public License version 2,
@@ -27,6 +28,8 @@
2728
<dimen name="passcode_margin_buttons">8dp</dimen>
2829

2930
<!-- Spaces -->
30-
<dimen name="spaces_thumbnail_height">256dp</dimen>
31+
<dimen name="spaces_thumbnail_height">200dp</dimen>
3132
<dimen name="spaces_header_card_height">150dp</dimen>
33+
<dimen name="spaces_margin_horizontal">30dp</dimen>
34+
<dimen name="spaces_margin_vertical">20dp</dimen>
3235
</resources>
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
<?xml version="1.0" encoding="utf-8"?><!--
2+
ownCloud Android client application
3+
4+
@author Jorge Aguado Recio
5+
6+
Copyright (C) 2025 ownCloud GmbH.
7+
8+
This program is free software: you can redistribute it and/or modify
9+
it under the terms of the GNU General Public License version 2,
10+
as published by the Free Software Foundation.
11+
12+
This program is distributed in the hope that it will be useful,
13+
but WITHOUT ANY WARRANTY; without even the implied warranty of
14+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15+
GNU General Public License for more details.
16+
17+
You should have received a copy of the GNU General Public License
18+
along with this program. If not, see <http://www.gnu.org/licenses/>.
19+
-->
20+
21+
<resources>
22+
<!-- Spaces -->
23+
<dimen name="spaces_thumbnail_height">200dp</dimen>
24+
<dimen name="spaces_header_card_height">150dp</dimen>
25+
<dimen name="spaces_margin_horizontal">50dp</dimen>
26+
<dimen name="spaces_margin_vertical">40dp</dimen>
27+
</resources>

owncloudApp/src/main/res/values/dims.xml

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
<?xml version="1.0" encoding="utf-8"?><!--
22
ownCloud Android client application
33
4-
Copyright (C) 2024 ownCloud GmbH.
4+
Copyright (C) 2025 ownCloud GmbH.
55
66
This program is free software: you can redistribute it and/or modify
77
it under the terms of the GNU General Public License version 2,
@@ -81,8 +81,10 @@
8181
<dimen name="passcode_margin_buttons">4dp</dimen>
8282

8383
<!-- Spaces -->
84-
<dimen name="spaces_thumbnail_height">156dp</dimen>
84+
<dimen name="spaces_thumbnail_height">200dp</dimen>
8585
<dimen name="spaces_header_card_height">80dp</dimen>
86+
<dimen name="spaces_margin_horizontal">30dp</dimen>
87+
<dimen name="spaces_margin_vertical">20dp</dimen>
8688

8789
<!-- Accessibility dims -->
8890
<dimen name="icon_button_size">48dp</dimen>

0 commit comments

Comments
 (0)