Skip to content

Commit

Permalink
Merge pull request #41 from emreesen27/develop
Browse files Browse the repository at this point in the history
version v1.0.0-beta4 is completed
  • Loading branch information
emreesen27 authored Feb 29, 2024
2 parents 2c64bdc + 4a038af commit d8da390
Show file tree
Hide file tree
Showing 26 changed files with 387 additions and 65 deletions.
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,9 @@
## v1.0.0-beta4 (29.02.2024)

* Home screen menu arrangement
* Create folder feature added
* Minor UI fix

## v1.0.0-beta3 (16.02.2024)

* UI improvement
Expand Down
28 changes: 28 additions & 0 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
RUN & CONTRIBUTING
---

#### Run the Project

The application performs operations related to media files through a [submodule](https://github.com/emreesen27/media-store).

Clone the project:
```
git clone
```

Run to fetch and update the submodule:
```
git submodule update --init
```

#### Contribute

At the commit stage, I run commit-msg and lint checks. Committing automatically triggers the lint task. If you encounter any issues, manually trigger it.

```
./gradlew ktlintFormat
```
Ensure your commit message follows this format:
```
[DEV]||[FIX] [commit message]
```
24 changes: 17 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,28 +1,38 @@
# <a href="https://play.google.com/store/apps/details?id=com.sn.secretive">Sn File Manager</a>
# <a href="https://play.google.com/store/apps/details?id=com.sn.snfilemanager">Sn File Manager</a>

Simple File Manager for Android

Overview
---

<img src="https://github.com/emreesen27/Android-Sn-File-Manager/blob/assets/assets/app_icon_512.png?raw=true" align="right" width="26%" height="100%"></img>


<div style="display:flex;">

- Open Source, light and smooth
- No ads or In-app purchases
- Supports dark theme
- Access media items efficiently with MediaStore
- Quick navigation with Breadcrumb
- It supports basic operations such as file moving, deleting, and copying
- A fast and user-friendly interface
- Lots more...

</div>

Preview
Downloads
---
| Home | Media | Folders |
|--------------|---------------|--------------|
| <img src="https://github.com/emreesen27/Android-Sn-File-Manager/blob/assets/assets/home_ss.png?raw=true" width="200" height="450"></img> |<img src="https://github.com/emreesen27/Android-Sn-File-Manager/blob/assets/assets/image_ss.png?raw=true" width="200" height="450"></img> | <img src="https://github.com/emreesen27/Android-Sn-File-Manager/blob/assets/assets/folders_ss.png?raw=true" width="200" height="450"></img> |
| <img src="https://github.com/emreesen27/Android-Sn-File-Manager/blob/assets/assets/home_dark_ss.png?raw=true" width="200" height="450"></img> |<img src="https://github.com/emreesen27/Android-Sn-File-Manager/blob/assets/assets/images_dark_ss.png?raw=true" width="200" height="450"></img> | <img src="https://github.com/emreesen27/Android-Sn-File-Manager/blob/assets/assets/folders_dark_ss.png?raw=true" width="200" height="450"></img> |

[<img alt="Get it on Google Play" height="100" src="https://play.google.com/intl/en_us/badges/images/generic/en_badge_web_generic.png">](https://play.google.com/store/apps/details?id=com.sn.snfilemanager)


Preview
---
| Home | Media | Folders |
|--------------|---------------|--------------|
| <img src="https://github.com/emreesen27/Android-Sn-File-Manager/blob/assets/assets/home_ss.png?raw=true" width="180" height="400"></img> | <img src="https://github.com/emreesen27/Android-Sn-File-Manager/blob/assets/assets/image_ss.png?raw=true" width="180" height="400"></img> | <img src="https://github.com/emreesen27/Android-Sn-File-Manager/blob/assets/assets/folders_ss.png?raw=true" width="180" height="400"></img> |
| <img src="https://github.com/emreesen27/Android-Sn-File-Manager/blob/assets/assets/home_dark_ss.png?raw=true" width="180" height="400"></img> |<img src="https://github.com/emreesen27/Android-Sn-File-Manager/blob/assets/assets/images_dark_ss.png?raw=true" width="180" height="400"></img> | <img src="https://github.com/emreesen27/Android-Sn-File-Manager/blob/assets/assets/folders_dark_ss.png?raw=true" width="180" height="400"></img> |

Run & Contributing
---
Read [this](https://github.com/emreesen27/Android-Sn-File-Manager/blob/develop/CONTRIBUTING.md) before running the project or contributing
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 3
versionName "1.0.0-beta3"
versionCode 4
versionName "1.0.0-beta4"

testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -115,3 +115,10 @@ fun Context.startActivitySafely(intent: Intent) {
// Todo
}
}

fun Context.openUrl(url: String) {
val intent = Intent(Intent.ACTION_VIEW, Uri.parse(url))
startActivitySafely(intent)
}

fun Context.getPackage(): String = "package:${this.packageName}"
Original file line number Diff line number Diff line change
Expand Up @@ -7,4 +7,5 @@ object Constant {
"https://github.com/emreesen27/Android-Sn-File-Manager/blob/develop/PRIVACY.md"
const val OPEN_SOURCE_LICENSE =
"https://github.com/emreesen27/Android-Sn-File-Manager/blob/develop/LICENSE"
const val STORE_URL = "https://play.google.com/store/apps/details?id=com.sn.snfilemanager"
}
Original file line number Diff line number Diff line change
@@ -1,11 +1,9 @@
package com.sn.snfilemanager.feature.about

import android.content.Intent
import android.net.Uri
import androidx.navigation.fragment.findNavController
import com.sn.snfilemanager.core.base.BaseFragment
import com.sn.snfilemanager.core.extensions.click
import com.sn.snfilemanager.core.extensions.startActivitySafely
import com.sn.snfilemanager.core.extensions.openUrl
import com.sn.snfilemanager.core.util.Constant.GITHUB_URL
import com.sn.snfilemanager.core.util.Constant.PRIVACY_URL
import com.sn.snfilemanager.databinding.FragmentAboutBinding
Expand All @@ -24,17 +22,12 @@ class AboutFragment : BaseFragment<FragmentAboutBinding, AboutViewModel>() {

private fun initClicks() {
binding.toolbar.setNavigationOnClickListener { findNavController().popBackStack() }
binding.btnGithub.click { openUrl(GITHUB_URL) }
binding.btnGithub.click { context?.openUrl(GITHUB_URL) }
binding.btnLicense.click { showLicensesDialog() }
binding.btnPrivacy.click { openUrl(PRIVACY_URL) }
binding.btnPrivacy.click { context?.openUrl(PRIVACY_URL) }
}

private fun showLicensesDialog() {
LicenseDialog().show(childFragmentManager, LicenseDialog.TAG)
}

private fun openUrl(url: String) {
val intent = Intent(Intent.ACTION_VIEW, Uri.parse(url))
context?.startActivitySafely(intent)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -24,14 +24,19 @@ class FileItemAdapter(
) : RecyclerView.Adapter<FileItemAdapter.FileViewHolder>() {
private val selectedItems: MutableList<FileModel> = mutableListOf()
private var isSelectionModeActive = false
private var fileItems: List<FileModel> = emptyList()
private var fileItems: MutableList<FileModel> = mutableListOf()

fun setItems(newItems: List<FileModel>) {
fun setItems(newItems: MutableList<FileModel>) {
val diffResult = DiffUtil.calculateDiff(FileDiffCallback(fileItems, newItems))
fileItems = newItems
diffResult.dispatchUpdatesTo(this)
}

fun addItem(newItems: FileModel) {
fileItems.add(newItems)
notifyItemInserted(fileItems.size)
}

fun removeItems(filesToRemove: List<FileModel>) {
for (fileToRemove in filesToRemove) {
val position = fileItems.indexOf(fileToRemove)
Expand All @@ -55,6 +60,8 @@ class FileItemAdapter(
selectionCallback?.onEndSelection()
}

fun getItems(): MutableList<FileModel> = fileItems

fun getSelectedItems(): MutableList<FileModel> = selectedItems

fun selectionIsActive(): Boolean = isSelectionModeActive
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ import com.sn.snfilemanager.core.util.RootPath
import com.sn.snfilemanager.databinding.FragmentFilesListBinding
import com.sn.snfilemanager.feature.files.adapter.FileItemAdapter
import com.sn.snfilemanager.feature.files.data.FileModel
import com.sn.snfilemanager.feature.files.data.toFileModel
import com.sn.snfilemanager.feature.pathpicker.presentation.PathPickerFragment
import com.sn.snfilemanager.job.JobCompletedCallback
import com.sn.snfilemanager.job.JobService
Expand All @@ -33,6 +34,7 @@ import com.sn.snfilemanager.view.component.breadcrumb.BreadCrumbItemClickListene
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.detail.DetailDialog
import dagger.hilt.android.AndroidEntryPoint
import java.io.File
Expand All @@ -54,7 +56,7 @@ class FilesListFragment :

override fun getViewBinding() = FragmentFilesListBinding.inflate(layoutInflater)

override fun getMenuResId(): Int = R.menu.menu_base
override fun getMenuResId(): Int = R.menu.menu_files

override fun getToolbar(): Toolbar = binding.toolbar

Expand All @@ -65,6 +67,13 @@ class FilesListFragment :
true
}

R.id.create_folder -> {
viewModel.currentPath?.let { path ->
showCreateDirectoryDialog(path)
}
true
}

else -> super.onMenuItemSelected(menuItemId)
}

Expand Down Expand Up @@ -164,6 +173,16 @@ 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) }
}
}
}
}
Expand Down Expand Up @@ -195,6 +214,11 @@ class FilesListFragment :
startDeleteService(data)
}
}
observe(viewModel.startCreateFolderJob) { event ->
event.getContentIfNotHandled()?.let { path ->
startCreateDirectory(path)
}
}
observe(viewModel.updateListLiveData) { event ->
event.getContentIfNotHandled()?.let { list ->
adapter?.setItems(list)
Expand Down Expand Up @@ -330,6 +354,12 @@ class FilesListFragment :
)
}

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

private fun actionDetail() {
DetailDialog(requireContext(), viewModel.getSelectedItem()).show(
childFragmentManager,
Expand Down Expand Up @@ -389,6 +419,14 @@ class FilesListFragment :
)
}

private fun startCreateDirectory(destinationPath: Path) {
JobService.createDirectory(
destinationPath,
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 @@ -62,13 +62,17 @@ class FilesListViewModel
MutableLiveData()
val startDeleteJobLiveData: LiveData<Event<List<FileModel>>> = _startDeleteJobLiveData

private val _updateListLiveData: MutableLiveData<Event<List<FileModel>>> = MutableLiveData()
val updateListLiveData: LiveData<Event<List<FileModel>>> = _updateListLiveData
private val _updateListLiveData: MutableLiveData<Event<MutableList<FileModel>>> =
MutableLiveData()
val updateListLiveData: LiveData<Event<MutableList<FileModel>>> = _updateListLiveData

private val _searchStateLiveData: MutableLiveData<Event<Pair<Boolean, Boolean>>> =
MutableLiveData()
val searchStateLiveData: LiveData<Event<Pair<Boolean, Boolean>>> = _searchStateLiveData

private val _startCreateFolderJob: MutableLiveData<Event<Path>> = MutableLiveData()
val startCreateFolderJob: LiveData<Event<Path>> = _startCreateFolderJob

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

companion object {
Expand Down Expand Up @@ -133,7 +137,7 @@ class FilesListViewModel
val fileList: MutableList<FileModel> = mutableListOf()

if (totalFiles == 0L) {
_updateListLiveData.postValue(Event(emptyList()))
_updateListLiveData.postValue(Event(mutableListOf()))
return@launch
}

Expand All @@ -145,25 +149,36 @@ class FilesListViewModel
.skip(processedFiles)
.limit(currentBatchSize)
.forEach { file ->
if (Files.isReadable(file) && (Config.hiddenFile || !Files.isHidden(file))) {
if (Files.isReadable(file) && (
Config.hiddenFile ||
!Files.isHidden(
file,
)
)
) {
fileList.add(file.toFileModel())
}
}
}
withContext(Dispatchers.Main) {
_updateListLiveData.postValue(Event(fileList.toList()))
_updateListLiveData.postValue(Event(fileList))
}
processedFiles += currentBatchSize
}
}
}

fun setUpdateList(files: MutableList<FileModel>) {
_updateListLiveData.postValue(Event(files))
}

fun cancelFileListJob() {
if (fileListJob != null && fileListJob?.isActive == true) {
fileListJob?.cancel()
}
}

// Todo check free space
fun moveFilesAndDirectories(destinationPath: Path) {
val operationItemList: MutableList<FileModel> = mutableListOf()
viewModelScope.launch {
Expand Down Expand Up @@ -208,6 +223,11 @@ class FilesListViewModel
}
}

// Todo check free space
fun createFolder(targetPath: Path) {
_startCreateFolderJob.value = Event(targetPath)
}

fun deleteFiles() {
val operationItemList: List<FileModel> = selectedItemList.toList()
_startDeleteJobLiveData.postValue(Event(operationItemList))
Expand Down Expand Up @@ -252,7 +272,7 @@ class FilesListViewModel
is BaseResult.Success -> {
val list = result.data.map { Paths.get(it).toFileModel() }
_searchStateLiveData.postValue(Event(Pair(false, false)))
_updateListLiveData.postValue(Event(list))
_updateListLiveData.postValue(Event(list.toMutableList()))
}

is BaseResult.Failure -> {
Expand Down
Loading

0 comments on commit d8da390

Please sign in to comment.