Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add option to drop DESCRIPTION on sync #264

Merged
merged 4 commits into from
Mar 27, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
151 changes: 151 additions & 0 deletions app/schemas/at.bitfire.icsdroid.db.AppDatabase/4.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,151 @@
{
"formatVersion": 1,
"database": {
"version": 4,
"identityHash": "1eec5a75f63cbbca3716bc789fd91375",
"entities": [
{
"tableName": "subscriptions",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `calendarId` INTEGER, `url` TEXT NOT NULL, `eTag` TEXT, `displayName` TEXT NOT NULL, `lastModified` INTEGER, `lastSync` INTEGER, `errorMessage` TEXT, `ignoreEmbeddedAlerts` INTEGER NOT NULL, `defaultAlarmMinutes` INTEGER, `defaultAllDayAlarmMinutes` INTEGER, `ignoreDescription` INTEGER NOT NULL DEFAULT 0, `color` INTEGER)",
"fields": [
{
"fieldPath": "id",
"columnName": "id",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "calendarId",
"columnName": "calendarId",
"affinity": "INTEGER",
"notNull": false
},
{
"fieldPath": "url",
"columnName": "url",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "eTag",
"columnName": "eTag",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "displayName",
"columnName": "displayName",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "lastModified",
"columnName": "lastModified",
"affinity": "INTEGER",
"notNull": false
},
{
"fieldPath": "lastSync",
"columnName": "lastSync",
"affinity": "INTEGER",
"notNull": false
},
{
"fieldPath": "errorMessage",
"columnName": "errorMessage",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "ignoreEmbeddedAlerts",
"columnName": "ignoreEmbeddedAlerts",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "defaultAlarmMinutes",
"columnName": "defaultAlarmMinutes",
"affinity": "INTEGER",
"notNull": false
},
{
"fieldPath": "defaultAllDayAlarmMinutes",
"columnName": "defaultAllDayAlarmMinutes",
"affinity": "INTEGER",
"notNull": false
},
{
"fieldPath": "ignoreDescription",
"columnName": "ignoreDescription",
"affinity": "INTEGER",
"notNull": true,
"defaultValue": "0"
},
{
"fieldPath": "color",
"columnName": "color",
"affinity": "INTEGER",
"notNull": false
}
],
"primaryKey": {
"autoGenerate": true,
"columnNames": [
"id"
]
},
"indices": [],
"foreignKeys": []
},
{
"tableName": "credentials",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`subscriptionId` INTEGER NOT NULL, `username` TEXT NOT NULL, `password` TEXT NOT NULL, PRIMARY KEY(`subscriptionId`), FOREIGN KEY(`subscriptionId`) REFERENCES `subscriptions`(`id`) ON UPDATE NO ACTION ON DELETE CASCADE )",
"fields": [
{
"fieldPath": "subscriptionId",
"columnName": "subscriptionId",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "username",
"columnName": "username",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "password",
"columnName": "password",
"affinity": "TEXT",
"notNull": true
}
],
"primaryKey": {
"autoGenerate": false,
"columnNames": [
"subscriptionId"
]
},
"indices": [],
"foreignKeys": [
{
"table": "subscriptions",
"onDelete": "CASCADE",
"onUpdate": "NO ACTION",
"columns": [
"subscriptionId"
],
"referencedColumns": [
"id"
]
}
]
}
],
"views": [],
"setupQueries": [
"CREATE TABLE IF NOT EXISTS room_master_table (id INTEGER PRIMARY KEY,identity_hash TEXT)",
"INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, '1eec5a75f63cbbca3716bc789fd91375')"
]
}
}
22 changes: 17 additions & 5 deletions app/src/main/java/at/bitfire/icsdroid/ProcessEventsTask.kt
Original file line number Diff line number Diff line change
Expand Up @@ -16,17 +16,17 @@ import at.bitfire.icsdroid.calendar.LocalCalendar
import at.bitfire.icsdroid.calendar.LocalEvent
import at.bitfire.icsdroid.db.AppDatabase
import at.bitfire.icsdroid.db.entity.Subscription
import at.bitfire.icsdroid.ui.views.EditCalendarActivity
import at.bitfire.icsdroid.ui.NotificationUtils
import at.bitfire.icsdroid.ui.views.EditCalendarActivity
import java.io.InputStream
import java.io.InputStreamReader
import java.time.Duration
import net.fortuna.ical4j.model.Property
import net.fortuna.ical4j.model.PropertyList
import net.fortuna.ical4j.model.component.VAlarm
import net.fortuna.ical4j.model.property.Action
import net.fortuna.ical4j.model.property.Trigger
import okhttp3.MediaType
import java.io.InputStream
import java.io.InputStreamReader
import java.time.Duration

/**
* Fetches the .ics for a given Webcal subscription and stores the events
Expand Down Expand Up @@ -103,6 +103,18 @@ class ProcessEventsTask(
}
}

/**
* Updates the advanced preferences of the given event according to the [subscription]'s:
* - [Subscription.ignoreDescription]
*/
private fun updateAdvancedPreferences(event: Event): Event = event.apply {
if (subscription.ignoreDescription) {
// Remove the description
Log.d(Constants.TAG, "Removing the description from $uid")
description = null
}
}

private suspend fun processEvents() {
val uri = subscription.url
Log.i(Constants.TAG, "Synchronizing $uri, forceResync=$forceResync")
Expand Down Expand Up @@ -209,7 +221,7 @@ class ProcessEventsTask(
val uids = HashSet<String>(events.size)

for (ev in events) {
val event = updateAlarms(ev)
val event = updateAlarms(ev).let(::updateAdvancedPreferences)
val uid = event.uid!!
Log.d(Constants.TAG, "Found VEVENT $uid: $event")
uids += uid
Expand Down
6 changes: 5 additions & 1 deletion app/src/main/java/at/bitfire/icsdroid/db/AppDatabase.kt
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ import at.bitfire.icsdroid.db.entity.Subscription
@TypeConverters(Converters::class)
@Database(
entities = [Subscription::class, Credential::class],
version = 3,
version = 4,
autoMigrations = [
AutoMigration (
from = 1,
Expand All @@ -34,6 +34,10 @@ import at.bitfire.icsdroid.db.entity.Subscription
AutoMigration (
from = 2,
to = 3
),
AutoMigration (
from = 3,
to = 4
)
]
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ package at.bitfire.icsdroid.db.entity
import android.net.Uri
import android.provider.CalendarContract.Calendars
import androidx.core.content.contentValuesOf
import androidx.room.ColumnInfo
import androidx.room.Entity
import androidx.room.PrimaryKey
import at.bitfire.icsdroid.calendar.LocalCalendar
Expand Down Expand Up @@ -42,6 +43,10 @@ data class Subscription(
/** setting: Shall a default alarm be added to every all-day event in the calendar? If yes, this field contains the minutes before the event. If no, it is `null`. */
val defaultAllDayAlarmMinutes: Long? = null,

/** If true, the `DESCRIPTION` field of events will be dropped when synchronization runs. */
@ColumnInfo(defaultValue = "0")
val ignoreDescription: Boolean = false,

/** The color that represents the subscription. */
val color: Int? = null
) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ class CreateSubscriptionModel(application: Application) : AndroidViewModel(appli
ignoreEmbeddedAlerts = subscriptionSettingsModel.ignoreAlerts.value ?: false,
defaultAlarmMinutes = subscriptionSettingsModel.defaultAlarmMinutes.value,
defaultAllDayAlarmMinutes = subscriptionSettingsModel.defaultAllDayAlarmMinutes.value,
ignoreDescription = subscriptionSettingsModel.ignoreDescription.value ?: false,
)

/** A list of all the ids of the inserted rows */
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,8 @@ class EditSubscriptionModel(
color = subscriptionSettingsModel.color.value,
defaultAlarmMinutes = subscriptionSettingsModel.defaultAlarmMinutes.value,
defaultAllDayAlarmMinutes = subscriptionSettingsModel.defaultAllDayAlarmMinutes.value,
ignoreEmbeddedAlerts = subscriptionSettingsModel.ignoreAlerts.value ?: false
ignoreEmbeddedAlerts = subscriptionSettingsModel.ignoreAlerts.value ?: false,
ignoreDescription = subscriptionSettingsModel.ignoreDescription.value ?: false
)
subscriptionsDao.update(newSubscription)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,9 @@ class SubscriptionSettingsModel : ViewModel() {
val defaultAlarmMinutes = MutableLiveData<Long?>(null)
val defaultAllDayAlarmMinutes = MutableLiveData<Long?>(null)

// advanced
val ignoreDescription = MutableLiveData(false)

val supportsAuthentication = MediatorLiveData(false).apply {
addSource(url) {
val uri = try {
Expand All @@ -32,9 +35,10 @@ class SubscriptionSettingsModel : ViewModel() {

fun equalsSubscription(subscription: Subscription) =
url.value == subscription.url.toString()
&& title.value == subscription.displayName
&& color.value == subscription.color
&& ignoreAlerts.value == subscription.ignoreEmbeddedAlerts
&& defaultAlarmMinutes.value == subscription.defaultAlarmMinutes
&& defaultAllDayAlarmMinutes.value == subscription.defaultAllDayAlarmMinutes
&& title.value == subscription.displayName
&& color.value == subscription.color
&& ignoreAlerts.value == subscription.ignoreEmbeddedAlerts
&& defaultAlarmMinutes.value == subscription.defaultAlarmMinutes
&& defaultAllDayAlarmMinutes.value == subscription.defaultAllDayAlarmMinutes
&& ignoreDescription.value == subscription.ignoreDescription
}
Original file line number Diff line number Diff line change
Expand Up @@ -54,10 +54,10 @@ import at.bitfire.icsdroid.ui.ResourceInfo
import at.bitfire.icsdroid.ui.partials.ExtendedTopAppBar
import at.bitfire.icsdroid.ui.theme.lightblue
import at.bitfire.icsdroid.ui.theme.setContentThemed
import kotlinx.coroutines.launch
import okhttp3.HttpUrl.Companion.toHttpUrl
import java.net.URI
import java.net.URISyntaxException
import kotlinx.coroutines.launch
import okhttp3.HttpUrl.Companion.toHttpUrl

@OptIn(ExperimentalFoundationApi::class)
class AddCalendarActivity : AppCompatActivity() {
Expand Down Expand Up @@ -125,6 +125,7 @@ class AddCalendarActivity : AppCompatActivity() {
val ignoreAlerts by subscriptionSettingsModel.ignoreAlerts.observeAsState(false)
val defaultAlarmMinutes by subscriptionSettingsModel.defaultAlarmMinutes.observeAsState(null)
val defaultAllDayAlarmMinutes by subscriptionSettingsModel.defaultAllDayAlarmMinutes.observeAsState(null)
val ignoreDescription by subscriptionSettingsModel.ignoreDescription.observeAsState(false)

val requiresAuth: Boolean by credentialsModel.requiresAuth.observeAsState(false)
val username: String? by credentialsModel.username.observeAsState(null)
Expand Down Expand Up @@ -229,6 +230,8 @@ class AddCalendarActivity : AppCompatActivity() {
it.toLongOrNull()
)
},
ignoreDescription = ignoreDescription,
onIgnoreDescriptionChanged = subscriptionSettingsModel.ignoreDescription::setValue,
isCreating = isCreating,
modifier = Modifier
.fillMaxSize()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,16 +8,17 @@ import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.text.KeyboardOptions
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.rounded.Visibility
import androidx.compose.material.icons.rounded.VisibilityOff
import androidx.compose.material3.Icon
import androidx.compose.material3.IconButton
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.OutlinedTextField
import androidx.compose.material3.Switch
import androidx.compose.material3.Text
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.rounded.Visibility
import androidx.compose.material.icons.rounded.VisibilityOff
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
Expand All @@ -30,6 +31,7 @@ import androidx.compose.ui.text.input.KeyboardType
import androidx.compose.ui.text.input.PasswordVisualTransformation
import androidx.compose.ui.text.input.VisualTransformation
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import at.bitfire.icsdroid.R

@Composable
Expand All @@ -50,6 +52,12 @@ fun LoginCredentialsComposable(
Column(
Modifier.fillMaxWidth()
) {
Text(
text = stringResource(R.string.add_calendar_authentication_title),
style = MaterialTheme.typography.headlineSmall,
modifier = Modifier.padding(top = 8.dp)
)

Row(
verticalAlignment = Alignment.CenterVertically,
horizontalArrangement = Arrangement.SpaceBetween,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,7 @@ class EditCalendarActivity: AppCompatActivity() {
addSource(subscriptionSettingsModel.ignoreAlerts) { value = subscriptionDirty() }
addSource(subscriptionSettingsModel.defaultAlarmMinutes) { value = subscriptionDirty() }
addSource(subscriptionSettingsModel.defaultAllDayAlarmMinutes) { value = subscriptionDirty() }
addSource(subscriptionSettingsModel.ignoreDescription) { value = subscriptionDirty() }
addSource(credentialsModel.requiresAuth) { value = credentialDirty() }
addSource(credentialsModel.username) { value = credentialDirty() }
addSource(credentialsModel.password) { value = credentialDirty() }
Expand Down Expand Up @@ -171,6 +172,9 @@ class EditCalendarActivity: AppCompatActivity() {
subscription.defaultAllDayAlarmMinutes.let {
subscriptionSettingsModel.defaultAllDayAlarmMinutes.postValue(it)
}
subscription.ignoreDescription.let {
subscriptionSettingsModel.ignoreDescription.postValue(it)
}

val credential = subscriptionWithCredential.credential
val requiresAuth = credential != null
Expand Down Expand Up @@ -217,6 +221,7 @@ class EditCalendarActivity: AppCompatActivity() {
val ignoreAlerts by subscriptionSettingsModel.ignoreAlerts.observeAsState(false)
val defaultAlarmMinutes by subscriptionSettingsModel.defaultAlarmMinutes.observeAsState()
val defaultAllDayAlarmMinutes by subscriptionSettingsModel.defaultAllDayAlarmMinutes.observeAsState()
val ignoreDescription by subscriptionSettingsModel.ignoreDescription.observeAsState(false)
val inputValid by inputValid.observeAsState(false)
val modelsDirty by modelsDirty.observeAsState(false)
Scaffold(
Expand Down Expand Up @@ -248,6 +253,8 @@ class EditCalendarActivity: AppCompatActivity() {
it.toLongOrNull()
)
},
ignoreDescription = ignoreDescription,
onIgnoreDescriptionChanged = subscriptionSettingsModel.ignoreDescription::postValue,
isCreating = false,
modifier = Modifier.fillMaxWidth()
)
Expand Down
Loading
Loading