mirror of
https://github.com/kiwix/kiwix-android.git
synced 2025-08-03 18:56:44 -04:00
Merge pull request #2803 from kiwix/Issue#2405
File picker feature is added.
This commit is contained in:
commit
9a227f532d
@ -19,7 +19,10 @@
|
|||||||
package org.kiwix.kiwixmobile.nav.destination.library
|
package org.kiwix.kiwixmobile.nav.destination.library
|
||||||
|
|
||||||
import android.Manifest
|
import android.Manifest
|
||||||
|
import android.content.ActivityNotFoundException
|
||||||
|
import android.content.Intent
|
||||||
import android.content.pm.PackageManager
|
import android.content.pm.PackageManager
|
||||||
|
import android.net.Uri
|
||||||
import android.os.Build
|
import android.os.Build
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.os.Environment
|
import android.os.Environment
|
||||||
@ -29,10 +32,12 @@ import android.view.MenuInflater
|
|||||||
import android.view.MenuItem
|
import android.view.MenuItem
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import android.view.ViewGroup
|
import android.view.ViewGroup
|
||||||
|
import android.widget.Toast
|
||||||
import androidx.appcompat.app.AppCompatActivity
|
import androidx.appcompat.app.AppCompatActivity
|
||||||
import androidx.appcompat.view.ActionMode
|
import androidx.appcompat.view.ActionMode
|
||||||
import androidx.appcompat.widget.Toolbar
|
import androidx.appcompat.widget.Toolbar
|
||||||
import androidx.core.content.ContextCompat
|
import androidx.core.content.ContextCompat
|
||||||
|
import androidx.core.net.toUri
|
||||||
import androidx.fragment.app.FragmentActivity
|
import androidx.fragment.app.FragmentActivity
|
||||||
import androidx.lifecycle.Observer
|
import androidx.lifecycle.Observer
|
||||||
import androidx.lifecycle.ViewModelProvider
|
import androidx.lifecycle.ViewModelProvider
|
||||||
@ -42,6 +47,7 @@ import io.reactivex.android.schedulers.AndroidSchedulers
|
|||||||
import io.reactivex.disposables.CompositeDisposable
|
import io.reactivex.disposables.CompositeDisposable
|
||||||
import kotlinx.android.synthetic.main.fragment_destination_library.file_management_no_files
|
import kotlinx.android.synthetic.main.fragment_destination_library.file_management_no_files
|
||||||
import kotlinx.android.synthetic.main.fragment_destination_library.go_to_downloads_button_no_files
|
import kotlinx.android.synthetic.main.fragment_destination_library.go_to_downloads_button_no_files
|
||||||
|
import kotlinx.android.synthetic.main.fragment_destination_library.select_file
|
||||||
import kotlinx.android.synthetic.main.fragment_destination_library.zim_swiperefresh
|
import kotlinx.android.synthetic.main.fragment_destination_library.zim_swiperefresh
|
||||||
import kotlinx.android.synthetic.main.fragment_destination_library.zimfilelist
|
import kotlinx.android.synthetic.main.fragment_destination_library.zimfilelist
|
||||||
import org.kiwix.kiwixmobile.R
|
import org.kiwix.kiwixmobile.R
|
||||||
@ -53,11 +59,13 @@ import org.kiwix.kiwixmobile.core.extensions.ActivityExtensions.viewModel
|
|||||||
import org.kiwix.kiwixmobile.core.extensions.toast
|
import org.kiwix.kiwixmobile.core.extensions.toast
|
||||||
import org.kiwix.kiwixmobile.core.main.CoreMainActivity
|
import org.kiwix.kiwixmobile.core.main.CoreMainActivity
|
||||||
import org.kiwix.kiwixmobile.core.navigateToSettings
|
import org.kiwix.kiwixmobile.core.navigateToSettings
|
||||||
|
import org.kiwix.kiwixmobile.core.utils.FILE_SELECT_CODE
|
||||||
import org.kiwix.kiwixmobile.core.utils.LanguageUtils
|
import org.kiwix.kiwixmobile.core.utils.LanguageUtils
|
||||||
import org.kiwix.kiwixmobile.core.utils.REQUEST_STORAGE_PERMISSION
|
import org.kiwix.kiwixmobile.core.utils.REQUEST_STORAGE_PERMISSION
|
||||||
import org.kiwix.kiwixmobile.core.utils.SharedPreferenceUtil
|
import org.kiwix.kiwixmobile.core.utils.SharedPreferenceUtil
|
||||||
import org.kiwix.kiwixmobile.core.utils.dialog.DialogShower
|
import org.kiwix.kiwixmobile.core.utils.dialog.DialogShower
|
||||||
import org.kiwix.kiwixmobile.core.utils.dialog.KiwixDialog
|
import org.kiwix.kiwixmobile.core.utils.dialog.KiwixDialog
|
||||||
|
import org.kiwix.kiwixmobile.core.utils.files.FileUtils
|
||||||
import org.kiwix.kiwixmobile.core.zim_manager.fileselect_view.adapter.BookOnDiskDelegate
|
import org.kiwix.kiwixmobile.core.zim_manager.fileselect_view.adapter.BookOnDiskDelegate
|
||||||
import org.kiwix.kiwixmobile.core.zim_manager.fileselect_view.adapter.BooksOnDiskAdapter
|
import org.kiwix.kiwixmobile.core.zim_manager.fileselect_view.adapter.BooksOnDiskAdapter
|
||||||
import org.kiwix.kiwixmobile.core.zim_manager.fileselect_view.adapter.BooksOnDiskListItem
|
import org.kiwix.kiwixmobile.core.zim_manager.fileselect_view.adapter.BooksOnDiskListItem
|
||||||
@ -67,6 +75,7 @@ import org.kiwix.kiwixmobile.zim_manager.ZimManageViewModel.FileSelectActions.Re
|
|||||||
import org.kiwix.kiwixmobile.zim_manager.ZimManageViewModel.FileSelectActions.RequestNavigateTo
|
import org.kiwix.kiwixmobile.zim_manager.ZimManageViewModel.FileSelectActions.RequestNavigateTo
|
||||||
import org.kiwix.kiwixmobile.zim_manager.ZimManageViewModel.FileSelectActions.RequestSelect
|
import org.kiwix.kiwixmobile.zim_manager.ZimManageViewModel.FileSelectActions.RequestSelect
|
||||||
import org.kiwix.kiwixmobile.zim_manager.fileselect_view.FileSelectListState
|
import org.kiwix.kiwixmobile.zim_manager.fileselect_view.FileSelectListState
|
||||||
|
import java.io.File
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
|
|
||||||
private const val WAS_IN_ACTION_MODE = "WAS_IN_ACTION_MODE"
|
private const val WAS_IN_ACTION_MODE = "WAS_IN_ACTION_MODE"
|
||||||
@ -139,6 +148,67 @@ class LocalLibraryFragment : BaseFragment() {
|
|||||||
go_to_downloads_button_no_files.setOnClickListener {
|
go_to_downloads_button_no_files.setOnClickListener {
|
||||||
offerAction(FileSelectActions.UserClickedDownloadBooksButton)
|
offerAction(FileSelectActions.UserClickedDownloadBooksButton)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
select_file.setOnClickListener {
|
||||||
|
showFileChooser()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun showFileChooser() {
|
||||||
|
val intent = Intent().apply {
|
||||||
|
action = Intent.ACTION_GET_CONTENT
|
||||||
|
type = "*/*"
|
||||||
|
addCategory(Intent.CATEGORY_OPENABLE)
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
startActivityForResult(
|
||||||
|
Intent.createChooser(intent, "Select a zim file"),
|
||||||
|
FILE_SELECT_CODE
|
||||||
|
)
|
||||||
|
} catch (ex: ActivityNotFoundException) {
|
||||||
|
activity.toast(resources.getString(R.string.no_app_found_to_open), Toast.LENGTH_SHORT)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
|
||||||
|
when (requestCode) {
|
||||||
|
FILE_SELECT_CODE -> {
|
||||||
|
data?.data?.let { uri ->
|
||||||
|
getZimFileFromUri(uri)?.let(::navigateToReaderFragment)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else -> super.onActivityResult(requestCode, resultCode, data)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun getZimFileFromUri(
|
||||||
|
uri: Uri
|
||||||
|
): File? {
|
||||||
|
val filePath = FileUtils.getLocalFilePathByUri(
|
||||||
|
requireActivity().applicationContext, uri
|
||||||
|
)
|
||||||
|
if (filePath == null || !File(filePath).exists()) {
|
||||||
|
activity.toast(R.string.error_file_not_found)
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
val file = File(filePath)
|
||||||
|
return if (!FileUtils.isValidZimFile(file.path)) {
|
||||||
|
activity.toast(R.string.error_file_invalid)
|
||||||
|
null
|
||||||
|
} else {
|
||||||
|
file
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun navigateToReaderFragment(file: File) {
|
||||||
|
if (!file.canRead()) {
|
||||||
|
activity.toast(R.string.unable_to_read_zim_file)
|
||||||
|
} else {
|
||||||
|
activity?.navigate(
|
||||||
|
LocalLibraryFragmentDirections.actionNavigationLibraryToNavigationReader()
|
||||||
|
.apply { zimFileUri = file.toUri().toString() }
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) {
|
override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) {
|
||||||
|
@ -77,5 +77,17 @@
|
|||||||
app:layout_constraintStart_toStartOf="@+id/file_management_no_files"
|
app:layout_constraintStart_toStartOf="@+id/file_management_no_files"
|
||||||
app:layout_constraintTop_toBottomOf="@+id/file_management_no_files" />
|
app:layout_constraintTop_toBottomOf="@+id/file_management_no_files" />
|
||||||
|
|
||||||
|
<com.google.android.material.floatingactionbutton.FloatingActionButton
|
||||||
|
android:id="@+id/select_file"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginEnd="10dp"
|
||||||
|
android:layout_marginBottom="60dp"
|
||||||
|
android:contentDescription="@string/app_name"
|
||||||
|
android:src="@drawable/ic_add_blue_24dp"
|
||||||
|
app:backgroundTint="@color/black"
|
||||||
|
app:fabSize="auto"
|
||||||
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent" />
|
||||||
|
|
||||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||||
|
@ -6,4 +6,5 @@
|
|||||||
<string name="cannot_open_file">Failed to open file\nPlease try looking for this file in the Device Tab of your Library</string>
|
<string name="cannot_open_file">Failed to open file\nPlease try looking for this file in the Device Tab of your Library</string>
|
||||||
<string name="send_files_title">Send Files</string>
|
<string name="send_files_title">Send Files</string>
|
||||||
<string name="receive_files_title">Receive Files</string>
|
<string name="receive_files_title">Receive Files</string>
|
||||||
|
<string name="no_app_found_to_open">No app found to select zim file!</string>
|
||||||
</resources>
|
</resources>
|
||||||
|
@ -42,3 +42,5 @@ const val OLD_PROVIDER_DOMAIN = "org.kiwix.zim.base"
|
|||||||
// For Storage select dialog
|
// For Storage select dialog
|
||||||
const val INTERNAL_SELECT_POSITION = 0
|
const val INTERNAL_SELECT_POSITION = 0
|
||||||
const val EXTERNAL_SELECT_POSITION = 1
|
const val EXTERNAL_SELECT_POSITION = 1
|
||||||
|
|
||||||
|
const val FILE_SELECT_CODE = 5
|
||||||
|
@ -36,6 +36,8 @@ import org.kiwix.kiwixmobile.core.extensions.toast
|
|||||||
import java.io.BufferedReader
|
import java.io.BufferedReader
|
||||||
import java.io.File
|
import java.io.File
|
||||||
import java.io.IOException
|
import java.io.IOException
|
||||||
|
import java.lang.Exception
|
||||||
|
import java.util.ArrayList
|
||||||
|
|
||||||
object FileUtils {
|
object FileUtils {
|
||||||
|
|
||||||
@ -105,6 +107,11 @@ object FileUtils {
|
|||||||
if (documentId[0] == "primary") {
|
if (documentId[0] == "primary") {
|
||||||
return "${Environment.getExternalStorageDirectory()}/${documentId[1]}"
|
return "${Environment.getExternalStorageDirectory()}/${documentId[1]}"
|
||||||
}
|
}
|
||||||
|
return try {
|
||||||
|
"${getSdCardMainPath(context)}/${documentId[1]}"
|
||||||
|
} catch (ignore: Exception) {
|
||||||
|
null
|
||||||
|
}
|
||||||
} else if ("com.android.providers.downloads.documents" == uri.authority)
|
} else if ("com.android.providers.downloads.documents" == uri.authority)
|
||||||
return try {
|
return try {
|
||||||
documentProviderContentQuery(context, uri)
|
documentProviderContentQuery(context, uri)
|
||||||
@ -235,6 +242,13 @@ object FileUtils {
|
|||||||
"".also { e.printStackTrace() }
|
"".also { e.printStackTrace() }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@JvmStatic fun isValidZimFile(filePath: String): Boolean =
|
||||||
|
filePath.endsWith(".zim") || filePath.endsWith(".zimaa")
|
||||||
|
|
||||||
|
@JvmStatic fun getSdCardMainPath(context: Context): String =
|
||||||
|
"${context.getExternalFilesDirs("")[1]}"
|
||||||
|
.substringBefore(context.getString(R.string.android_directory_seperator))
|
||||||
|
|
||||||
@SuppressLint("WrongConstant")
|
@SuppressLint("WrongConstant")
|
||||||
@JvmStatic fun getPathFromUri(activity: Activity, data: Intent): String? {
|
@JvmStatic fun getPathFromUri(activity: Activity, data: Intent): String? {
|
||||||
val uri: Uri? = data.data
|
val uri: Uri? = data.data
|
||||||
|
@ -45,6 +45,7 @@
|
|||||||
<string name="server_started_message" tools:keep="@string/server_started_message">Enter this ip address into your browser to access the server %s</string>
|
<string name="server_started_message" tools:keep="@string/server_started_message">Enter this ip address into your browser to access the server %s</string>
|
||||||
<string name="share_host_address">Share URL via other applications</string>
|
<string name="share_host_address">Share URL via other applications</string>
|
||||||
<string name="error_file_not_found">Error: The selected ZIM file could not be found.</string>
|
<string name="error_file_not_found">Error: The selected ZIM file could not be found.</string>
|
||||||
|
<string name="unable_to_read_zim_file">Unable to read this zim file!</string>
|
||||||
<string name="zim_not_opened">Unable to open zim file</string>
|
<string name="zim_not_opened">Unable to open zim file</string>
|
||||||
<string name="error_file_invalid">Error: The selected file is not a valid ZIM file.</string>
|
<string name="error_file_invalid">Error: The selected file is not a valid ZIM file.</string>
|
||||||
<string name="error_article_url_not_found">Error: Loading article (Url: %1$s) failed.</string>
|
<string name="error_article_url_not_found">Error: Loading article (Url: %1$s) failed.</string>
|
||||||
|
Loading…
x
Reference in New Issue
Block a user