diff --git a/app/src/main/java/com/etesync/syncadapter/ui/etebase/CollectionActivity.kt b/app/src/main/java/com/etesync/syncadapter/ui/etebase/CollectionActivity.kt index b762f6d1..809d2fa0 100644 --- a/app/src/main/java/com/etesync/syncadapter/ui/etebase/CollectionActivity.kt +++ b/app/src/main/java/com/etesync/syncadapter/ui/etebase/CollectionActivity.kt @@ -5,6 +5,7 @@ import android.content.Context import android.content.Intent import android.os.Bundle import androidx.activity.viewModels +import androidx.fragment.app.commit import androidx.lifecycle.LifecycleOwner import androidx.lifecycle.MutableLiveData import androidx.lifecycle.ViewModel @@ -34,9 +35,9 @@ class CollectionActivity() : BaseActivity() { model.observe(this) { itemsModel.loadItems(it) } - supportFragmentManager.beginTransaction() - .add(R.id.fragment_container, ViewCollectionFragment()) - .commit() + supportFragmentManager.commit { + replace(R.id.fragment_container, ViewCollectionFragment()) + } } supportActionBar?.setDisplayHomeAsUpEnabled(true) @@ -69,6 +70,7 @@ class AccountCollectionViewModel : ViewModel() { } uiThread { collection.value = AccountCollectionHolder( + account, etebaseLocalCache, etebase, colMgr, @@ -80,9 +82,12 @@ class AccountCollectionViewModel : ViewModel() { fun observe(owner: LifecycleOwner, observer: (AccountCollectionHolder) -> Unit) = collection.observe(owner, observer) + + val value: AccountCollectionHolder? + get() = collection.value } -data class AccountCollectionHolder(val etebaseLocalCache: EtebaseLocalCache, val etebase: com.etebase.client.Account, val colMgr: CollectionManager, val cachedCollection: CachedCollection) +data class AccountCollectionHolder(val account: Account, val etebaseLocalCache: EtebaseLocalCache, val etebase: com.etebase.client.Account, val colMgr: CollectionManager, val cachedCollection: CachedCollection) class ItemsViewModel : ViewModel() { private val cachedItems = MutableLiveData>() @@ -100,4 +105,19 @@ class ItemsViewModel : ViewModel() { fun observe(owner: LifecycleOwner, observer: (List) -> Unit) = cachedItems.observe(owner, observer) + + val value: List? + get() = cachedItems.value +} + + +class LoadingViewModel : ViewModel() { + private val loading = MutableLiveData() + + fun setLoading(value: Boolean) { + loading.value = value + } + + fun observe(owner: LifecycleOwner, observer: (Boolean) -> Unit) = + loading.observe(owner, observer) } \ No newline at end of file diff --git a/app/src/main/java/com/etesync/syncadapter/ui/etebase/EditCollectionFragment.kt b/app/src/main/java/com/etesync/syncadapter/ui/etebase/EditCollectionFragment.kt new file mode 100644 index 00000000..0b08a8a7 --- /dev/null +++ b/app/src/main/java/com/etesync/syncadapter/ui/etebase/EditCollectionFragment.kt @@ -0,0 +1,235 @@ +package com.etesync.syncadapter.ui.etebase + +import android.graphics.Color.parseColor +import android.graphics.drawable.ColorDrawable +import android.os.Bundle +import android.text.TextUtils +import android.view.* +import android.widget.EditText +import androidx.appcompat.app.AlertDialog +import androidx.fragment.app.Fragment +import androidx.fragment.app.activityViewModels +import androidx.fragment.app.viewModels +import com.etebase.client.Collection +import com.etebase.client.exceptions.EtebaseException +import com.etesync.syncadapter.Constants +import com.etesync.syncadapter.R +import com.etesync.syncadapter.resource.LocalCalendar +import com.etesync.syncadapter.ui.BaseActivity +import org.apache.commons.lang3.StringUtils +import org.jetbrains.anko.doAsync +import org.jetbrains.anko.uiThread +import yuku.ambilwarna.AmbilWarnaDialog +import java.lang.String + +class EditCollectionFragment() : Fragment() { + private val model: AccountCollectionViewModel by activityViewModels() + private val loadingModel: LoadingViewModel by viewModels() + + override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? { + val ret = inflater.inflate(R.layout.activity_create_collection, container, false) + setHasOptionsMenu(true) + + if (savedInstanceState == null) { + model.observe(this) { + updateTitle(it) + if (container != null) { + initUi(inflater, ret, it) + } + } + } + + return ret + } + + fun updateTitle(accountCollectionHolder: AccountCollectionHolder) { + accountCollectionHolder.let { + val new = false + var titleId: Int = R.string.create_calendar + if (new) { + when (it.cachedCollection.meta.collectionType) { + Constants.ETEBASE_TYPE_CALENDAR -> { + titleId = R.string.create_calendar + } + Constants.ETEBASE_TYPE_TASKS -> { + titleId = R.string.create_tasklist + } + Constants.ETEBASE_TYPE_ADDRESS_BOOK -> { + titleId = R.string.create_addressbook + } + } + } else { + titleId = R.string.edit_collection + } + (activity as? BaseActivity?)?.supportActionBar?.setTitle(titleId) + } + } + + private fun initUi(inflater: LayoutInflater, v: View, collectionHolder: AccountCollectionHolder) { + val title = v.findViewById(R.id.display_name) + val desc = v.findViewById(R.id.description) + + val meta = collectionHolder.cachedCollection.meta + + title.setText(meta.name) + desc.setText(meta.description) + + val colorSquare = v.findViewById(R.id.color) + when (collectionHolder.cachedCollection.meta.collectionType) { + Constants.ETEBASE_TYPE_CALENDAR -> { + title.setHint(R.string.create_calendar_display_name_hint) + + val color = if (!meta.color.isNullOrBlank()) parseColor(meta.color) else LocalCalendar.defaultColor + colorSquare.setBackgroundColor(color) + colorSquare.setOnClickListener { + AmbilWarnaDialog(context, (colorSquare.background as ColorDrawable).color, true, object : AmbilWarnaDialog.OnAmbilWarnaListener { + override fun onCancel(dialog: AmbilWarnaDialog) {} + + override fun onOk(dialog: AmbilWarnaDialog, color: Int) { + colorSquare.setBackgroundColor(color) + } + }).show() + } + } + Constants.ETEBASE_TYPE_TASKS -> { + title.setHint(R.string.create_tasklist_display_name_hint) + + val color = if (!meta.color.isNullOrBlank()) parseColor(meta.color) else LocalCalendar.defaultColor + colorSquare.setBackgroundColor(color) + colorSquare.setOnClickListener { + AmbilWarnaDialog(context, (colorSquare.background as ColorDrawable).color, true, object : AmbilWarnaDialog.OnAmbilWarnaListener { + override fun onCancel(dialog: AmbilWarnaDialog) {} + + override fun onOk(dialog: AmbilWarnaDialog, color: Int) { + colorSquare.setBackgroundColor(color) + } + }).show() + } + } + Constants.ETEBASE_TYPE_ADDRESS_BOOK -> { + title.setHint(R.string.create_addressbook_display_name_hint) + + val colorGroup = v.findViewById(R.id.color_group) + colorGroup.visibility = View.GONE + } + } + } + + override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) { + super.onCreateOptionsMenu(menu, inflater) + inflater.inflate(R.menu.fragment_edit_collection, menu) + } + + override fun onOptionsItemSelected(item: MenuItem): Boolean { + when (item.itemId) { + R.id.on_delete -> { + deleteColection() + } + R.id.on_save -> { + saveCollection() + } + } + return super.onOptionsItemSelected(item) + } + + private fun deleteColection() { + val meta = model.value!!.cachedCollection.meta + val name = meta.name + + AlertDialog.Builder(requireContext()) + .setTitle(R.string.delete_collection_confirm_title) + .setMessage(getString(R.string.delete_collection_confirm_warning, name)) + .setPositiveButton(android.R.string.yes) { dialog, _ -> + doDeleteCollection() + dialog.dismiss() + } + .setNegativeButton(android.R.string.no) { _, _ -> } + .show() + } + + private fun doDeleteCollection() { + loadingModel.setLoading(true) + doAsync { + try { + val col = model.value!!.cachedCollection.col + col.delete() + uploadCollection(col) + activity?.finish() + } catch (e: EtebaseException) { + uiThread { + AlertDialog.Builder(requireContext()) + .setIcon(R.drawable.ic_info_dark) + .setTitle(R.string.exception) + .setMessage(e.localizedMessage) + .setPositiveButton(android.R.string.yes) { _, _ -> }.show() + } + } finally { + uiThread { + loadingModel.setLoading(false) + } + } + } + } + + private fun saveCollection() { + var ok = true + + val meta = model.value!!.cachedCollection.meta + val v = requireView() + + var edit = v.findViewById(R.id.display_name) + meta.name = edit.text.toString() + if (TextUtils.isEmpty(meta.name)) { + edit.error = getString(R.string.create_collection_display_name_required) + ok = false + } + + edit = v.findViewById(R.id.description) + meta.description = StringUtils.trimToNull(edit.text.toString()) + + if (ok) { + when (meta.collectionType) { + Constants.ETEBASE_TYPE_CALENDAR, Constants.ETEBASE_TYPE_TASKS -> { + val view = v.findViewById(R.id.color) + val color = (view.background as ColorDrawable).color + meta.color = String.format("#%06X", 0xFFFFFF and color) + } + Constants.ETEBASE_TYPE_ADDRESS_BOOK -> { + } + } + + loadingModel.setLoading(true) + doAsync { + try { + val col = model.value!!.cachedCollection.col + col.meta = meta + uploadCollection(col) + parentFragmentManager.popBackStack() + } catch (e: EtebaseException) { + uiThread { + AlertDialog.Builder(requireContext()) + .setIcon(R.drawable.ic_info_dark) + .setTitle(R.string.exception) + .setMessage(e.localizedMessage) + .setPositiveButton(android.R.string.yes) { _, _ -> }.show() + } + } finally { + uiThread { + loadingModel.setLoading(false) + } + } + } + } + } + + private fun uploadCollection(col: Collection) { + val accountHolder = model.value!! + val etebaseLocalCache = accountHolder.etebaseLocalCache + val colMgr = accountHolder.colMgr + colMgr.upload(col) + synchronized(etebaseLocalCache) { + etebaseLocalCache.collectionSet(colMgr, col) + } + model.loadCollection(requireContext(), accountHolder.account, col.uid) + } +} \ No newline at end of file diff --git a/app/src/main/java/com/etesync/syncadapter/ui/etebase/ViewCollectionFragment.kt b/app/src/main/java/com/etesync/syncadapter/ui/etebase/ViewCollectionFragment.kt index 6e89f503..6a1c52fd 100644 --- a/app/src/main/java/com/etesync/syncadapter/ui/etebase/ViewCollectionFragment.kt +++ b/app/src/main/java/com/etesync/syncadapter/ui/etebase/ViewCollectionFragment.kt @@ -10,6 +10,7 @@ import android.widget.Toast import androidx.appcompat.app.AlertDialog import androidx.fragment.app.Fragment import androidx.fragment.app.activityViewModels +import androidx.fragment.app.commit import com.etesync.syncadapter.Constants import com.etesync.syncadapter.R import com.etesync.syncadapter.resource.LocalCalendar @@ -26,15 +27,14 @@ class ViewCollectionFragment : Fragment() { private val itemsModel: ItemsViewModel by activityViewModels() override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? { - val ret = super.onCreateView(inflater, container, savedInstanceState) - - inflater.inflate(R.layout.view_collection_fragment, container) + val ret = inflater.inflate(R.layout.view_collection_fragment, container, false) setHasOptionsMenu(true) if (savedInstanceState == null) { model.observe(this) { + (activity as? BaseActivity?)?.supportActionBar?.title = it.cachedCollection.meta.name if (container != null) { - initUi(inflater, container, it) + initUi(inflater, ret, it) } } } @@ -42,15 +42,7 @@ class ViewCollectionFragment : Fragment() { return ret } - override fun onAttach(context: Context) { - super.onAttach(context) - - model.observe(this) { - (activity as? BaseActivity?)?.supportActionBar?.title = it.cachedCollection.meta.name - } - } - - private fun initUi(inflater: LayoutInflater, container: ViewGroup, collectionHolder: AccountCollectionHolder) { + private fun initUi(inflater: LayoutInflater, container: View, collectionHolder: AccountCollectionHolder) { val title = container.findViewById(R.id.display_name) if (!HintManager.getHintSeen(requireContext(), HINT_IMPORT)) { val tourGuide = ShowcaseBuilder.getBuilder(requireActivity()) @@ -119,7 +111,10 @@ class ViewCollectionFragment : Fragment() { override fun onOptionsItemSelected(item: MenuItem): Boolean { when (item.itemId) { R.id.on_edit -> { - Toast.makeText(context, "Edit", Toast.LENGTH_LONG).show() + parentFragmentManager.commit { + replace(R.id.fragment_container, EditCollectionFragment()) + addToBackStack(EditCollectionFragment::class.java.name) + } } R.id.on_manage_members -> { Toast.makeText(context, "Manage", Toast.LENGTH_LONG).show() diff --git a/app/src/main/res/menu/fragment_edit_collection.xml b/app/src/main/res/menu/fragment_edit_collection.xml new file mode 100644 index 00000000..d9b5ec5d --- /dev/null +++ b/app/src/main/res/menu/fragment_edit_collection.xml @@ -0,0 +1,25 @@ + + + + + + + + + + \ No newline at end of file