Commit 4be57313 authored by Ricki Hirner's avatar Ricki Hirner 🐑

New collection setting: "force read-only"

* collections in AccountActivity: replace long click by action overflow
parent 4e4cf764
Pipeline #13885411 passed with stages
in 6 minutes and 37 seconds
......@@ -23,6 +23,7 @@ data class CollectionInfo @JvmOverloads constructor(
var type: Type? = null,
var readOnly: Boolean = false,
var forceReadOnly: Boolean = false,
var displayName: String? = null,
var description: String? = null,
var color: Int? = null,
......@@ -112,6 +113,7 @@ data class CollectionInfo @JvmOverloads constructor(
}
readOnly = values.getAsInteger(Collections.READ_ONLY) != 0
forceReadOnly = values.getAsInteger(Collections.FORCE_READ_ONLY) != 0
displayName = values.getAsString(Collections.DISPLAY_NAME)
description = values.getAsString(Collections.DESCRIPTION)
......@@ -133,6 +135,7 @@ data class CollectionInfo @JvmOverloads constructor(
values.put(Collections.URL, url)
values.put(Collections.READ_ONLY, if (readOnly) 1 else 0)
values.put(Collections.FORCE_READ_ONLY, if (forceReadOnly) 1 else 0)
values.put(Collections.DISPLAY_NAME, displayName)
values.put(Collections.DESCRIPTION, description)
values.put(Collections.COLOR, color)
......
......@@ -54,6 +54,7 @@ class ServiceDB {
@JvmField val SERVICE_ID = "serviceID"
@JvmField val URL = "url"
@JvmField val READ_ONLY = "readOnly"
@JvmField val FORCE_READ_ONLY = "forceReadOnly"
@JvmField val DISPLAY_NAME = "displayName"
@JvmField val DESCRIPTION = "description"
@JvmField val COLOR = "color"
......@@ -82,7 +83,7 @@ class ServiceDB {
companion object {
val DATABASE_NAME = "services.db"
val DATABASE_VERSION = 3
val DATABASE_VERSION = 4
}
override fun onConfigure(db: SQLiteDatabase) {
......@@ -112,6 +113,7 @@ class ServiceDB {
"${Collections.TYPE} TEXT NOT NULL," +
"${Collections.URL} TEXT NOT NULL," +
"${Collections.READ_ONLY} INTEGER DEFAULT 0 NOT NULL," +
"${Collections.FORCE_READ_ONLY} INTEGER DEFAULT 0 NOT NULL," +
"${Collections.DISPLAY_NAME} TEXT NULL," +
"${Collections.DESCRIPTION} TEXT NULL," +
"${Collections.COLOR} INTEGER NULL," +
......@@ -136,6 +138,11 @@ class ServiceDB {
}
}
@Suppress("unused")
private fun upgrade_3_4(db: SQLiteDatabase) {
db.execSQL("ALTER TABLE ${Collections._TABLE} ADD COLUMN ${Collections.FORCE_READ_ONLY} INTEGER DEFAULT 0 NOT NULL")
}
@Suppress("unused")
private fun upgrade_2_3(db: SQLiteDatabase) {
val edit = PreferenceManager.getDefaultSharedPreferences(context).edit()
......
......@@ -127,7 +127,7 @@ class LocalAddressBook(
}
Constants.log.info("Address book read-only? = ${info.readOnly}")
setReadOnly(info.readOnly)
setReadOnly(info.readOnly || info.forceReadOnly)
// make sure it will still be synchronized when contacts are updated
ContentResolver.setSyncAutomatically(account, ContactsContract.AUTHORITY, true)
......
......@@ -69,7 +69,7 @@ class LocalCalendar private constructor(
if (withColor)
values.put(Calendars.CALENDAR_COLOR, info.color ?: defaultColor)
if (info.readOnly)
if (info.readOnly || info.forceReadOnly)
values.put(Calendars.CALENDAR_ACCESS_LEVEL, Calendars.CAL_ACCESS_READ)
else {
values.put(Calendars.CALENDAR_ACCESS_LEVEL, Calendars.CAL_ACCESS_OWNER)
......
......@@ -192,7 +192,7 @@ class AccountActivity: AppCompatActivity(), Toolbar.OnMenuItemClickListener, Pop
val info = adapter.getItem(position)
val nowChecked = !info.selected
OpenHelper(this@AccountActivity).use { dbHelper ->
OpenHelper(this).use { dbHelper ->
val db = dbHelper.writableDatabase
db.beginTransactionNonExclusive()
......@@ -211,15 +211,34 @@ class AccountActivity: AppCompatActivity(), Toolbar.OnMenuItemClickListener, Pop
Snackbar.make(parent, R.string.account_read_only_address_book_selected, Snackbar.LENGTH_LONG).show()
}
private val onItemLongClickListener = AdapterView.OnItemLongClickListener { parent, view, position, _ ->
val list = parent as ListView
val adapter = list.adapter as ArrayAdapter<CollectionInfo>
val info = adapter.getItem(position)
val popup = PopupMenu(this@AccountActivity, view)
private val onActionOverflowListener = { anchor: View, info: CollectionInfo ->
val popup = PopupMenu(this, anchor, Gravity.RIGHT)
popup.inflate(R.menu.account_collection_operations)
with(popup.menu.findItem(R.id.force_read_only)) {
if (info.readOnly)
isVisible = false
else
isChecked = info.forceReadOnly
}
popup.setOnMenuItemClickListener({ item ->
when (item.itemId) {
R.id.force_read_only -> {
val nowChecked = !item.isChecked
OpenHelper(this).use { dbHelper ->
val db = dbHelper.writableDatabase
db.beginTransactionNonExclusive()
val values = ContentValues(1)
values.put(Collections.FORCE_READ_ONLY, nowChecked)
db.update(Collections._TABLE, values, "${Collections.ID}=?", arrayOf(info.id.toString()))
db.setTransactionSuccessful()
db.endTransaction()
reload()
}
}
R.id.delete_collection ->
DeleteCollectionFragment.ConfirmDeleteCollectionFragment.newInstance(account, info).show(getSupportFragmentManager(), null);
}
......@@ -309,7 +328,6 @@ class AccountActivity: AppCompatActivity(), Toolbar.OnMenuItemClickListener, Pop
adapter.addAll(carddav.collections)
address_books.adapter = adapter
address_books.onItemClickListener = onItemClickListener
address_books.onItemLongClickListener = onItemLongClickListener
View.VISIBLE
} ?: View.GONE
......@@ -326,7 +344,6 @@ class AccountActivity: AppCompatActivity(), Toolbar.OnMenuItemClickListener, Pop
adapter.addAll(caldav.collections.filter { it.type == CollectionInfo.Type.CALENDAR })
calendars.adapter = adapter
calendars.onItemClickListener = onItemClickListener
calendars.onItemLongClickListener = onItemLongClickListener
View.VISIBLE
} ?: View.GONE
......@@ -512,7 +529,13 @@ class AccountActivity: AppCompatActivity(), Toolbar.OnMenuItemClickListener, Pop
}
v.findViewById<ImageView>(R.id.read_only).visibility =
if (info.readOnly) View.VISIBLE else View.GONE
if (info.readOnly || info.forceReadOnly) View.VISIBLE else View.GONE
v.findViewById<ImageView>(R.id.action_overflow).setOnClickListener({ view ->
(context as? AccountActivity)?.let {
it.onActionOverflowListener(view, info)
}
})
return v
}
......@@ -536,7 +559,7 @@ class AccountActivity: AppCompatActivity(), Toolbar.OnMenuItemClickListener, Pop
vColor.visibility = info.color?.let {
vColor.setBackgroundColor(it)
View.VISIBLE
} ?: View.GONE
} ?: View.INVISIBLE
var tv: TextView = v.findViewById(R.id.title)
tv.text = if (!info.displayName.isNullOrBlank()) info.displayName else info.url
......@@ -550,7 +573,7 @@ class AccountActivity: AppCompatActivity(), Toolbar.OnMenuItemClickListener, Pop
}
v.findViewById<ImageView>(R.id.read_only).visibility =
if (info.readOnly) View.VISIBLE else View.GONE
if (info.readOnly || info.forceReadOnly) View.VISIBLE else View.GONE
v.findViewById<ImageView>(R.id.events).visibility =
if (info.supportsVEVENT) View.VISIBLE else View.GONE
......@@ -558,6 +581,16 @@ class AccountActivity: AppCompatActivity(), Toolbar.OnMenuItemClickListener, Pop
v.findViewById<ImageView>(R.id.tasks).visibility =
if (info.supportsVTODO) View.VISIBLE else View.GONE
val overflow = v.findViewById<ImageView>(R.id.action_overflow)
if (info.type == CollectionInfo.Type.WEBCAL)
overflow.visibility = View.GONE
else
overflow.setOnClickListener({ view ->
(context as? AccountActivity)?.let {
it.onActionOverflowListener(view, info)
}
})
return v
}
}
......
......@@ -13,68 +13,85 @@
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="8dp"
android:gravity="center_vertical">
<CheckBox
android:id="@+id/checked"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:focusable="false"
android:focusableInTouchMode="false"
android:clickable="false"
android:contentDescription="@string/account_synchronize_this_collection"
android:layout_marginRight="4dp"/>
android:paddingLeft="0dp"
android:paddingRight="8dp">
<View
android:id="@+id/color"
android:layout_width="28dp"
android:layout_height="28dp"
android:layout_width="8dp"
android:layout_height="match_parent"
android:layout_marginRight="4dp"
tools:background="@color/primaryColor"/>
<LinearLayout
android:layout_width="0dp"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_weight="1"
android:orientation="vertical">
android:gravity="center_vertical"
android:paddingTop="8dp"
android:paddingBottom="8dp"
android:orientation="horizontal">
<TextView
android:id="@+id/title"
android:layout_width="match_parent"
<CheckBox
android:id="@+id/checked"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textAppearance="?android:attr/textAppearanceMedium"
android:textColor="@color/primaryTextColor"
tools:text="My Calendar"/>
android:focusable="false"
android:focusableInTouchMode="false"
android:clickable="false"
android:contentDescription="@string/account_synchronize_this_collection"
android:layout_marginRight="4dp"/>
<TextView
android:id="@+id/description"
android:layout_width="match_parent"
<LinearLayout
android:layout_width="0dp"
android:layout_height="wrap_content"
android:textAppearance="?android:attr/textAppearanceSmall"
tools:text="Calendar Description"/>
android:layout_weight="1"
android:orientation="vertical">
</LinearLayout>
<TextView
android:id="@+id/title"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textAppearance="?android:attr/textAppearanceMedium"
android:textColor="@color/primaryTextColor"
tools:text="My Calendar"/>
<TextView
android:id="@+id/description"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textAppearance="?android:attr/textAppearanceSmall"
tools:text="Calendar Description"/>
</LinearLayout>
<ImageView
android:id="@+id/read_only"
android:layout_width="32dp"
android:layout_height="32dp"
android:contentDescription="@string/account_read_only"
app:srcCompat="@drawable/ic_remove_circle_dark"/>
<ImageView
android:id="@+id/read_only"
android:layout_width="24dp"
android:layout_height="24dp"
android:contentDescription="@string/account_read_only"
app:srcCompat="@drawable/ic_remove_circle_dark"/>
<ImageView
android:id="@+id/events"
android:layout_width="32dp"
android:layout_height="32dp"
android:contentDescription="@string/account_calendar"
app:srcCompat="@drawable/ic_today_dark"/>
<ImageView
android:id="@+id/events"
android:layout_width="24dp"
android:layout_height="24dp"
android:contentDescription="@string/account_calendar"
app:srcCompat="@drawable/ic_today_dark"/>
<ImageView
android:id="@+id/tasks"
android:layout_width="32dp"
android:layout_height="32dp"
android:contentDescription="@string/account_task_list"
app:srcCompat="@drawable/ic_playlist_add_check_dark"/>
<ImageView
android:id="@+id/tasks"
android:layout_width="24dp"
android:layout_height="24dp"
android:contentDescription="@string/account_task_list"
app:srcCompat="@drawable/ic_playlist_add_check_dark"/>
<ImageView
android:id="@+id/action_overflow"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:paddingRight="0dp"
style="@style/Widget.AppCompat.ActionButton.Overflow"/>
</LinearLayout>
</LinearLayout>
......@@ -48,8 +48,16 @@
<ImageView
android:id="@+id/read_only"
android:layout_width="32dp"
android:layout_height="32dp"
android:layout_width="24dp"
android:layout_height="24dp"
android:contentDescription="@string/account_read_only"
app:srcCompat="@drawable/ic_remove_circle_dark"/>
<ImageView
android:id="@+id/action_overflow"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:paddingRight="0dp"
style="@style/Widget.AppCompat.ActionButton.Overflow"/>
</LinearLayout>
\ No newline at end of file
......@@ -9,6 +9,10 @@
<menu xmlns:android="http://schemas.android.com/apk/res/android">
<item android:id="@+id/force_read_only"
android:checkable="true"
android:title="@string/collection_force_read_only"/>
<item android:id="@+id/delete_collection"
android:title="@string/delete_collection"/>
......
......@@ -252,6 +252,7 @@
<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_deleting_collection">Deleting collection</string>
<string name="collection_force_read_only">Force read-only</string>
<!-- ExceptionInfoFragment -->
<string name="exception">An error has occurred.</string>
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment