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

[feature] Automatically switch-on Roots tab on first root pinned. #54

Merged
merged 2 commits into from
Feb 15, 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
17 changes: 17 additions & 0 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ on:

jobs:
build:
if: ${{ ! startsWith(github.actor, 'dependabot') }}
environment: Development
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
Expand All @@ -22,6 +24,21 @@ jobs:

- name: Validate Gradle wrapper
uses: gradle/[email protected]


- name: Decrypt the keystore for signing
run: |
echo "${{ secrets.KEYSTORE_ENCRYPTED }}" > keystore.asc
gpg -d --passphrase "${{ secrets.KEYSTORE_PASSWORD }}" --batch keystore.asc > keystore.jks

- name: Build components
run: ./gradlew assembleRelease

- name: Build release sample APK
run: ./gradlew sample:assembleRelease

- name: Upload release APK
uses: actions/upload-artifact@v3
with:
name: release-universal-apk
path: ./sample/build/outputs/apk/release/sample-release.apk
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ import coil.dispose
import coil.load
import coil.memory.MemoryCache
import coil.request.CachePolicy
import com.google.android.material.tabs.TabLayout
import com.google.android.material.tabs.TabLayoutMediator
import com.mikepenz.fastadapter.FastAdapter
import com.mikepenz.fastadapter.GenericItem
Expand All @@ -46,7 +47,6 @@ import dev.arkbuilders.components.databinding.ArkFilePickerHostFragmentBinding
import dev.arkbuilders.components.databinding.ArkFilePickerItemFileBinding
import dev.arkbuilders.components.databinding.ArkFilePickerItemFilesRootsPageBinding
import dev.arkbuilders.components.filepicker.callback.OnFileItemLongClick
import dev.arkbuilders.components.filepicker.callback.PinFileCallback
import dev.arkbuilders.components.folderstree.FolderTreeView
import dev.arkbuilders.components.utils.args
import dev.arkbuilders.components.utils.dpToPx
Expand Down Expand Up @@ -92,11 +92,21 @@ open class ArkFilePickerFragment :
}

private val pagesAdapter = ItemAdapter<GenericItem>()
private var mCurrentRootsWithFavorites: Map<Path, List<Path>>? = null

private val mPinFileCallback = object : PinFileCallback {
override fun onPinFileClick(file: Path) {
pinFile(file)
private val mSharedPref by lazy { activity?.getPreferences(Context.MODE_PRIVATE) }
private val PREF_LAST_ACTIVE_TAB_INDEX = "pref_last_active_tab_index"

private val mOnTabSelectListener by lazy {
object : TabLayout.OnTabSelectedListener {
override fun onTabSelected(tab: TabLayout.Tab?) {
mSharedPref?.edit()?.putInt(PREF_LAST_ACTIVE_TAB_INDEX, tab?.position ?: 0)?.apply()
}

override fun onTabUnselected(tab: TabLayout.Tab?) {
}

override fun onTabReselected(tab: TabLayout.Tab?) {
}
}
}

Expand Down Expand Up @@ -160,6 +170,10 @@ open class ArkFilePickerFragment :
TabLayoutMediator(tabs, vp) { tab, pos ->
tab.text = tabsTitle[pos]
}.attach()
mSharedPref?.getInt(PREF_LAST_ACTIVE_TAB_INDEX, 0)?.let {
tabs.getTabAt(it)?.select()
}
tabs.addOnTabSelectedListener(mOnTabSelectListener)
} else {
tabs.isVisible = false
}
Expand Down Expand Up @@ -197,7 +211,7 @@ open class ArkFilePickerFragment :

if (newFolder.mkdirs()) {
if (isARKMode()) {
pinFile(newFolder.toPath())
viewModel.pinFile(newFolder.toPath())
}
//Reload current files tree
currentFolder?.let { viewModel.onItemClick(it) }
Expand All @@ -208,7 +222,6 @@ open class ArkFilePickerFragment :
}

private fun render(state: FilePickerState) = binding.apply {
mCurrentRootsWithFavorites = state.rootsWithFavs

displayPath(state)

Expand Down Expand Up @@ -272,6 +285,23 @@ open class ArkFilePickerFragment :
)
})
}

FilePickerSideEffect.PinAsRoot ->
activity?.toast(R.string.ark_file_picker_pinned_as_root)

FilePickerSideEffect.AlreadyRoot ->
activity?.toast(R.string.ark_file_picker_already_be_a_root)

FilePickerSideEffect.PinAsFavorite ->
activity?.toast(R.string.ark_file_picker_pinned_as_favorite)

FilePickerSideEffect.AlreadyFavorite ->
activity?.toast(R.string.ark_file_picker_already_a_favorite)

FilePickerSideEffect.PinAsFirstRoot -> {
pagesAdapter.set(getPages())
activity?.toast(R.string.ark_file_picker_pinned_as_root)
}
}


Expand Down Expand Up @@ -338,16 +368,15 @@ open class ArkFilePickerFragment :
}
}

private fun getPages() = if (showRoots!!) {
private fun getPages() = if (showRoots!! && viewModel.haveRoot()) {
if (rootsFirstPage!!) {
listOf(
RootsPage(this, viewModel),
FilesPage(this, viewModel, itemsPluralId!!)
)
} else {
listOf(
FilesPage(this, viewModel, itemsPluralId!!,
pinFileCallback = mPinFileCallback),
FilesPage(this, viewModel, itemsPluralId!!),
RootsPage(this, viewModel)
)
}
Expand All @@ -357,7 +386,6 @@ open class ArkFilePickerFragment :
)
}


fun setConfig(config: ArkFilePickerConfig) {
titleStringId = config.titleStringId
pickButtonStringId = config.pickButtonStringId
Expand Down Expand Up @@ -386,42 +414,6 @@ open class ArkFilePickerFragment :
private const val PATH_PART_PADDING = 4f
}

private fun pinFile(file: Path) {
val roots = mCurrentRootsWithFavorites?.keys
val root = roots?.find { root -> file.startsWith(root) }
val favorites = mCurrentRootsWithFavorites?.get(root)?.flatten()

root?.let {

//Make sure file isn't inside a root folder
if (root != file) {
var foundAsFavorite = false
favorites?.forEach {
if (file.endsWith(it)) {
foundAsFavorite = true
return@forEach
}
}

if (!foundAsFavorite) {
viewModel.addFavorite(file)
activity?.toast(R.string.ark_file_picker_pinned_as_favorite)
} else {
activity?.toast(R.string.ark_file_picker_already_a_favorite)
}
} else {
activity?.toast(R.string.ark_file_picker_already_be_a_root)
}
} ?: let {

if (mCurrentRootsWithFavorites?.keys?.contains(file) == true) {
activity?.toast(R.string.ark_file_picker_already_be_a_root)
} else {
viewModel.addRoot(file)
activity?.toast(R.string.ark_file_picker_pinned_as_root)
}
}
}
}

private fun pickerImageLoader(ctx: Context) = ImageLoader.Builder(ctx)
Expand All @@ -445,8 +437,7 @@ private fun pickerImageLoader(ctx: Context) = ImageLoader.Builder(ctx)
internal class FilesPage(
private val fragment: Fragment,
private val viewModel: ArkFilePickerViewModel,
private val itemsPluralId: Int,
private val pinFileCallback: PinFileCallback? = null
private val itemsPluralId: Int
) : AbstractBindingItem<ArkFilePickerItemFilesRootsPageBinding>() {
private val filesAdapter = ItemAdapter<FileItem>()
private var currentFiles = emptyList<Path>()
Expand Down Expand Up @@ -487,7 +478,7 @@ internal class FilesPage(
val popupMenu = PopupMenu(fragment.activity, anchor, Gravity.END)
popupMenu.menuInflater.inflate(R.menu.file_select_menu, popupMenu.menu)
popupMenu.setOnMenuItemClickListener {
pinFileCallback?.onPinFileClick(file)
viewModel.pinFile(file)
true
}
popupMenu.show()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package dev.arkbuilders.components.filepicker
import androidx.lifecycle.ViewModel
import androidx.lifecycle.ViewModelProvider
import androidx.lifecycle.viewModelScope
import dev.arkbuilders.arklib.arkGlobal
import kotlinx.coroutines.launch
import org.orbitmvi.orbit.Container
import org.orbitmvi.orbit.ContainerHost
Expand All @@ -13,7 +14,10 @@ import org.orbitmvi.orbit.viewmodel.container
import dev.arkbuilders.arklib.data.folders.FoldersRepo
import dev.arkbuilders.arklib.utils.DeviceStorageUtils
import dev.arkbuilders.arklib.utils.listChildren
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext
import java.nio.file.Path
import kotlin.io.path.exists
import kotlin.io.path.isDirectory

enum class ArkFilePickerMode {
Expand All @@ -34,6 +38,12 @@ internal sealed class FilePickerSideEffect {
object DismissDialog : FilePickerSideEffect()
object ToastAccessDenied : FilePickerSideEffect()
class NotifyPathPicked(val path: Path) : FilePickerSideEffect()
data object PinAsRoot : FilePickerSideEffect()
data object AlreadyRoot : FilePickerSideEffect()
data object PinAsFavorite : FilePickerSideEffect()
data object AlreadyFavorite : FilePickerSideEffect()
data object PinAsFirstRoot : FilePickerSideEffect()

}

internal class ArkFilePickerViewModel(
Expand All @@ -53,15 +63,13 @@ internal class ArkFilePickerViewModel(
}
}

fun addRoot(root:Path) {
viewModelScope.launch {
foldersRepo.addRoot(root)
refreshRootsWithFavs()
}
private suspend fun addRoot(root:Path) = withContext(Dispatchers.IO) {
foldersRepo.addRoot(root)
refreshRootsWithFavs()
}

fun addFavorite(favorite: Path) {
viewModelScope.launch {
private fun addFavorite(favorite: Path) {
viewModelScope.launch(Dispatchers.IO) {
val favoritePath = favorite.toRealPath()
val folders = foldersRepo.provideFolders()
val root = folders.keys.find { favoritePath.startsWith(it) }
Expand Down Expand Up @@ -165,6 +173,49 @@ internal class ArkFilePickerViewModel(

return children
}

fun haveRoot(): Boolean {
val arkGlobal = deviceStorageUtils.listStorages().firstOrNull()?.arkGlobal()
return arkGlobal?.exists() == true
}

fun pinFile(file: Path) = intent {
val rootsWithFavorites = container.stateFlow.value.rootsWithFavs
val roots = rootsWithFavorites.keys
val root = roots.find { root -> file.startsWith(root) }
val favorites = rootsWithFavorites[root]?.flatten()
val haveRoot = haveRoot()

root?.let {

//Make sure file isn't inside a root folder
if (root != file) {
val foundAsFavorite = favorites?.any { file.endsWith(it) } ?: false

if (!foundAsFavorite) {
addFavorite(file)
postSideEffect(FilePickerSideEffect.PinAsFavorite)
} else {
postSideEffect(FilePickerSideEffect.AlreadyFavorite)
}
} else {
postSideEffect(FilePickerSideEffect.AlreadyRoot)
}
} ?: let {

if (rootsWithFavorites.keys.contains(file)) {
postSideEffect(FilePickerSideEffect.AlreadyRoot)
} else {

addRoot(file)
if (!haveRoot) {
postSideEffect(FilePickerSideEffect.PinAsFirstRoot)
} else {
postSideEffect(FilePickerSideEffect.PinAsRoot)
}
}
}
}
}

internal class ArkFilePickerViewModelFactory(
Expand Down

This file was deleted.

10 changes: 10 additions & 0 deletions sample/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,19 @@ android {
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
}

signingConfigs {
create("release") {
storeFile = project.rootProject.file("keystore.jks")
storePassword = "sw0rdf1sh"
keyAlias = "ark-builders-test"
keyPassword = "rybamech"
}
}

buildTypes {
release {
isMinifyEnabled = false
signingConfig = signingConfigs.getByName("release")
proguardFiles(
getDefaultProguardFile("proguard-android-optimize.txt"),
"proguard-rules.pro"
Expand Down
Loading