2020
2121package com.owncloud.android.presentation.spaces.members
2222
23+ import android.app.DatePickerDialog
24+ import android.icu.util.Calendar
2325import android.os.Bundle
2426import android.view.LayoutInflater
2527import android.view.View
@@ -30,15 +32,23 @@ import androidx.recyclerview.widget.LinearLayoutManager
3032import androidx.recyclerview.widget.RecyclerView
3133import com.owncloud.android.R
3234import com.owncloud.android.databinding.AddMemberFragmentBinding
35+ import com.owncloud.android.domain.members.model.OCMember
36+ import com.owncloud.android.domain.members.model.OCMemberType
37+ import com.owncloud.android.domain.roles.model.OCRole
3338import com.owncloud.android.domain.spaces.model.OCSpace
3439import com.owncloud.android.domain.spaces.model.SpaceMember
3540import com.owncloud.android.extensions.collectLatestLifecycleFlow
3641import com.owncloud.android.extensions.showErrorInSnackbar
42+ import com.owncloud.android.presentation.common.UIResult
43+ import com.owncloud.android.utils.DisplayUtils
3744import org.koin.androidx.viewmodel.ext.android.viewModel
3845import org.koin.core.parameter.parametersOf
3946import timber.log.Timber
47+ import java.text.SimpleDateFormat
48+ import java.util.Locale
49+ import java.util.TimeZone
4050
41- class AddMemberFragment : Fragment () {
51+ class AddMemberFragment : Fragment (), SearchMembersAdapter.SearchMembersAdapterListener {
4252 private var _binding : AddMemberFragmentBinding ? = null
4353 private val binding get() = _binding !!
4454
@@ -50,6 +60,7 @@ class AddMemberFragment: Fragment() {
5060 }
5161
5262 private lateinit var searchMembersAdapter: SearchMembersAdapter
63+ private lateinit var rolesAdapter: SpaceRolesAdapter
5364 private lateinit var recyclerView: RecyclerView
5465
5566 override fun onCreateView (inflater : LayoutInflater , container : ViewGroup ? , savedInstanceState : Bundle ? ): View {
@@ -59,7 +70,7 @@ class AddMemberFragment: Fragment() {
5970
6071 override fun onViewCreated (view : View , savedInstanceState : Bundle ? ) {
6172 super .onViewCreated(view, savedInstanceState)
62- searchMembersAdapter = SearchMembersAdapter ()
73+ searchMembersAdapter = SearchMembersAdapter (this )
6374 recyclerView = binding.membersRecyclerView
6475 recyclerView.apply {
6576 layoutManager = LinearLayoutManager (requireContext())
@@ -89,8 +100,49 @@ class AddMemberFragment: Fragment() {
89100 }
90101 }
91102
103+ collectLatestLifecycleFlow(spaceMembersViewModel.addMemberUIState) { uiState ->
104+ uiState?.let {
105+ binding.apply {
106+ searchMemberLayout.visibility = View .GONE
107+ addMemberLayout.visibility = View .VISIBLE
108+ inviteMemberButton.visibility = View .VISIBLE
109+ }
110+ it.selectedMember?.let { member ->
111+ bindSelectedMember(member)
112+ }
113+ it.selectedExpirationDate?.let { expirationDate ->
114+ binding.expirationDateLayout.expirationDateValue.apply {
115+ visibility = View .VISIBLE
116+ text = DisplayUtils .displayDateToHumanReadable(expirationDate)
117+ }
118+ }
119+ bindRoles(uiState.selectedRole?.id)
120+ bindDatePickerDialog()
121+
122+ binding.inviteMemberButton.setOnClickListener {
123+ uiState.selectedMember?.let { selectedMember ->
124+ uiState.selectedRole?.let { selectedRole ->
125+ spaceMembersViewModel.addMember(selectedMember, selectedRole.id, uiState.selectedExpirationDate)
126+ }
127+ }
128+ }
129+ }
130+ }
131+
132+ collectLatestLifecycleFlow(spaceMembersViewModel.addMemberResultFlow) { event ->
133+ event?.peekContent()?.let { uiResult ->
134+ when (uiResult) {
135+ is UIResult .Loading -> { }
136+ is UIResult .Success -> requireActivity().onBackPressed()
137+ is UIResult .Error -> showErrorInSnackbar(R .string.members_add_failed, uiResult.error)
138+ }
139+ }
140+ }
141+
92142 binding.searchBar.apply {
93- requestFocus()
143+ if (savedInstanceState == null ) {
144+ requestFocus()
145+ }
94146 setOnQueryTextListener(object : androidx.appcompat.widget.SearchView .OnQueryTextListener {
95147 override fun onQueryTextSubmit (query : String ): Boolean = true
96148
@@ -120,20 +172,91 @@ class AddMemberFragment: Fragment() {
120172 requireActivity().setTitle(R .string.members_add)
121173 }
122174
175+ override fun onMemberClick (member : OCMember ) {
176+ spaceMembersViewModel.onMemberSelected(member)
177+ }
178+
179+ private fun bindSelectedMember (member : OCMember ) {
180+ binding.selectedMemberLayout.apply {
181+ memberIcon.setImageResource(if (member.type == OCMemberType .GROUP ) R .drawable.ic_group else R .drawable.ic_user)
182+ memberName.text = member.displayName
183+ memberRole.text = member.surname
184+ }
185+ }
186+
187+ private fun bindRoles (selectedRoleId : String? ) {
188+ val roles = requireArguments().getParcelableArrayList<OCRole >(ARG_ROLES ) ? : arrayListOf ()
189+ rolesAdapter = SpaceRolesAdapter (onRoleSelected = {
190+ binding.inviteMemberButton.isEnabled = true
191+ spaceMembersViewModel.onRoleSelected(it)
192+ })
193+ binding.rolesRecyclerView.apply {
194+ layoutManager = LinearLayoutManager (requireContext())
195+ adapter = rolesAdapter
196+ }
197+ rolesAdapter.setRoles(roles)
198+ selectedRoleId?.let {
199+ binding.inviteMemberButton.isEnabled = true
200+ rolesAdapter.setSelectedRole(it)
201+ }
202+ }
203+
204+ private fun bindDatePickerDialog () {
205+ binding.expirationDateLayout.expirationDateSwitch.setOnCheckedChangeListener { _, isChecked ->
206+ if (isChecked) {
207+ val calendar = Calendar .getInstance()
208+
209+ DatePickerDialog (
210+ requireContext(),
211+ { _, selectedYear, selectedMonth, selectedDay ->
212+ calendar.set(selectedYear, selectedMonth, selectedDay, 23 , 59 , 59 )
213+ calendar.set(Calendar .MILLISECOND , 999 )
214+ val formatter = SimpleDateFormat (DisplayUtils .DATE_FORMAT_ISO , Locale .ROOT )
215+ formatter.timeZone = TimeZone .getTimeZone(" UTC" )
216+ val isoExpirationDate = formatter.format(calendar.time)
217+ spaceMembersViewModel.onExpirationDateSelected(isoExpirationDate)
218+ binding.expirationDateLayout.expirationDateValue.apply {
219+ visibility = View .VISIBLE
220+ text = DisplayUtils .displayDateToHumanReadable(isoExpirationDate)
221+ }
222+ },
223+ calendar.get(Calendar .YEAR ),
224+ calendar.get(Calendar .MONTH ),
225+ calendar.get(Calendar .DAY_OF_MONTH )
226+ ).apply {
227+ datePicker.minDate = calendar.timeInMillis
228+ show()
229+ setOnCancelListener {
230+ binding.expirationDateLayout.apply {
231+ expirationDateSwitch.isChecked = false
232+ expirationDateValue.visibility = View .GONE
233+ }
234+ }
235+ }
236+ } else {
237+ binding.expirationDateLayout.expirationDateValue.visibility = View .GONE
238+ spaceMembersViewModel.onExpirationDateSelected(null )
239+ }
240+ }
241+ }
242+
123243 companion object {
124244 private const val ARG_ACCOUNT_NAME = " ACCOUNT_NAME"
125245 private const val ARG_CURRENT_SPACE = " CURRENT_SPACE"
126246 private const val ARG_SPACE_MEMBERS = " SPACE_MEMBERS"
247+ private const val ARG_ROLES = " ROLES"
127248
128249 fun newInstance (
129250 accountName : String ,
130251 currentSpace : OCSpace ,
131- spaceMembers : List <SpaceMember >
252+ spaceMembers : List <SpaceMember >,
253+ roles : List <OCRole >
132254 ): AddMemberFragment {
133255 val args = Bundle ().apply {
134256 putString(ARG_ACCOUNT_NAME , accountName)
135257 putParcelable(ARG_CURRENT_SPACE , currentSpace)
136258 putParcelableArrayList(ARG_SPACE_MEMBERS , ArrayList (spaceMembers))
259+ putParcelableArrayList(ARG_ROLES , ArrayList (roles))
137260 }
138261 return AddMemberFragment ().apply {
139262 arguments = args
0 commit comments