Loading app/src/main/java/at/bitfire/davdroid/model/CollectionInfo.kt +4 −0 Original line number Diff line number Diff line Loading @@ -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 /** Loading Loading @@ -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) Loading app/src/main/java/at/bitfire/davdroid/ui/AccountActivity.kt +1 −1 Original line number Diff line number Diff line Loading @@ -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) } Loading app/src/main/java/at/bitfire/davdroid/ui/DeleteCollectionFragment.kt +78 −95 Original line number Diff line number Diff line Loading @@ -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 -> Loading @@ -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 } } } app/src/main/res/layout/delete_collection.xml 0 → 100644 +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 app/src/main/res/values/strings.xml +12 −10 Original line number Diff line number Diff line Loading @@ -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> Loading Loading
app/src/main/java/at/bitfire/davdroid/model/CollectionInfo.kt +4 −0 Original line number Diff line number Diff line Loading @@ -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 /** Loading Loading @@ -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) Loading
app/src/main/java/at/bitfire/davdroid/ui/AccountActivity.kt +1 −1 Original line number Diff line number Diff line Loading @@ -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) } Loading
app/src/main/java/at/bitfire/davdroid/ui/DeleteCollectionFragment.kt +78 −95 Original line number Diff line number Diff line Loading @@ -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 -> Loading @@ -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 } } }
app/src/main/res/layout/delete_collection.xml 0 → 100644 +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
app/src/main/res/values/strings.xml +12 −10 Original line number Diff line number Diff line Loading @@ -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> Loading