diff --git a/.github/workflows/android-tests.yml b/.github/workflows/android-tests.yml
index 58b7532b0..065a63a36 100644
--- a/.github/workflows/android-tests.yml
+++ b/.github/workflows/android-tests.yml
@@ -19,7 +19,7 @@ jobs:
with:
distribution: temurin
java-version: 17
- - uses: gradle/actions/setup-gradle@v3
+ - uses: gradle/actions/setup-gradle@v4
- name: Enable KVM group perms
run: |
diff --git a/.github/workflows/create-alpha.yml b/.github/workflows/create-alpha.yml
index fe45a0e27..9f0a6bc5f 100644
--- a/.github/workflows/create-alpha.yml
+++ b/.github/workflows/create-alpha.yml
@@ -17,7 +17,7 @@ jobs:
with:
distribution: temurin
java-version: 17
- - uses: gradle/actions/setup-gradle@v3
+ - uses: gradle/actions/setup-gradle@v4
- name: Prepare keystore
run: echo ${{ secrets.android_keystore_base64 }} | base64 -d >$GITHUB_WORKSPACE/keystore.jks
diff --git a/.github/workflows/create-baseline-profiles.yml b/.github/workflows/create-baseline-profiles.yml
index 7d653da5b..e2526053f 100644
--- a/.github/workflows/create-baseline-profiles.yml
+++ b/.github/workflows/create-baseline-profiles.yml
@@ -50,7 +50,7 @@ jobs:
# Sets gradle up
- name: Setup Gradle
- uses: gradle/actions/setup-gradle@v3
+ uses: gradle/actions/setup-gradle@v4
# Grants execute permission to gradle (safety step)
- name: Grant Permissions to gradlew
diff --git a/.github/workflows/create-beta.yml b/.github/workflows/create-beta.yml
index 37c68fb5a..e11ecea7b 100644
--- a/.github/workflows/create-beta.yml
+++ b/.github/workflows/create-beta.yml
@@ -17,7 +17,7 @@ jobs:
with:
distribution: temurin
java-version: 17
- - uses: gradle/actions/setup-gradle@v3
+ - uses: gradle/actions/setup-gradle@v4
- name: Prepare keystore
run: echo ${{ secrets.android_keystore_base64 }} | base64 -d >$GITHUB_WORKSPACE/keystore.jks
@@ -53,7 +53,7 @@ jobs:
run: cp app/build/outputs/apk/ose/release/app-ose-release.apk jtxBoard-${{ github.ref_name }}.apk
- name: Create Github release
- uses: softprops/action-gh-release@v2.0.6
+ uses: softprops/action-gh-release@v2.0.9
with:
prerelease: ${{ contains(github.ref_name, '-alpha') || contains(github.ref_name, '-beta') || contains(github.ref_name, '-rc') }}
files: |
diff --git a/.github/workflows/create-release.yml b/.github/workflows/create-release.yml
index 7a99bcee7..9e4c4f3b0 100644
--- a/.github/workflows/create-release.yml
+++ b/.github/workflows/create-release.yml
@@ -19,7 +19,7 @@ jobs:
with:
distribution: temurin
java-version: 17
- - uses: gradle/actions/setup-gradle@v3
+ - uses: gradle/actions/setup-gradle@v4
- name: Prepare keystore
run: echo ${{ secrets.android_keystore_base64 }} | base64 -d >$GITHUB_WORKSPACE/keystore.jks
@@ -66,7 +66,7 @@ jobs:
run: cp app/build/outputs/apk/ose/release/app-ose-release.apk jtxBoard-${{ github.ref_name }}.apk
- name: Create Github release
- uses: softprops/action-gh-release@v2.0.6
+ uses: softprops/action-gh-release@v2.0.9
with:
prerelease: ${{ contains(github.ref_name, '-alpha') || contains(github.ref_name, '-beta') || contains(github.ref_name, '-rc') }}
files: |
diff --git a/app/build.gradle.kts b/app/build.gradle.kts
index 19ab194b2..e72a55965 100644
--- a/app/build.gradle.kts
+++ b/app/build.gradle.kts
@@ -29,8 +29,8 @@ android {
buildConfigField("long", "buildTime", "${System.currentTimeMillis()}L")
minSdk = 23
targetSdk = 34
- versionCode = 209000010
- versionName = "2.09.00-beta01" // keep -release as a suffix also for release, build flavor adds the suffix e.g. .gplay (e.g. 1.00.00-rc0.gplay)
+ versionCode = 209030005
+ versionName = "2.09.03-beta03" // keep -release as a suffix also for release, build flavor adds the suffix e.g. .gplay (e.g. 1.00.00-rc0.gplay)
buildConfigField("String", "versionCodename", "\"Pride is a protest \uD83C\uDF08\"")
multiDexEnabled = true
vectorDrawables.useSupportLibrary = true
diff --git a/app/src/main/java/at/techbee/jtx/database/properties/Alarm.kt b/app/src/main/java/at/techbee/jtx/database/properties/Alarm.kt
index 6cd004020..fbcf3ba19 100644
--- a/app/src/main/java/at/techbee/jtx/database/properties/Alarm.kt
+++ b/app/src/main/java/at/techbee/jtx/database/properties/Alarm.kt
@@ -418,14 +418,6 @@ data class Alarm(
if (isReadOnly && SettingsStateHolder(context).settingDisableAlarmsReadonly.value) // don't schedule alarm for read only if option was deactivated!
return
- if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) {
- Log.i(
- "scheduleNotification",
- "Due to necessity of PendingIntent.FLAG_IMMUTABLE, the notification functionality can only be used from Build Versions > M (Api-Level 23)"
- )
- return
- }
-
val notification = createNotification(
icalObjectId,
alarmId,
@@ -452,10 +444,20 @@ data class Alarm(
// the alarmManager finally takes care, that the pendingIntent is queued to start the notification Intent that on click would start the contentIntent
val alarmManager = context.getSystemService(Context.ALARM_SERVICE) as AlarmManager
- if ((Build.VERSION.SDK_INT >= Build.VERSION_CODES.S && alarmManager.canScheduleExactAlarms()) || Build.VERSION.SDK_INT < Build.VERSION_CODES.S)
- alarmManager.setExactAndAllowWhileIdle(AlarmManager.RTC_WAKEUP, triggerTime!!, pendingIntent)
- else
- alarmManager.set(AlarmManager.RTC_WAKEUP, triggerTime!!, pendingIntent)
+ try {
+ if ((Build.VERSION.SDK_INT >= Build.VERSION_CODES.S && alarmManager.canScheduleExactAlarms()) || Build.VERSION.SDK_INT < Build.VERSION_CODES.S)
+ alarmManager.setExactAndAllowWhileIdle(AlarmManager.RTC_WAKEUP, triggerTime!!, pendingIntent)
+ else
+ alarmManager.set(AlarmManager.RTC_WAKEUP, triggerTime!!, pendingIntent)
+ } catch (e: IllegalStateException) {
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.UPSIDE_DOWN_CAKE) {
+ alarmManager.cancelAll()
+ } else {
+ while(alarmManager.nextAlarmClock!=null) {
+ alarmManager.cancel(alarmManager.nextAlarmClock.showIntent)
+ }
+ }
+ }
}
/**
diff --git a/app/src/main/java/at/techbee/jtx/database/relations/ICal4ListRel.kt b/app/src/main/java/at/techbee/jtx/database/relations/ICal4ListRel.kt
index cf391b715..b749b11e5 100644
--- a/app/src/main/java/at/techbee/jtx/database/relations/ICal4ListRel.kt
+++ b/app/src/main/java/at/techbee/jtx/database/relations/ICal4ListRel.kt
@@ -97,7 +97,12 @@ data class ICal4ListRel(
this[context.getString(R.string.filter_no_category)] = mutableListOf(sortedEntry)
}
}
- }
+ }.toSortedMap(
+ if(sortOrder == SortOrder.DESC)
+ compareByDescending { it.uppercase() }
+ else
+ compareBy { it.uppercase() }
+ )
GroupBy.RESOURCE -> mutableMapOf>().apply {
sortedList.forEach { sortedEntry ->
if (sortedEntry.resources.isNotEmpty()) {
@@ -114,7 +119,12 @@ data class ICal4ListRel(
this[context.getString(R.string.filter_no_resource)] = mutableListOf(sortedEntry)
}
}
- }
+ }.toSortedMap(
+ if(sortOrder == SortOrder.DESC)
+ compareByDescending { it.uppercase() }
+ else
+ compareBy { it.uppercase() }
+ )
//GroupBy.CATEGORY -> sortedList.groupBy { if(it.categories.isEmpty()) context.getString(R.string.filter_no_category) else it.categories.joinToString(separator = ", ") { category -> category.text } }.toSortedMap()
//GroupBy.RESOURCE -> sortedList.groupBy { if(it.resources.isEmpty()) context.getString(R.string.filter_no_resource) else it.resources.joinToString(separator = ", ") { resource -> resource.text?:"" } }.toSortedMap()
GroupBy.STATUS -> sortedList.groupBy {
diff --git a/app/src/main/java/at/techbee/jtx/ui/collections/CollectionsScreen.kt b/app/src/main/java/at/techbee/jtx/ui/collections/CollectionsScreen.kt
index 62a257bb0..db908073d 100644
--- a/app/src/main/java/at/techbee/jtx/ui/collections/CollectionsScreen.kt
+++ b/app/src/main/java/at/techbee/jtx/ui/collections/CollectionsScreen.kt
@@ -42,18 +42,22 @@ import androidx.compose.ui.res.stringResource
import androidx.compose.ui.tooling.preview.Preview
import androidx.navigation.NavHostController
import androidx.navigation.compose.rememberNavController
+import androidx.preference.PreferenceManager
import at.techbee.jtx.R
import at.techbee.jtx.database.ICalCollection
import at.techbee.jtx.database.Module
+import at.techbee.jtx.database.locals.StoredListSettingData
import at.techbee.jtx.database.views.CollectionsView
import at.techbee.jtx.ui.GlobalStateHolder
import at.techbee.jtx.ui.reusable.appbars.JtxNavigationDrawer
import at.techbee.jtx.ui.reusable.appbars.JtxTopAppBar
import at.techbee.jtx.ui.reusable.appbars.OverflowMenu
+import at.techbee.jtx.ui.reusable.destinations.FilteredListDestination
import at.techbee.jtx.ui.reusable.dialogs.CollectionsAddOrEditDialog
import at.techbee.jtx.ui.reusable.dialogs.SelectModuleForTxtImportDialog
import at.techbee.jtx.ui.settings.DropdownSettingOption
import at.techbee.jtx.ui.settings.SettingsStateHolder
+import at.techbee.jtx.ui.settings.SettingsStateHolder.Companion.PREFS_LAST_MODULE
import at.techbee.jtx.util.DateTimeUtils
import at.techbee.jtx.util.SyncUtil
@@ -305,8 +309,25 @@ fun CollectionsScreen(
}
},
onCollectionClicked = { collection ->
- if (globalStateHolder.icalString2Import.value?.isNotEmpty() == true && !collection.readonly)
+ if (globalStateHolder.icalString2Import.value?.isNotEmpty() == true && !collection.readonly) {
importCollection = collection
+ } else {
+ val prefs = PreferenceManager.getDefaultSharedPreferences(context)
+ val lastUsedModule = try { Module.valueOf(prefs.getString(PREFS_LAST_MODULE, null)?: Module.JOURNAL.name) } catch (e: java.lang.IllegalArgumentException) { Module.JOURNAL }
+
+ navController.navigate(
+ FilteredListDestination.FilteredList.getRoute(
+ module = when {
+ lastUsedModule == Module.JOURNAL && collection.supportsVJOURNAL -> lastUsedModule
+ lastUsedModule == Module.NOTE && collection.supportsVJOURNAL -> lastUsedModule
+ lastUsedModule == Module.TODO && collection.supportsVTODO -> lastUsedModule
+ collection.supportsVTODO -> Module.TODO
+ else -> Module.JOURNAL
+ },
+ storedListSettingData = StoredListSettingData(searchCollection = listOf(collection.displayName?:""))
+ )
+ )
+ }
},
onDeleteAccount = { account -> collectionsViewModel.removeAccount(account) }
)
diff --git a/app/src/main/java/at/techbee/jtx/ui/detail/DetailViewModel.kt b/app/src/main/java/at/techbee/jtx/ui/detail/DetailViewModel.kt
index ffdafcfc1..5371e0da2 100644
--- a/app/src/main/java/at/techbee/jtx/ui/detail/DetailViewModel.kt
+++ b/app/src/main/java/at/techbee/jtx/ui/detail/DetailViewModel.kt
@@ -106,6 +106,7 @@ class DetailViewModel(application: Application) : AndroidViewModel(application)
val mediaPlayer = MediaPlayer()
private var _isAuthenticated = false
+ private var immediateAlarmTriggeredOnce = false
companion object {
const val PREFS_DETAIL_JOURNALS = "prefsDetailJournals"
@@ -116,6 +117,7 @@ class DetailViewModel(application: Application) : AndroidViewModel(application)
fun load(icalObjectId: Long, isAuthenticated: Boolean) {
mainICalObjectId = icalObjectId
_isAuthenticated = isAuthenticated
+ immediateAlarmTriggeredOnce = false
viewModelScope.launch {
withContext(Dispatchers.Main) { changeState.value = DetailChangeState.LOADING }
@@ -210,6 +212,7 @@ class DetailViewModel(application: Application) : AndroidViewModel(application)
} ?: emptyList() else emptyList(),
searchAccount = if (sameAccount) collection.value?.accountName?.let { listOf(it) }
?: emptyList() else emptyList(),
+ flatView = true,
orderBy = OrderBy.LAST_MODIFIED,
sortOrder = SortOrder.DESC,
hideBiometricProtected = if (_isAuthenticated) emptyList() else ListSettings.getProtectedClassificationsFromSettings(
@@ -443,9 +446,16 @@ class DetailViewModel(application: Application) : AndroidViewModel(application)
databaseDao.setAlarmNotification(it.id, false)
}
- if(triggerImmediateAlarm)
- NotificationPublisher.triggerImmediateAlarm(it, _application)
+ val triggerInPastButNotDone =
+ mutableAlarms.any { alarm -> (alarm.triggerTime?:0L) <= System.currentTimeMillis() }
+ && mutableAlarms.none { alarm -> (alarm.triggerTime?:0L) > System.currentTimeMillis() }
+ && it.percent != 100
+ && it.status != Status.COMPLETED.status
+ if(!immediateAlarmTriggeredOnce && (triggerImmediateAlarm || triggerInPastButNotDone)) {
+ NotificationPublisher.triggerImmediateAlarm(it, _application)
+ immediateAlarmTriggeredOnce = true
+ }
}
}
diff --git a/app/src/main/java/at/techbee/jtx/ui/list/ListScreen.kt b/app/src/main/java/at/techbee/jtx/ui/list/ListScreen.kt
index 82b6e3198..089cbfaf8 100644
--- a/app/src/main/java/at/techbee/jtx/ui/list/ListScreen.kt
+++ b/app/src/main/java/at/techbee/jtx/ui/list/ListScreen.kt
@@ -10,12 +10,9 @@ package at.techbee.jtx.ui.list
import android.widget.Toast
-import androidx.compose.foundation.layout.Column
-import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.livedata.observeAsState
-import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalContext
import androidx.navigation.NavController
import at.techbee.jtx.database.ICalDatabase
@@ -23,7 +20,6 @@ import at.techbee.jtx.database.relations.ICal4ListRel
import at.techbee.jtx.database.views.ICal4List
import at.techbee.jtx.ui.reusable.destinations.DetailDestination
import at.techbee.jtx.ui.settings.SettingsStateHolder
-import at.techbee.jtx.util.SyncUtil
@Composable
@@ -34,7 +30,6 @@ fun ListScreen(
val context = LocalContext.current
val database = ICalDatabase.getInstance(context).iCalDatabaseDao()
val settingsStateHolder = SettingsStateHolder(context)
- val isPullRefreshEnabled = SyncUtil.availableSyncApps(context).any { SyncUtil.isSyncAppCompatible(it, context) } && settingsStateHolder.settingSyncOnPullRefresh.value
listViewModel.toastMessage.value?.let {
Toast.makeText(context, it, Toast.LENGTH_SHORT).show()
@@ -73,131 +68,122 @@ fun ListScreen(
}
- Column(modifier = Modifier.fillMaxSize()) {
- when (listViewModel.listSettings.viewMode.value) {
- ViewMode.LIST -> {
- ListScreenList(
- groupedList = groupedList,
- subtasksLive = listViewModel.allSubtasks,
- subnotesLive = listViewModel.allSubnotes,
- parentsLive = listViewModel.allParents,
- selectedEntries = listViewModel.selectedEntries,
- attachmentsLive = listViewModel.allAttachmentsMap,
- scrollOnceId = listViewModel.scrollOnceId,
- listSettings = listViewModel.listSettings,
- storedCategories = database.getStoredCategories().observeAsState(emptyList()).value,
- storedResources = database.getStoredResources().observeAsState(emptyList()).value,
- storedStatuses = database.getStoredStatuses().observeAsState(emptyList()).value,
- isSubtasksExpandedDefault = settingsStateHolder.settingAutoExpandSubtasks.value,
- isSubnotesExpandedDefault = settingsStateHolder.settingAutoExpandSubnotes.value,
- isAttachmentsExpandedDefault = settingsStateHolder.settingAutoExpandAttachments.value,
- settingShowProgressMaintasks = settingsStateHolder.settingShowProgressForMainTasks.value,
- settingShowProgressSubtasks = settingsStateHolder.settingShowProgressForSubTasks.value,
- settingProgressIncrement = settingsStateHolder.settingStepForProgress.value,
- settingLinkProgressToSubtasks = settingsStateHolder.settingLinkProgressToSubtasks.value,
- settingDisplayTimezone = settingsStateHolder.settingDisplayTimezone.value,
- settingIsAccessibilityMode = settingsStateHolder.settingAccessibilityMode.value,
- isPullRefreshEnabled = isPullRefreshEnabled,
- markdownEnabled = listViewModel.listSettings.markdownEnabled.value,
- player = listViewModel.mediaPlayer,
- isListDragAndDropEnabled = listViewModel.listSettings.orderBy.value == OrderBy.DRAG_AND_DROP || listViewModel.listSettings.orderBy2.value == OrderBy.DRAG_AND_DROP,
- isSubtaskDragAndDropEnabled = listViewModel.listSettings.subtasksOrderBy.value == OrderBy.DRAG_AND_DROP,
- isSubnoteDragAndDropEnabled = listViewModel.listSettings.subnotesOrderBy.value == OrderBy.DRAG_AND_DROP,
- onClick = { itemId, ical4list, isReadOnly -> processOnClick(itemId, ical4list, isReadOnly) },
- onLongClick = { itemId, isReadOnly -> processOnLongClick(itemId, isReadOnly) },
- onProgressChanged = { itemId, newPercent ->
- processOnProgressChanged(itemId, newPercent)
- },
- onExpandedChanged = { itemId: Long, isSubtasksExpanded: Boolean, isSubnotesExpanded: Boolean, isParentsExpanded: Boolean, isAttachmentsExpanded: Boolean ->
- listViewModel.updateExpanded(
- itemId,
- isSubtasksExpanded,
- isSubnotesExpanded,
- isParentsExpanded,
- isAttachmentsExpanded
- )
- },
- onSyncRequested = { listViewModel.syncAccounts() },
- onSaveListSettings = { listViewModel.saveListSettings() },
- onUpdateSortOrder = { listViewModel.updateSortOrder(it) }
- )
- }
- ViewMode.GRID -> {
- ListScreenGrid(
- list = list,
- subtasksLive = listViewModel.allSubtasks,
- storedCategories = database.getStoredCategories().observeAsState(emptyList()).value,
- storedStatuses = database.getStoredStatuses().observeAsState(emptyList()).value,
- selectedEntries = listViewModel.selectedEntries,
- scrollOnceId = listViewModel.scrollOnceId,
- settingLinkProgressToSubtasks = settingsStateHolder.settingLinkProgressToSubtasks.value,
- isPullRefreshEnabled = isPullRefreshEnabled,
- markdownEnabled = listViewModel.listSettings.markdownEnabled.value,
- player = listViewModel.mediaPlayer,
- onClick = { itemId, ical4list, isReadOnly -> processOnClick(itemId, ical4list, isReadOnly) },
- onLongClick = { itemId, isReadOnly -> processOnLongClick(itemId, isReadOnly) },
- onProgressChanged = { itemId, newPercent ->
- processOnProgressChanged(itemId, newPercent)
- },
- onSyncRequested = { listViewModel.syncAccounts() },
- isListDragAndDropEnabled = listViewModel.listSettings.orderBy.value == OrderBy.DRAG_AND_DROP || listViewModel.listSettings.orderBy2.value == OrderBy.DRAG_AND_DROP
+ when (listViewModel.listSettings.viewMode.value) {
+ ViewMode.LIST -> {
+ ListScreenList(
+ groupedList = groupedList,
+ subtasksLive = listViewModel.allSubtasks,
+ subnotesLive = listViewModel.allSubnotes,
+ parentsLive = listViewModel.allParents,
+ selectedEntries = listViewModel.selectedEntries,
+ attachmentsLive = listViewModel.allAttachmentsMap,
+ scrollOnceId = listViewModel.scrollOnceId,
+ listSettings = listViewModel.listSettings,
+ storedCategories = database.getStoredCategories().observeAsState(emptyList()).value,
+ storedResources = database.getStoredResources().observeAsState(emptyList()).value,
+ storedStatuses = database.getStoredStatuses().observeAsState(emptyList()).value,
+ isSubtasksExpandedDefault = settingsStateHolder.settingAutoExpandSubtasks.value,
+ isSubnotesExpandedDefault = settingsStateHolder.settingAutoExpandSubnotes.value,
+ isAttachmentsExpandedDefault = settingsStateHolder.settingAutoExpandAttachments.value,
+ isParentsExpandedDefault = settingsStateHolder.settingAutoExpandParents.value,
+ settingShowProgressMaintasks = settingsStateHolder.settingShowProgressForMainTasks.value,
+ settingShowProgressSubtasks = settingsStateHolder.settingShowProgressForSubTasks.value,
+ settingProgressIncrement = settingsStateHolder.settingStepForProgress.value,
+ settingLinkProgressToSubtasks = settingsStateHolder.settingLinkProgressToSubtasks.value,
+ settingDisplayTimezone = settingsStateHolder.settingDisplayTimezone.value,
+ settingIsAccessibilityMode = settingsStateHolder.settingAccessibilityMode.value,
+ markdownEnabled = listViewModel.listSettings.markdownEnabled.value,
+ player = listViewModel.mediaPlayer,
+ isListDragAndDropEnabled = listViewModel.listSettings.orderBy.value == OrderBy.DRAG_AND_DROP || listViewModel.listSettings.orderBy2.value == OrderBy.DRAG_AND_DROP,
+ isSubtaskDragAndDropEnabled = listViewModel.listSettings.subtasksOrderBy.value == OrderBy.DRAG_AND_DROP,
+ isSubnoteDragAndDropEnabled = listViewModel.listSettings.subnotesOrderBy.value == OrderBy.DRAG_AND_DROP,
+ onClick = { itemId, ical4list, isReadOnly -> processOnClick(itemId, ical4list, isReadOnly) },
+ onLongClick = { itemId, ical4list -> processOnLongClick(itemId, ical4list) },
+ onProgressChanged = { itemId, newPercent ->
+ processOnProgressChanged(itemId, newPercent)
+ },
+ onExpandedChanged = { itemId: Long, isSubtasksExpanded: Boolean, isSubnotesExpanded: Boolean, isParentsExpanded: Boolean, isAttachmentsExpanded: Boolean ->
+ listViewModel.updateExpanded(
+ itemId,
+ isSubtasksExpanded,
+ isSubnotesExpanded,
+ isParentsExpanded,
+ isAttachmentsExpanded
)
- }
- ViewMode.COMPACT -> {
- ListScreenCompact(
- groupedList = groupedList,
- subtasksLive = listViewModel.allSubtasks,
- storedCategories = database.getStoredCategories().observeAsState(emptyList()).value,
- storedStatuses = database.getStoredStatuses().observeAsState(emptyList()).value,
- selectedEntries = listViewModel.selectedEntries,
- scrollOnceId = listViewModel.scrollOnceId,
- listSettings = listViewModel.listSettings,
- settingLinkProgressToSubtasks = settingsStateHolder.settingLinkProgressToSubtasks.value,
- isPullRefreshEnabled = isPullRefreshEnabled,
- player = listViewModel.mediaPlayer,
- isListDragAndDropEnabled = listViewModel.listSettings.orderBy.value == OrderBy.DRAG_AND_DROP || listViewModel.listSettings.orderBy2.value == OrderBy.DRAG_AND_DROP,
- isSubtaskDragAndDropEnabled = listViewModel.listSettings.subtasksOrderBy.value == OrderBy.DRAG_AND_DROP,
- onClick = { itemId, ical4list, isReadOnly -> processOnClick(itemId, ical4list, isReadOnly) },
- onLongClick = { itemId, isReadOnly -> processOnLongClick(itemId, isReadOnly) },
- onProgressChanged = { itemId, newPercent -> processOnProgressChanged(itemId, newPercent) },
- onSyncRequested = { listViewModel.syncAccounts() },
- onSaveListSettings = { listViewModel.saveListSettings() },
- onUpdateSortOrder = { listViewModel.updateSortOrder(it) }
- )
- }
- ViewMode.KANBAN -> {
- ListScreenKanban(
- module = listViewModel.module,
- list = list,
- subtasksLive = listViewModel.allSubtasks,
- storedCategories = database.getStoredCategories().observeAsState(emptyList()).value,
- storedStatuses = database.getStoredStatuses().observeAsState(emptyList()).value,
- selectedEntries = listViewModel.selectedEntries,
- kanbanColumnsStatus = listViewModel.listSettings.kanbanColumnsStatus,
- kanbanColumnsXStatus = listViewModel.listSettings.kanbanColumnsXStatus,
- kanbanColumnsCategory = listViewModel.listSettings.kanbanColumnsCategory,
- scrollOnceId = listViewModel.scrollOnceId,
- settingLinkProgressToSubtasks = settingsStateHolder.settingLinkProgressToSubtasks.value,
- isPullRefreshEnabled = isPullRefreshEnabled,
- markdownEnabled = listViewModel.listSettings.markdownEnabled.value,
- player = listViewModel.mediaPlayer,
- onClick = { itemId, ical4list, isReadOnly -> processOnClick(itemId, ical4list, isReadOnly) },
- onLongClick = { itemId, isReadOnly -> processOnLongClick(itemId, isReadOnly) },
- onStatusChanged = { itemId, newStatus, scrollOnce -> listViewModel.updateStatus(itemId, newStatus, scrollOnce) },
- onXStatusChanged = { itemId, newXStatus, scrollOnce -> listViewModel.updateXStatus(itemId, newXStatus, scrollOnce) },
- onSwapCategories = { itemId, oldCategory, newCategory -> listViewModel.swapCategories(itemId, oldCategory, newCategory) },
- onSyncRequested = { listViewModel.syncAccounts() }
- )
- }
- ViewMode.WEEK -> {
- ListScreenWeek(
- list = list,
- selectedEntries = listViewModel.selectedEntries,
- scrollOnceId = listViewModel.scrollOnceId,
- onClick = { itemId, ical4list, isReadOnly -> processOnClick(itemId, ical4list, isReadOnly) },
- onLongClick = { itemId, isReadOnly -> processOnLongClick(itemId, isReadOnly) },
+ },
+ onSaveListSettings = { listViewModel.saveListSettings() },
+ onUpdateSortOrder = { listViewModel.updateSortOrder(it) }
+ )
+ }
+ ViewMode.GRID -> {
+ ListScreenGrid(
+ list = list,
+ subtasksLive = listViewModel.allSubtasks,
+ storedCategories = database.getStoredCategories().observeAsState(emptyList()).value,
+ storedStatuses = database.getStoredStatuses().observeAsState(emptyList()).value,
+ selectedEntries = listViewModel.selectedEntries,
+ scrollOnceId = listViewModel.scrollOnceId,
+ settingLinkProgressToSubtasks = settingsStateHolder.settingLinkProgressToSubtasks.value,
+ markdownEnabled = listViewModel.listSettings.markdownEnabled.value,
+ player = listViewModel.mediaPlayer,
+ onClick = { itemId, ical4list, isReadOnly -> processOnClick(itemId, ical4list, isReadOnly) },
+ onLongClick = { itemId, ical4list -> processOnLongClick(itemId, ical4list) },
+ onProgressChanged = { itemId, newPercent ->
+ processOnProgressChanged(itemId, newPercent)
+ },
+ isListDragAndDropEnabled = listViewModel.listSettings.orderBy.value == OrderBy.DRAG_AND_DROP || listViewModel.listSettings.orderBy2.value == OrderBy.DRAG_AND_DROP
)
- }
+ }
+ ViewMode.COMPACT -> {
+ ListScreenCompact(
+ groupedList = groupedList,
+ subtasksLive = listViewModel.allSubtasks,
+ storedCategories = database.getStoredCategories().observeAsState(emptyList()).value,
+ storedStatuses = database.getStoredStatuses().observeAsState(emptyList()).value,
+ selectedEntries = listViewModel.selectedEntries,
+ scrollOnceId = listViewModel.scrollOnceId,
+ listSettings = listViewModel.listSettings,
+ settingLinkProgressToSubtasks = settingsStateHolder.settingLinkProgressToSubtasks.value,
+ player = listViewModel.mediaPlayer,
+ isListDragAndDropEnabled = listViewModel.listSettings.orderBy.value == OrderBy.DRAG_AND_DROP || listViewModel.listSettings.orderBy2.value == OrderBy.DRAG_AND_DROP,
+ isSubtaskDragAndDropEnabled = listViewModel.listSettings.subtasksOrderBy.value == OrderBy.DRAG_AND_DROP,
+ onClick = { itemId, ical4list, isReadOnly -> processOnClick(itemId, ical4list, isReadOnly) },
+ onLongClick = { itemId, ical4list -> processOnLongClick(itemId, ical4list) },
+ onProgressChanged = { itemId, newPercent -> processOnProgressChanged(itemId, newPercent) },
+ onSaveListSettings = { listViewModel.saveListSettings() },
+ onUpdateSortOrder = { listViewModel.updateSortOrder(it) }
+ )
+ }
+ ViewMode.KANBAN -> {
+ ListScreenKanban(
+ module = listViewModel.module,
+ list = list,
+ subtasksLive = listViewModel.allSubtasks,
+ storedCategories = database.getStoredCategories().observeAsState(emptyList()).value,
+ storedStatuses = database.getStoredStatuses().observeAsState(emptyList()).value,
+ selectedEntries = listViewModel.selectedEntries,
+ kanbanColumnsStatus = listViewModel.listSettings.kanbanColumnsStatus,
+ kanbanColumnsXStatus = listViewModel.listSettings.kanbanColumnsXStatus,
+ kanbanColumnsCategory = listViewModel.listSettings.kanbanColumnsCategory,
+ scrollOnceId = listViewModel.scrollOnceId,
+ settingLinkProgressToSubtasks = settingsStateHolder.settingLinkProgressToSubtasks.value,
+ markdownEnabled = listViewModel.listSettings.markdownEnabled.value,
+ player = listViewModel.mediaPlayer,
+ onClick = { itemId, ical4list, isReadOnly -> processOnClick(itemId, ical4list, isReadOnly) },
+ onLongClick = { itemId, ical4list -> processOnLongClick(itemId, ical4list) },
+ onStatusChanged = { itemId, newStatus, scrollOnce -> listViewModel.updateStatus(itemId, newStatus, scrollOnce) },
+ onXStatusChanged = { itemId, newXStatus, scrollOnce -> listViewModel.updateXStatus(itemId, newXStatus, scrollOnce) },
+ onSwapCategories = { itemId, oldCategory, newCategory -> listViewModel.swapCategories(itemId, oldCategory, newCategory) }
+ )
+ }
+ ViewMode.WEEK -> {
+ ListScreenWeek(
+ list = list,
+ selectedEntries = listViewModel.selectedEntries,
+ scrollOnceId = listViewModel.scrollOnceId,
+ onClick = { itemId, ical4list, isReadOnly -> processOnClick(itemId, ical4list, isReadOnly) },
+ onLongClick = { itemId, isReadOnly -> processOnLongClick(itemId, isReadOnly) },
+ )
}
}
}
diff --git a/app/src/main/java/at/techbee/jtx/ui/list/ListScreenCompact.kt b/app/src/main/java/at/techbee/jtx/ui/list/ListScreenCompact.kt
index 667c067ab..8d421d719 100644
--- a/app/src/main/java/at/techbee/jtx/ui/list/ListScreenCompact.kt
+++ b/app/src/main/java/at/techbee/jtx/ui/list/ListScreenCompact.kt
@@ -19,7 +19,6 @@ import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
-import androidx.compose.foundation.layout.offset
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.items
@@ -30,14 +29,11 @@ import androidx.compose.material.icons.outlined.ArrowDropUp
import androidx.compose.material.icons.outlined.VerticalAlignTop
import androidx.compose.material3.Button
import androidx.compose.material3.ButtonDefaults
-import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.HorizontalDivider
import androidx.compose.material3.Icon
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Text
import androidx.compose.material3.TextButton
-import androidx.compose.material3.pulltorefresh.PullToRefreshContainer
-import androidx.compose.material3.pulltorefresh.rememberPullToRefreshState
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.getValue
@@ -52,7 +48,6 @@ import androidx.compose.ui.draw.alpha
import androidx.compose.ui.draw.clip
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.toArgb
-import androidx.compose.ui.input.nestedscroll.nestedScroll
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.tooling.preview.Preview
@@ -78,7 +73,7 @@ import sh.calvin.reorderable.rememberReorderableLazyListState
import java.util.UUID
-@OptIn(ExperimentalFoundationApi::class, ExperimentalMaterial3Api::class)
+@OptIn(ExperimentalFoundationApi::class)
@Composable
fun ListScreenCompact(
groupedList: Map>,
@@ -89,14 +84,12 @@ fun ListScreenCompact(
scrollOnceId: MutableLiveData,
listSettings: ListSettings,
settingLinkProgressToSubtasks: Boolean,
- isPullRefreshEnabled: Boolean,
player: MediaPlayer?,
isListDragAndDropEnabled: Boolean,
isSubtaskDragAndDropEnabled: Boolean,
onProgressChanged: (itemId: Long, newPercent: Int) -> Unit,
onClick: (itemId: Long, list: List, isReadOnly: Boolean) -> Unit,
onLongClick: (itemId: Long, isReadOnly: Boolean) -> Unit,
- onSyncRequested: () -> Unit,
onSaveListSettings: () -> Unit,
onUpdateSortOrder: (List) -> Unit
) {
@@ -115,88 +108,76 @@ fun ListScreenCompact(
}
val scope = rememberCoroutineScope()
- val pullToRefreshState = rememberPullToRefreshState(
- enabled = { isPullRefreshEnabled }
- )
- LaunchedEffect(pullToRefreshState.isRefreshing) {
- if(pullToRefreshState.isRefreshing) {
- onSyncRequested()
- pullToRefreshState.endRefresh()
- }
- }
-
- Box(
- contentAlignment = Alignment.TopCenter,
- modifier = Modifier.fillMaxSize().nestedScroll(pullToRefreshState.nestedScrollConnection)
+ LazyColumn(
+ modifier = Modifier
+ .padding(start = 2.dp, end = 2.dp)
+ .fillMaxSize(),
+ state = listState,
) {
- LazyColumn(
- modifier = Modifier.padding(start = 2.dp, end = 2.dp).fillMaxSize(),
- state = listState,
- ) {
- groupedList.forEach { (groupName, group) ->
+ groupedList.forEach { (groupName, group) ->
- if (groupedList.keys.size > 1) {
- stickyHeader {
+ if (groupedList.keys.size > 1) {
+ stickyHeader {
- Row(
- verticalAlignment = Alignment.CenterVertically,
- horizontalArrangement = Arrangement.Center,
- modifier = Modifier
- .fillMaxWidth()
- .background(MaterialTheme.colorScheme.background)
+ Row(
+ verticalAlignment = Alignment.CenterVertically,
+ horizontalArrangement = Arrangement.Center,
+ modifier = Modifier
+ .fillMaxWidth()
+ .background(MaterialTheme.colorScheme.background)
- ) {
- TextButton(onClick = {
- if (listSettings.collapsedGroups.contains(groupName))
- listSettings.collapsedGroups.remove(groupName)
- else
- listSettings.collapsedGroups.add(groupName)
- onSaveListSettings()
- }) {
- Text(
- text = groupName,
- style = MaterialTheme.typography.titleMedium,
- modifier = Modifier.padding(horizontal = 4.dp)
- )
+ ) {
+ TextButton(onClick = {
+ if (listSettings.collapsedGroups.contains(groupName))
+ listSettings.collapsedGroups.remove(groupName)
+ else
+ listSettings.collapsedGroups.add(groupName)
+ onSaveListSettings()
+ }) {
+ Text(
+ text = groupName,
+ style = MaterialTheme.typography.titleMedium,
+ modifier = Modifier.padding(horizontal = 4.dp)
+ )
- if (listSettings.collapsedGroups.contains(groupName))
- Icon(Icons.Outlined.ArrowDropUp, stringResource(R.string.list_collapse))
- else
- Icon(Icons.Outlined.ArrowDropDown, stringResource(R.string.list_expand))
- }
+ if (listSettings.collapsedGroups.contains(groupName))
+ Icon(Icons.Outlined.ArrowDropUp, stringResource(R.string.list_collapse))
+ else
+ Icon(Icons.Outlined.ArrowDropDown, stringResource(R.string.list_expand))
}
}
}
+ }
- if (groupedList.keys.size <= 1 || (groupedList.keys.size > 1 && !listSettings.collapsedGroups.contains(groupName))) {
- items(
- items = group.toList(),
- key = { item ->
- if(listSettings.groupBy.value == GroupBy.CATEGORY || listSettings.groupBy.value == GroupBy.RESOURCE)
- item.iCal4List.id.toString() + UUID.randomUUID()
- else
- item.iCal4List.id
- }
- )
- { iCal4ListRelObject ->
+ if (groupedList.keys.size <= 1 || (groupedList.keys.size > 1 && !listSettings.collapsedGroups.contains(groupName))) {
+ items(
+ items = group.toList(),
+ key = { item ->
+ if(listSettings.groupBy.value == GroupBy.CATEGORY || listSettings.groupBy.value == GroupBy.RESOURCE)
+ item.iCal4List.id.toString() + UUID.randomUUID()
+ else
+ item.iCal4List.id
+ }
+ )
+ { iCal4ListRelObject ->
- var currentSubtasks =
- subtasks.filter { iCal4ListRel -> iCal4ListRel.relatedto.any { relatedto -> relatedto.reltype == Reltype.PARENT.name && relatedto.text == iCal4ListRelObject.iCal4List.uid } }
- .map { it.iCal4List }
- if (listSettings.isExcludeDone.value) // exclude done if applicable
- currentSubtasks = currentSubtasks.filter { subtask -> subtask.percent != 100 && subtask.status != Status.COMPLETED.status }
+ var currentSubtasks =
+ subtasks.filter { iCal4ListRel -> iCal4ListRel.relatedto.any { relatedto -> relatedto.reltype == Reltype.PARENT.name && relatedto.text == iCal4ListRelObject.iCal4List.uid } }
+ .map { it.iCal4List }
+ if (listSettings.isExcludeDone.value) // exclude done if applicable
+ currentSubtasks = currentSubtasks.filter { subtask -> subtask.percent != 100 && subtask.status != Status.COMPLETED.status }
- if (scrollId != null) {
- LaunchedEffect(group) {
- val index = group.indexOfFirst { iCalObject -> iCalObject.iCal4List.id == scrollId }
- if (index > -1) {
- listState.scrollToItem(index)
- scrollOnceId.postValue(null)
- }
+ if (scrollId != null) {
+ LaunchedEffect(group) {
+ val index = group.indexOfFirst { iCalObject -> iCalObject.iCal4List.id == scrollId }
+ if (index > -1) {
+ listState.scrollToItem(index)
+ scrollOnceId.postValue(null)
}
}
+ }
ReorderableItem(
reorderableLazyListState,
@@ -230,7 +211,7 @@ fun ListScreenCompact(
)
},
onLongClick = {
- onLongClick(iCal4ListRelObject.iCal4List.id, iCal4ListRelObject.iCal4List.isReadOnly)
+ onLongClick(iCal4ListRelObject.iCal4List.id, iCal4ListRelObject.iCal4List.isReadOnly)
}
),
onProgressChanged = onProgressChanged,
@@ -240,38 +221,32 @@ fun ListScreenCompact(
)
}
- if (iCal4ListRelObject != group.last())
- HorizontalDivider(
- color = MaterialTheme.colorScheme.onSurfaceVariant,
- modifier = Modifier.alpha(0.25f)
- )
- }
+ if (iCal4ListRelObject != group.last())
+ HorizontalDivider(
+ color = MaterialTheme.colorScheme.onSurfaceVariant,
+ modifier = Modifier.alpha(0.25f)
+ )
}
}
}
+ }
- PullToRefreshContainer(
- modifier = Modifier.align(Alignment.TopCenter).offset(y = (-30).dp),
- state = pullToRefreshState,
- )
-
- Crossfade(listState.canScrollBackward, label = "showScrollUp") {
- if(it) {
- Box(
- contentAlignment = Alignment.BottomCenter,
- modifier = Modifier.fillMaxSize()
+ Crossfade(listState.canScrollBackward, label = "showScrollUp") {
+ if(it) {
+ Box(
+ contentAlignment = Alignment.BottomCenter,
+ modifier = Modifier.fillMaxSize()
+ ) {
+ Button(
+ onClick = {
+ scope.launch { listState.scrollToItem(0) }
+ },
+ colors = ButtonDefaults.filledTonalButtonColors(),
+ modifier = Modifier
+ .padding(8.dp)
+ .alpha(0.33f)
) {
- Button(
- onClick = {
- scope.launch { listState.scrollToItem(0) }
- },
- colors = ButtonDefaults.filledTonalButtonColors(),
- modifier = Modifier
- .padding(8.dp)
- .alpha(0.33f)
- ) {
- Icon(Icons.Outlined.VerticalAlignTop, stringResource(R.string.list_scroll_to_top))
- }
+ Icon(Icons.Outlined.VerticalAlignTop, stringResource(R.string.list_scroll_to_top))
}
}
}
@@ -330,14 +305,12 @@ fun ListScreenCompact_TODO() {
selectedEntries = remember { mutableStateListOf() },
listSettings = listSettings,
settingLinkProgressToSubtasks = false,
- isPullRefreshEnabled = true,
player = null,
isListDragAndDropEnabled = true,
isSubtaskDragAndDropEnabled = true,
onProgressChanged = { _, _ -> },
onClick = { _, _, _ -> },
onLongClick = { _, _ -> },
- onSyncRequested = { },
onSaveListSettings = { },
onUpdateSortOrder = { }
)
@@ -397,14 +370,12 @@ fun ListScreenCompact_JOURNAL() {
scrollOnceId = MutableLiveData(null),
listSettings = listSettings,
settingLinkProgressToSubtasks = false,
- isPullRefreshEnabled = true,
player = null,
isListDragAndDropEnabled = true,
isSubtaskDragAndDropEnabled = true,
onProgressChanged = { _, _ -> },
onClick = { _, _, _ -> },
onLongClick = { _, _ -> },
- onSyncRequested = { },
onSaveListSettings = { },
onUpdateSortOrder = { }
)
diff --git a/app/src/main/java/at/techbee/jtx/ui/list/ListScreenGrid.kt b/app/src/main/java/at/techbee/jtx/ui/list/ListScreenGrid.kt
index 6bc70bfe3..728079f9f 100644
--- a/app/src/main/java/at/techbee/jtx/ui/list/ListScreenGrid.kt
+++ b/app/src/main/java/at/techbee/jtx/ui/list/ListScreenGrid.kt
@@ -17,7 +17,6 @@ import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.PaddingValues
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
-import androidx.compose.foundation.layout.offset
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.lazy.staggeredgrid.LazyVerticalStaggeredGrid
import androidx.compose.foundation.lazy.staggeredgrid.StaggeredGridCells
@@ -27,11 +26,8 @@ import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.outlined.VerticalAlignTop
import androidx.compose.material3.Button
import androidx.compose.material3.ButtonDefaults
-import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.Icon
import androidx.compose.material3.MaterialTheme
-import androidx.compose.material3.pulltorefresh.PullToRefreshContainer
-import androidx.compose.material3.pulltorefresh.rememberPullToRefreshState
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.getValue
@@ -46,7 +42,6 @@ import androidx.compose.ui.draw.alpha
import androidx.compose.ui.draw.clip
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.toArgb
-import androidx.compose.ui.input.nestedscroll.nestedScroll
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.tooling.preview.Preview
@@ -71,7 +66,7 @@ import sh.calvin.reorderable.ReorderableItem
import sh.calvin.reorderable.rememberReorderableLazyStaggeredGridState
-@OptIn(ExperimentalFoundationApi::class, ExperimentalMaterial3Api::class)
+@OptIn(ExperimentalFoundationApi::class)
@Composable
fun ListScreenGrid(
list: List,
@@ -81,14 +76,12 @@ fun ListScreenGrid(
selectedEntries: SnapshotStateList,
scrollOnceId: MutableLiveData,
settingLinkProgressToSubtasks: Boolean,
- isPullRefreshEnabled: Boolean,
markdownEnabled: Boolean,
player: MediaPlayer?,
isListDragAndDropEnabled: Boolean,
onProgressChanged: (itemId: Long, newPercent: Int) -> Unit,
onClick: (itemId: Long, list: List, isReadOnly: Boolean) -> Unit,
- onLongClick: (itemId: Long, isReadOnly: Boolean) -> Unit,
- onSyncRequested: () -> Unit
+ onLongClick: (itemId: Long, isReadOnly: Boolean) -> Unit
) {
val context = LocalContext.current
@@ -115,45 +108,28 @@ fun ListScreenGrid(
}
}
- val pullToRefreshState = rememberPullToRefreshState(
- enabled = { isPullRefreshEnabled }
- )
- LaunchedEffect(pullToRefreshState.isRefreshing) {
- if(pullToRefreshState.isRefreshing) {
- onSyncRequested()
- pullToRefreshState.endRefresh()
- }
- }
-
- Box(
- modifier = Modifier
- .fillMaxSize()
- .nestedScroll(pullToRefreshState.nestedScrollConnection),
- contentAlignment = Alignment.TopCenter
+ LazyVerticalStaggeredGrid(
+ state = gridState,
+ columns = StaggeredGridCells.Adaptive(150.dp),
+ contentPadding = PaddingValues(8.dp),
+ verticalItemSpacing = 8.dp,
+ horizontalArrangement = Arrangement.spacedBy(8.dp),
+ modifier = Modifier.fillMaxSize()
) {
+ items(
+ items = list,
+ key = { item -> item.iCal4List.id }
+ )
+ { iCal4ListRelObject ->
- LazyVerticalStaggeredGrid(
- state = gridState,
- columns = StaggeredGridCells.Adaptive(150.dp),
- contentPadding = PaddingValues(8.dp),
- verticalItemSpacing = 8.dp,
- horizontalArrangement = Arrangement.spacedBy(8.dp),
- modifier = Modifier.fillMaxSize()
- ) {
- items(
- items = list,
- key = { item -> item.iCal4List.id }
- )
- { iCal4ListRelObject ->
-
- val currentSubtasks =
- subtasks.filter { iCal4ListRel -> iCal4ListRel.relatedto.any { relatedto -> relatedto.reltype == Reltype.PARENT.name && relatedto.text == iCal4ListRelObject.iCal4List.uid } }
- .map { it.iCal4List }
+ val currentSubtasks =
+ subtasks.filter { iCal4ListRel -> iCal4ListRel.relatedto.any { relatedto -> relatedto.reltype == Reltype.PARENT.name && relatedto.text == iCal4ListRelObject.iCal4List.uid } }
+ .map { it.iCal4List }
- ReorderableItem(
- state = reorderableLazyListState,
- key = iCal4ListRelObject.iCal4List.id
- ) {
+ ReorderableItem(
+ state = reorderableLazyListState,
+ key = iCal4ListRelObject.iCal4List.id
+ ) {
ListCardGrid(
iCal4ListRelObject.iCal4List,
@@ -188,30 +164,22 @@ fun ListScreenGrid(
}
}
- PullToRefreshContainer(
- modifier = Modifier
- .align(Alignment.TopCenter)
- .offset(y = (-30).dp),
- state = pullToRefreshState,
- )
-
- Crossfade(gridState.canScrollBackward, label = "showScrollUp") {
- if (it) {
- Box(
- contentAlignment = Alignment.BottomCenter,
- modifier = Modifier.fillMaxSize()
+ Crossfade(gridState.canScrollBackward, label = "showScrollUp") {
+ if (it) {
+ Box(
+ contentAlignment = Alignment.BottomCenter,
+ modifier = Modifier.fillMaxSize()
+ ) {
+ Button(
+ onClick = {
+ scope.launch { gridState.scrollToItem(0) }
+ },
+ colors = ButtonDefaults.filledTonalButtonColors(),
+ modifier = Modifier
+ .padding(8.dp)
+ .alpha(0.33f)
) {
- Button(
- onClick = {
- scope.launch { gridState.scrollToItem(0) }
- },
- colors = ButtonDefaults.filledTonalButtonColors(),
- modifier = Modifier
- .padding(8.dp)
- .alpha(0.33f)
- ) {
- Icon(Icons.Outlined.VerticalAlignTop, stringResource(R.string.list_scroll_to_top))
- }
+ Icon(Icons.Outlined.VerticalAlignTop, stringResource(R.string.list_scroll_to_top))
}
}
}
@@ -263,13 +231,11 @@ fun ListScreenGrid_TODO() {
selectedEntries = remember { mutableStateListOf() },
scrollOnceId = MutableLiveData(null),
settingLinkProgressToSubtasks = false,
- isPullRefreshEnabled = true,
markdownEnabled = false,
player = null,
onProgressChanged = { _, _ -> },
onClick = { _, _, _ -> },
onLongClick = { _, _ -> },
- onSyncRequested = { },
isListDragAndDropEnabled = true
)
}
@@ -320,13 +286,11 @@ fun ListScreenGrid_JOURNAL() {
selectedEntries = remember { mutableStateListOf() },
scrollOnceId = MutableLiveData(null),
settingLinkProgressToSubtasks = false,
- isPullRefreshEnabled = true,
markdownEnabled = false,
player = null,
onProgressChanged = { _, _ -> },
onClick = { _, _, _ -> },
onLongClick = { _, _ -> },
- onSyncRequested = { },
isListDragAndDropEnabled = false
)
}
diff --git a/app/src/main/java/at/techbee/jtx/ui/list/ListScreenKanban.kt b/app/src/main/java/at/techbee/jtx/ui/list/ListScreenKanban.kt
index 6b2cd0a7b..714fa43fb 100644
--- a/app/src/main/java/at/techbee/jtx/ui/list/ListScreenKanban.kt
+++ b/app/src/main/java/at/techbee/jtx/ui/list/ListScreenKanban.kt
@@ -22,20 +22,15 @@ import androidx.compose.foundation.gestures.Orientation
import androidx.compose.foundation.gestures.draggable
import androidx.compose.foundation.gestures.rememberDraggableState
import androidx.compose.foundation.layout.Arrangement
-import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.PaddingValues
import androidx.compose.foundation.layout.Row
-import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.offset
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.items
import androidx.compose.foundation.lazy.rememberLazyListState
-import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Text
-import androidx.compose.material3.pulltorefresh.PullToRefreshContainer
-import androidx.compose.material3.pulltorefresh.rememberPullToRefreshState
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.getValue
@@ -50,7 +45,6 @@ import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.toArgb
-import androidx.compose.ui.input.nestedscroll.nestedScroll
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.style.TextAlign
@@ -73,8 +67,7 @@ import kotlin.math.abs
import kotlin.math.roundToInt
-@OptIn(ExperimentalFoundationApi::class, ExperimentalMaterial3Api::class
-)
+@OptIn(ExperimentalFoundationApi::class)
@Composable
fun ListScreenKanban(
module: Module,
@@ -88,15 +81,13 @@ fun ListScreenKanban(
kanbanColumnsCategory: SnapshotStateList,
scrollOnceId: MutableLiveData,
settingLinkProgressToSubtasks: Boolean,
- isPullRefreshEnabled: Boolean,
markdownEnabled: Boolean,
player: MediaPlayer?,
onStatusChanged: (itemid: Long, status: Status, scrollOnce: Boolean) -> Unit,
onXStatusChanged: (itemid: Long, status: ExtendedStatus, scrollOnce: Boolean) -> Unit,
onSwapCategories: (itemid: Long, old: String, new: String) -> Unit,
onClick: (itemId: Long, list: List, isReadOnly: Boolean) -> Unit,
- onLongClick: (itemId: Long, isReadOnly: Boolean) -> Unit,
- onSyncRequested: () -> Unit
+ onLongClick: (itemId: Long, isReadOnly: Boolean) -> Unit
) {
val context = LocalContext.current
@@ -134,69 +125,55 @@ fun ListScreenKanban(
}
}
- val pullToRefreshState = rememberPullToRefreshState(
- enabled = { isPullRefreshEnabled }
- )
- LaunchedEffect(pullToRefreshState.isRefreshing) {
- if(pullToRefreshState.isRefreshing) {
- onSyncRequested()
- pullToRefreshState.endRefresh()
- }
- }
-
- Box(
- modifier = Modifier.fillMaxSize().nestedScroll(pullToRefreshState.nestedScrollConnection),
- contentAlignment = Alignment.TopCenter
- ) {
- Row(modifier = Modifier.fillMaxWidth()) {
+ Row(modifier = Modifier.fillMaxWidth()) {
- columns.forEachIndexed { index, column ->
+ columns.forEachIndexed { index, column ->
- val listState = rememberLazyListState()
+ val listState = rememberLazyListState()
- if (scrollId != null) {
- LaunchedEffect(list) {
- val itemIndex = groupedList[column]?.indexOfFirst { iCal4ListRelObject -> iCal4ListRelObject.iCal4List.id == scrollId } ?: -1
- if (itemIndex > -1) {
- listState.scrollToItem(itemIndex)
- scrollOnceId.postValue(null)
- }
+ if (scrollId != null) {
+ LaunchedEffect(list) {
+ val itemIndex = groupedList[column]?.indexOfFirst { iCal4ListRelObject -> iCal4ListRelObject.iCal4List.id == scrollId } ?: -1
+ if (itemIndex > -1) {
+ listState.scrollToItem(itemIndex)
+ scrollOnceId.postValue(null)
}
}
+ }
- LazyColumn(
- state = listState,
- contentPadding = PaddingValues(4.dp),
- verticalArrangement = Arrangement.spacedBy(8.dp),
- horizontalAlignment = Alignment.CenterHorizontally,
- modifier = Modifier.fillMaxWidth().weight(1F)
- ) {
-
- stickyHeader {
- Text(
- text = column,
- modifier = Modifier
- .align(Alignment.CenterVertically)
- .background(MaterialTheme.colorScheme.background)
- .fillMaxWidth(),
- style = MaterialTheme.typography.titleSmall,
- textAlign = TextAlign.Center
- )
- }
+ LazyColumn(
+ state = listState,
+ contentPadding = PaddingValues(4.dp),
+ verticalArrangement = Arrangement.spacedBy(8.dp),
+ horizontalAlignment = Alignment.CenterHorizontally,
+ modifier = Modifier.fillMaxWidth().weight(1F)
+ ) {
- items(
- items = groupedList[column]?: emptyList(),
- key = { item -> item.iCal4List.id }
+ stickyHeader {
+ Text(
+ text = column,
+ modifier = Modifier
+ .align(Alignment.CenterVertically)
+ .background(MaterialTheme.colorScheme.background)
+ .fillMaxWidth(),
+ style = MaterialTheme.typography.titleSmall,
+ textAlign = TextAlign.Center
)
- { iCal4ListRelObject ->
+ }
- val currentSubtasks =
- subtasks.filter { iCal4ListRel -> iCal4ListRel.relatedto.any { relatedto -> relatedto.reltype == Reltype.PARENT.name && relatedto.text == iCal4ListRel.iCal4List.uid } }
- .map { it.iCal4List }
+ items(
+ items = groupedList[column]?: emptyList(),
+ key = { item -> item.iCal4List.id }
+ )
+ { iCal4ListRelObject ->
- var offsetX by remember { mutableFloatStateOf(0f) } // see https://developer.android.com/jetpack/compose/gestures
- val maxOffset = 50f
+ val currentSubtasks =
+ subtasks.filter { iCal4ListRel -> iCal4ListRel.relatedto.any { relatedto -> relatedto.reltype == Reltype.PARENT.name && relatedto.text == iCal4ListRel.iCal4List.uid } }
+ .map { it.iCal4List }
+
+ var offsetX by remember { mutableFloatStateOf(0f) } // see https://developer.android.com/jetpack/compose/gestures
+ val maxOffset = 50f
ListCardKanban(
iCal4ListRelObject.iCal4List,
@@ -228,57 +205,51 @@ fun ListScreenKanban(
onDragStopped = {
if (abs(offsetX) > maxOffset / 2 && !iCal4ListRelObject.iCal4List.isReadOnly) {
- val draggedToColumn = when {
- offsetX < 0f && index > 0 -> index - 1
- offsetX > 0F && index < columns.lastIndex -> index + 1
- else -> {
- offsetX = 0f
- return@draggable
- }
+ val draggedToColumn = when {
+ offsetX < 0f && index > 0 -> index - 1
+ offsetX > 0F && index < columns.lastIndex -> index + 1
+ else -> {
+ offsetX = 0f
+ return@draggable
}
+ }
- when {
- kanbanColumnsXStatus.isNotEmpty() -> storedStatuses
- .find { xstatus -> xstatus.module == module && xstatus.xstatus == columns[draggedToColumn] }
- ?.let { xstatus ->
- onXStatusChanged(iCal4ListRelObject.iCal4List.id, xstatus, true)
- }
+ when {
+ kanbanColumnsXStatus.isNotEmpty() -> storedStatuses
+ .find { xstatus -> xstatus.module == module && xstatus.xstatus == columns[draggedToColumn] }
+ ?.let { xstatus ->
+ onXStatusChanged(iCal4ListRelObject.iCal4List.id, xstatus, true)
+ }
- kanbanColumnsCategory.isNotEmpty() -> onSwapCategories(iCal4ListRelObject.iCal4List.id, column, columns[draggedToColumn])
+ kanbanColumnsCategory.isNotEmpty() -> onSwapCategories(iCal4ListRelObject.iCal4List.id, column, columns[draggedToColumn])
- else -> Status.entries
- .find { status -> context.getString(status.stringResource) == columns[draggedToColumn] }
- ?.let { status ->
- onStatusChanged(iCal4ListRelObject.iCal4List.id, status, true)
- }
- }
+ else -> Status.entries
+ .find { status -> context.getString(status.stringResource) == columns[draggedToColumn] }
+ ?.let { status ->
+ onStatusChanged(iCal4ListRelObject.iCal4List.id, status, true)
+ }
+ }
- // make a short vibration
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
- val vibratorManager = context.getSystemService(VIBRATOR_MANAGER_SERVICE) as VibratorManager
- val vibrator = vibratorManager.defaultVibrator
- val vibrationEffect = VibrationEffect.createPredefined(VibrationEffect.EFFECT_CLICK)
- vibrator.vibrate(vibrationEffect)
- } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
- @Suppress("DEPRECATION")
- val vibrator = context.getSystemService(VIBRATOR_SERVICE) as Vibrator
- val vibrationEffect = VibrationEffect.createOneShot(150, 10)
- vibrator.vibrate(vibrationEffect)
- }
+ // make a short vibration
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
+ val vibratorManager = context.getSystemService(VIBRATOR_MANAGER_SERVICE) as VibratorManager
+ val vibrator = vibratorManager.defaultVibrator
+ val vibrationEffect = VibrationEffect.createPredefined(VibrationEffect.EFFECT_CLICK)
+ vibrator.vibrate(vibrationEffect)
+ } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
+ @Suppress("DEPRECATION")
+ val vibrator = context.getSystemService(VIBRATOR_SERVICE) as Vibrator
+ val vibrationEffect = VibrationEffect.createOneShot(150, 10)
+ vibrator.vibrate(vibrationEffect)
}
- offsetX = 0f
}
- ),
- )
- }
+ offsetX = 0f
+ }
+ ),
+ )
}
}
}
-
- PullToRefreshContainer(
- modifier = Modifier.align(Alignment.TopCenter).offset(y = (-30).dp),
- state = pullToRefreshState,
- )
}
}
@@ -331,15 +302,13 @@ fun ListScreenKanban_TODO() {
kanbanColumnsCategory = remember { mutableStateListOf() },
scrollOnceId = MutableLiveData(null),
settingLinkProgressToSubtasks = false,
- isPullRefreshEnabled = true,
markdownEnabled = false,
player = null,
onStatusChanged = { _, _, _ -> },
onXStatusChanged = { _, _, _ -> },
onSwapCategories = { _, _, _ -> },
onClick = { _, _, _ -> },
- onLongClick = { _, _ -> },
- onSyncRequested = { }
+ onLongClick = { _, _ -> }
)
}
}
@@ -393,15 +362,13 @@ fun ListScreenKanban_JOURNAL() {
kanbanColumnsCategory = remember { mutableStateListOf() },
scrollOnceId = MutableLiveData(null),
settingLinkProgressToSubtasks = false,
- isPullRefreshEnabled = true,
markdownEnabled = false,
player = null,
onStatusChanged = { _, _, _ -> },
onXStatusChanged = { _, _, _ -> },
onSwapCategories = { _, _, _ -> },
onClick = { _, _, _ -> },
- onLongClick = { _, _ -> },
- onSyncRequested = { }
+ onLongClick = { _, _ -> }
)
}
}
diff --git a/app/src/main/java/at/techbee/jtx/ui/list/ListScreenList.kt b/app/src/main/java/at/techbee/jtx/ui/list/ListScreenList.kt
index ec30674cf..b87d530cb 100644
--- a/app/src/main/java/at/techbee/jtx/ui/list/ListScreenList.kt
+++ b/app/src/main/java/at/techbee/jtx/ui/list/ListScreenList.kt
@@ -19,7 +19,6 @@ import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
-import androidx.compose.foundation.layout.offset
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.items
@@ -30,13 +29,10 @@ import androidx.compose.material.icons.outlined.ArrowDropUp
import androidx.compose.material.icons.outlined.VerticalAlignTop
import androidx.compose.material3.Button
import androidx.compose.material3.ButtonDefaults
-import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.Icon
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Text
import androidx.compose.material3.TextButton
-import androidx.compose.material3.pulltorefresh.PullToRefreshContainer
-import androidx.compose.material3.pulltorefresh.rememberPullToRefreshState
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.getValue
@@ -51,7 +47,6 @@ import androidx.compose.ui.draw.alpha
import androidx.compose.ui.draw.clip
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.toArgb
-import androidx.compose.ui.input.nestedscroll.nestedScroll
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.platform.testTag
import androidx.compose.ui.res.stringResource
@@ -81,8 +76,7 @@ import sh.calvin.reorderable.rememberReorderableLazyListState
import java.util.UUID
-@OptIn(ExperimentalFoundationApi::class, ExperimentalMaterial3Api::class
-)
+@OptIn(ExperimentalFoundationApi::class)
@Composable
fun ListScreenList(
groupedList: Map>,
@@ -99,13 +93,13 @@ fun ListScreenList(
isSubtasksExpandedDefault: Boolean,
isSubnotesExpandedDefault: Boolean,
isAttachmentsExpandedDefault: Boolean,
+ isParentsExpandedDefault: Boolean,
settingShowProgressMaintasks: Boolean,
settingShowProgressSubtasks: Boolean,
settingProgressIncrement: DropdownSettingOption,
settingDisplayTimezone: DropdownSettingOption,
settingLinkProgressToSubtasks: Boolean,
settingIsAccessibilityMode: Boolean,
- isPullRefreshEnabled: Boolean,
markdownEnabled: Boolean,
player: MediaPlayer?,
isListDragAndDropEnabled: Boolean,
@@ -115,7 +109,6 @@ fun ListScreenList(
onLongClick: (itemId: Long, isReadOnly: Boolean) -> Unit,
onProgressChanged: (itemId: Long, newPercent: Int) -> Unit,
onExpandedChanged: (itemId: Long, isSubtasksExpanded: Boolean, isSubnotesExpanded: Boolean, isParentsExpanded: Boolean, isAttachmentsExpanded: Boolean) -> Unit,
- onSyncRequested: () -> Unit,
onSaveListSettings: () -> Unit,
onUpdateSortOrder: (List) -> Unit
) {
@@ -137,95 +130,81 @@ fun ListScreenList(
}
ICalDatabase.getInstance(context).iCalDatabaseDao().updateSortOrder(reordered.map { it.id })
}
- val pullToRefreshState = rememberPullToRefreshState(
- enabled = { isPullRefreshEnabled }
- )
- LaunchedEffect(pullToRefreshState.isRefreshing) {
- if(pullToRefreshState.isRefreshing) {
- onSyncRequested()
- pullToRefreshState.endRefresh()
- }
- }
- Box(
- contentAlignment = Alignment.TopCenter,
- modifier = Modifier.fillMaxSize().nestedScroll(pullToRefreshState.nestedScrollConnection)
+ LazyColumn(
+ modifier = Modifier.padding(start = 8.dp, end = 8.dp, top = 4.dp),
+ state = listState,
) {
+ groupedList.forEach { (groupName, group) ->
- LazyColumn(
- modifier = Modifier.padding(start = 8.dp, end = 8.dp, top = 4.dp),
- state = listState,
- ) {
- groupedList.forEach { (groupName, group) ->
-
- if (groupedList.keys.size > 1) {
- stickyHeader {
+ if (groupedList.keys.size > 1) {
+ stickyHeader {
- Row(
- verticalAlignment = Alignment.CenterVertically,
- horizontalArrangement = Arrangement.Center,
- modifier = Modifier
- .fillMaxWidth()
- .background(MaterialTheme.colorScheme.background)
+ Row(
+ verticalAlignment = Alignment.CenterVertically,
+ horizontalArrangement = Arrangement.Center,
+ modifier = Modifier
+ .fillMaxWidth()
+ .background(MaterialTheme.colorScheme.background)
- ) {
- TextButton(onClick = {
- if (listSettings.collapsedGroups.contains(groupName))
- listSettings.collapsedGroups.remove(groupName)
- else
- listSettings.collapsedGroups.add(groupName)
- onSaveListSettings()
- }) {
- Text(
- text = groupName,
- style = MaterialTheme.typography.titleMedium,
- modifier = Modifier.padding(horizontal = 4.dp)
- )
+ ) {
+ TextButton(onClick = {
+ if (listSettings.collapsedGroups.contains(groupName))
+ listSettings.collapsedGroups.remove(groupName)
+ else
+ listSettings.collapsedGroups.add(groupName)
+ onSaveListSettings()
+ }) {
+ Text(
+ text = groupName,
+ style = MaterialTheme.typography.titleMedium,
+ modifier = Modifier.padding(horizontal = 4.dp)
+ )
- if (listSettings.collapsedGroups.contains(groupName))
- Icon(Icons.Outlined.ArrowDropUp, stringResource(R.string.list_collapse))
- else
- Icon(Icons.Outlined.ArrowDropDown, stringResource(R.string.list_expand))
- }
+ if (listSettings.collapsedGroups.contains(groupName))
+ Icon(Icons.Outlined.ArrowDropUp, stringResource(R.string.list_collapse))
+ else
+ Icon(Icons.Outlined.ArrowDropDown, stringResource(R.string.list_expand))
}
}
}
+ }
- if (groupedList.keys.size <= 1 || (groupedList.keys.size > 1 && !listSettings.collapsedGroups.contains(groupName))) {
- items(
- items = group,
- key = { item ->
- if(listSettings.groupBy.value == GroupBy.CATEGORY || listSettings.groupBy.value == GroupBy.RESOURCE)
- item.iCal4List.id.toString() + UUID.randomUUID()
- else
- item.iCal4List.id
- }
- ) { iCal4ListRelObject ->
-
- var currentSubtasks =
- subtasks.filter { iCal4ListRel -> iCal4ListRel.relatedto.any { relatedto -> relatedto.reltype == Reltype.PARENT.name && relatedto.text == iCal4ListRelObject.iCal4List.uid } }
- .map { it.iCal4List }
- if (listSettings.isExcludeDone.value) // exclude done if applicable
- currentSubtasks =
- currentSubtasks.filter { subtask -> subtask.percent != 100 && subtask.status != Status.COMPLETED.status }
-
- val currentSubnotes =
- subnotes.filter { iCal4ListRel -> iCal4ListRel.relatedto.any { relatedto -> relatedto.reltype == Reltype.PARENT.name && relatedto.text == iCal4ListRelObject.iCal4List.uid } }
- .map { it.iCal4List }
- val currentParents = parents.filter { iCal4ListRel -> iCal4ListRelObject.relatedto.any { related -> related.text == iCal4ListRel.iCal4List.uid } }.map { it.iCal4List }
- val currentAttachments = attachments[iCal4ListRelObject.iCal4List.id]
-
- if (scrollId != null) {
- LaunchedEffect(group) {
- val index =
- group.indexOfFirst { iCalObject -> iCalObject.iCal4List.id == scrollId }
- if (index > -1) {
- listState.scrollToItem(index)
- scrollOnceId.postValue(null)
- }
+ if (groupedList.keys.size <= 1 || (groupedList.keys.size > 1 && !listSettings.collapsedGroups.contains(groupName))) {
+ items(
+ items = group,
+ key = { item ->
+ if(listSettings.groupBy.value == GroupBy.CATEGORY || listSettings.groupBy.value == GroupBy.RESOURCE)
+ item.iCal4List.id.toString() + UUID.randomUUID()
+ else
+ item.iCal4List.id
+ }
+ ) { iCal4ListRelObject ->
+
+ var currentSubtasks =
+ subtasks.filter { iCal4ListRel -> iCal4ListRel.relatedto.any { relatedto -> relatedto.reltype == Reltype.PARENT.name && relatedto.text == iCal4ListRelObject.iCal4List.uid } }
+ .map { it.iCal4List }
+ if (listSettings.isExcludeDone.value) // exclude done if applicable
+ currentSubtasks =
+ currentSubtasks.filter { subtask -> subtask.percent != 100 && subtask.status != Status.COMPLETED.status }
+
+ val currentSubnotes =
+ subnotes.filter { iCal4ListRel -> iCal4ListRel.relatedto.any { relatedto -> relatedto.reltype == Reltype.PARENT.name && relatedto.text == iCal4ListRelObject.iCal4List.uid } }
+ .map { it.iCal4List }
+ val currentParents = parents.filter { iCal4ListRel -> iCal4ListRelObject.relatedto.any { related -> related.text == iCal4ListRel.iCal4List.uid } }.map { it.iCal4List }
+ val currentAttachments = attachments[iCal4ListRelObject.iCal4List.id]
+
+ if (scrollId != null) {
+ LaunchedEffect(group) {
+ val index =
+ group.indexOfFirst { iCalObject -> iCalObject.iCal4List.id == scrollId }
+ if (index > -1) {
+ listState.scrollToItem(index)
+ scrollOnceId.postValue(null)
}
}
+ }
ReorderableItem(reorderableLazyListState, key = iCal4ListRelObject.iCal4List.id) {
ListCard(
@@ -243,6 +222,7 @@ fun ListScreenList(
isSubtasksExpandedDefault = isSubtasksExpandedDefault,
isSubnotesExpandedDefault = isSubnotesExpandedDefault,
isAttachmentsExpandedDefault = isAttachmentsExpandedDefault,
+ isParentsExpandedDefault = isParentsExpandedDefault,
settingShowProgressMaintasks = settingShowProgressMaintasks,
settingShowProgressSubtasks = settingShowProgressSubtasks,
settingDisplayTimezone = settingDisplayTimezone,
@@ -288,26 +268,20 @@ fun ListScreenList(
}
}
- PullToRefreshContainer(
- modifier = Modifier.align(Alignment.TopCenter).offset(y = (-30).dp),
- state = pullToRefreshState,
- )
-
- Crossfade(listState.canScrollBackward, label = "showScrollUp") {
- if (it) {
- Box(
- contentAlignment = Alignment.BottomCenter,
- modifier = Modifier.fillMaxSize()
+ Crossfade(listState.canScrollBackward, label = "showScrollUp") {
+ if (it) {
+ Box(
+ contentAlignment = Alignment.BottomCenter,
+ modifier = Modifier.fillMaxSize()
+ ) {
+ Button(
+ onClick = {
+ scope.launch { listState.scrollToItem(0) }
+ },
+ colors = ButtonDefaults.filledTonalButtonColors(),
+ modifier = Modifier.padding(8.dp).alpha(0.33f)
) {
- Button(
- onClick = {
- scope.launch { listState.scrollToItem(0) }
- },
- colors = ButtonDefaults.filledTonalButtonColors(),
- modifier = Modifier.padding(8.dp).alpha(0.33f)
- ) {
- Icon(Icons.Outlined.VerticalAlignTop, stringResource(R.string.list_scroll_to_top))
- }
+ Icon(Icons.Outlined.VerticalAlignTop, stringResource(R.string.list_scroll_to_top))
}
}
}
@@ -371,13 +345,13 @@ fun ListScreenList_TODO() {
isSubtasksExpandedDefault = true,
isSubnotesExpandedDefault = true,
isAttachmentsExpandedDefault = true,
+ isParentsExpandedDefault = true,
settingShowProgressMaintasks = true,
settingShowProgressSubtasks = true,
settingProgressIncrement = DropdownSettingOption.PROGRESS_STEP_1,
settingLinkProgressToSubtasks = false,
settingDisplayTimezone = DropdownSettingOption.DISPLAY_TIMEZONE_LOCAL,
settingIsAccessibilityMode = false,
- isPullRefreshEnabled = true,
markdownEnabled = false,
player = null,
isListDragAndDropEnabled = true,
@@ -388,7 +362,6 @@ fun ListScreenList_TODO() {
onLongClick = { _, _ -> },
listSettings = listSettings,
onExpandedChanged = { _, _, _, _, _ -> },
- onSyncRequested = { },
onSaveListSettings = { },
onUpdateSortOrder = { }
)
@@ -455,13 +428,13 @@ fun ListScreenList_JOURNAL() {
isSubtasksExpandedDefault = false,
isSubnotesExpandedDefault = false,
isAttachmentsExpandedDefault = false,
+ isParentsExpandedDefault = false,
settingShowProgressMaintasks = false,
settingShowProgressSubtasks = false,
settingProgressIncrement = DropdownSettingOption.PROGRESS_STEP_1,
settingDisplayTimezone = DropdownSettingOption.DISPLAY_TIMEZONE_LOCAL,
settingLinkProgressToSubtasks = false,
settingIsAccessibilityMode = false,
- isPullRefreshEnabled = true,
markdownEnabled = false,
player = null,
isListDragAndDropEnabled = true,
@@ -472,7 +445,6 @@ fun ListScreenList_JOURNAL() {
onLongClick = { _, _ -> },
listSettings = listSettings,
onExpandedChanged = { _, _, _, _, _ -> },
- onSyncRequested = { },
onSaveListSettings = { },
onUpdateSortOrder = { }
)
diff --git a/app/src/main/java/at/techbee/jtx/ui/list/ListScreenTabContainer.kt b/app/src/main/java/at/techbee/jtx/ui/list/ListScreenTabContainer.kt
index 705ab1382..6cf44d325 100644
--- a/app/src/main/java/at/techbee/jtx/ui/list/ListScreenTabContainer.kt
+++ b/app/src/main/java/at/techbee/jtx/ui/list/ListScreenTabContainer.kt
@@ -17,9 +17,8 @@ import android.location.LocationManager
import android.widget.Toast
import androidx.biometric.BiometricPrompt
import androidx.compose.animation.AnimatedVisibility
-import androidx.compose.foundation.ExperimentalFoundationApi
-import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
+import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.pager.HorizontalPager
@@ -45,6 +44,8 @@ import androidx.compose.material3.Scaffold
import androidx.compose.material3.SheetValue
import androidx.compose.material3.Tab
import androidx.compose.material3.Text
+import androidx.compose.material3.pulltorefresh.PullToRefreshBox
+import androidx.compose.material3.pulltorefresh.rememberPullToRefreshState
import androidx.compose.material3.rememberDrawerState
import androidx.compose.material3.rememberModalBottomSheetState
import androidx.compose.runtime.Composable
@@ -102,8 +103,7 @@ import kotlin.time.Duration.Companion.seconds
@OptIn(
- ExperimentalMaterial3Api::class,
- ExperimentalFoundationApi::class, ExperimentalPermissionsApi::class
+ ExperimentalMaterial3Api::class, ExperimentalPermissionsApi::class
)
@Composable
fun ListScreenTabContainer(
@@ -186,6 +186,10 @@ fun ListScreenTabContainer(
var showUpdateEntriesDialog by rememberSaveable { mutableStateOf(false) }
var showCollectionSelectorDialog by rememberSaveable { mutableStateOf(false) }
+ var isRefreshing by remember { mutableStateOf(false) }
+ val isPullRefreshEnabled = remember {
+ SyncUtil.availableSyncApps(context).any { SyncUtil.isSyncAppCompatible(it, context) } && settingsStateHolder.settingSyncOnPullRefresh.value
+ }
val goToEdit = listViewModel.goToEdit.observeAsState()
goToEdit.value?.let { icalObjectId ->
listViewModel.goToEdit.value = null
@@ -661,11 +665,11 @@ fun ListScreenTabContainer(
JtxNavigationDrawer(
drawerState,
mainContent = {
- Column {
+ Column(modifier = Modifier.fillMaxSize()) {
if(enabledTabs.size > 1) {
PrimaryTabRow(
- selectedTabIndex = pagerState.currentPage // adding the indicator might make a smooth movement of the tabIndicator, but Accompanist does not support all components (TODO: Check again in future) https://www.geeksforgeeks.org/tab-layout-in-android-using-jetpack-compose/
+ selectedTabIndex = pagerState.currentPage
) {
enabledTabs.forEach { enabledTab ->
Tab(
@@ -761,12 +765,36 @@ fun ListScreenTabContainer(
)
}
- Box {
- HorizontalPager(
- state = pagerState,
- userScrollEnabled = !filterSheetState.isVisible,
- verticalAlignment = Alignment.Top
- ) {
+ HorizontalPager(
+ state = pagerState,
+ userScrollEnabled = !filterSheetState.isVisible,
+ verticalAlignment = Alignment.Top,
+ modifier = Modifier.fillMaxSize()
+ ) { page ->
+
+ // TODO: Remove this stupid condition once PullToRefreshBox allows a disabled state!
+ if (isPullRefreshEnabled) {
+ PullToRefreshBox(
+ state = rememberPullToRefreshState(),
+ onRefresh = {
+ //TODO: Get rid of this stupid workaround with isRefreshing and delay once the new version properly makes the animation disappear!!!
+ isRefreshing = true
+ listViewModel.syncAccounts()
+ scope.launch {
+ delay(100)
+ isRefreshing = false
+ }
+ },
+ isRefreshing = isRefreshing,
+ contentAlignment = Alignment.TopCenter,
+ modifier = Modifier.fillMaxSize()
+ ) {
+ ListScreen(
+ listViewModel = listViewModel,
+ navController = navController
+ )
+ }
+ } else {
ListScreen(
listViewModel = listViewModel,
navController = navController
diff --git a/app/src/main/java/at/techbee/jtx/ui/list/ListViewModel.kt b/app/src/main/java/at/techbee/jtx/ui/list/ListViewModel.kt
index bcb108fde..aeefe9166 100644
--- a/app/src/main/java/at/techbee/jtx/ui/list/ListViewModel.kt
+++ b/app/src/main/java/at/techbee/jtx/ui/list/ListViewModel.kt
@@ -212,6 +212,9 @@ open class ListViewModel(application: Application, val module: Module) : Android
selectFromAllListQuery.postValue(ICal4List.constructQuery(
modules = listOf(Module.JOURNAL, Module.NOTE, Module.TODO),
searchText = searchText,
+ flatView = true,
+ orderBy = OrderBy.LAST_MODIFIED,
+ sortOrder = SortOrder.DESC,
hideBiometricProtected = if(isAuthenticated) emptyList() else ListSettings.getProtectedClassificationsFromSettings(_application)
))
}
diff --git a/app/src/main/java/at/techbee/jtx/ui/reusable/destinations/NavigationDrawerDestination.kt b/app/src/main/java/at/techbee/jtx/ui/reusable/destinations/NavigationDrawerDestination.kt
index ed326e4b7..9015d9b31 100644
--- a/app/src/main/java/at/techbee/jtx/ui/reusable/destinations/NavigationDrawerDestination.kt
+++ b/app/src/main/java/at/techbee/jtx/ui/reusable/destinations/NavigationDrawerDestination.kt
@@ -24,7 +24,7 @@ enum class NavigationDrawerDestination (
BOARD(
titleResource = R.string.navigation_drawer_board,
iconRes = R.drawable.ic_widget_jtx,
- navigationAction = { navHost, _ -> navHost.popBackStack(BOARD.name, false)}
+ navigationAction = { navHost, _ -> navHost.navigate(BOARD.name)}
),
PRESETS(
titleResource = R.string.navigation_drawer_presets,
diff --git a/app/src/main/java/at/techbee/jtx/ui/settings/SettingsScreen.kt b/app/src/main/java/at/techbee/jtx/ui/settings/SettingsScreen.kt
index f77e6a598..370fbd6d7 100644
--- a/app/src/main/java/at/techbee/jtx/ui/settings/SettingsScreen.kt
+++ b/app/src/main/java/at/techbee/jtx/ui/settings/SettingsScreen.kt
@@ -71,6 +71,7 @@ import at.techbee.jtx.ui.settings.DropdownSetting.SETTING_PROTECT_BIOMETRIC
import at.techbee.jtx.ui.settings.DropdownSetting.SETTING_THEME
import at.techbee.jtx.ui.settings.SwitchSetting.SETTING_ACCESSIBILITY_MODE
import at.techbee.jtx.ui.settings.SwitchSetting.SETTING_AUTO_EXPAND_ATTACHMENTS
+import at.techbee.jtx.ui.settings.SwitchSetting.SETTING_AUTO_EXPAND_PARENTS
import at.techbee.jtx.ui.settings.SwitchSetting.SETTING_AUTO_EXPAND_SUBNOTES
import at.techbee.jtx.ui.settings.SwitchSetting.SETTING_AUTO_EXPAND_SUBTASKS
import at.techbee.jtx.ui.settings.SwitchSetting.SETTING_DISABLE_ALARMS_FOR_READONLY
@@ -393,6 +394,13 @@ fun SettingsScreen(
settingsStateHolder.settingAutoExpandAttachments.value = it
SETTING_AUTO_EXPAND_ATTACHMENTS.saveSetting(it, settingsStateHolder.prefs)
})
+ SwitchSettingElement(
+ setting = SETTING_AUTO_EXPAND_PARENTS,
+ checked = settingsStateHolder.settingAutoExpandParents,
+ onCheckedChanged = {
+ settingsStateHolder.settingAutoExpandParents.value = it
+ SETTING_AUTO_EXPAND_PARENTS.saveSetting(it, settingsStateHolder.prefs)
+ })
}
ExpandableSettingsSection(
diff --git a/app/src/main/java/at/techbee/jtx/ui/settings/SettingsStateHolder.kt b/app/src/main/java/at/techbee/jtx/ui/settings/SettingsStateHolder.kt
index dd7f0a9cb..46b1423c6 100644
--- a/app/src/main/java/at/techbee/jtx/ui/settings/SettingsStateHolder.kt
+++ b/app/src/main/java/at/techbee/jtx/ui/settings/SettingsStateHolder.kt
@@ -19,7 +19,7 @@ class SettingsStateHolder(val context: Context) {
companion object {
private const val SETTINGS_PRO_INFO_SHOWN = "settingsProInfoShown"
- private const val PREFS_LAST_MODULE = "lastUsedModule"
+ const val PREFS_LAST_MODULE = "lastUsedModule"
private const val PREFS_DETAIL_TOP_APP_BAR_MODE = "detailTopAppBarMode"
}
@@ -36,6 +36,7 @@ class SettingsStateHolder(val context: Context) {
var settingAutoExpandSubtasks = mutableStateOf(SwitchSetting.SETTING_AUTO_EXPAND_SUBTASKS.getSetting(prefs))
var settingAutoExpandSubnotes = mutableStateOf(SwitchSetting.SETTING_AUTO_EXPAND_SUBNOTES.getSetting(prefs))
var settingAutoExpandAttachments = mutableStateOf(SwitchSetting.SETTING_AUTO_EXPAND_ATTACHMENTS.getSetting(prefs))
+ var settingAutoExpandParents = mutableStateOf(SwitchSetting.SETTING_AUTO_EXPAND_PARENTS.getSetting(prefs))
var settingShowProgressForMainTasks = mutableStateOf(SwitchSetting.SETTING_SHOW_PROGRESS_FOR_MAINTASKS.getSetting(prefs))
var settingShowProgressForSubTasks = mutableStateOf(SwitchSetting.SETTING_SHOW_PROGRESS_FOR_SUBTASKS.getSetting(prefs))
diff --git a/app/src/main/java/at/techbee/jtx/ui/settings/SwitchSetting.kt b/app/src/main/java/at/techbee/jtx/ui/settings/SwitchSetting.kt
index e82bb1c45..b9a0e2ee6 100644
--- a/app/src/main/java/at/techbee/jtx/ui/settings/SwitchSetting.kt
+++ b/app/src/main/java/at/techbee/jtx/ui/settings/SwitchSetting.kt
@@ -25,6 +25,7 @@ import androidx.compose.material.icons.outlined.Fullscreen
import androidx.compose.material.icons.outlined.MyLocation
import androidx.compose.material.icons.outlined.PublishedWithChanges
import androidx.compose.material.icons.outlined.RestartAlt
+import androidx.compose.material.icons.outlined.SubdirectoryArrowRight
import androidx.compose.material.icons.outlined.SwipeDown
import androidx.compose.material.icons.outlined.TaskAlt
import androidx.compose.material3.Icon
@@ -80,6 +81,15 @@ enum class SwitchSetting(
title = R.string.settings_default_expand_attachments,
default = false
),
+ SETTING_AUTO_EXPAND_PARENTS(
+ key = "settings_auto_expand_parents",
+ icon = { Icon(
+ Icons.Outlined.SubdirectoryArrowRight, null, modifier = Modifier.padding(
+ 16.dp
+ )) },
+ title = R.string.settings_default_expand_parents,
+ default = false
+ ),
SETTING_SHOW_PROGRESS_FOR_MAINTASKS(
key = "settings_show_progress_for_maintasks_in_list",
icon = { Icon(
diff --git a/app/src/main/java/at/techbee/jtx/widgets/ListWidget.kt b/app/src/main/java/at/techbee/jtx/widgets/ListWidget.kt
index 3b7507616..2fd749650 100644
--- a/app/src/main/java/at/techbee/jtx/widgets/ListWidget.kt
+++ b/app/src/main/java/at/techbee/jtx/widgets/ListWidget.kt
@@ -184,6 +184,19 @@ class ListWidget : GlanceAppWidget() {
)
}
+ val defaultOnSurfaceVariantColor = GlanceTheme.colors.onSurfaceVariant
+ val entryHeaderTextColor = remember(listWidgetConfig) {
+ if (listWidgetConfig.widgetColorEntries == null)
+ defaultOnSurfaceVariantColor
+ else
+ FixedColorProvider(
+ if(UiUtil.isDarkColor(entryColor.getColor(context)))
+ Color.White.copy(alpha = if(listWidgetConfig.widgetAlphaEntries < MIN_ALPHA_FOR_TEXT) MIN_ALPHA_FOR_TEXT else listWidgetConfig.widgetAlphaEntries)
+ else
+ Color.Black.copy(alpha = if(listWidgetConfig.widgetAlphaEntries < MIN_ALPHA_FOR_TEXT) MIN_ALPHA_FOR_TEXT else listWidgetConfig.widgetAlphaEntries)
+ )
+ }
+
GlanceTheme {
ListWidgetContent(
listWidgetConfig,
@@ -194,6 +207,7 @@ class ListWidget : GlanceAppWidget() {
textColor = textColor,
entryColor = entryColor,
entryTextColor = entryTextColor,
+ entryHeaderTextColor = entryHeaderTextColor,
onCheckedChange = { iCalObjectId, checked ->
scope.launch(Dispatchers.IO) {
val settingsStateHolder = SettingsStateHolder(context)
diff --git a/app/src/main/java/at/techbee/jtx/widgets/ListWidgetContent.kt b/app/src/main/java/at/techbee/jtx/widgets/ListWidgetContent.kt
index 45761015e..3f66a75e9 100644
--- a/app/src/main/java/at/techbee/jtx/widgets/ListWidgetContent.kt
+++ b/app/src/main/java/at/techbee/jtx/widgets/ListWidgetContent.kt
@@ -50,6 +50,7 @@ fun ListWidgetContent(
textColor: ColorProvider,
entryColor: ColorProvider,
entryTextColor: ColorProvider,
+ entryHeaderTextColor: ColorProvider,
onCheckedChange: (iCalObjectId: Long, checked: Boolean) -> Unit,
onOpenWidgetConfig: () -> Unit,
onAddNew: () -> Unit,
@@ -149,6 +150,7 @@ fun ListWidgetContent(
obj = entry.iCal4List,
entryColor = entryColor,
textColor = entryTextColor,
+ headerTextColor = entryHeaderTextColor,
checkboxPosition = listWidgetConfig.checkboxPosition,
showDescription = listWidgetConfig.showDescription,
onCheckedChange = onCheckedChange,
@@ -177,6 +179,7 @@ fun ListWidgetContent(
obj = subtask.iCal4List,
entryColor = entryColor,
textColor = entryTextColor,
+ headerTextColor = entryHeaderTextColor,
checkboxPosition = listWidgetConfig.checkboxPosition,
showDescription = listWidgetConfig.showDescription,
onCheckedChange = onCheckedChange,
@@ -204,6 +207,7 @@ fun ListWidgetContent(
obj = subnote.iCal4List,
entryColor = entryColor,
textColor = entryTextColor,
+ headerTextColor = entryHeaderTextColor,
checkboxPosition = listWidgetConfig.checkboxPosition,
showDescription = listWidgetConfig.showDescription,
onCheckedChange = onCheckedChange,
diff --git a/app/src/main/java/at/techbee/jtx/widgets/ListWidgetEntry.kt b/app/src/main/java/at/techbee/jtx/widgets/ListWidgetEntry.kt
index 1d45c04cc..53af4b4af 100644
--- a/app/src/main/java/at/techbee/jtx/widgets/ListWidgetEntry.kt
+++ b/app/src/main/java/at/techbee/jtx/widgets/ListWidgetEntry.kt
@@ -50,6 +50,7 @@ fun ListEntry(
obj: ICal4List,
entryColor: ColorProvider,
textColor: ColorProvider,
+ headerTextColor: ColorProvider,
checkboxPosition: CheckboxPosition,
showDescription: Boolean,
onCheckedChange: (iCalObjectId: Long, checked: Boolean) -> Unit,
@@ -57,8 +58,7 @@ fun ListEntry(
) {
val context = LocalContext.current
- val metaBarColor = ColorProvider(textColor.getColor(context).copy(alpha = 0.7f))
- val textStyleMetaInfo = TextStyle(fontStyle = FontStyle.Italic, fontSize = 12.sp, color = metaBarColor)
+ val textStyleMetaInfo = TextStyle(fontStyle = FontStyle.Italic, fontSize = 12.sp, color = headerTextColor)
val textStyleDateOverdue = textStyleMetaInfo.copy(color = ColorProvider(Color.Red), fontWeight = FontWeight.Bold)
val textStyleSummary = TextStyle(fontWeight = FontWeight.Bold, fontSize = 14.sp, color = textColor)
val textStyleDescription = TextStyle(color = textColor, fontSize = 12.sp)
@@ -108,7 +108,7 @@ fun ListEntry(
provider = ImageProvider(if (obj.module == Module.TODO.name) R.drawable.ic_widget_start else R.drawable.ic_start2),
contentDescription = context.getString(R.string.started),
modifier = GlanceModifier.size(imageSize).padding(end = 4.dp),
- colorFilter = ColorFilter.tint(metaBarColor)
+ colorFilter = ColorFilter.tint(textStyleMetaInfo.color)
)
Text(
text = ICalObject.getDtstartTextInfo(
@@ -128,7 +128,7 @@ fun ListEntry(
provider = ImageProvider(R.drawable.ic_widget_due),
contentDescription = context.getString(R.string.due),
modifier = GlanceModifier.size(imageSize).padding(end = 4.dp),
- colorFilter = ColorFilter.tint(metaBarColor)
+ colorFilter = ColorFilter.tint(textStyleMetaInfo.color)
)
Text(
text = ICalObject.getDueTextInfo(
@@ -149,7 +149,7 @@ fun ListEntry(
provider = ImageProvider(R.drawable.ic_priority),
contentDescription = context.getString(R.string.priority),
modifier = GlanceModifier.size(imageSize).padding(end = 4.dp),
- colorFilter = ColorFilter.tint(metaBarColor)
+ colorFilter = ColorFilter.tint(textStyleMetaInfo.color)
)
Text(
text = obj.priority.toString(),
@@ -164,7 +164,7 @@ fun ListEntry(
provider = ImageProvider(R.drawable.ic_status),
contentDescription = context.getString(R.string.status),
modifier = GlanceModifier.size(imageSize).padding(end = 4.dp),
- colorFilter = ColorFilter.tint(metaBarColor)
+ colorFilter = ColorFilter.tint(textStyleMetaInfo.color)
)
Text(
text = obj.xstatus
@@ -181,7 +181,7 @@ fun ListEntry(
provider = ImageProvider(R.drawable.ic_classification),
contentDescription = context.getString(R.string.classification),
modifier = GlanceModifier.size(imageSize).padding(end = 4.dp),
- colorFilter = ColorFilter.tint(metaBarColor)
+ colorFilter = ColorFilter.tint(textStyleMetaInfo.color)
)
Text(
text = Classification.getClassificationFromString(obj.classification)?.let { context.getString(it.stringResource) } ?: "",
diff --git a/app/src/main/res/values-ca/strings.xml b/app/src/main/res/values-ca/strings.xml
index 9e1eac891..6fc18439c 100644
--- a/app/src/main/res/values-ca/strings.xml
+++ b/app/src/main/res/values-ca/strings.xml
@@ -384,6 +384,7 @@ Gràcies!"
"Expandeix les tasques en llista per defecte"
"Expandeix les sub-notes en llista per defecte"
"Expandeix els adjunts en llista per defecte"
+ "Expandeix els elements superiors en llistes per defecte"
"Disculpa"
"Enrere"
"Detalls"
diff --git a/app/src/main/res/values-cs/strings.xml b/app/src/main/res/values-cs/strings.xml
index 64c468526..cc54618f9 100644
--- a/app/src/main/res/values-cs/strings.xml
+++ b/app/src/main/res/values-cs/strings.xml
@@ -383,6 +383,7 @@ Děkujeme vám!"
"Rozbalovat dílčí úkoly v seznamu ve výchozím nastavení"
"Rozbalovat dílčí poznámky v seznamu ve výchozím nastavení"
"Rozbalovat přílohy v seznamu ve výchozím nastavení"
+ "Ve výchozím nastavení rozbalovat nadřezené položky"
"Omlouváme se"
"Zpět"
"Podrobnosti"
diff --git a/app/src/main/res/values-de/strings.xml b/app/src/main/res/values-de/strings.xml
index d524774f8..fad6691d7 100644
--- a/app/src/main/res/values-de/strings.xml
+++ b/app/src/main/res/values-de/strings.xml
@@ -384,6 +384,7 @@ Danke!"
"Unteraufgaben standardmäßig erweitern"
"Unternotizen standardmäßig erweitern"
"Anhänge standardmäßig erweitern"
+ "Übergeordnete Einträge in der Liste standardmäßig erweitern"
"Sorry"
"Zurück"
"Details"
diff --git a/app/src/main/res/values-el/strings.xml b/app/src/main/res/values-el/strings.xml
index 142f5aeda..79f879cbd 100644
--- a/app/src/main/res/values-el/strings.xml
+++ b/app/src/main/res/values-el/strings.xml
@@ -382,6 +382,7 @@
"Ανάπτυξη των δευτερευουσών εργασιών στη λίστα από προεπιλογή"
"Ανάπτυξη των δευτερευουσών σημειώσεων στη λίστα από προεπιλογή"
"Ανάπτυξη των επισυναπτωμένων στην λίστα από προεπιλογή"
+ "Ανάπτυξη των κύριων επισυναπτωμένων στην λίστα από προεπιλογή"
"Συγνώμη"
"Πίσω"
"Λεπτομέριες"
diff --git a/app/src/main/res/values-fr/strings.xml b/app/src/main/res/values-fr/strings.xml
index e638cbad5..de922d5c8 100644
--- a/app/src/main/res/values-fr/strings.xml
+++ b/app/src/main/res/values-fr/strings.xml
@@ -358,6 +358,7 @@
"Afficher l'heure dans le fuseau horaire local"
"Afficher l'heure dans le fuseau horaire d'origine"
"Afficher l'heure en local et dans le fuseau horaire d'origine (vue détaillée seulement)"
+ "Police"
"Vous aimez jtx Board?"
"Le développement d'une application est complexe et la maintenance et le support sont des tâches difficiles. Si vous aimez cette application et si vous souhaitez en assurer le développement continu, pensez à faire un don :-)
Merci !"
@@ -382,6 +383,7 @@ Merci !"
"Développer les sous-tâches dans la liste par défaut"
"Développer les sous-notes dans la liste par défaut"
"Développer les pièces jointes dans la liste par défaut"
+ "Développer les parents en liste par défaut"
"Désolé"
"Retour"
"Détails"
@@ -521,6 +523,7 @@ Merci !"
"Alarmes en plein écran"
"Affiche les alarmes en plein écran lorsque l'appareil est verrouillé"
"Mode d'accessibilité"
+ "Assurer une taille de police minimale pour les petits élements"
"Veuillez autoriser les notifications en plein écran dans les paramètres du système."
"Synchroniser au démarrage de l'appli"
"Synchroniser lors du tirage au sort"
@@ -609,6 +612,7 @@ Merci !"
"Mettre à jour le widget"
"Note : Ceci est une fonctionnalité expérimentale! Des changements d'opacité réduits dans le thème de couleur peuvent ne pas être reflétés immédiatement!"
"Note : Ceci est une fonctionnalité expérimentale ! Les changements dans le thème de couleur ne seront pas reflétés ! Ne choisissez aucune couleur pour revenir à la valeur par défaut du système."
+ "Définir des catégories par défaut pour les nouvelles entrées depuis le widget"
"Opacité"
"Général"
"Fermer"
diff --git a/app/src/main/res/values-it/strings.xml b/app/src/main/res/values-it/strings.xml
index 5e9c86f0f..3677cf570 100644
--- a/app/src/main/res/values-it/strings.xml
+++ b/app/src/main/res/values-it/strings.xml
@@ -1,7 +1,7 @@
- "jtx Board sync Diari, Note e Attività"
+ "jtx Board sincronizza Diari, Note & Attività"
"sincronizza il contenuto della jtx Board con altre applicazioni come DAVx⁵"
@@ -49,7 +49,7 @@
"Tavola"
"Sincronizzazione"
"Informazioni / Licenza"
- "Diari, Note ed Attività"
+ "diari, note & attività"
"Impostazioni"
"Notizie e aggiornamenti"
"Link esterni"
@@ -102,7 +102,7 @@
"Aggiungi link allegato"
"Aggiungi una sottoattività"
"Aggiunta rapida sottoattività"
- "Aggiunta rapida subnota"
+ "Aggiunta rapida sottonota"
"Aggiungi link allegato"
"Ripeti ogni"
"in poi"
@@ -157,7 +157,7 @@
Mostra l\'avanzamento delle sottoattività nell\'elenco
Mostra i progressi per le attività principali
"Impostazioni dell'app"
- "Seleziona Tipo MI per le note audio"
+ "Seleziona formato per le note audio"
"Sincronizza con %1$s"
"jtx Board non fornisce la sincronizzazione del server, ma supporta la sincronizzazione tramite DAVx5. Questo metodo ti permetterà di utilizzare un server CalDAV-compatibile di tua scelta per memorizzare, eseguire il backup e sincronizzare i tuoi dati."
@@ -184,7 +184,7 @@
"Grazie a"
"jtx Board è un'app open source che apprezza la partecipazione e il contributo della comunità open source. In questa pagina vorremmo attribuire gli sforzi dei membri della comunità per le traduzioni."
"Se desideri modificare/aggiungere traduzioni o aggiungere nuove lingue a questa app, sentiti libero di unirti al progetto jtx Board sulla piattaforma di traduzione Crowdin:"
- "Partecipa a Crowdin.com"
+ "Partecipa su Crowdin.com"
"Congratulazioni, questa è la tua prima annotazione nel diario :-)"
"I Diari possono essere utilizzati per conservare i tuoi appunti per una data specifica. Utilizzare questa funzionalità ad esempio per i protocolli, i verbali delle riunioni, le voci del diario e così via. Se modifichi questa voce, vedrai le opzioni per aggiungere categorie, partecipanti, allegati, … Sentiti libero di eliminare questa voce quando vuoi!"
"Congratulazioni, questa è la tua prima nota :-)"
@@ -192,7 +192,7 @@
"Congratulazioni, questa è la tua prima voce di Attività :-)"
"Oltre ai Diari e alle Note, le Attività possono avere un inizio pianificato, una data di scadenza e una data di completamento. Possono essere verificati al termine o è possibile impostare un avanzamento. Modifica questa voce per controllare tutte le opzioni :-)"
"#PrimiPassi"
- "Salva e modifica"
+ "Salva & modifica"
"Salva & nuovo"
"Salva & chiudi"
"Registra allegato audio"
@@ -200,7 +200,7 @@
"Aggiungere contenuto a un Diario, una Nota o un'Attività?"
"Aggiungi"
"Modifica"
- "Resettare"
+ "Reimposta"
"Applica"
"n/d"
"Collezione"
@@ -217,7 +217,7 @@
"All'inizio"
"Alla scadenza"
"prima dell'inizio"
- "Dopo l'inizio"
+ "dopo l'inizio"
"prima della scadenza"
"dopo la scadenza"
"minuti"
@@ -235,7 +235,7 @@
"Eliminare \"%1$s\"?"
"La cancellazione di una collezione cancellerà anche tutti i diari, le note e le attività all'interno di questa collezione. Questo non può essere annullato. Sei sicuro di voler continuare?"
"Aggiungi collezione locale"
- "Notizie e aggiornamenti"
+ "Notizie & Note di Rilascio"
"Colore"
"Nessuna priorità"
"1 - Più alto"
@@ -273,7 +273,7 @@
"Relativo a"
"Commenti"
"Allegati"
- "Notificazioni"
+ "Notifiche"
"Ricorrenza"
"Eccezioni"
"Aggiunte"
@@ -319,6 +319,7 @@
Senza risorse
Ordina sottoattività per
Ordina note collegate per
+ "Trascina & Rilascia"
"Nessun filtro"
"Altro (%1$d)"
"Meno"
@@ -382,6 +383,7 @@ Grazie!"
"Espansione predefinita delle sottoattività nell'elenco"
"Espansione predefinita delle note secondarie nell'elenco"
"Espansione predefinita degli allegati nell'elenco"
+ "Espansione predefinita dei genitori nell'elenco"
"Spiacente"
"Indietro"
"Dettagli"
@@ -392,9 +394,12 @@ Grazie!"
"Inizio (giorno)"
"Inizio (settimana)"
"Inizio (mese)"
+ "Scadenza (giorno)"
"Scadenza (settimana)"
"Scadenza (mese)"
"Settimana %1$d/%2$d"
+ "Riassunto/Descrizione"
+ "Stato/Classificazione/Priorità"
"Fuso orario"
"Non impostato"
"Inverti selezione"
@@ -442,8 +447,8 @@ Grazie!"
"Scollega dal genitore"
"Rimuovere la relazione come sotto-voce? La voce rimarrà come voce autonoma."
"Modifica commento"
- "Aggiungere nota secondaria"
- "Modifica sottoattività"
+ "Aggiungere sotto-nota"
+ "Modifica sotto-attività"
"Modifica nota secondaria"
"jtx Board visualizza le notifiche quando gli allarmi sono in scadenza. Per utilizzare questa funzione, concedere l'autorizzazione alle notifiche."
"jtx Board può usare la vostra posizione per zoomare automaticamente verso la vostra posizione quando si usano le mappe. Se si desidera utilizzare questa funzione, concedere l'autorizzazione alla localizzazione grossolana."
@@ -470,16 +475,19 @@ Grazie!"
"Staccare questo elemento dalla serie ti permetterà di avere sotto-attività indipendenti o note collegate, ma non ci sarà più link alla serie originale. Vorresti continuare?"
"Attenzione: Questa operazione non può essere annullata!"
"Scollega dalla serie"
+ "Applicazione di sincronizzazione obsoleta"
"La tua versione attuale di %1$s non è compatibile con questa versione di jtx Board. Si prega di aggiornare a %1$s %2$s o successivamente! La sincronizzazione attraverso %1$s è attualmente sospesa."
"Salva la configurazione del filtro corrente"
- "Mio filtro"
+ "Il mio filtro"
"Aggiungi/modifica preimpostazione categoria"
"Aggiungi/modifica preimpostazione risorsa"
"Aggiungi/modifica preimpostato di stato"
"Aggiungi voce audio"
"Vista compatta"
"Vista Kanban"
+ "Vista per settimana"
"Impostazioni delle attività"
+ "Impostazioni Allarmi"
"Impostazioni Attività (stato/progresso)"
"Impostazioni Di Sincronizzazione"
"Impostare una data di inizio predefinita per le attività"
@@ -509,6 +517,8 @@ Grazie!"
"Mantieni lo stato, avanzamento & completato in sincronizzazione"
"Attenzione: Questa è una funzione sperimentale"
"Crea nuove voci con la posizione corrente"
+ "Concedi l'accesso alla tua posizione durante l'utilizzo di questa app per utilizzare questa funzionalità."
+ "Allarmi persistenti"
"Mantieni le notifiche fino al termine o al rinvio"
"Allarmi a schermo intero"
"Mostra gli allarmi a schermo intero quando il dispositivo è bloccato"
@@ -531,11 +541,15 @@ Grazie!"
"Seleziona lingua"
"Sistema predefinito"
"Filtri speciali"
- "Filtro preimpostati"
+ "Filtri preimpostati"
"Si prega di aggiungere/aggiornare/eliminare le preimpostazioni del filtro dal menu filtro nella vista elenco."
"Qualsiasi"
"Tutti/e"
"Nessuno/a"
+ "Data: %1$s - %2$s"
+ "Inizi(at)o: %1$s - %2$s"
+ "Scadenza: %1$s - %2$s"
+ "Completato: %1$s - %2$s"
"Data nel passato"
"Oggi"
@@ -555,6 +569,7 @@ Grazie!"
Voci biometriche protette sbloccate
"Allarme automatico"
"Sempre in scadenza"
+ "Sempre al salvataggio (sperimentale)"
"Attivare per creare automaticamente gli allarmi. Scegliere ´\"Sempre attivo\" per non creare un allarme, ma per essere avvisati in ogni caso quando un'attività è in scadenza."
"Proteggi le voci con la biometria"
"Questa funzione nasconde le voci selezionate fino a quando non vengono sbloccate con dati biometrici, ma non crittografa/decifrano i dati in background."
@@ -568,7 +583,7 @@ Grazie!"
"Senza data di scadenza"
"Aggiungere una raccolta locale o sincronizzare una raccolta remota che supporti questo modulo."
"Quindi ordinare per"
- "Gruppo per"
+ "Raggruppa per"
"Il raggruppamento è disponibile per l'elenco e la vista compatta"
"Salva come preimpostato"
"Vista piana"
@@ -597,6 +612,7 @@ Grazie!"
"Aggiornamento del widget"
"Nota: Questa è una funzione sperimentale! Con cambiamenti di opacità ridotti nel tema di colore potrebbe non essere riflessa immediatamente!"
"Nota: Questa è una funzione sperimentale! Le modifiche al tema dei colori non saranno riflesse! Scegli nessun colore per tornare al valore predefinito di sistema."
+ "Imposta categorie predefinite per le nuove voci dal widget"
"Opacità"
"Generale"
"Ripiega"
@@ -607,8 +623,8 @@ Grazie!"
"Sfondo del widget"
"Sfondo delle voci"
"Mostra descrizione"
- "Vero Scuro (AMOLED)"
- "Contrasto (e-Inchiostro)"
+ "Nero Puro (AMOLED)"
+ "Contrasto (e-Ink)"
"Impostazioni diari"
"Impostazioni Delle Note"
"Impostare una data/ora predefinita per i diari"
@@ -640,6 +656,7 @@ Grazie!"
\"Stato esteso
Filtri attivi:
"Kanban"
+ "Colonne Kanban"
basato su stati standard
basato su stati estesi
basato sulla prima categoria
@@ -652,4 +669,12 @@ Grazie!"
"jtx Board può avvisarti quando sei vicino alle coordinate date. Si prega di impostare l'autorizzazione di posizione per 'Consenti tutto il tempo' e concedere l'autorizzazione di notifica per utilizzare questa funzione."
"Geofence attivato"
"jtx Board ha bisogno del permesso di pianificare gli avvisi esatti, altrimenti le notifiche di allarme potrebbero essere ritardate. Si prega di concedere questa autorizzazione per utilizzare questa funzione."
+ "Chiama %1$s"
+ "E-mail a %1$s"
+ Crea sottoattività in massa
+ Crea note collegate in massa
+ Il testo sembra contenere più sottoattività. Vuoi creare %d sottoattività?
+ Il testo sembra contenere più note collegate. Vuoi creare %d note collegate?
+ Crea multipli
+ Crea singolo
diff --git a/app/src/main/res/values-ja/strings.xml b/app/src/main/res/values-ja/strings.xml
index 1c461f6fa..b06f2e7b7 100644
--- a/app/src/main/res/values-ja/strings.xml
+++ b/app/src/main/res/values-ja/strings.xml
@@ -382,6 +382,7 @@
"デフォルトでサブ ToDo を一覧に展開"
"デフォルトでサブメモを一覧に展開"
"デフォルトで添付ファイルを一覧に展開"
+ "デフォルトでリストに親を展開する"
"申し訳ありません"
"戻る"
"詳細"
diff --git a/app/src/main/res/values-nl/strings.xml b/app/src/main/res/values-nl/strings.xml
index d88a105a4..e2fd248e5 100644
--- a/app/src/main/res/values-nl/strings.xml
+++ b/app/src/main/res/values-nl/strings.xml
@@ -383,6 +383,7 @@ Dank u!"
"Subtaken standaard uitvouwen in lijst"
"Subtaken standaard uitvouwen in lijst"
"Subtaken standaard uitvouwen in lijst"
+ "Bovenliggende elementen automatisch uitklappen in lijst"
"Sorry"
"Terug"
"Details"
diff --git a/app/src/main/res/values-pa/strings.xml b/app/src/main/res/values-pa/strings.xml
index 41114f99a..ee7fa5f22 100644
--- a/app/src/main/res/values-pa/strings.xml
+++ b/app/src/main/res/values-pa/strings.xml
@@ -19,7 +19,8 @@
"ਲੰਬਕਾਰ"
"ਅਨਲਿੰਕ ਕਰੋ"
"ਬੰਦ"
- "ਮਨਜ਼ੂਰੀਆਂ"
+ "ਟਿਕਾਣੇ ਦੀ ਮਨਜ਼ੂਰੀ ਰੋਕੀ ਗਈ"
+ "ਮਨਜੂਰੀਆਂ"
"ਮੌਜੂਦਾ ਟਿਕਾਣਾ"
"ਜਰਨਲ ਸ਼ਾਮਲ ਕਰੋ"
"ਨੋਟ ਸ਼ਾਮਲ ਕਰੋ"
@@ -105,6 +106,8 @@
"ਅਟੈਚਮੈਂਟ ਲਿੰਕ ਜੋੜੋ"
"ਰੋਜ਼ਾਨਾ ਦੁਹਰਾਓ"
"ਚਾਲੂ"
+ "ਤੇ"
+ "ਮਹੀਨੇ ਦਾ ਦਿਨ"
"ਅਖੀਰਲਾ"
"ਵਾਰੀ"
"ਦੁਹਰਾਓ ਨੂੰ ਸੈੱਟ ਕਰਨ ਲਈ ਇੱਕ ਸ਼ੁਰੂਆਤੀ ਮਿਤੀ ਦੀ ਲੋੜ ਹੁੰਦੀ ਹੈ!"
@@ -113,6 +116,15 @@
"ਸਮਾਂ ਜੋੜੋ"
"ਸਮੇਂ ਵਿੱਚ ਤਰਮੀਮ ਕਰੋ"
"ਸਮਾਂ ਖੇਤਰ ਸ਼ਾਮਲ ਕਰੋ"
+ "ਸਮਾਂ ਖੇਤਰ ਸ਼ਾਮਲ ਕਰੋ"
+ "\"%1$s\" ਮਿਟਾਓ?"
+ "ਇਸ ਐਂਟਰੀ ਨੂੰ ਖ਼ਾਰਜ ਕਰਨਾ ਹੈ?"
+ "ਮੁਕੰਮਲ ਹੋਏ ਸਾਰੇ ਕਾਰਜ ਮਿਟਾਉਣੇ ਹਨ?"
+ "ਧਿਆਨ ਦਿਓ: ਉਪ-ਕਾਰਜ ਆਪਣੀ ਸਥਿਤੀ ਤੋਂ ਸੁਤੰਤਰ ਤੌਰ 'ਤੇ ਮਿਟਾ ਦਿੱਤੇ ਜਾਂਦੇ ਹਨ ਜੇਕਰ ਉਹਨਾਂ ਦੇ ਪਿੱਤਰ ਕਾਰਜ ਦੀ ਕੀਤੇ ਵਜੋਂ ਨਿਸ਼ਾਨਦੇਹੀ ਕਰ ਦਿੱਤੀ ਗਈ ਹੋਵੇ। ਇਸ ਕਾਰਵਾਈ ਨੂੰ ਅਣਕੀਤਾ ਨਹੀਂ ਕੀਤਾ ਜਾ ਸਕਦਾ!"
+ "ਕੀ ਤੁਸੀਂ ਯਕੀਨੀ ਤੌਰ 'ਤੇ \"%1$s\" ਨੂੰ ਮਿਟਾਉਣਾ ਚਾਹੁੰਦੇ ਹੋ?"
+ "ਕੀ ਤੁਸੀਂ ਯਕੀਨੀ ਤੌਰ 'ਤੇ ਇਸ ਐਂਟਰੀ ਨੂੰ ਰੱਦ ਕਰਨਾ ਚਾਹੁੰਦੇ ਹੋ? ਇਹ ਐਂਟਰੀ ਸੁਰੱਖਿਅਤ ਨਹੀਂ ਕੀਤੀ ਜਾਵੇਗੀ।"
+ "ਨਿਯਤ ਮਿਤੀ ਸ਼ੁਰੂਆਤੀ ਮਿਤੀ ਤੋਂ ਪਹਿਲਾਂ ਨਹੀਂ ਹੋ ਸਕਦੀ।"
+ "ਐਪ ਦੀ ਇਜਾਜ਼ਤ"
diff --git a/app/src/main/res/values-pl/strings.xml b/app/src/main/res/values-pl/strings.xml
index 903e1b7df..1f6ad98d2 100644
--- a/app/src/main/res/values-pl/strings.xml
+++ b/app/src/main/res/values-pl/strings.xml
@@ -207,8 +207,20 @@
"Właściciel: %1$s"
"Połącz z zadaniem głównym"
"Zadanie główne"
+ "Podzadanie/-notatka"
+ "Załącz wybrane jako …"
"Kolekcje"
+ "Szablony"
+ "Data/Czas"
+ "Czas trwania"
+ "Na początku"
+ "W terminie"
+ "przed rozpoczęciem"
+ "po rozpoczęciu"
+ "przed terminem"
+ "po terminie"
+ "Minut"
"Godzina(-ny)"
"Dzień/Dni"
@@ -216,10 +228,14 @@
"Notatki: %1$s"
"Zadania: %1$s"
+ "Kolekcje są zbiorem wpisów podobnie foldery z plikami. Możesz tworzyć nowe lokalne kolekcje za pomocą menu lub zsynchronizować nowe kolekcje zdalne, jeśli masz zainstalowaną aplikację synchronizacji (np. DAVx5)."
+ "Menu kolekcji"
"Dodaj lokalną Kolekcję"
"Edytuj lokalną Kolekcję"
"Usunąć \"%1$s\"?"
+ "Usunięcie kolekcji spowoduje również usunięcie wszystkich dzienników, notatek i zadań w tej kolekcji. Tej operacji nie można cofnąć. Czy na pewno chcesz kontynuować?"
"Dodaj lokalną Kolekcję"
+ "Aktualności & Informacje o wersji"
"Kolor"
"Bez priorytetu"
"Najwyższy"
@@ -232,16 +248,27 @@
"tydzień/tygodnie"
"miesiąc/miesiące"
"rok/lata"
+ "Zapisano pomyślnie"
+ "Wystąpił błąd podczas zapisywania wybranego pliku!"
+ "Dodaj zdalną kolekcję (%1$s)"
+ "Pokaż w %1$s"
"Wyeksportuj jako .ics"
"Dziennik"
"Notatka"
"Zadanie"
"Konto"
+ "Stan"
"Klasyfikacja"
"Kategoria"
+ "Zasób"
"Priorytet"
+ "Tylko do odczytu"
+ "Przesyłanie w toku"
+ "Adres URL"
"Lokalizacja"
"Uczestnicy"
+ "Zasoby"
+ "Organizer"
"Kontakt"
"Związane z"
"Komentarze"
@@ -249,17 +276,40 @@
"Alarmy"
"Powtarzanie"
"Wyjątki"
+ "Dodatki"
"Tytuł"
"Opis"
"Szukaj"
+ Szukaj dzienników
+ Szukaj notatek
+ Szukaj zadań
"Filtr"
+ "Widoczność"
+ "Kolejność"
"Synchornizuj teraz"
+ "Do"
+ "Ukończone"
+ "Rozpoczęto"
+ "Dodaj czas"
+ "Postęp"
"Kategorie"
"Podzadania"
+ "Połączenie z zadaniem głównym"
"Niski"
"Niższy"
"Najniższy"
+ "Termin w przyszłości"
+ "Ten wpis jest częścią serii."
+ "Ten wpis powtarza się co"
+ "Przenieś wszystkie wpisy z \"%1$s\" do"
+ "Uwaga: Można wybrać tylko kolekcje z możliwością zapisu i kolekcje z obsługą tych samych komponentów (dzienniki, notatki, zadania)."
"Przenieść wpisy"
+ "Brak czasu"
+ "Nie wybrano daty"
+ "Bez daty rozpoczęcia"
+ "Bez terminu zakończenia"
+ "Bez daty wykonania"
+ "Pokaż tylko pasujące wpisy podrzędne"
"Utworzono"
"Ostatnio zmodyfikowano"
"Importuj z .ics"
@@ -277,6 +327,7 @@
"Dziękujemy za zakup jtx Board Pro!"
"Dziękujemy!"
"Widok siatki"
+ "Dzienniki"
"Cofnij"
"Szczegóły"
"Odtwórz"
diff --git a/app/src/main/res/values-pt/strings.xml b/app/src/main/res/values-pt/strings.xml
index 7e4658b32..d6334f112 100644
--- a/app/src/main/res/values-pt/strings.xml
+++ b/app/src/main/res/values-pt/strings.xml
@@ -161,10 +161,20 @@
"Sincronizar com %1$s"
"jtx Board não fornece sincronização com servidor por si mesmo, mas suporta a sincronização pelo DAVx⁵. Esse método permite que você use qualquer servidor CalDAV de sua escolha para armazenar, fazer backup e sincronizar seus dados."
"kSync é um aplicativo baseado no DAVx⁵ desenvolvido por Infomaniak especialmente para seus serviços. Enquanto o DAVx⁵ está aberto a qualquer servidor CalDAV compatível, kSync só permite sincronização com contas Infomaniak."
+ "Parabéns! :-)"
+ "Nós detectamos %1$s no seu telefone."
+ "Instruções de instalação"
+ "Confira %1$s!"
"Não detectamos %1$s no seu telefone."
"Saiba mais sobre %1$s"
"Baixar %1$s"
+ "Adicione uma conta em %1$s"
+ "Falhou em abrir %1$s, por favor, abra o app manualmente."
+ "Olá, eu sou Patrick, o desenvolvedor do jtx Board. Eu estou dedicando muito tempo e esforço neste app que eu estou oferecendo para você de graça. Se você gosta do meu app, por favor mande algum carinho e faça uma pequena doação!"
+ "Obrigado!"
+ "Doar com"
+ "Se você gostaria de considerar outro método de doação, por favor, visite nosso site:"
"Nenhum aplicativo foi encontrado para abrir este arquivo/URL."
"Item recorrente agora é uma exceção."
"Tarefas concluídas excluídas (%d)."
@@ -176,6 +186,8 @@
"Parabéns, esta é a sua primeira entrada no diário :-)"
"Os diários podem ser usados para guardar as suas notas para uma data específica. Utilizar esta funcionalidade por exemplo para protocolos, atas de reunião, entradas do diário e assim por diante. Se você editar esta postagem, você verá as opções para adicionar categorias, participantes, anexos, … Sinta-se à vontade para apagar esta entrada quando quiser!"
"Parabéns, esta é a sua primeira nota :-)"
+ "Notas são notas tradicionais e não estão ligadas a uma data específica. Como entradas de diário, você pode adicionar anexos, participantes e mais quando edita ou adiciona uma entrada. Aliás, você pode também adicionar subtarefas a qualquer entrada, não importa se é uma entrada de diário, nota ou tarefa!"
+ "Parabéns, esta é a sua primeira tarefa :-)"
"Vincular a um nível superior"
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index f111b7d4a..8e3246340 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -397,6 +397,7 @@ Thank you!"
"Expand subtasks in list by default"
"Expand subnotes in list by default"
"Expand attachments in list by default"
+ "Expand parents in list by default"
"https://www.paypal.com/donate?hosted_button_id=8BVX7PUVVTCWY"
"https://jtx.techbee.at/contribute"
"Sorry"
diff --git a/fastlane/metadata/android/en-US/changelogs/209000011.txt b/fastlane/metadata/android/en-US/changelogs/209000011.txt
new file mode 100644
index 000000000..61e12aa34
--- /dev/null
+++ b/fastlane/metadata/android/en-US/changelogs/209000011.txt
@@ -0,0 +1,4 @@
+* Improved alarm handling
+* Version updates and several technical upgrades
+
+Attention: From this version the minimum required Android version is Android 6. Due to dependencies Android 5 is not supported anymore.
\ No newline at end of file
diff --git a/fastlane/metadata/android/en-US/changelogs/209010003.txt b/fastlane/metadata/android/en-US/changelogs/209010003.txt
new file mode 100644
index 000000000..aaaa697b4
--- /dev/null
+++ b/fastlane/metadata/android/en-US/changelogs/209010003.txt
@@ -0,0 +1,2 @@
+- Show a notification immediately when an alarm is set in the past
+- Allow linking entries to parents that can be sub-entries
\ No newline at end of file
diff --git a/fastlane/metadata/android/en-US/changelogs/209020004.txt b/fastlane/metadata/android/en-US/changelogs/209020004.txt
new file mode 100644
index 000000000..e5a09da28
--- /dev/null
+++ b/fastlane/metadata/android/en-US/changelogs/209020004.txt
@@ -0,0 +1,2 @@
+- Open filtered list from collections overview
+- Added setting to automatically collapse/expand parents in list
\ No newline at end of file
diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml
index 329b2e0f5..515fe4330 100644
--- a/gradle/libs.versions.toml
+++ b/gradle/libs.versions.toml
@@ -2,57 +2,57 @@
[versions]
amazonAppstoreSdk = "3.0.5"
-android-agp = "8.5.0"
-android-desugaring = "2.0.4"
-androidx-activityCompose = "1.9.0"
+android-agp = "8.5.2"
+android-desugaring = "2.1.2"
+androidx-activityCompose = "1.9.3"
androidx-appcompat = "1.7.0"
androidx-arch = "2.2.0"
androidx-core = "1.13.1"
-androidx-lifecycle = "2.8.3"
+androidx-lifecycle = "2.8.7"
androidx-preference = "1.2.1"
androidx-test-core = "1.6.1"
-androidx-test-runner = "1.6.1"
+androidx-test-runner = "1.6.2"
androidx-test-rules = "1.6.1"
androidx-test-junit = "1.2.1"
-androidx-work = "2.9.0"
-annotation = "1.8.0"
+androidx-work = "2.9.1"
+annotation = "1.9.1"
biometricKtx = "1.2.0-alpha05"
bitfire-ical4android = "83cda23ceb"
-calendarCompose = "2.5.2"
-coilCompose = "2.6.0"
-compose-accompanist = "0.34.0"
-compose-bom = "2024.06.00"
-compose-navigation = "2.7.7"
-glance = "1.1.0"
+calendarCompose = "2.6.0"
+coilCompose = "2.7.0"
+compose-accompanist = "0.36.0"
+compose-bom = "2024.10.01"
+compose-navigation = "2.8.3"
+glance = "1.1.1"
godaddy-colorpicker = "0.7.0"
#huawei = "1.8.1.300"
#huawei-iap = "6.10.0.300"
-kotlin = "2.0.0"
-kotlinx-coroutines = "1.8.1"
-kotlinxSerializationJson = "1.7.1"
+kotlin = "2.0.21"
+kotlinx-coroutines = "1.9.0"
+kotlinxSerializationJson = "1.7.3"
# see https://github.com/google/ksp/releases for version numbers
-ksp = "2.0.0-1.0.22"
-libphonenumber = "8.13.40"
-mapsCompose = "6.0.0"
+ksp = "2.0.21-1.0.26"
+libphonenumber = "8.13.49"
+mapsCompose = "6.1.1"
markdowntext = "1.3.2"
-mikepenz-aboutLibraries = "11.2.2"
+mikepenz-aboutLibraries = "11.2.3"
mockitoCore = "5.12.0"
-osmdroidAndroid = "6.1.18"
+osmdroidAndroid = "6.1.20"
playServicesLocation = "21.3.0"
playServicesMaps = "19.0.0"
-profileinstaller = "1.3.1"
-reorderable = "2.1.1"
-uiTextGoogleFonts = "1.6.8"
+profileinstaller = "1.4.1"
+reorderable = "2.4.0"
+uiTextGoogleFonts = "1.7.5"
room = "2.6.1"
volley = "1.2.1"
# gplay and managed build variants
-android-billing = "7.0.0"
-android-review = "2.0.1"
+android-billing = "7.1.1"
+android-review = "2.0.2"
espressoCore = "3.6.1"
uiautomator = "2.3.0"
-benchmarkMacroJunit4 = "1.2.4"
-baselineprofile = "1.2.4"
+benchmarkMacroJunit4 = "1.3.3"
+baselineprofile = "1.3.3"
[libraries]
amazon-appstore-sdk = { module = "com.amazon.device:amazon-appstore-sdk", version.ref = "amazonAppstoreSdk" }