Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

V1.0.0 beta6 #51

Merged
merged 10 commits into from
Apr 24, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions app/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -39,8 +39,8 @@ android {
applicationId "com.sn.snfilemanager"
minSdk 26
targetSdk 34
versionCode 5
versionName "1.0.0-beta5"
versionCode 6
versionName "1.0.0-beta6"

testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
}
Expand Down
59 changes: 59 additions & 0 deletions app/src/main/java/com/sn/snfilemanager/core/base/BaseDialog.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
package com.sn.snfilemanager.core.base

import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.constraintlayout.widget.ConstraintLayout
import androidx.fragment.app.DialogFragment
import androidx.fragment.app.FragmentManager
import androidx.viewbinding.ViewBinding
import com.sn.snfilemanager.R

abstract class BaseDialog<VBinding : ViewBinding> : DialogFragment() {
protected lateinit var binding: VBinding

protected abstract fun getViewBinding(): VBinding

open var setCancelable: Boolean = true

protected abstract val dialogTag: String

open fun setupViews() {}

fun showDialog(fragmentManager: FragmentManager) {
show(fragmentManager, dialogTag)
}

override fun onStart() {
super.onStart()
dialog?.window?.setLayout(
ConstraintLayout.LayoutParams.MATCH_PARENT,
ConstraintLayout.LayoutParams.WRAP_CONTENT,
)
}

override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = getViewBinding()
isCancelable = setCancelable
setStyle(STYLE_NO_TITLE, R.style.DialogTheme_transparent)
dialog?.window?.setBackgroundDrawableResource(R.drawable.dialog_rounded)
}

override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?,
): View? {
return binding.root
}

override fun onViewCreated(
view: View,
savedInstanceState: Bundle?,
) {
super.onViewCreated(view, savedInstanceState)
setupViews()
}
}
23 changes: 23 additions & 0 deletions app/src/main/java/com/sn/snfilemanager/core/util/FileUtils.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
package com.sn.snfilemanager.core.util

import com.sn.snfilemanager.feature.files.data.FileModel
import com.sn.snfilemanager.feature.files.data.toFileModel
import java.nio.file.Files
import java.nio.file.Paths
import java.util.stream.Collectors

object FileUtils {
fun getTotalSizeAndFileCount(itemList: List<FileModel>): Pair<Long, Long> =
itemList.fold(Pair(0L, 0L)) { acc, item ->
if (item.isDirectory && Files.isReadable(Paths.get(item.absolutePath))) {
val childResult =
getTotalSizeAndFileCount(
Files.list(Paths.get(item.absolutePath)).collect(Collectors.toList())
.map { it.toFileModel() },
)
Pair(acc.first + childResult.first, acc.second + childResult.second)
} else {
Pair(acc.first + item.size, acc.second + 1)
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,6 @@ class AboutFragment : BaseFragment<FragmentAboutBinding, AboutViewModel>() {
}

private fun showLicensesDialog() {
LicenseDialog().show(childFragmentManager, LicenseDialog.TAG)
LicenseDialog().showDialog(childFragmentManager)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,12 @@ class FileItemAdapter(
notifyItemInserted(fileItems.size)
}

fun updateItem(item: FileModel) {
val index = fileItems.indexOfFirst { it.id == item.id }
fileItems[index] = item
notifyItemChanged(index)
}

fun removeItems(filesToRemove: List<FileModel>) {
for (fileToRemove in filesToRemove) {
val position = fileItems.indexOf(fileToRemove)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ import com.sn.snfilemanager.view.component.breadcrumb.BreadItem
import com.sn.snfilemanager.view.dialog.ConfirmationDialog
import com.sn.snfilemanager.view.dialog.ConflictDialog
import com.sn.snfilemanager.view.dialog.CreateDirectoryDialog
import com.sn.snfilemanager.view.dialog.RenameFileDialog
import com.sn.snfilemanager.view.dialog.detail.DetailDialog
import dagger.hilt.android.AndroidEntryPoint
import java.io.File
Expand Down Expand Up @@ -133,6 +134,10 @@ class FilesListFragment :
R.id.action_select_all -> {
adapter?.selectAll()
}

R.id.action_rename -> {
showRenameDialog()
}
}

return true
Expand Down Expand Up @@ -177,15 +182,21 @@ class FilesListFragment :
JobType.DELETE -> {
activity?.runOnUiThread {
data?.filterIsInstance<FileModel>()?.let { adapter?.removeItems(it) }
adapter?.getItems()?.let { viewModel.setUpdateList(it) }
}
}

JobType.CREATE -> {
activity?.runOnUiThread {
data?.filterIsInstance<Path>()?.firstOrNull()?.toFileModel()?.let { file ->
adapter?.addItem(file)
adapter?.getItems()?.let { viewModel.setUpdateList(it) }
}
}
}

JobType.RENAME -> {
activity?.runOnUiThread {
data?.filterIsInstance<FileModel>()?.firstOrNull()?.let { file ->
adapter?.updateItem(file)
}
}
}
Expand All @@ -196,12 +207,12 @@ class FilesListFragment :
override fun observeData() {
observe(viewModel.conflictQuestionLiveData) { event ->
event.getContentIfNotHandled()?.let { fileName ->
ConflictDialog(requireContext(), fileName).apply {
ConflictDialog(fileName).apply {
onSelected = { strategy: ConflictStrategy, isAll: Boolean ->
viewModel.conflictDialogDeferred.complete(Pair(strategy, isAll))
}
onDismiss = { actionMode?.finish() }
}.show()
}.showDialog(childFragmentManager)
}
}
observe(viewModel.startMoveJobLiveData) { event ->
Expand All @@ -220,7 +231,7 @@ class FilesListFragment :
}
observe(viewModel.startCreateFolderJob) { event ->
event.getContentIfNotHandled()?.let { path ->
startCreateDirectory(path)
startCreateDirectoryService(path)
}
}
observe(viewModel.updateListLiveData) { event ->
Expand All @@ -242,6 +253,12 @@ class FilesListFragment :
}
}
}
observe(viewModel.startRenameFileJob) { event ->
event.getContentIfNotHandled()?.let { data ->
actionMode?.finish()
startRenameService(data.first, data.second)
}
}
}

private fun initFirstList() {
Expand Down Expand Up @@ -303,6 +320,7 @@ class FilesListFragment :
actionMode?.menu?.findItem(R.id.action_open_with)?.isVisible =
viewModel.isSingleItemSelected()
}
actionMode?.menu?.findItem(R.id.action_rename)?.isVisible = viewModel.isSingleItemSelected()
}

private fun initAdapter() {
Expand Down Expand Up @@ -352,23 +370,26 @@ class FilesListFragment :
} else {
viewModel.moveFilesAndDirectories(Paths.get(path))
}
}).show(
childFragmentManager,
DetailDialog.TAG,
)
}).showDialog(childFragmentManager)
}

private fun showCreateDirectoryDialog(path: String) {
CreateDirectoryDialog(path = path, onCreate = { folderName ->
viewModel.createFolder(folderName)
}).show(childFragmentManager, CreateDirectoryDialog.TAG)
}).showDialog(childFragmentManager)
}

private fun showRenameDialog() {
RenameFileDialog(file = viewModel.getSelectedItem().first(), onRename = { newName ->
viewModel.renameFile(newName)
}).showDialog(childFragmentManager)
}

private fun actionDetail() {
DetailDialog(requireContext(), viewModel.getSelectedItem()).show(
childFragmentManager,
DetailDialog.TAG,
)
DetailDialog(
requireContext(),
viewModel.getSelectedItem(),
).showDialog(childFragmentManager)
}

private fun actionOpenWith() {
Expand All @@ -388,7 +409,6 @@ class FilesListFragment :

private fun actionDelete() {
ConfirmationDialog(
requireContext(),
getString(R.string.are_you_sure),
getString(R.string.delete_warning),
).apply {
Expand All @@ -399,7 +419,7 @@ class FilesListFragment :
actionMode?.finish()
}
}
}.show()
}.showDialog(childFragmentManager)
}

private fun startCopyService(
Expand All @@ -423,14 +443,26 @@ class FilesListFragment :
)
}

private fun startCreateDirectory(destinationPath: Path) {
private fun startCreateDirectoryService(destinationPath: Path) {
JobService.createDirectory(
destinationPath,
this@FilesListFragment,
requireContext(),
)
}

private fun startRenameService(
file: FileModel,
newName: String,
) {
JobService.rename(
file,
newName,
this@FilesListFragment,
requireContext(),
)
}

private fun initSearch() {
binding.toolbar.menu?.findItem(R.id.action_search)?.let { item ->
val searchView = item.actionView as? SearchView
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,9 @@ class FilesListViewModel
private val _startCreateFolderJob: MutableLiveData<Event<Path>> = MutableLiveData()
val startCreateFolderJob: LiveData<Event<Path>> = _startCreateFolderJob

private val _startRenameFileJob: MutableLiveData<Event<Pair<FileModel, String>>> = MutableLiveData()
val startRenameFileJob: LiveData<Event<Pair<FileModel, String>>> = _startRenameFileJob

var conflictDialogDeferred = CompletableDeferred<Pair<ConflictStrategy, Boolean>>()

companion object {
Expand Down Expand Up @@ -223,6 +226,17 @@ class FilesListViewModel
}
}

fun renameFile(newName: String) {
val file = selectedItemList.firstOrNull()
file?.let {
if (Files.isWritable(Paths.get(file.absolutePath))) {
_startRenameFileJob.value = Event(Pair(file, newName))
} else {
// show toast
}
}
}

// Todo check free space
fun createFolder(targetPath: Path) {
_startCreateFolderJob.value = Event(targetPath)
Expand Down Expand Up @@ -270,7 +284,14 @@ class FilesListViewModel
)
) {
is BaseResult.Success -> {
val list = result.data.map { Paths.get(it).toFileModel() }
val list =
result.data.mapNotNull {
if (Files.exists(Paths.get(it))) {
Paths.get(it).toFileModel()
} else {
null
}
}
_searchStateLiveData.postValue(Event(Pair(false, false)))
_updateListLiveData.postValue(Event(list.toMutableList()))
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -161,20 +161,19 @@ class HomeFragment : BaseFragment<FragmentHomeBinding, HomeViewModel>() {
}

private fun showPermissionDialog(type: PermissionDialogType = PermissionDialogType.DEFAULT) {
if (permissionDialog == null || permissionDialog?.isShowing == false) {
if (permissionDialog == null || permissionDialog?.isVisible == false) {
permissionDialog =
PermissionDialog(requireContext(), type).apply {
PermissionDialog(type).apply {
onAllow = { allowStoragePermission() }
}
permissionDialog?.show()
permissionDialog?.showDialog(childFragmentManager)
}
}

private fun showNotificationDialog() {
if (confirmationDialog == null || confirmationDialog?.isShowing == false) {
if (confirmationDialog == null || confirmationDialog?.isVisible == false) {
confirmationDialog =
ConfirmationDialog(
requireContext(),
getString(R.string.permission_warning_title),
getString(R.string.notification_permission_info),
).apply {
Expand All @@ -184,7 +183,7 @@ class HomeFragment : BaseFragment<FragmentHomeBinding, HomeViewModel>() {
}
}
}
confirmationDialog?.show()
confirmationDialog?.showDialog(childFragmentManager)
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,9 +32,9 @@ class MediaItemAdapter(
) : RecyclerView.Adapter<MediaItemAdapter.AutoCompleteViewHolder>() {
private val selectedItems: MutableList<Media> = mutableListOf()
private var isSelectionModeActive = false
private var mediaItems: List<Media> = emptyList()
private var mediaItems: MutableList<Media> = mutableListOf()

fun setItems(newItems: List<Media>) {
fun setItems(newItems: MutableList<Media>) {
val diffResult = DiffUtil.calculateDiff(MediaDiffCallback(mediaItems, newItems))
mediaItems = newItems
diffResult.dispatchUpdatesTo(this)
Expand All @@ -50,6 +50,12 @@ class MediaItemAdapter(
}
}

fun updateItem(mediaFile: Media) {
val index = mediaItems.indexOfFirst { it.id == mediaFile.id }
mediaItems[index] = mediaFile
notifyItemChanged(index)
}

fun finishSelectionAndReset() {
for (selectedItem in selectedItems) {
val position = mediaItems.indexOf(selectedItem)
Expand Down
Loading