Skip to content

Commit

Permalink
add copy and move function
Browse files Browse the repository at this point in the history
  • Loading branch information
WirelessAlien committed Jan 1, 2025
1 parent 294b74a commit fda1d5c
Show file tree
Hide file tree
Showing 6 changed files with 175 additions and 2 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
/*
* Copyright (C) 2023 WirelessAlien <https://github.com/WirelessAlien>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/

package com.wirelessalien.zipxtract

import androidx.lifecycle.ViewModel
import java.io.File

class FileOperationViewModel : ViewModel() {
var isCopyAction: Boolean = false
var filesToCopyMove: List<File> = emptyList()
}
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ import androidx.core.view.MenuProvider
import androidx.fragment.app.Fragment
import androidx.fragment.app.FragmentManager
import androidx.fragment.app.FragmentTransaction
import androidx.fragment.app.activityViewModels
import androidx.lifecycle.Lifecycle
import androidx.localbroadcastmanager.content.LocalBroadcastManager
import androidx.preference.PreferenceManager
Expand All @@ -73,6 +74,7 @@ import com.google.android.material.snackbar.Snackbar
import com.google.android.material.textfield.TextInputEditText
import com.google.android.material.transition.MaterialSharedAxis
import com.wirelessalien.zipxtract.BuildConfig
import com.wirelessalien.zipxtract.FileOperationViewModel
import com.wirelessalien.zipxtract.R
import com.wirelessalien.zipxtract.activity.SettingsActivity
import com.wirelessalien.zipxtract.adapter.FileAdapter
Expand Down Expand Up @@ -139,6 +141,7 @@ class MainFragment : Fragment(), FileAdapter.OnItemClickListener, FileAdapter.On
private lateinit var aProgressText: TextView
private lateinit var eProgressText: TextView
private var areFabsVisible: Boolean = false
private val fileOperationViewModel: FileOperationViewModel by activityViewModels()
private lateinit var eProgressBar: LinearProgressIndicator
private lateinit var aProgressBar: LinearProgressIndicator
private lateinit var binding: FragmentMainBinding
Expand Down Expand Up @@ -327,6 +330,12 @@ class MainFragment : Fragment(), FileAdapter.OnItemClickListener, FileAdapter.On
currentPath = arguments?.getString("path")
searchHandler = Handler(Looper.getMainLooper())

if (fileOperationViewModel.filesToCopyMove.isNotEmpty()) {
showPasteFab()
} else {
binding.pasteFab.visibility = View.GONE
}

if (!checkStoragePermissions()) {
showPermissionRequestLayout()
} else {
Expand Down Expand Up @@ -673,6 +682,22 @@ class MainFragment : Fragment(), FileAdapter.OnItemClickListener, FileAdapter.On
actionMode?.finish() // Destroy the action mode
true
}

R.id.menu_action_copy_to -> {
startCopyMoveAction(isCopy = true)
true
}

R.id.menu_action_move_to -> {
startCopyMoveAction(isCopy = false)
true
}

R.id.menu_action_delete -> {
deleteSelectedFiles()
actionMode?.finish()
true
}
else -> false
}
}
Expand All @@ -688,6 +713,76 @@ class MainFragment : Fragment(), FileAdapter.OnItemClickListener, FileAdapter.On
updateActionModeTitle()
}


private fun startCopyMoveAction(isCopy: Boolean) {
fileOperationViewModel.isCopyAction = isCopy
fileOperationViewModel.filesToCopyMove = selectedFiles.toList()
showPasteFab()
actionMode?.finish()
}

private fun showPasteFab() {
binding.pasteFab.visibility = View.VISIBLE
binding.pasteFab.setOnClickListener {
pasteFiles()
}
}

private fun pasteFiles() {
val destinationPath = currentPath ?: return
CoroutineScope(Dispatchers.IO).launch {
for (file in fileOperationViewModel.filesToCopyMove) {
if (file.exists()) {
val destinationFile = File(destinationPath, file.name)
if (fileOperationViewModel.isCopyAction) {
file.copyRecursively(destinationFile, overwrite = true)
} else {
file.moveTo(destinationFile, overwrite = true)
}
} else {
withContext(Dispatchers.Main) {
Toast.makeText(requireContext(),
getString(R.string.the_file_doesn_t_exist, file.name), Toast.LENGTH_SHORT).show()
}
}
}
withContext(Dispatchers.Main) {
fileOperationViewModel.filesToCopyMove = emptyList()
binding.pasteFab.visibility = View.GONE
updateAdapterWithFullList()
}
}
}

private fun File.moveTo(destination: File, overwrite: Boolean = false) {
if (overwrite && destination.exists()) {
destination.deleteRecursively()
}
this.copyRecursively(destination, overwrite)
this.deleteRecursively()
}

private fun deleteSelectedFiles() {
MaterialAlertDialogBuilder(requireContext(), R.style.MaterialDialog)
.setTitle(getString(R.string.confirm_delete))
.setMessage(getString(R.string.confirm_delete_message))
.setPositiveButton(getString(R.string.delete)) { _, _ ->
CoroutineScope(Dispatchers.IO).launch {
for (file in selectedFiles) {
file.deleteRecursively()
}
withContext(Dispatchers.Main) {
unselectAllFiles()
updateAdapterWithFullList()
}
}
}
.setNegativeButton(getString(R.string.cancel)) { dialog, _ ->
dialog.dismiss()
}
.show()
}

fun toggleSelection(position: Int) {
val file = adapter.files[position]
if (selectedFiles.contains(file)) {
Expand Down
20 changes: 20 additions & 0 deletions app/src/main/res/drawable/ic_paste.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
<?xml version="1.0" encoding="utf-8"?><!--
~ Copyright (C) 2023 WirelessAlien <https://github.com/WirelessAlien>
~
~ This program is free software: you can redistribute it and/or modify
~ it under the terms of the GNU General Public License as published by
~ the Free Software Foundation, either version 3 of the License, or
~ any later version.
~
~ This program is distributed in the hope that it will be useful,
~ but WITHOUT ANY WARRANTY; without even the implied warranty of
~ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
~ GNU General Public License for more details.
~
~ You should have received a copy of the GNU General Public License
~ along with this program. If not, see <https://www.gnu.org/licenses/>.
-->

<vector xmlns:android="http://schemas.android.com/apk/res/android" android:width="24dp" android:height="24dp" android:viewportWidth="960" android:viewportHeight="960" android:tint="?attr/colorControlNormal">
<path android:fillColor="@android:color/white" android:pathData="M200,840Q167,840 143.5,816.5Q120,793 120,760L120,200Q120,167 143.5,143.5Q167,120 200,120L367,120Q378,85 410,62.5Q442,40 480,40Q520,40 551.5,62.5Q583,85 594,120L760,120Q793,120 816.5,143.5Q840,167 840,200L840,760Q840,793 816.5,816.5Q793,840 760,840L200,840ZM200,760L760,760Q760,760 760,760Q760,760 760,760L760,200Q760,200 760,200Q760,200 760,200L680,200L680,280Q680,297 668.5,308.5Q657,320 640,320L320,320Q303,320 291.5,308.5Q280,297 280,280L280,200L200,200Q200,200 200,200Q200,200 200,200L200,760Q200,760 200,760Q200,760 200,760ZM480,200Q497,200 508.5,188.5Q520,177 520,160Q520,143 508.5,131.5Q497,120 480,120Q463,120 451.5,131.5Q440,143 440,160Q440,177 451.5,188.5Q463,200 480,200Z"/>
</vector>
13 changes: 13 additions & 0 deletions app/src/main/res/layout/fragment_main.xml
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,19 @@
app:layout_behavior="com.google.android.material.behavior.HideViewOnScrollBehavior"
android:src="@drawable/ic_compress" />

<com.google.android.material.floatingactionbutton.FloatingActionButton
android:id="@+id/pasteFab"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="bottom|end"
android:layout_marginBottom="80dp"
android:layout_marginEnd="16dp"
app:shapeAppearance="@style/ShapeAppearance.Material3.Corner.Medium"
android:text="@string/paste"
android:visibility="gone"
app:layout_behavior="com.google.android.material.behavior.HideViewOnScrollBehavior"
android:src="@drawable/ic_paste" />

<com.google.android.material.floatingactionbutton.ExtendedFloatingActionButton
android:id="@+id/createZipFab"
android:layout_width="wrap_content"
Expand Down
15 changes: 15 additions & 0 deletions app/src/main/res/menu/menu_action.xml
Original file line number Diff line number Diff line change
Expand Up @@ -28,4 +28,19 @@
android:icon="@drawable/ic_select_all"
app:showAsAction="ifRoom" />

<item
android:id="@+id/menu_action_copy_to"
android:title="@string/copy_to"
app:showAsAction="ifRoom" />

<item
android:id="@+id/menu_action_move_to"
android:title="@string/move"
app:showAsAction="ifRoom" />

<item
android:id="@+id/menu_action_delete"
android:title="@string/delete"
app:showAsAction="ifRoom" />

</menu>
8 changes: 6 additions & 2 deletions app/src/main/res/values/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -140,8 +140,8 @@
<string name="about">About</string>
<string name="delete">Delete</string>
<string name="confirm_delete">Confirm Delete</string>
<string name="confirm_delete_message">Do you really want to delete this file?</string>
<string name="file_deleted">File Deleted</string>
<string name="confirm_delete_message">Do you really want to delete?</string>
<string name="file_deleted">Deleted</string>
<string name="file_name">Name: %1$s</string>
<string name="file_path">Path: %1$s</string>
<string name="file_size">Size: %1$s</string>
Expand All @@ -167,4 +167,8 @@
<string name="extract_path_summary">Modify the default extract folder. \nDefault is \"parent folder\" or Internal Storage/ZipXtract (for \"Open With\" menu extracted archive)</string>
<string name="info_tip">Useful Tip</string>
<string name="info_tip_description">\u25CF Long press on files and folders or click on file and folder icons to select them for archive creation.\n\n\u25CF Click on a file to display the extraction menu, where you can choose the appropriate extraction option.\n\n\u25CF Files extracted using the \"Open With\" menu of OS will default to the \"Internal Storage/ZipXtract\" directory. This can be modified in the app settings.\n\n\u25CF The default location for archive creation and extraction within the app is the parent directory of the respective file/files. This can also be changed in the app settings.</string>
<string name="move">Move to</string>
<string name="copy_to">Copy to</string>
<string name="paste">Paste</string>
<string name="the_file_doesn_t_exist">The file doesn\'t exist: %1$s</string>
</resources>

0 comments on commit fda1d5c

Please sign in to comment.