From 225480ee9c134033b8342136985cdda134bed3b2 Mon Sep 17 00:00:00 2001 From: emreesen27 <45034416+emreesen27@users.noreply.github.com> Date: Sat, 17 Feb 2024 16:56:18 +0300 Subject: [PATCH 01/12] [DEV][Update README.md] --- README.md | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/README.md b/README.md index 739f04c..b6a83c1 100644 --- a/README.md +++ b/README.md @@ -5,6 +5,7 @@ Simple File Manager for Android Overview --- +
@@ -16,6 +17,12 @@ Overview
+Downloads +--- + +[Get it on Google Play](https://play.google.com/store/apps/details?id=com.sn.snfilemanager) + + Preview --- | Home | Media | Folders | From b6b97c64308b3f6a96e9e0b0eaf86cdc2c911908 Mon Sep 17 00:00:00 2001 From: emreesen27 <45034416+emreesen27@users.noreply.github.com> Date: Sat, 17 Feb 2024 16:59:51 +0300 Subject: [PATCH 02/12] [FIX][README.md icon size fix] --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index b6a83c1..ccc632c 100644 --- a/README.md +++ b/README.md @@ -5,7 +5,7 @@ Simple File Manager for Android Overview --- - +
@@ -20,7 +20,7 @@ Overview Downloads --- -[Get it on Google Play](https://play.google.com/store/apps/details?id=com.sn.snfilemanager) +[Get it on Google Play](https://play.google.com/store/apps/details?id=com.sn.snfilemanager) Preview From f52579d5257af8582e00ba843a788134842520b8 Mon Sep 17 00:00:00 2001 From: Emre Esen Date: Wed, 21 Feb 2024 13:21:59 +0300 Subject: [PATCH 03/12] [DEV][version update] --- app/build.gradle | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/build.gradle b/app/build.gradle index 981dc5f..c6acb5a 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -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" } From 45b8e732406f056931ad3f1079666aa8ba29bd11 Mon Sep 17 00:00:00 2001 From: Emre Esen Date: Wed, 21 Feb 2024 20:48:07 +0300 Subject: [PATCH 04/12] [DEV][home menu edited] --- .../sn/snfilemanager/core/extensions/Context.kt | 7 +++++++ .../com/sn/snfilemanager/core/util/Constant.kt | 1 + .../snfilemanager/feature/about/AboutFragment.kt | 13 +++---------- .../sn/snfilemanager/feature/home/HomeFragment.kt | 15 +++++++-------- .../snfilemanager/feature/start/StartFragment.kt | 13 +++---------- .../view/dialog/license/LicenseAdapter.kt | 13 +++---------- app/src/main/res/menu/menu_home.xml | 9 ++------- app/src/main/res/values-tr/strings.xml | 1 + app/src/main/res/values/strings.xml | 1 + 9 files changed, 28 insertions(+), 45 deletions(-) diff --git a/app/src/main/java/com/sn/snfilemanager/core/extensions/Context.kt b/app/src/main/java/com/sn/snfilemanager/core/extensions/Context.kt index 2ba9ea2..e9e0642 100644 --- a/app/src/main/java/com/sn/snfilemanager/core/extensions/Context.kt +++ b/app/src/main/java/com/sn/snfilemanager/core/extensions/Context.kt @@ -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}" diff --git a/app/src/main/java/com/sn/snfilemanager/core/util/Constant.kt b/app/src/main/java/com/sn/snfilemanager/core/util/Constant.kt index 755beaf..88f3070 100644 --- a/app/src/main/java/com/sn/snfilemanager/core/util/Constant.kt +++ b/app/src/main/java/com/sn/snfilemanager/core/util/Constant.kt @@ -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" } diff --git a/app/src/main/java/com/sn/snfilemanager/feature/about/AboutFragment.kt b/app/src/main/java/com/sn/snfilemanager/feature/about/AboutFragment.kt index d628b04..52ba261 100644 --- a/app/src/main/java/com/sn/snfilemanager/feature/about/AboutFragment.kt +++ b/app/src/main/java/com/sn/snfilemanager/feature/about/AboutFragment.kt @@ -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 @@ -24,17 +22,12 @@ class AboutFragment : BaseFragment() { 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) - } } diff --git a/app/src/main/java/com/sn/snfilemanager/feature/home/HomeFragment.kt b/app/src/main/java/com/sn/snfilemanager/feature/home/HomeFragment.kt index 45a498d..92d2427 100644 --- a/app/src/main/java/com/sn/snfilemanager/feature/home/HomeFragment.kt +++ b/app/src/main/java/com/sn/snfilemanager/feature/home/HomeFragment.kt @@ -18,8 +18,11 @@ import com.sn.mediastorepv.data.MediaType import com.sn.snfilemanager.R import com.sn.snfilemanager.core.base.BaseFragment import com.sn.snfilemanager.core.extensions.click +import com.sn.snfilemanager.core.extensions.getPackage import com.sn.snfilemanager.core.extensions.infoToast import com.sn.snfilemanager.core.extensions.observe +import com.sn.snfilemanager.core.extensions.openUrl +import com.sn.snfilemanager.core.util.Constant import com.sn.snfilemanager.core.util.DocumentType import com.sn.snfilemanager.core.util.RootPath import com.sn.snfilemanager.databinding.FragmentHomeBinding @@ -53,12 +56,8 @@ class HomeFragment : BaseFragment() { override fun onMenuItemSelected(menuItemId: Int) = when (menuItemId) { - R.id.settings -> { - navigate(HomeFragmentDirections.actionSettings()) - true - } - - R.id.about -> { + R.id.store -> { + context?.openUrl(Constant.STORE_URL) true } @@ -135,7 +134,7 @@ class HomeFragment : BaseFragment() { val intent = Intent( Settings.ACTION_MANAGE_APP_ALL_FILES_ACCESS_PERMISSION, - Uri.parse("package:${requireActivity().packageName}"), + Uri.parse(context?.getPackage()), ) startActivity(intent) } @@ -144,7 +143,7 @@ class HomeFragment : BaseFragment() { val intent = Intent( Settings.ACTION_APPLICATION_DETAILS_SETTINGS, - Uri.parse("package:${requireActivity().packageName}"), + Uri.parse(context?.getPackage()), ) startActivity(intent) } diff --git a/app/src/main/java/com/sn/snfilemanager/feature/start/StartFragment.kt b/app/src/main/java/com/sn/snfilemanager/feature/start/StartFragment.kt index ce7cc6c..3fe9b7b 100644 --- a/app/src/main/java/com/sn/snfilemanager/feature/start/StartFragment.kt +++ b/app/src/main/java/com/sn/snfilemanager/feature/start/StartFragment.kt @@ -1,11 +1,9 @@ package com.sn.snfilemanager.feature.start -import android.content.Intent -import android.net.Uri import com.sn.snfilemanager.BuildConfig 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.OPEN_SOURCE_LICENSE import com.sn.snfilemanager.core.util.Constant.PRIVACY_URL import com.sn.snfilemanager.databinding.FragmentStartBinding @@ -35,12 +33,7 @@ class StartFragment : BaseFragment() { } private fun clicksPolicy() { - binding.mtvPrivacyPolicy.click { openUrl(PRIVACY_URL) } - binding.mtvOpenSourcePolicy.click { openUrl(OPEN_SOURCE_LICENSE) } - } - - private fun openUrl(url: String) { - val intent = Intent(Intent.ACTION_VIEW, Uri.parse(url)) - context?.startActivitySafely(intent) + binding.mtvPrivacyPolicy.click { context?.openUrl(PRIVACY_URL) } + binding.mtvOpenSourcePolicy.click { context?.openUrl(OPEN_SOURCE_LICENSE) } } } diff --git a/app/src/main/java/com/sn/snfilemanager/view/dialog/license/LicenseAdapter.kt b/app/src/main/java/com/sn/snfilemanager/view/dialog/license/LicenseAdapter.kt index 464d29e..319536b 100644 --- a/app/src/main/java/com/sn/snfilemanager/view/dialog/license/LicenseAdapter.kt +++ b/app/src/main/java/com/sn/snfilemanager/view/dialog/license/LicenseAdapter.kt @@ -1,13 +1,11 @@ package com.sn.snfilemanager.view.dialog.license import android.content.Context -import android.content.Intent -import android.net.Uri import android.view.LayoutInflater import android.view.ViewGroup import androidx.recyclerview.widget.RecyclerView 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.databinding.ItemLicenseBinding class LicenseAdapter(private val context: Context) : @@ -72,13 +70,13 @@ class LicenseAdapter(private val context: Context) : binding.mtvGithub.click { if (adapterPosition != RecyclerView.NO_POSITION) { val clickedLicense = licenses[adapterPosition] - openUrl(clickedLicense.url) + context.openUrl(clickedLicense.url) } } binding.mtvLicense.click { if (adapterPosition != RecyclerView.NO_POSITION) { val clickedLicense = licenses[adapterPosition] - openUrl(clickedLicense.license) + context.openUrl(clickedLicense.url) } } } @@ -87,9 +85,4 @@ class LicenseAdapter(private val context: Context) : binding.mtvName.text = model.name } } - - private fun openUrl(url: String) { - val intent = Intent(Intent.ACTION_VIEW, Uri.parse(url)) - context.startActivitySafely(intent) - } } diff --git a/app/src/main/res/menu/menu_home.xml b/app/src/main/res/menu/menu_home.xml index 71f931a..066275e 100644 --- a/app/src/main/res/menu/menu_home.xml +++ b/app/src/main/res/menu/menu_home.xml @@ -3,13 +3,8 @@ xmlns:app="http://schemas.android.com/apk/res-auto"> - - \ No newline at end of file diff --git a/app/src/main/res/values-tr/strings.xml b/app/src/main/res/values-tr/strings.xml index 9d02f7c..775439b 100644 --- a/app/src/main/res/values-tr/strings.xml +++ b/app/src/main/res/values-tr/strings.xml @@ -98,4 +98,5 @@ Sistem Koyu Açık + Mağazada göster \ No newline at end of file diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 3b4fa1f..3e025cf 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -102,4 +102,5 @@ System Dark Light + Show in store \ No newline at end of file From 30382328f82b545a7a08e87745ee6528e75b1e71 Mon Sep 17 00:00:00 2001 From: Emre Esen Date: Wed, 21 Feb 2024 20:50:49 +0300 Subject: [PATCH 05/12] [DEV][changelog updated] --- CHANGELOG.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index baea749..e6fc4e1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,7 @@ +## v1.0.0-beta4 (--.--.----) + +* Home screen menu arrangement + ## v1.0.0-beta3 (16.02.2024) * UI improvement From bd27ee67d577ec1a91683be59912207667d9b9a0 Mon Sep 17 00:00:00 2001 From: Emre Esen Date: Sat, 24 Feb 2024 14:15:52 +0300 Subject: [PATCH 06/12] [DEV][create folder feature is completed] --- .../feature/files/adapter/FileItemAdapter.kt | 11 ++- .../files/presentation/FilesListFragment.kt | 40 ++++++++- .../files/presentation/FilesListViewModel.kt | 32 +++++-- .../media/presentation/MediaFragment.kt | 1 + .../com/sn/snfilemanager/job/JobService.kt | 9 ++ .../java/com/sn/snfilemanager/job/JobType.kt | 1 + .../snfilemanager/job/file/CreateDirectory.kt | 23 +++++ .../view/dialog/CreateDirectoryDialog.kt | 72 ++++++++++++++++ .../color/text_input_layout_stroke_color.xml | 6 ++ .../res/layout/dialog_create_directory.xml | 85 +++++++++++++++++++ app/src/main/res/menu/menu_files.xml | 19 +++++ app/src/main/res/values-tr/strings.xml | 4 + app/src/main/res/values/strings.xml | 4 + app/src/main/res/values/styles.xml | 5 ++ 14 files changed, 303 insertions(+), 9 deletions(-) create mode 100644 app/src/main/java/com/sn/snfilemanager/job/file/CreateDirectory.kt create mode 100644 app/src/main/java/com/sn/snfilemanager/view/dialog/CreateDirectoryDialog.kt create mode 100644 app/src/main/res/color/text_input_layout_stroke_color.xml create mode 100644 app/src/main/res/layout/dialog_create_directory.xml create mode 100644 app/src/main/res/menu/menu_files.xml diff --git a/app/src/main/java/com/sn/snfilemanager/feature/files/adapter/FileItemAdapter.kt b/app/src/main/java/com/sn/snfilemanager/feature/files/adapter/FileItemAdapter.kt index 8e93ee5..2fe8c2b 100644 --- a/app/src/main/java/com/sn/snfilemanager/feature/files/adapter/FileItemAdapter.kt +++ b/app/src/main/java/com/sn/snfilemanager/feature/files/adapter/FileItemAdapter.kt @@ -24,14 +24,19 @@ class FileItemAdapter( ) : RecyclerView.Adapter() { private val selectedItems: MutableList = mutableListOf() private var isSelectionModeActive = false - private var fileItems: List = emptyList() + private var fileItems: MutableList = mutableListOf() - fun setItems(newItems: List) { + fun setItems(newItems: MutableList) { 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) { for (fileToRemove in filesToRemove) { val position = fileItems.indexOf(fileToRemove) @@ -55,6 +60,8 @@ class FileItemAdapter( selectionCallback?.onEndSelection() } + fun getItems(): MutableList = fileItems + fun getSelectedItems(): MutableList = selectedItems fun selectionIsActive(): Boolean = isSelectionModeActive diff --git a/app/src/main/java/com/sn/snfilemanager/feature/files/presentation/FilesListFragment.kt b/app/src/main/java/com/sn/snfilemanager/feature/files/presentation/FilesListFragment.kt index 0914b9d..b9600b6 100644 --- a/app/src/main/java/com/sn/snfilemanager/feature/files/presentation/FilesListFragment.kt +++ b/app/src/main/java/com/sn/snfilemanager/feature/files/presentation/FilesListFragment.kt @@ -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 @@ -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 @@ -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 @@ -65,6 +67,13 @@ class FilesListFragment : true } + R.id.create_folder -> { + viewModel.currentPath?.let { path -> + showCreateDirectoryDialog(path) + } + true + } + else -> super.onMenuItemSelected(menuItemId) } @@ -164,6 +173,16 @@ class FilesListFragment : JobType.DELETE -> { activity?.runOnUiThread { data?.filterIsInstance()?.let { adapter?.removeItems(it) } + adapter?.getItems()?.let { viewModel.setUpdateList(it) } + } + } + + JobType.CREATE -> { + activity?.runOnUiThread { + data?.filterIsInstance()?.firstOrNull()?.toFileModel()?.let { file -> + adapter?.addItem(file) + adapter?.getItems()?.let { viewModel.setUpdateList(it) } + } } } } @@ -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) @@ -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, @@ -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 diff --git a/app/src/main/java/com/sn/snfilemanager/feature/files/presentation/FilesListViewModel.kt b/app/src/main/java/com/sn/snfilemanager/feature/files/presentation/FilesListViewModel.kt index 3a76f35..15d35c3 100644 --- a/app/src/main/java/com/sn/snfilemanager/feature/files/presentation/FilesListViewModel.kt +++ b/app/src/main/java/com/sn/snfilemanager/feature/files/presentation/FilesListViewModel.kt @@ -62,13 +62,17 @@ class FilesListViewModel MutableLiveData() val startDeleteJobLiveData: LiveData>> = _startDeleteJobLiveData - private val _updateListLiveData: MutableLiveData>> = MutableLiveData() - val updateListLiveData: LiveData>> = _updateListLiveData + private val _updateListLiveData: MutableLiveData>> = + MutableLiveData() + val updateListLiveData: LiveData>> = _updateListLiveData private val _searchStateLiveData: MutableLiveData>> = MutableLiveData() val searchStateLiveData: LiveData>> = _searchStateLiveData + private val _startCreateFolderJob: MutableLiveData> = MutableLiveData() + val startCreateFolderJob: LiveData> = _startCreateFolderJob + var conflictDialogDeferred = CompletableDeferred>() companion object { @@ -133,7 +137,7 @@ class FilesListViewModel val fileList: MutableList = mutableListOf() if (totalFiles == 0L) { - _updateListLiveData.postValue(Event(emptyList())) + _updateListLiveData.postValue(Event(mutableListOf())) return@launch } @@ -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) { + _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 = mutableListOf() viewModelScope.launch { @@ -208,6 +223,11 @@ class FilesListViewModel } } + // Todo check free space + fun createFolder(targetPath: Path) { + _startCreateFolderJob.value = Event(targetPath) + } + fun deleteFiles() { val operationItemList: List = selectedItemList.toList() _startDeleteJobLiveData.postValue(Event(operationItemList)) @@ -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 -> { diff --git a/app/src/main/java/com/sn/snfilemanager/feature/media/presentation/MediaFragment.kt b/app/src/main/java/com/sn/snfilemanager/feature/media/presentation/MediaFragment.kt index ffb6737..684f062 100644 --- a/app/src/main/java/com/sn/snfilemanager/feature/media/presentation/MediaFragment.kt +++ b/app/src/main/java/com/sn/snfilemanager/feature/media/presentation/MediaFragment.kt @@ -170,6 +170,7 @@ class MediaFragment : data?.filterIsInstance()?.let { adapter?.removeItems(it) } } } + JobType.CREATE -> {} } activity?.runOnUiThread { context?.infoToast(getString(R.string.completed)) } } diff --git a/app/src/main/java/com/sn/snfilemanager/job/JobService.kt b/app/src/main/java/com/sn/snfilemanager/job/JobService.kt index ce7dae9..c1d7311 100644 --- a/app/src/main/java/com/sn/snfilemanager/job/JobService.kt +++ b/app/src/main/java/com/sn/snfilemanager/job/JobService.kt @@ -12,6 +12,7 @@ import com.sn.snfilemanager.core.util.FrNotificationManager import com.sn.snfilemanager.core.util.WakeWifiLock import com.sn.snfilemanager.feature.files.data.FileModel import com.sn.snfilemanager.job.file.CopyFileJob +import com.sn.snfilemanager.job.file.CreateDirectory import com.sn.snfilemanager.job.file.DeleteFileJob import com.sn.snfilemanager.job.media.DeleteMediaJob import com.sn.snfilemanager.job.media.MoveMediaJob @@ -151,6 +152,14 @@ class JobService : Service() { startJob(MoveMediaJob(sources, targetPath, isCopy, completed), context) } + fun createDirectory( + targetPath: Path, + completed: JobCompletedCallback, + context: Context, + ) { + startJob(CreateDirectory(targetPath, completed), context) + } + @MainThread fun cancelJob(id: Int) { pendingJobs.removeFirst { it.id == id } diff --git a/app/src/main/java/com/sn/snfilemanager/job/JobType.kt b/app/src/main/java/com/sn/snfilemanager/job/JobType.kt index 0165b70..0b256f7 100644 --- a/app/src/main/java/com/sn/snfilemanager/job/JobType.kt +++ b/app/src/main/java/com/sn/snfilemanager/job/JobType.kt @@ -3,4 +3,5 @@ package com.sn.snfilemanager.job enum class JobType { COPY, DELETE, + CREATE, } diff --git a/app/src/main/java/com/sn/snfilemanager/job/file/CreateDirectory.kt b/app/src/main/java/com/sn/snfilemanager/job/file/CreateDirectory.kt new file mode 100644 index 0000000..7319942 --- /dev/null +++ b/app/src/main/java/com/sn/snfilemanager/job/file/CreateDirectory.kt @@ -0,0 +1,23 @@ +package com.sn.snfilemanager.job.file + +import com.sn.snfilemanager.core.base.BaseJob +import com.sn.snfilemanager.job.JobCompletedCallback +import com.sn.snfilemanager.job.JobType +import java.nio.file.Files +import java.nio.file.Path + +class CreateDirectory( + private val targetPath: Path, + private val completed: JobCompletedCallback, +) : BaseJob() { + private val directory: MutableList = mutableListOf() + + override fun run() { + val dir = Files.createDirectories(targetPath) + directory.add(dir) + } + + override fun onCompleted() { + completed.jobOnCompleted(JobType.CREATE, directory) + } +} diff --git a/app/src/main/java/com/sn/snfilemanager/view/dialog/CreateDirectoryDialog.kt b/app/src/main/java/com/sn/snfilemanager/view/dialog/CreateDirectoryDialog.kt new file mode 100644 index 0000000..1b4bb90 --- /dev/null +++ b/app/src/main/java/com/sn/snfilemanager/view/dialog/CreateDirectoryDialog.kt @@ -0,0 +1,72 @@ +package com.sn.snfilemanager.view.dialog + +import android.os.Bundle +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import androidx.constraintlayout.widget.ConstraintLayout +import androidx.core.widget.addTextChangedListener +import androidx.fragment.app.DialogFragment +import com.sn.snfilemanager.R +import com.sn.snfilemanager.core.extensions.click +import com.sn.snfilemanager.databinding.DialogCreateDirectoryBinding +import java.nio.file.Files +import java.nio.file.Path +import java.nio.file.Paths + +class CreateDirectoryDialog( + private val path: String, + private val onCreate: ((Path) -> Unit)? = null, +) : + DialogFragment() { + private val binding: DialogCreateDirectoryBinding by lazy { + DialogCreateDirectoryBinding.inflate(layoutInflater) + } + + companion object { + const val TAG = "CREATE_DIRECTORY_DIALOG" + } + + override fun onStart() { + super.onStart() + dialog?.window?.setLayout( + ConstraintLayout.LayoutParams.MATCH_PARENT, + ConstraintLayout.LayoutParams.WRAP_CONTENT, + ) + } + + override fun onCreateView( + inflater: LayoutInflater, + container: ViewGroup?, + savedInstanceState: Bundle?, + ): View { + return binding.root + } + + override fun onViewCreated( + view: View, + savedInstanceState: Bundle?, + ) { + super.onViewCreated(view, savedInstanceState) + binding.etFolderName.requestFocus() + binding.btnCancel.click { dismiss() } + binding.btnCreate.click { + val name = binding.etFolderName.text.toString() + if (checkNameExists(name)) { + binding.inputLayout.error = getString(R.string.folder_exists_warning) + } else { + onCreate?.invoke(Paths.get(path).resolve(name)) + dismiss() + } + } + binding.etFolderName.addTextChangedListener { text -> + binding.btnCreate.isEnabled = !text.isNullOrEmpty() + binding.inputLayout.error = null + } + } + + private fun checkNameExists(name: String): Boolean { + val targetPath = Paths.get(path).resolve(name) + return Files.exists(targetPath) + } +} diff --git a/app/src/main/res/color/text_input_layout_stroke_color.xml b/app/src/main/res/color/text_input_layout_stroke_color.xml new file mode 100644 index 0000000..61e815d --- /dev/null +++ b/app/src/main/res/color/text_input_layout_stroke_color.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/dialog_create_directory.xml b/app/src/main/res/layout/dialog_create_directory.xml new file mode 100644 index 0000000..471335d --- /dev/null +++ b/app/src/main/res/layout/dialog_create_directory.xml @@ -0,0 +1,85 @@ + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/menu/menu_files.xml b/app/src/main/res/menu/menu_files.xml new file mode 100644 index 0000000..d744562 --- /dev/null +++ b/app/src/main/res/menu/menu_files.xml @@ -0,0 +1,19 @@ + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/values-tr/strings.xml b/app/src/main/res/values-tr/strings.xml index 775439b..ce14d1a 100644 --- a/app/src/main/res/values-tr/strings.xml +++ b/app/src/main/res/values-tr/strings.xml @@ -99,4 +99,8 @@ Koyu Açık Mağazada göster + Klasör oluştur + Oluştur + Klasör adı + Bu ada sahip klasör zaten mevcut \ No newline at end of file diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 3e025cf..d8ffd53 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -103,4 +103,8 @@ Dark Light Show in store + Create folder + Create + Folder name + The folder with this name already exists \ No newline at end of file diff --git a/app/src/main/res/values/styles.xml b/app/src/main/res/values/styles.xml index fff775f..659c3c5 100644 --- a/app/src/main/res/values/styles.xml +++ b/app/src/main/res/values/styles.xml @@ -47,4 +47,9 @@ @android:color/transparent + + \ No newline at end of file From fede5081ed06f995686753e8ad41ffb690bef883 Mon Sep 17 00:00:00 2001 From: Emre Esen Date: Sat, 24 Feb 2024 14:18:05 +0300 Subject: [PATCH 07/12] [DEV][changelog edited] --- CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index e6fc4e1..8d0d136 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,8 @@ ## v1.0.0-beta4 (--.--.----) * Home screen menu arrangement +* Create folder feature added +* Minor UI fix ## v1.0.0-beta3 (16.02.2024) From ca60916020dfe1051499c3eb4fafaee67e89f1aa Mon Sep 17 00:00:00 2001 From: Emre Esen Date: Thu, 29 Feb 2024 19:39:41 +0300 Subject: [PATCH 08/12] [FIX][media open with selection bug fixed] --- .../snfilemanager/feature/media/presentation/MediaFragment.kt | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/app/src/main/java/com/sn/snfilemanager/feature/media/presentation/MediaFragment.kt b/app/src/main/java/com/sn/snfilemanager/feature/media/presentation/MediaFragment.kt index 684f062..38ceaaf 100644 --- a/app/src/main/java/com/sn/snfilemanager/feature/media/presentation/MediaFragment.kt +++ b/app/src/main/java/com/sn/snfilemanager/feature/media/presentation/MediaFragment.kt @@ -93,6 +93,7 @@ class MediaFragment : mode: ActionMode?, item: MenuItem?, ): Boolean { + checkActionMenuStatus() when (item?.itemId) { R.id.action_copy -> { viewModel.isCopy = true @@ -373,8 +374,8 @@ class MediaFragment : MediaItemAdapter( onClick = { model -> openFile(model) }, onSelected = { model, selected -> - checkActionMenuStatus() viewModel.addSelectedItem(model, selected) + checkActionMenuStatus() }, selectionCallback = this@MediaFragment, ) From 4d65c9c73e239e8978da96ff96c98763ba8ba077 Mon Sep 17 00:00:00 2001 From: Emre Esen Date: Thu, 29 Feb 2024 19:56:25 +0300 Subject: [PATCH 09/12] [DEV][v1.0.0-beta4 is completed] --- CHANGELOG.md | 2 +- app/src/main/res/layout/layout_chip.xml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8d0d136..ac4dac4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,4 +1,4 @@ -## v1.0.0-beta4 (--.--.----) +## v1.0.0-beta4 (29.02.2024) * Home screen menu arrangement * Create folder feature added diff --git a/app/src/main/res/layout/layout_chip.xml b/app/src/main/res/layout/layout_chip.xml index 4a5c5ec..b2bd3f9 100644 --- a/app/src/main/res/layout/layout_chip.xml +++ b/app/src/main/res/layout/layout_chip.xml @@ -2,7 +2,7 @@ Date: Thu, 29 Feb 2024 21:40:19 +0300 Subject: [PATCH 10/12] [DEV][Update README.md] --- README.md | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index ccc632c..819003f 100644 --- a/README.md +++ b/README.md @@ -5,7 +5,7 @@ Simple File Manager for Android Overview --- - +
@@ -13,8 +13,11 @@ Overview - 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... -
Downloads @@ -27,8 +30,8 @@ Preview --- | Home | Media | Folders | |--------------|---------------|--------------| -| | | | -| | | | +| | | | +| | | | From 1c5b03f7099d0bfb2434bba701a9d4a695bfccb6 Mon Sep 17 00:00:00 2001 From: emreesen27 <45034416+emreesen27@users.noreply.github.com> Date: Thu, 29 Feb 2024 22:21:10 +0300 Subject: [PATCH 11/12] [DEV][Create CONTRIBUTING.md] --- CONTRIBUTING.md | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) create mode 100644 CONTRIBUTING.md diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 0000000..28114c0 --- /dev/null +++ b/CONTRIBUTING.md @@ -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] +``` From 4a038af17ee00e29a68352201553b5abc7d083f9 Mon Sep 17 00:00:00 2001 From: emreesen27 <45034416+emreesen27@users.noreply.github.com> Date: Thu, 29 Feb 2024 22:33:12 +0300 Subject: [PATCH 12/12] [DEV][Update README.md] --- README.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 819003f..0c716bd 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -# Sn File Manager +# Sn File Manager Simple File Manager for Android @@ -33,6 +33,6 @@ Preview | | | | | | | | - - - +Run & Contributing +--- + Read [this](https://github.com/emreesen27/Android-Sn-File-Manager/blob/develop/CONTRIBUTING.md) before running the project or contributing