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

Sample for ark-core FileStorage JNI bindings usage #110

Open
wants to merge 15 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 7 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
1 change: 0 additions & 1 deletion .github/workflows/build_sample.yml
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,6 @@ jobs:
- name: Validate Gradle wrapper
uses: gradle/[email protected]


- name: Decrypt the keystore for signing
run: |
echo "${{ secrets.KEYSTORE_ENCRYPTED }}" > keystore.asc
Expand Down
1 change: 0 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,4 +28,3 @@ git push --tags

- Create an action build file under `.github/workflows/` folder, following any existing build script.
- Create a release build file under `.github/workflows/` folder, following any existing release script.

2 changes: 2 additions & 0 deletions gradle/libs.versions.toml
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ coil = "2.4.0"
androidxFragmentKtx = "1.6.1"
fastadapter = "5.7.0"
arkLib = "0.3.5"
core = "1.0.0"
orbitMvi = "6.1.0"
viewbindingPropertyDelegate = "1.5.9"
androidXCore = "1.9.0"
Expand All @@ -28,6 +29,7 @@ fastadapter = { group = "com.mikepenz", name = "fastadapter", version.ref = "fas
fastadapter-extensions-binding = { group = "com.mikepenz", name = "fastadapter-extensions-binding", version.ref = "fastadapter" }
fastadapter-extensions-diff = { group = "com.mikepenz", name = "fastadapter-extensions-diff", version.ref = "fastadapter" }
arklib = { group = "dev.arkbuilders", name = "arklib", version.ref = "arkLib" }
core = { group = "dev.arkbuilders", name = "core", version.ref = "core" }
orbit-mvi-viewmodel = { group = "org.orbit-mvi", name = "orbit-viewmodel", version.ref = "orbitMvi" }
viewbinding-property-delegate = { group = "com.github.kirich1409", name = "viewbindingpropertydelegate-noreflection", version.ref = "viewbindingPropertyDelegate" }
androidx-core-ktx = { group = "androidx.core", name = "core-ktx", version.ref = "androidXCore" }
Expand Down
4 changes: 2 additions & 2 deletions sample/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -72,12 +72,12 @@ android {
dependencies {
implementation(project(":filepicker"))
implementation(project(":about"))

implementation(libraries.core)
implementation(libraries.arklib)
implementation("androidx.core:core-ktx:1.12.0")
implementation(libraries.androidx.appcompat)
implementation(libraries.android.material)
testImplementation(libraries.junit)
androidTestImplementation(libraries.androidx.test.junit)
androidTestImplementation(libraries.androidx.test.espresso)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ class MapEntryDialog(private val isDelete: Boolean,
false
}
} else {
mBinding.tvTitle.text = getString(R.string.new_map_entry)
mBinding.tvTitle.text = getString(R.string.set_map_entry)
mBinding.edtValue.visibility = View.VISIBLE
mBinding.edtValue.setOnEditorActionListener { v, actionId, event ->
if (actionId == EditorInfo.IME_ACTION_DONE) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,38 +4,41 @@ import android.annotation.SuppressLint
import android.content.Context
import android.content.Intent
import android.os.Bundle
import android.util.Log
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.view.inputmethod.EditorInfo
import androidx.activity.result.contract.ActivityResultContracts
import androidx.fragment.app.DialogFragment
import dev.arkbuilders.core.FileStorage
import dev.arkbuilders.sample.R
import dev.arkbuilders.sample.databinding.FragmentStorageDemoBinding
import dev.arkbuilders.sample.extension.getAbsolutePath
import java.io.File
import java.util.UUID

class StorageDemoFragment: DialogFragment() {
class StorageDemoFragment : DialogFragment() {

private val TAG = StorageDemoFragment::class.java.name

private lateinit var binding: FragmentStorageDemoBinding
private val map by lazy { mutableMapOf<String, String>() }
private var workingDir: String = "/"

private val selectDirRequest = registerForActivityResult(ActivityResultContracts.OpenDocumentTree()) { uri ->
uri?.let {
// call this to persist permission across device reboots
context?.contentResolver?.takePersistableUriPermission(uri, Intent.FLAG_GRANT_READ_URI_PERMISSION)
workingDir = uri.getAbsolutePath()
refreshFilesTree()
private var storage: FileStorage? = null
oluiscabral marked this conversation as resolved.
Show resolved Hide resolved

private val selectDirRequest =
registerForActivityResult(ActivityResultContracts.OpenDocumentTree()) { uri ->
uri?.let {
// call this to persist permission across device reboots
context?.contentResolver?.takePersistableUriPermission(
uri,
Intent.FLAG_GRANT_READ_URI_PERMISSION
)
workingDir = uri.getAbsolutePath()
val storageName = UUID.randomUUID().toString().take(6)
binding.edtStorageName.setText(storageName)
newStorage(storageName)
updateDisplayMap()
}
}
}

private fun getCurrentAbsolutePath(): String {
return workingDir + "/" + binding.edtStoragePath.text.toString()
}

override fun onCreate(savedInstanceState: Bundle?) {
setStyle(STYLE_NORMAL, R.style.Theme_ArkComponents)
Expand All @@ -48,7 +51,8 @@ class StorageDemoFragment: DialogFragment() {
container: ViewGroup?,
savedInstanceState: Bundle?
): View {
val layoutInflater = context?.getSystemService(Context.LAYOUT_INFLATER_SERVICE) as? LayoutInflater
val layoutInflater =
context?.getSystemService(Context.LAYOUT_INFLATER_SERVICE) as? LayoutInflater
binding = FragmentStorageDemoBinding.inflate(layoutInflater ?: LayoutInflater.from(context))
initViews(binding)
return binding.root
Expand All @@ -59,61 +63,64 @@ class StorageDemoFragment: DialogFragment() {
selectDirRequest.launch(null)
}

binding.edtStoragePath.setOnEditorActionListener { v, actionId, event ->
binding.edtStorageName.setOnEditorActionListener { v, actionId, event ->
if (actionId == EditorInfo.IME_ACTION_DONE) {
refreshFilesTree()
val storageName = v.text.toString()
newStorage(storageName)
return@setOnEditorActionListener true
}
false
}

binding.btnNewMapEntry.setOnClickListener {
MapEntryDialog(isDelete = false, onDone = { key, value ->
map[key] = value ?: ""
refreshMap()
}).show(parentFragmentManager, MapEntryDialog::class.java.name)
binding.btnSetEntry.setOnClickListener {
MapEntryDialog(
isDelete = false,
onDone = { key, value ->
storage?.set(key, value)
updateDisplayMap()
}
).show(parentFragmentManager, MapEntryDialog::class.java.name)
}

binding.btnDeleteEntry.setOnClickListener {
MapEntryDialog(isDelete = true, onDone = { key, value ->
map.remove(key)
refreshMap()
}).show(parentFragmentManager, MapEntryDialog::class.java.name)
MapEntryDialog(
isDelete = true,
onDone = { key, _ ->
storage?.remove(key)
updateDisplayMap()
}
).show(parentFragmentManager, MapEntryDialog::class.java.name)
}

binding.btnClearMap.setOnClickListener {
map.clear()
refreshMap()
binding.btnErase.setOnClickListener {
storage?.erase()
storage = null
binding.tvCurrentAbsolutePath.text = workingDir
binding.edtStorageName.setText("")
updateDisplayMap()
}
}

private fun refreshFilesTree() {
val currentAbsolutePath = getCurrentAbsolutePath()
binding.tvCurrentAbsolutePath.text = currentAbsolutePath

try {
val currentDir = File(currentAbsolutePath)
currentDir.mkdirs()
val listFiles = currentDir.listFiles() ?: return
val fileTreeBuilder = StringBuilder()
for (file in listFiles) {
fileTreeBuilder.append(file.name).append("\n")
}
binding.tvCurrentFileTree.text = fileTreeBuilder.toString()
} catch (e: Exception) {
Log.e(TAG, e.message.toString())
binding.btnWriteFs.setOnClickListener {
storage?.writeFS()
}
}

private fun refreshMap() {
if (map.isEmpty()) {
private fun newStorage(name: String) {
val absolutePath = "$workingDir/$name"
storage = FileStorage(name, absolutePath)
binding.tvCurrentAbsolutePath.text = absolutePath
updateDisplayMap()
}

private fun updateDisplayMap() {
storage ?: let {
binding.tvMapValues.text = getString(R.string.empty_map)
return
}
val mapEntries = StringBuilder()
for (entry in map) {
mapEntries.append(entry.key).append(" -> ").append(entry.value).append("\n")
storage!!.iterator().forEach { (key, value) ->
mapEntries.append(key).append(" -> ").append(value).append("\n")
}
binding.tvMapValues.text = mapEntries.toString()
binding.tvMapValues.text = mapEntries.toString().ifEmpty { getString(R.string.empty_map) }
}
}
43 changes: 23 additions & 20 deletions sample/src/main/res/layout/fragment_storage_demo.xml
Original file line number Diff line number Diff line change
Expand Up @@ -26,15 +26,15 @@
android:layout_marginTop="10dp"
android:imeOptions="actionDone"
android:inputType="text"
android:id="@+id/edt_storage_path"
android:hint="Relative storage path (without leading slash)"/>
android:id="@+id/edt_storage_name"
android:hint="Name"/>

<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:layout_constraintStart_toStartOf="@+id/btn_working_dir"
app:layout_constraintEnd_toEndOf="@+id/btn_working_dir"
app:layout_constraintTop_toBottomOf="@+id/edt_storage_path"
app:layout_constraintTop_toBottomOf="@+id/edt_storage_name"
android:layout_marginTop="10dp"
android:textStyle="bold"
android:id="@+id/tv_current_absolute_path"
Expand All @@ -47,17 +47,6 @@
app:layout_constraintStart_toStartOf="@+id/btn_working_dir"
app:layout_constraintEnd_toEndOf="@+id/btn_working_dir"
app:layout_constraintTop_toBottomOf="@+id/tv_current_absolute_path"
android:layout_marginTop="10dp"
android:id="@+id/tv_current_file_tree"
tools:text="/sdcard/Documents/.ark/test"
android:layout_marginStart="10dp"/>

<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:layout_constraintStart_toStartOf="@+id/btn_working_dir"
app:layout_constraintEnd_toEndOf="@+id/btn_working_dir"
app:layout_constraintTop_toBottomOf="@+id/tv_current_file_tree"
android:layout_marginTop="20dp"
android:id="@+id/tv_map_title"
android:textStyle="bold"
Expand All @@ -77,21 +66,21 @@
<Button
android:layout_width="0dp"
android:layout_height="wrap_content"
android:id="@+id/btn_new_map_entry"
android:id="@+id/btn_set_entry"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintHorizontal_chainStyle="packed"
app:layout_constraintEnd_toStartOf="@+id/btn_delete_entry"
app:layout_constraintTop_toBottomOf="@+id/tv_map_values"
android:ellipsize="middle"
android:maxLines="1"
android:layout_marginTop="20dp"
android:text="@string/new_map_entry"/>
android:text="Set entry"/>

<Button
android:layout_width="0dp"
android:layout_height="wrap_content"
android:id="@+id/btn_delete_entry"
app:layout_constraintStart_toEndOf="@+id/btn_new_map_entry"
app:layout_constraintStart_toEndOf="@+id/btn_set_entry"
app:layout_constraintHorizontal_chainStyle="packed"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toBottomOf="@+id/tv_map_values"
Expand All @@ -104,15 +93,29 @@
<Button
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="@+id/btn_clear_map"
android:id="@+id/btn_erase"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_chainStyle="packed"
app:layout_constraintTop_toBottomOf="@+id/btn_set_entry"
android:ellipsize="middle"
android:maxLines="1"
android:layout_marginStart="10dp"
android:layout_marginTop="20dp"
android:text="Erase"/>

<Button
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="@+id/btn_write_fs"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_chainStyle="packed"
app:layout_constraintTop_toBottomOf="@+id/btn_new_map_entry"
app:layout_constraintTop_toBottomOf="@+id/btn_erase"
android:ellipsize="middle"
android:maxLines="1"
android:layout_marginStart="10dp"
android:layout_marginTop="20dp"
android:text="Clear map"/>
android:text="Write FS"/>

</androidx.constraintlayout.widget.ConstraintLayout>
1 change: 1 addition & 0 deletions sample/src/main/res/values/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -9,4 +9,5 @@
<string name="delete_map_entry">Delete map entry</string>
<string name="empty_map">Empty</string>
<string name="open_about">Open About</string>
<string name="set_map_entry">Set map entry</string>
</resources>
10 changes: 9 additions & 1 deletion settings.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -16,13 +16,21 @@ dependencyResolutionManagement {
url = URI("https://jitpack.io")
}
maven {
name = "GitHubPackages"
name = "arklib-android GitHub Packages"
url = URI("https://maven.pkg.github.com/ARK-Builders/arklib-android")
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's use ark-android to avoid confusion with the archived repo.

It was just a fat lib when we were prototyping, now we moved to the next level with modular framework 😁

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes. I don't know if I understood it correctly. This is indeed a reference to arklib-android archive, it is not a name for the current repo. Should we use another repo instead?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh, I didn't notice the link leads to the archived repo.

We certainly should not use archived repos.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

But what do we use from arklib-android?

Copy link
Collaborator Author

@oluiscabral oluiscabral Dec 12, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@kirillt It's being used in at least 23 places, just search for dev.arkbuilders.arklib and you'll realize it too. Here's an example on the sample package

import dev.arkbuilders.arklib.data.folders.FoldersRepo
import dev.arkbuilders.arklib.initArkLib
import dev.arkbuilders.arklib.initRustLogger

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

But what do we use from arklib-android?

TagSelector and ScoreWidget dependent on arklib, they need ResourceIndex, TagStorage, ScoreStorage and so on

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks guys, I wasn't realizing it.. I'll come up with plan for the upgrade later.

credentials {
username = "token"
password = "\u0037\u0066\u0066\u0036\u0030\u0039\u0033\u0066\u0032\u0037\u0033\u0036\u0033\u0037\u0064\u0036\u0037\u0066\u0038\u0030\u0034\u0039\u0062\u0030\u0039\u0038\u0039\u0038\u0066\u0034\u0066\u0034\u0031\u0064\u0062\u0033\u0064\u0033\u0038\u0065"
}
}
maven {
name = "ark-core GitHub Packages"
url = URI("https://maven.pkg.github.com/ARK-Builders/ark-core")
credentials {
username = "token"
password = "\u0037\u0066\u0066\u0036\u0030\u0039\u0033\u0066\u0032\u0037\u0033\u0036\u0033\u0037\u0064\u0036\u0037\u0066\u0038\u0030\u0034\u0039\u0062\u0030\u0039\u0038\u0039\u0038\u0066\u0034\u0066\u0034\u0031\u0064\u0062\u0033\u0064\u0033\u0038\u0065"
}
}
}

versionCatalogs {
Expand Down
Loading