Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit e99acb29 authored by Ricki Hirner's avatar Ricki Hirner
Browse files

Delete collection: use ViewModel

parent 88e0c16f
Loading
Loading
Loading
Loading
+4 −0
Original line number Diff line number Diff line
@@ -14,7 +14,9 @@ import android.os.Parcelable
import at.bitfire.dav4jvm.Response
import at.bitfire.dav4jvm.UrlUtils
import at.bitfire.dav4jvm.property.*
import at.bitfire.davdroid.DavUtils
import at.bitfire.davdroid.model.ServiceDB.Collections
import at.bitfire.ical4android.MiscUtils
import okhttp3.HttpUrl

/**
@@ -152,6 +154,8 @@ data class CollectionInfo(
        return values
    }

    fun title() = displayName ?: DavUtils.lastSegmentOfUrl(url)


    private fun getAsBooleanOrNull(values: ContentValues, field: String): Boolean? {
        val i = values.getAsInteger(field)
+1 −1
Original line number Diff line number Diff line
@@ -216,7 +216,7 @@ class AccountActivity: AppCompatActivity(), Toolbar.OnMenuItemClickListener, Pop
                    SetReadOnlyTask(WeakReference(this), info.id!!, nowChecked).execute()
                }
                R.id.delete_collection ->
                    DeleteCollectionFragment.ConfirmDeleteCollectionFragment.newInstance(account, info).show(supportFragmentManager, null)
                    DeleteCollectionFragment.newInstance(account, info).show(supportFragmentManager, null)
                R.id.properties ->
                    CollectionInfoFragment.newInstance(info).show(supportFragmentManager, null)
            }
+78 −95
Original line number Diff line number Diff line
@@ -9,79 +9,93 @@
package at.bitfire.davdroid.ui

import android.accounts.Account
import android.app.Dialog
import android.app.ProgressDialog
import android.content.Context
import android.app.Application
import android.os.Bundle
import androidx.appcompat.app.AlertDialog
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.fragment.app.DialogFragment
import androidx.loader.app.LoaderManager
import androidx.loader.content.AsyncTaskLoader
import androidx.loader.content.Loader
import androidx.lifecycle.*
import at.bitfire.dav4jvm.DavResource
import at.bitfire.davdroid.HttpClient
import at.bitfire.davdroid.R
import at.bitfire.davdroid.databinding.DeleteCollectionBinding
import at.bitfire.davdroid.model.CollectionInfo
import at.bitfire.davdroid.model.ServiceDB
import at.bitfire.davdroid.settings.AccountSettings
import kotlin.concurrent.thread

class DeleteCollectionFragment: DialogFragment(), LoaderManager.LoaderCallbacks<Exception> {
class DeleteCollectionFragment: DialogFragment() {

    companion object {
        const val ARG_ACCOUNT = "account"
        const val ARG_COLLECTION_INFO = "collectionInfo"

        fun newInstance(account: Account, collectionInfo: CollectionInfo): DialogFragment {
            val frag = DeleteCollectionFragment()
            val args = Bundle(2)
            args.putParcelable(ARG_ACCOUNT, account)
            args.putParcelable(ARG_COLLECTION_INFO, collectionInfo)
            frag.arguments = args
            return frag
        }
    }

    private lateinit var account: Account
    private lateinit var collectionInfo: CollectionInfo
    private lateinit var model: DeleteCollectionModel

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        model = ViewModelProviders.of(this).get(DeleteCollectionModel::class.java)

        account = arguments!!.getParcelable(ARG_ACCOUNT)!!
        collectionInfo = arguments!!.getParcelable(ARG_COLLECTION_INFO)!!

        LoaderManager.getInstance(this).initLoader(0, null, this)
        model.account = arguments?.getParcelable(ARG_ACCOUNT) as? Account
        model.collectionInfo = arguments?.getParcelable(ARG_COLLECTION_INFO) as? CollectionInfo
    }

    @Suppress("DEPRECATION")
    override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
        val progress = ProgressDialog(context)
        progress.setTitle(R.string.delete_collection_deleting_collection)
        progress.setMessage(getString(R.string.please_wait))
        progress.isIndeterminate = true
        progress.setCanceledOnTouchOutside(false)
        isCancelable = false
        return progress
    }
    override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
        val binding = DeleteCollectionBinding.inflate(layoutInflater, null, false)
        binding.lifecycleOwner = this
        binding.model = model

        binding.ok.setOnClickListener {
            isCancelable = false
            binding.progress.visibility = View.VISIBLE
            binding.controls.visibility = View.GONE

    override fun onCreateLoader(id: Int, args: Bundle?) =
            DeleteCollectionLoader(activity!!, account, collectionInfo)
            model.deleteCollection().observe(this, Observer { exception ->
                if (exception == null)
                    // reload collection list
                    (activity as? AccountActivity)?.reload()
                else
                    requireFragmentManager().beginTransaction()
                            .add(ExceptionInfoFragment.newInstance(exception, model.account), null)
                            .commit()
                dismiss()
            })
        }

    override fun onLoadFinished(loader: Loader<Exception>, exception: Exception?) {
        binding.cancel.setOnClickListener {
            dismiss()
        }

        if (exception != null)
            requireFragmentManager().beginTransaction()
                    .add(ExceptionInfoFragment.newInstance(exception, account), null)
                    .commit()
        else
            (activity as? AccountActivity)?.reload()
        return binding.root
    }

    override fun onLoaderReset(loader: Loader<Exception>) {}

    class DeleteCollectionModel(
            application: Application
    ): AndroidViewModel(application) {

    class DeleteCollectionLoader(
            context: Context,
            val account: Account,
            val collectionInfo: CollectionInfo
    ): AsyncTaskLoader<Exception>(context) {
        var account: Account? = null
        var collectionInfo: CollectionInfo? = null

        override fun onStartLoading() = forceLoad()
        val confirmation = MutableLiveData<Boolean>()
        val result = MutableLiveData<Exception>()

        override fun loadInBackground(): Exception? {
        fun deleteCollection(): LiveData<Exception> {
            thread {
                val account = requireNotNull(account)
                val collectionInfo = requireNotNull(collectionInfo)

                val context = getApplication<Application>()
                HttpClient.Builder(context, AccountSettings(context, account))
                        .setForeground(true)
                        .build().use { httpClient ->
@@ -96,50 +110,19 @@ class DeleteCollectionFragment: DialogFragment(), LoaderManager.LoaderCallbacks<
                                    val db = dbHelper.writableDatabase
                                    db.delete(ServiceDB.Collections._TABLE, "${ServiceDB.Collections.ID}=?", arrayOf(collectionInfo.id.toString()))
                                }
                } catch(e: Exception) {
                    return e
                }
            }
            return null
        }
    }

                                // return success
                                result.postValue(null)

    class ConfirmDeleteCollectionFragment: DialogFragment() {

        companion object {

            fun newInstance(account: Account, collectionInfo: CollectionInfo): DialogFragment {
                val frag = ConfirmDeleteCollectionFragment()
                val args = Bundle(2)
                args.putParcelable(ARG_ACCOUNT, account)
                args.putParcelable(ARG_COLLECTION_INFO, collectionInfo)
                frag.arguments = args
                return frag
            }

                            } catch(e: Exception) {
                                // return error
                                result.postValue(e)
                            }

        override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
            val collectionInfo = arguments!!.getParcelable(ARG_COLLECTION_INFO) as CollectionInfo
            val name = if (collectionInfo.displayName.isNullOrBlank())
                collectionInfo.url.toString()
            else
                collectionInfo.displayName

            return AlertDialog.Builder(activity!!)
                    .setTitle(R.string.delete_collection_confirm_title)
                    .setMessage(getString(R.string.delete_collection_confirm_warning, name))
                    .setPositiveButton(android.R.string.yes) { _, _ ->
                        val frag = DeleteCollectionFragment()
                        frag.arguments = arguments
                        frag.show(fragmentManager, null)
                        }
                    .setNegativeButton(android.R.string.no) { _, _ ->
                        dismiss()
            }
                    .create()
            return result
        }

    }

}
+80 −0
Original line number Diff line number Diff line
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools">
    <data>
        <variable
            name="model"
            type="at.bitfire.davdroid.ui.DeleteCollectionFragment.DeleteCollectionModel" />
    </data>

    <ScrollView
        android:layout_width="match_parent"
        android:layout_height="wrap_content">
        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:orientation="vertical"
            android:padding="@dimen/activity_margin">

            <TextView
                style="@style/TextView.Heading"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:text="@string/delete_collection_confirm_title"/>

            <TextView
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_marginTop="16dp"
                android:layout_marginBottom="16dp"
                android:text="@{@string/delete_collection_confirm_warning(model.collectionInfo.title())}" />

            <ProgressBar
                android:id="@+id/progress"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:indeterminate="true"
                android:layout_marginBottom="8dp"
                android:visibility="gone"
                tools:visibility="visible"
                style="@style/Widget.AppCompat.ProgressBar.Horizontal"/>

            <LinearLayout
                android:id="@+id/controls"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:orientation="vertical">

                <CheckBox
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:checked="@={model.confirmation}"
                    android:layout_marginBottom="8dp"
                    android:text="@string/delete_collection_data_shall_be_deleted"/>

                <LinearLayout
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content"
                    android:gravity="right"
                    android:orientation="horizontal">

                    <Button
                        android:id="@+id/ok"
                        android:layout_width="wrap_content"
                        android:layout_height="wrap_content"
                        style="@style/Widget.AppCompat.Button.ButtonBar.AlertDialog"
                        android:enabled="@{model.confirmation ?? false}"
                        android:text="@android:string/cancel"/>

                    <Button
                        android:id="@+id/cancel"
                        android:layout_width="wrap_content"
                        android:layout_height="wrap_content"
                        style="@style/Widget.AppCompat.Button.ButtonBar.AlertDialog"
                        android:text="@android:string/ok"/>
                </LinearLayout>
            </LinearLayout>

        </LinearLayout>
    </ScrollView>
</layout>
 No newline at end of file
+12 −10
Original line number Diff line number Diff line
@@ -248,23 +248,25 @@
    <!-- collection management -->
    <string name="create_addressbook">Create address book</string>
    <string name="create_addressbook_display_name_hint">My Address Book</string>
    <string name="create_calendar">Create CalDAV collection</string>
    <string name="create_calendar_display_name_hint">My Calendar</string>
    <string name="create_calendar_time_zone">Time zone:</string>
    <string name="create_calendar_type">Collection type:</string>
    <string name="create_calendar_type_only_events">Calendar (only events)</string>
    <string name="create_calendar_type_only_tasks">Task list (only tasks)</string>
    <string name="create_calendar">Create calendar</string>
    <string name="create_calendar_time_zone">Time zone</string>
    <string name="create_calendar_type">Calendar type</string>
    <string name="create_calendar_type_vevent">Events</string>
    <string name="create_calendar_type_vtodo">Tasks</string>
    <string name="create_calendar_type_vjournal">Notes / journal entries</string>
    <string name="create_calendar_type_events_and_tasks">Combined (events and tasks)</string>
    <string name="create_collection_color">Set a collection color</string>
    <string name="create_collection_color">Select a color</string>
    <string name="create_collection_creating">Creating collection</string>
    <string name="create_collection_display_name">Display name (title) of this collection:</string>
    <string name="create_collection_display_name">Title</string>
    <string name="create_collection_display_name_required">Title is required</string>
    <string name="create_collection_description">Description (optional):</string>
    <string name="create_collection_home_set">Home set:</string>
    <string name="create_collection_description">Description</string>
    <string name="create_collection_optional">optional</string>
    <string name="create_collection_home_set">Home set</string>
    <string name="create_collection_create">Create</string>
    <string name="delete_collection">Delete collection</string>
    <string name="delete_collection_confirm_title">Are you sure?</string>
    <string name="delete_collection_confirm_warning">This collection (%s) and all its data will be removed from the server.</string>
    <string name="delete_collection_data_shall_be_deleted">These data shall be deleted permanently.</string>
    <string name="delete_collection_deleting_collection">Deleting collection</string>
    <string name="collection_force_read_only">Force read-only</string>
    <string name="collection_properties">Properties</string>