Convert FilesControlSet to compose

pull/1931/head
Alex Baker 2 years ago
parent 9b3f5a0c65
commit 3fa9040549

@ -10,39 +10,46 @@ import android.app.Activity
import android.content.Intent import android.content.Intent
import android.net.Uri import android.net.Uri
import android.os.Bundle import android.os.Bundle
import android.view.View import androidx.compose.foundation.clickable
import android.view.ViewGroup import androidx.compose.foundation.layout.Column
import android.widget.LinearLayout import androidx.compose.foundation.layout.Row
import android.widget.TextView import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.material.Icon
import androidx.compose.material.IconButton
import androidx.compose.material.Text
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.outlined.Delete
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment.Companion.CenterVertically
import androidx.compose.ui.Modifier
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.unit.dp
import androidx.lifecycle.lifecycleScope import androidx.lifecycle.lifecycleScope
import dagger.hilt.android.AndroidEntryPoint import dagger.hilt.android.AndroidEntryPoint
import kotlinx.coroutines.NonCancellable import kotlinx.coroutines.NonCancellable
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext import kotlinx.coroutines.withContext
import org.tasks.R import org.tasks.R
import org.tasks.compose.DisabledText
import org.tasks.compose.collectAsStateLifecycleAware
import org.tasks.data.TaskAttachment import org.tasks.data.TaskAttachment
import org.tasks.data.TaskAttachmentDao import org.tasks.data.TaskAttachmentDao
import org.tasks.databinding.ControlSetFilesBinding
import org.tasks.dialogs.AddAttachmentDialog import org.tasks.dialogs.AddAttachmentDialog
import org.tasks.dialogs.DialogBuilder import org.tasks.dialogs.DialogBuilder
import org.tasks.files.FileHelper import org.tasks.files.FileHelper
import org.tasks.preferences.Preferences import org.tasks.preferences.Preferences
import org.tasks.ui.TaskEditControlFragment import org.tasks.ui.TaskEditControlComposeFragment
import java.util.*
import javax.inject.Inject import javax.inject.Inject
@AndroidEntryPoint @AndroidEntryPoint
class FilesControlSet : TaskEditControlFragment() { class FilesControlSet : TaskEditControlComposeFragment() {
@Inject lateinit var activity: Activity
@Inject lateinit var taskAttachmentDao: TaskAttachmentDao @Inject lateinit var taskAttachmentDao: TaskAttachmentDao
@Inject lateinit var dialogBuilder: DialogBuilder @Inject lateinit var dialogBuilder: DialogBuilder
@Inject lateinit var preferences: Preferences @Inject lateinit var preferences: Preferences
private lateinit var attachmentContainer: LinearLayout
private lateinit var addAttachment: TextView
override fun createView(savedInstanceState: Bundle?) { override fun createView(savedInstanceState: Bundle?) {
val task = viewModel.task!! val task = viewModel.task
if (savedInstanceState == null) { if (savedInstanceState == null) {
if (task.hasTransitory(TaskAttachment.KEY)) { if (task.hasTransitory(TaskAttachment.KEY)) {
for (uri in (task.getTransitory<ArrayList<Uri>>(TaskAttachment.KEY))!!) { for (uri in (task.getTransitory<ArrayList<Uri>>(TaskAttachment.KEY))!!) {
@ -50,26 +57,53 @@ class FilesControlSet : TaskEditControlFragment() {
} }
} }
} }
lifecycleScope.launch {
taskAttachmentDao
.getAttachments(task.uuid)
.forEach { addAttachment(it) }
}
} }
private fun addAttachment() { private fun addAttachment() {
AddAttachmentDialog.newAddAttachmentDialog(this).show(parentFragmentManager, FRAG_TAG_ADD_ATTACHMENT_DIALOG) AddAttachmentDialog.newAddAttachmentDialog(this)
.show(parentFragmentManager, FRAG_TAG_ADD_ATTACHMENT_DIALOG)
} }
override fun bind(parent: ViewGroup?) = @Composable
ControlSetFilesBinding.inflate(layoutInflater, parent, true).let { override fun Body() {
attachmentContainer = it.attachmentContainer val attachments =
addAttachment = it.addAttachment.apply { taskAttachmentDao.watchAttachments(viewModel.task.uuid)
setOnClickListener { addAttachment() } .collectAsStateLifecycleAware(initial = emptyList()).value
Column(
modifier = Modifier.padding(top = if (attachments.isEmpty()) 0.dp else 8.dp),
) {
attachments.forEach {
Row(
modifier = Modifier
.clickable { showFile(it) },
verticalAlignment = CenterVertically,
) {
Text(
text = it.name!!,
modifier = Modifier.weight(1f),
)
IconButton(onClick = { deleteAttachment(it) }) {
Icon(
imageVector = Icons.Outlined.Delete,
contentDescription = stringResource(
id = R.string.delete
)
)
}
}
} }
it.root DisabledText(
text = stringResource(id = R.string.add_attachment),
modifier = Modifier
.fillMaxWidth()
.clickable { addAttachment() }
.padding(
top = if (attachments.isEmpty()) 20.dp else 8.dp,
bottom = 20.dp,
)
)
} }
}
override val icon = R.drawable.ic_outline_attachment_24px override val icon = R.drawable.ic_outline_attachment_24px
@ -80,7 +114,7 @@ class FilesControlSet : TaskEditControlFragment() {
if (resultCode == Activity.RESULT_OK) { if (resultCode == Activity.RESULT_OK) {
val uri = data!!.data val uri = data!!.data
copyToAttachmentDirectory(uri) copyToAttachmentDirectory(uri)
FileHelper.delete(activity, uri) FileHelper.delete(requireContext(), uri)
} }
} else if (requestCode == AddAttachmentDialog.REQUEST_STORAGE || requestCode == AddAttachmentDialog.REQUEST_GALLERY) { } else if (requestCode == AddAttachmentDialog.REQUEST_STORAGE || requestCode == AddAttachmentDialog.REQUEST_GALLERY) {
if (resultCode == Activity.RESULT_OK) { if (resultCode == Activity.RESULT_OK) {
@ -99,34 +133,19 @@ class FilesControlSet : TaskEditControlFragment() {
} }
} }
private fun addAttachment(taskAttachment: TaskAttachment) { private fun deleteAttachment(attachment: TaskAttachment) {
val fileRow = requireActivity().layoutInflater.inflate(R.layout.file_row, attachmentContainer, false) dialogBuilder
fileRow.tag = taskAttachment .newDialog(R.string.premium_remove_file_confirm)
attachmentContainer.addView(fileRow) .setPositiveButton(R.string.ok) { _, _ ->
addAttachment(taskAttachment, fileRow) lifecycleScope.launch {
} withContext(NonCancellable) {
taskAttachmentDao.delete(attachment)
private fun addAttachment(taskAttachment: TaskAttachment, fileRow: View) { FileHelper.delete(context, attachment.parseUri())
val nameView = fileRow.findViewById<TextView>(R.id.file_text)
val name = LEFT_TO_RIGHT_MARK.toString() + taskAttachment.name
nameView.text = name
nameView.setOnClickListener { showFile(taskAttachment) }
val clearFile = fileRow.findViewById<View>(R.id.clear)
clearFile.setOnClickListener {
dialogBuilder
.newDialog(R.string.premium_remove_file_confirm)
.setPositiveButton(R.string.ok) { _, _ ->
lifecycleScope.launch {
withContext(NonCancellable) {
taskAttachmentDao.delete(taskAttachment)
FileHelper.delete(context, taskAttachment.parseUri())
}
attachmentContainer.removeView(fileRow)
}
} }
.setNegativeButton(R.string.cancel, null) }
.show() }
} .setNegativeButton(R.string.cancel, null)
.show()
} }
@SuppressLint("NewApi") @SuppressLint("NewApi")
@ -140,18 +159,16 @@ class FilesControlSet : TaskEditControlFragment() {
private fun newAttachment(output: Uri) { private fun newAttachment(output: Uri) {
val attachment = TaskAttachment( val attachment = TaskAttachment(
viewModel.task!!.uuid, viewModel.task.uuid,
output, output,
FileHelper.getFilename(requireContext(), output)!!) FileHelper.getFilename(requireContext(), output)!!)
lifecycleScope.launch { lifecycleScope.launch {
taskAttachmentDao.createNew(attachment) taskAttachmentDao.createNew(attachment)
addAttachment(attachment)
} }
} }
companion object { companion object {
const val TAG = R.string.TEA_ctrl_files_pref const val TAG = R.string.TEA_ctrl_files_pref
private const val FRAG_TAG_ADD_ATTACHMENT_DIALOG = "frag_tag_add_attachment_dialog" private const val FRAG_TAG_ADD_ATTACHMENT_DIALOG = "frag_tag_add_attachment_dialog"
private const val LEFT_TO_RIGHT_MARK = '\u200e'
} }
} }

@ -3,6 +3,7 @@ package org.tasks.data
import androidx.room.* import androidx.room.*
import com.todoroo.astrid.data.Task import com.todoroo.astrid.data.Task
import com.todoroo.astrid.helper.UUIDHelper import com.todoroo.astrid.helper.UUIDHelper
import kotlinx.coroutines.flow.Flow
@Dao @Dao
abstract class TaskAttachmentDao { abstract class TaskAttachmentDao {
@ -15,6 +16,9 @@ abstract class TaskAttachmentDao {
@Query("SELECT * FROM task_attachments") @Query("SELECT * FROM task_attachments")
abstract suspend fun getAttachments(): List<TaskAttachment> abstract suspend fun getAttachments(): List<TaskAttachment>
@Query("SELECT * FROM task_attachments WHERE task_id = :taskUuid")
abstract fun watchAttachments(taskUuid: String): Flow<List<TaskAttachment>>
@Delete @Delete
abstract suspend fun delete(taskAttachment: TaskAttachment) abstract suspend fun delete(taskAttachment: TaskAttachment)

@ -1,36 +0,0 @@
<?xml version="1.0" encoding="utf-8"?><!--
** Copyright (c) 2012 Todoroo Inc
**
** See the file "LICENSE" for the full license governing this code.
-->
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<LinearLayout
android:id="@+id/attachment_container"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:orientation="vertical"/>
<LinearLayout
android:layout_width="fill_parent"
android:layout_height="0dp"
android:layout_weight="50"
android:layout_gravity="start"
android:gravity="start"
android:orientation="horizontal">
<TextView
android:id="@+id/add_attachment"
style="@style/TaskEditTextPrimary"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="start"
android:hint="@string/add_attachment"
android:textAlignment="viewStart"/>
</LinearLayout>
</LinearLayout>

@ -1,26 +0,0 @@
<?xml version="1.0" encoding="utf-8"?><!--
** Copyright (c) 2012 Todoroo Inc
**
** See the file "LICENSE" for the full license governing this code.
-->
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingBottom="@dimen/keyline_first">
<include layout="@layout/control_set_clear_button"/>
<TextView
android:id="@+id/file_text"
style="@android:style/TextAppearance"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentStart="true"
android:layout_gravity="start"
android:layout_toStartOf="@id/clear"
android:gravity="start"
android:textDirection="locale"
tools:ignore="UnusedAttribute"/>
</RelativeLayout>
Loading…
Cancel
Save