diff --git a/app/src/main/java/ca/pkay/rcloneexplorer/Activities/TriggerActivity.kt b/app/src/main/java/ca/pkay/rcloneexplorer/Activities/TriggerActivity.kt index 25fc1713..acedf616 100644 --- a/app/src/main/java/ca/pkay/rcloneexplorer/Activities/TriggerActivity.kt +++ b/app/src/main/java/ca/pkay/rcloneexplorer/Activities/TriggerActivity.kt @@ -29,11 +29,14 @@ class TriggerActivity : AppCompatActivity() { companion object { const val ID_EXTRA = "TRIGGER_EDIT_ID" + const val ID_ALL_TASKS = -1000L + const val UNICODE_CHAR_RANGE = -10_000_000L } private lateinit var mTrigger: Trigger private lateinit var dbHandler: DatabaseHandler private var mTaskList: List = ArrayList() + private var firstCharOfTasksUnique: List = ArrayList() private lateinit var mCardInterval: CardView private lateinit var mCardWeekday: CardView @@ -87,6 +90,14 @@ class TriggerActivity : AppCompatActivity() { dbHandler = DatabaseHandler(this) mTaskList = dbHandler.allTasks + if (this.mTaskList.isNotEmpty()) { + val firstCharsOfTaskTitles : HashSet = HashSet() + for (i in this.mTaskList.indices) { + firstCharsOfTaskTitles.add(this.mTaskList[i].title.trim().uppercase().first()) + } + firstCharOfTasksUnique = firstCharsOfTaskTitles.toList().sortedBy { it.toString() } + } + val extras = intent.extras val triggerId: Long if (extras != null) { @@ -195,7 +206,14 @@ class TriggerActivity : AppCompatActivity() { mTargetDropdown.onItemSelectedListener = object : AdapterView.OnItemSelectedListener { override fun onItemSelected(parent: AdapterView<*>?, view: View, pos: Int, id: Long) { - mTrigger.triggerTarget = mTaskList[pos].id + if (pos == (mTaskList.size)) { + mTrigger.triggerTarget = ID_ALL_TASKS + } else if (pos > (mTaskList.size)) { + val charForGrouping = firstCharOfTasksUnique[pos - mTaskList.size - 1] + mTrigger.triggerTarget = UNICODE_CHAR_RANGE - charForGrouping.code.toLong() + } else { + mTrigger.triggerTarget = mTaskList[pos].id + } } override fun onNothingSelected(parent: AdapterView<*>?) {} @@ -213,10 +231,14 @@ class TriggerActivity : AppCompatActivity() { * Set up Task-Target Dropdown */ private fun setUpTargetsDropdown() { - val items = arrayOfNulls(this.mTaskList.size) + val items = arrayOfNulls(if (this.mTaskList.size == 0) 0 else (this.mTaskList.size + firstCharOfTasksUnique.size + 1)) for (i in this.mTaskList.indices) { items[i] = this.mTaskList[i].title } + if (this.mTaskList.size > 0) items[this.mTaskList.size] = this.resources.getString(R.string.sync_option_all_tasks_asc) + for (i in firstCharOfTasksUnique.indices) { + items[i + this.mTaskList.size + 1] = this.resources.getString(R.string.sync_option_all) + " " + firstCharOfTasksUnique[i] + this.resources.getString(R.string.sync_option_all_tasks_prefixed_asc) + } val adapter = ArrayAdapter(this, android.R.layout.simple_spinner_dropdown_item, items) mTargetDropdown.adapter = adapter } @@ -258,8 +280,15 @@ class TriggerActivity : AppCompatActivity() { //Todo properly populate the fields for (task in mTaskList) { - if (task.id == mTrigger.triggerTarget) { + if (mTrigger.triggerTarget == ID_ALL_TASKS) { + mTargetDropdown.setSelection(mTaskList.size) + } else if (task.id == mTrigger.triggerTarget) { mTargetDropdown.setSelection(mTaskList.indexOf(task)) + } else if (UNICODE_CHAR_RANGE - mTrigger.triggerTarget >= 0) { + val firstChar = (UNICODE_CHAR_RANGE - mTrigger.triggerTarget).toInt().toChar() + if (firstCharOfTasksUnique.contains(firstChar)) { + mTargetDropdown.setSelection(mTaskList.size + firstCharOfTasksUnique.indexOf(firstChar) + 1) + } } } } diff --git a/app/src/main/java/ca/pkay/rcloneexplorer/RecyclerViewAdapters/TriggerRecyclerViewAdapter.java b/app/src/main/java/ca/pkay/rcloneexplorer/RecyclerViewAdapters/TriggerRecyclerViewAdapter.java index 09d558f3..acb07045 100644 --- a/app/src/main/java/ca/pkay/rcloneexplorer/RecyclerViewAdapters/TriggerRecyclerViewAdapter.java +++ b/app/src/main/java/ca/pkay/rcloneexplorer/RecyclerViewAdapters/TriggerRecyclerViewAdapter.java @@ -1,6 +1,8 @@ package ca.pkay.rcloneexplorer.RecyclerViewAdapters; +import static ca.pkay.rcloneexplorer.Activities.TriggerActivity.ID_ALL_TASKS; +import static ca.pkay.rcloneexplorer.Activities.TriggerActivity.UNICODE_CHAR_RANGE; import static ca.pkay.rcloneexplorer.Items.Trigger.TRIGGER_DAY_FRI; import static ca.pkay.rcloneexplorer.Items.Trigger.TRIGGER_DAY_MON; import static ca.pkay.rcloneexplorer.Items.Trigger.TRIGGER_DAY_SAT; @@ -82,9 +84,16 @@ public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int public void onBindViewHolder(@NonNull final RecyclerView.ViewHolder holder, final int position) { final Trigger selectedTrigger = triggers.get(position); - Task task = (new DatabaseHandler(context)).getTask(selectedTrigger.getTriggerTarget()); String targetTaskTitle = "ERR: NOTFOUND"; - if(task != null){ targetTaskTitle = task.getTitle(); } + if (selectedTrigger.getTriggerTarget() == ID_ALL_TASKS) { + targetTaskTitle = context.getResources().getString(R.string.sync_title_all_tasks_asc); + } else if (UNICODE_CHAR_RANGE - selectedTrigger.getTriggerTarget() >= 0) { + String firstCharOfTaskName = new String(Character.toChars((int) (UNICODE_CHAR_RANGE - selectedTrigger.getTriggerTarget()))); + targetTaskTitle = firstCharOfTaskName + context.getResources().getString(R.string.sync_title_all_tasks_prefixed_asc); + } else { + Task task = (new DatabaseHandler(context)).getTask(selectedTrigger.getTriggerTarget()); + if (task != null) { targetTaskTitle = task.getTitle(); } + } switch (holder.getItemViewType()) { case VIEW_TYPE_SCHEDULE: diff --git a/app/src/main/java/ca/pkay/rcloneexplorer/workmanager/SyncManager.kt b/app/src/main/java/ca/pkay/rcloneexplorer/workmanager/SyncManager.kt index 39dc6466..eb86474f 100644 --- a/app/src/main/java/ca/pkay/rcloneexplorer/workmanager/SyncManager.kt +++ b/app/src/main/java/ca/pkay/rcloneexplorer/workmanager/SyncManager.kt @@ -3,18 +3,30 @@ package ca.pkay.rcloneexplorer.workmanager import android.content.Context import android.util.Log import androidx.work.Data +import androidx.work.ExistingWorkPolicy +import androidx.work.OneTimeWorkRequest import androidx.work.OneTimeWorkRequestBuilder import androidx.work.WorkManager import androidx.work.WorkRequest +import ca.pkay.rcloneexplorer.Activities.TriggerActivity +import ca.pkay.rcloneexplorer.Activities.TriggerActivity.Companion.ID_ALL_TASKS +import ca.pkay.rcloneexplorer.Database.DatabaseHandler import ca.pkay.rcloneexplorer.Items.Task import ca.pkay.rcloneexplorer.Items.Trigger import java.util.Random class SyncManager(private var mContext: Context) { + private var mDatabase = DatabaseHandler(mContext) fun queue(trigger: Trigger) { - queue(trigger.triggerTarget) + if (trigger.triggerTarget == ID_ALL_TASKS) { + queueAllTasks(null) + } else if (TriggerActivity.UNICODE_CHAR_RANGE - trigger.triggerTarget >= 0) { + queueAllTasks((TriggerActivity.UNICODE_CHAR_RANGE - trigger.triggerTarget).toInt().toChar().toString()) + } else{ + queue(trigger.triggerTarget) + } } fun queue(task: Task) { @@ -22,6 +34,24 @@ class SyncManager(private var mContext: Context) { } fun queue(taskID: Long) { + work(getOneTimeWorkRequest(taskID)) + } + + private fun queueAllTasks(prefixFilter: String?) { + val mTaskList = mDatabase.allTasks + mTaskList.sortedBy { it.title } + for (i in mTaskList.indices) { + if (prefixFilter == null) { + workOneByOne(getOneTimeWorkRequest(mTaskList[i].id)) + } else { + if (mTaskList[i].title.trim().uppercase().startsWith(prefixFilter)) { + workOneByOne(getOneTimeWorkRequest(mTaskList[i].id)) + } + } + } + } + + private fun getOneTimeWorkRequest(taskID: Long): OneTimeWorkRequest { val uploadWorkRequest = OneTimeWorkRequestBuilder() val data = Data.Builder() @@ -29,7 +59,7 @@ class SyncManager(private var mContext: Context) { uploadWorkRequest.setInputData(data.build()) uploadWorkRequest.addTag(taskID.toString()) - work(uploadWorkRequest.build()) + return uploadWorkRequest.build() } fun queueEphemeral(task: Task) { @@ -50,6 +80,10 @@ class SyncManager(private var mContext: Context) { .enqueue(request) } + private fun workOneByOne(request: OneTimeWorkRequest) { + WorkManager.getInstance(mContext).enqueueUniqueWork("all_tasks_one_by_one", ExistingWorkPolicy.APPEND_OR_REPLACE, request) + } + fun cancel() { WorkManager.getInstance(mContext) .cancelAllWork() diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 5b8a020d..b7430f0b 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -484,6 +484,11 @@ Copy new or modified files from local storage to remote storage. No files are deleted, existing files on the remote may be overwritten. Copy new or modified files from remote storage to local storage. No files are deleted, existing files on the local storage may be overwritten. Make sure local and remote storage have the same files by transferring, downloading, and deleting files as needed to maintain an identical folder structure. + All tasks (in alphabetical order) + All tasks + All + … named tasks + … tasks Success! You are now ready to start! File access permission not granted