Skip to content
Open
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
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package org.fossify.commons.enums

enum class ConnectionTypes(val type: String) {
SMB("SMB"),
WebDav("WebDav"),
DAVx5("DAVx5"),
SFTP("SFTP"),
FTP("FTP"),

Default("Default");

companion object {
fun fromType(value: String): ConnectionTypes {
return entries.find { it.type == value } ?: Default
}
}
}

Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ import androidx.biometric.BiometricPrompt
import androidx.biometric.auth.AuthPromptCallback
import androidx.biometric.auth.AuthPromptHost
import androidx.biometric.auth.Class2BiometricAuthPrompt
import androidx.core.content.FileProvider
import androidx.core.net.toUri
import androidx.core.view.WindowInsetsCompat
import androidx.fragment.app.FragmentActivity
Expand All @@ -56,6 +57,7 @@ import org.fossify.commons.dialogs.UpgradeToProDialog
import org.fossify.commons.dialogs.WhatsNewDialog
import org.fossify.commons.dialogs.WritePermissionDialog
import org.fossify.commons.dialogs.WritePermissionDialog.WritePermissionDialogMode
import org.fossify.commons.enums.ConnectionTypes
import org.fossify.commons.helpers.CREATE_DOCUMENT_SDK_30
import org.fossify.commons.helpers.EXTRA_SHOW_ADVANCED
import org.fossify.commons.helpers.IS_FROM_GALLERY
Expand Down Expand Up @@ -470,6 +472,34 @@ fun Activity.sharePathIntent(path: String, applicationId: String) {
}
}

fun Activity.shareNetworkPathIntent(path: String, applicationId: String,file: File) {
ensureBackgroundThread {
val newUri = FileProvider.getUriForFile(this, "$applicationId.provider", file)
Intent().apply {
action = Intent.ACTION_SEND
putExtra(EXTRA_STREAM, newUri)
type = getUriMimeType(path, newUri).normalizeMimeTypeForSharing()
addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
grantUriPermission("android", newUri, Intent.FLAG_GRANT_READ_URI_PERMISSION)

try {
startActivity(Intent.createChooser(this, getString(R.string.share_via)))
} catch (e: ActivityNotFoundException) {
toast(R.string.no_app_found)
} catch (e: RuntimeException) {
if (e.cause is TransactionTooLargeException) {
toast(R.string.maximum_share_reached)
} else {
showErrorToast(e)
}
} catch (e: Exception) {
showErrorToast(e)
}
}
}
}

fun Activity.sharePathsIntent(paths: List<String>, applicationId: String) {
ensureBackgroundThread {
if (paths.size == 1) {
Expand Down Expand Up @@ -513,6 +543,49 @@ fun Activity.sharePathsIntent(paths: List<String>, applicationId: String) {
}
}

fun Activity.shareNetworkPathsIntent(paths: List<String>, applicationId: String,file: File) {
ensureBackgroundThread {
if (paths.size == 1) {
shareNetworkPathIntent(paths.first(), applicationId,file)
} else {
val uriPaths = ArrayList<String>()
val newUris = paths.map {
val uri = getFinalUriFromPath(it, applicationId) ?: return@ensureBackgroundThread
uriPaths.add(uri.path!!)
uri
} as ArrayList<Uri>

var mimeType = uriPaths.getMimeType()
if (mimeType.isEmpty() || mimeType == "*/*") {
mimeType = paths.getMimeType()
}
mimeType = mimeType.normalizeMimeTypeForSharing()

Intent().apply {
action = Intent.ACTION_SEND_MULTIPLE
type = mimeType
addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
putParcelableArrayListExtra(EXTRA_STREAM, newUris)

try {
startActivity(Intent.createChooser(this, getString(R.string.share_via)))
} catch (e: ActivityNotFoundException) {
toast(R.string.no_app_found)
} catch (e: RuntimeException) {
if (e.cause is TransactionTooLargeException) {
toast(R.string.maximum_share_reached)
} else {
showErrorToast(e)
}
} catch (e: Exception) {
showErrorToast(e)
}
}
}
}
}

fun Activity.setAsIntent(path: String, applicationId: String) {
ensureBackgroundThread {
val newUri = getFinalUriFromPath(path, applicationId) ?: return@ensureBackgroundThread
Expand All @@ -534,6 +607,27 @@ fun Activity.setAsIntent(path: String, applicationId: String) {
}
}

fun Activity.setAsNetworkIntent(path: String, applicationId: String,file: File) {
ensureBackgroundThread {
val newUri = FileProvider.getUriForFile(this, "$applicationId.provider", file)
Intent().apply {
action = Intent.ACTION_ATTACH_DATA
setDataAndType(newUri, getUriMimeType(path, newUri))
addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
val chooser = Intent.createChooser(this, getString(R.string.set_as))

try {
startActivityForResult(chooser, REQUEST_SET_AS)
} catch (e: ActivityNotFoundException) {
toast(R.string.no_app_found)
} catch (e: Exception) {
showErrorToast(e)
}
}
}
}

fun Activity.shareTextIntent(text: String) {
ensureBackgroundThread {
Intent().apply {
Expand Down Expand Up @@ -702,6 +796,8 @@ fun Activity.getFinalUriFromPath(path: String, applicationId: String): Uri? {
return uri
}



fun Activity.tryGenericMimeType(intent: Intent, mimeType: String, uri: Uri): Boolean {
var genericMimeType = mimeType.getGenericMimeType()
if (genericMimeType.isEmpty()) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import android.net.Uri
import android.provider.MediaStore
import androidx.compose.runtime.Immutable
import com.bumptech.glide.signature.ObjectKey
import org.fossify.commons.enums.ConnectionTypes
import org.fossify.commons.extensions.*
import org.fossify.commons.helpers.*
import java.io.File
Expand All @@ -16,7 +17,8 @@ open class FileDirItem(
var children: Int = 0,
var size: Long = 0L,
var modified: Long = 0L,
var mediaStoreId: Long = 0L
var mediaStoreId: Long = 0L,
var connectionType: ConnectionTypes = ConnectionTypes.Default
) :
Comparable<FileDirItem> {
companion object {
Expand Down
99 changes: 87 additions & 12 deletions commons/src/main/kotlin/org/fossify/commons/views/Breadcrumbs.kt
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import android.content.Context
import android.content.res.ColorStateList
import android.graphics.drawable.GradientDrawable
import android.graphics.drawable.RippleDrawable
import android.net.Uri
import android.util.AttributeSet
import android.util.TypedValue
import android.view.LayoutInflater
Expand All @@ -16,6 +17,7 @@ import androidx.core.view.updatePadding
import androidx.core.widget.TextViewCompat
import org.fossify.commons.R
import org.fossify.commons.databinding.ItemBreadcrumbBinding
import org.fossify.commons.enums.ConnectionTypes
import org.fossify.commons.extensions.adjustAlpha
import org.fossify.commons.extensions.getBasePath
import org.fossify.commons.extensions.getDialogBackgroundColor
Expand All @@ -26,6 +28,7 @@ import org.fossify.commons.extensions.onGlobalLayout
import org.fossify.commons.extensions.setDrawablesRelativeWithIntrinsicBounds
import org.fossify.commons.helpers.MEDIUM_ALPHA
import org.fossify.commons.models.FileDirItem
import androidx.core.net.toUri

class Breadcrumbs(context: Context, attrs: AttributeSet) : HorizontalScrollView(context, attrs) {
private val inflater =
Expand All @@ -40,7 +43,7 @@ class Breadcrumbs(context: Context, attrs: AttributeSet) : HorizontalScrollView(
private var isFirstScroll = true
private var stickyRootInitialLeft = 0
private var rootStartPadding = 0

val breadcrumbNames = LinkedHashMap<String, String?>()
private val textColorStateList: ColorStateList
get() = ColorStateList(
arrayOf(intArrayOf(android.R.attr.state_activated), intArrayOf()),
Expand Down Expand Up @@ -151,14 +154,35 @@ class Breadcrumbs(context: Context, attrs: AttributeSet) : HorizontalScrollView(
super.requestLayout()
}

fun setBreadcrumb(fullPath: String) {
fun setBreadcrumb(fullPath: String, connectionType: ConnectionTypes = ConnectionTypes.Default) {
lastPath = fullPath
val basePath = fullPath.getBasePath(context)
var currPath = basePath
val tempPath = context.humanizePath(fullPath)

val tempPath = if (
connectionType != ConnectionTypes.WebDav &&
connectionType != ConnectionTypes.SMB
) {
context.humanizePath(fullPath)
} else {
lastPath
}
itemsLayout.removeAllViews()
tempPath.split("/")
var pathSegments = mutableListOf<String>()
if(connectionType == ConnectionTypes.WebDav || connectionType == ConnectionTypes.SMB) {
val uri = tempPath.toUri()
val baseUrl = "${uri.scheme}://${uri.host}:${uri.port}"
pathSegments.add(baseUrl)
pathSegments.addAll(uri.pathSegments)
}

else if (connectionType == ConnectionTypes.DAVx5){
pathSegments.add(lastPath)
}
else {
pathSegments = tempPath.split("/").toMutableList()
}

pathSegments
.dropLastWhile(String::isEmpty)
.forEachIndexed { i, dir ->
if (i > 0) {
Expand All @@ -167,18 +191,46 @@ class Breadcrumbs(context: Context, attrs: AttributeSet) : HorizontalScrollView(
if (dir.isEmpty()) {
return@forEachIndexed
}
currPath = "${currPath.trimEnd('/')}/"
val item = FileDirItem(currPath, dir, true, 0, 0, 0)
currPath = if (connectionType != ConnectionTypes.WebDav && connectionType != ConnectionTypes.SMB) {
"${currPath.trimEnd('/')}/"
}
else
{dir}
val item = FileDirItem(currPath, dir, true, 0, 0, 0, connectionType = connectionType)
addBreadcrumb(
item = item,
index = i,
isLast = item.path.trimEnd('/') == lastPath.trimEnd('/')
)
scrollToSelectedItem()
}
}

fun setBreadcrumbWithName(fullPath: String, name: String?,connectionType: ConnectionTypes) {
if (fullPath == "") return
lastPath = fullPath
if (!breadcrumbNames.containsKey(fullPath)){
breadcrumbNames[fullPath] = name
}
else{
breadcrumbNames.removeAfter(fullPath)
}
itemsLayout.removeAllViews()

breadcrumbNames.entries.forEachIndexed { i, entry ->
entry.value?.let {
val item = FileDirItem(entry.key, it, true, 0, 0, 0, connectionType = connectionType)
addBreadcrumb(
item = item,
index = i,
isLast = item.path.trimEnd('/') == lastPath.trimEnd('/')
)
scrollToSelectedItem()
}
}
}

private fun addBreadcrumb(item: FileDirItem, index: Int, isLast: Boolean) {
public fun addBreadcrumb(item: FileDirItem, index: Int, isLast: Boolean) {
ItemBreadcrumbBinding.inflate(inflater, itemsLayout, false).apply {
breadcrumbText.isActivated = isLast && index != 0

Expand Down Expand Up @@ -230,15 +282,15 @@ class Breadcrumbs(context: Context, attrs: AttributeSet) : HorizontalScrollView(
}
}

fun updateColor(color: Int) {
fun updateColor(color: Int,connectionType: ConnectionTypes = ConnectionTypes.Default) {
textColor = color
setBreadcrumb(lastPath)
setBreadcrumb(lastPath,connectionType)
}

fun updateFontSize(size: Float, updateTexts: Boolean) {
fun updateFontSize(size: Float, updateTexts: Boolean,connectionType: ConnectionTypes = ConnectionTypes.Default) {
fontSize = size
if (updateTexts) {
setBreadcrumb(lastPath)
setBreadcrumb(lastPath, connectionType = connectionType)
}
}

Expand All @@ -252,6 +304,29 @@ class Breadcrumbs(context: Context, attrs: AttributeSet) : HorizontalScrollView(

fun getItemCount() = itemsLayout.childCount

fun getItemsTillIndex(index: Int): List<FileDirItem>{
return (0..index).mapNotNull { index ->
itemsLayout.getChildAt(index).tag as? FileDirItem
}
}

fun getAllItems(): List<FileDirItem> {
return (0 until itemsLayout.childCount).mapNotNull { index ->
itemsLayout.getChildAt(index).tag as? FileDirItem
}
}

fun <K, V> LinkedHashMap<K, V>.removeAfter(key: K) {
val index = breadcrumbNames.keys.indexOf(key as String)
if (index != -1) {
val keysToRemove = breadcrumbNames.keys.drop(index + 1)

for (key in keysToRemove) {
breadcrumbNames.remove(key)
}
}
}

interface BreadcrumbsListener {
fun breadcrumbClicked(id: Int)
}
Expand Down
7 changes: 6 additions & 1 deletion commons/src/main/res/values/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -302,6 +302,7 @@
<string name="loading">Loading…</string>
<string name="access_storage_prompt">Please grant our app access to all your files, it might not work well without it.</string>

<string name="unknown_items">--- items</string>
<plurals name="items">
<item quantity="one">%d item</item>
<item quantity="other">%d items</item>
Expand Down Expand Up @@ -485,6 +486,7 @@
<!-- Confirmation dialog -->
<string name="proceed_with_deletion">Are you sure you want to proceed with the deletion?</string>
<string name="deletion_confirmation">Are you sure you want to delete %s?</string> <!-- Are you sure you want to delete 5 items? -->
<string name="deletion_confirmation_connection">Are you sure you want to delete connection %s?</string> <!-- Are you sure you want to delete 5 items? -->
<string name="deletion_confirmation_short">Delete %s?</string>
<string name="move_to_recycle_bin_confirmation">Are you sure you want to move %s into the recycle bin?</string> <!-- Are you sure you want to move 3 items into the recycle bin? -->
<string name="are_you_sure_delete">Are you sure you want to delete this item?</string>
Expand Down Expand Up @@ -1212,4 +1214,7 @@

<!-- Description of our developer profile on Google Play, it can have max 140 characters -->
<string name="developer_description">A group of simple, open source Android apps with customizable widgets, without ads and unnecessary permissions.</string>
</resources>



</resources>
Loading