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

improve breadcrumbs #48

Merged
merged 8 commits into from
Jan 9, 2025
Merged
Show file tree
Hide file tree
Changes from 4 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
164 changes: 45 additions & 119 deletions commons/src/main/kotlin/org/fossify/commons/views/Breadcrumbs.kt
Original file line number Diff line number Diff line change
Expand Up @@ -2,39 +2,41 @@ package org.fossify.commons.views

import android.content.Context
import android.content.res.ColorStateList
import android.graphics.drawable.ColorDrawable
import android.util.AttributeSet
import android.util.TypedValue
import android.view.LayoutInflater
import android.view.View
import android.widget.HorizontalScrollView
import android.widget.LinearLayout
import androidx.core.content.ContextCompat
import androidx.core.view.ViewCompat
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.databinding.ItemBreadcrumbFirstBinding
import org.fossify.commons.extensions.*
import org.fossify.commons.extensions.applyColorFilter
import org.fossify.commons.extensions.getBasePath
import org.fossify.commons.extensions.getProperPrimaryColor
import org.fossify.commons.extensions.getProperTextColor
import org.fossify.commons.extensions.humanizePath
import org.fossify.commons.models.FileDirItem

class Breadcrumbs(context: Context, attrs: AttributeSet) : HorizontalScrollView(context, attrs) {
private val inflater = context.getSystemService(Context.LAYOUT_INFLATER_SERVICE) as LayoutInflater
private val itemsLayout: LinearLayout
private var textColor = context.getProperTextColor()
private var accentColor = context.getProperPrimaryColor()
private var fontSize = resources.getDimension(R.dimen.bigger_text_size)
private var lastPath = ""
private var isLayoutDirty = true
private var isScrollToSelectedItemPending = false
private var isFirstScroll = true
private var stickyRootInitialLeft = 0
private var rootStartPadding = 0

private val textColorStateList: ColorStateList
get() = ColorStateList(
arrayOf(intArrayOf(android.R.attr.state_activated), intArrayOf()),
intArrayOf(
textColor,
textColor.adjustAlpha(0.6f)
accentColor,
textColor
)
)

Expand All @@ -45,49 +47,9 @@ class Breadcrumbs(context: Context, attrs: AttributeSet) : HorizontalScrollView(
isHorizontalScrollBarEnabled = false
itemsLayout = LinearLayout(context)
itemsLayout.orientation = LinearLayout.HORIZONTAL
rootStartPadding = paddingStart
itemsLayout.setPaddingRelative(0, paddingTop, paddingEnd, paddingBottom)
itemsLayout.setPaddingRelative(paddingStart, paddingTop, paddingEnd, paddingBottom)
setPaddingRelative(0, 0, 0, 0)
addView(itemsLayout, LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.MATCH_PARENT))
onGlobalLayout {
stickyRootInitialLeft = if (itemsLayout.childCount > 0) {
itemsLayout.getChildAt(0).left
} else {
0
}
}
}

private fun recomputeStickyRootLocation(left: Int) {
stickyRootInitialLeft = left
handleRootStickiness(scrollX)
}

private fun handleRootStickiness(scrollX: Int) {
if (scrollX > stickyRootInitialLeft) {
stickRoot(scrollX - stickyRootInitialLeft)
} else {
freeRoot()
}
}

private fun freeRoot() {
if (itemsLayout.childCount > 0) {
itemsLayout.getChildAt(0).translationX = 0f
}
}

private fun stickRoot(translationX: Int) {
if (itemsLayout.childCount > 0) {
val root = itemsLayout.getChildAt(0)
root.translationX = translationX.toFloat()
ViewCompat.setTranslationZ(root, translationZ)
}
}

override fun onScrollChanged(scrollX: Int, scrollY: Int, oldScrollX: Int, oldScrollY: Int) {
super.onScrollChanged(scrollX, scrollY, oldScrollX, oldScrollY)
handleRootStickiness(scrollX)
}

override fun onLayout(changed: Boolean, left: Int, top: Int, right: Int, bottom: Int) {
Expand All @@ -98,8 +60,6 @@ class Breadcrumbs(context: Context, attrs: AttributeSet) : HorizontalScrollView(
scrollToSelectedItem()
isScrollToSelectedItemPending = false
}

recomputeStickyRootLocation(left)
}

private fun scrollToSelectedItem() {
Expand Down Expand Up @@ -146,86 +106,52 @@ class Breadcrumbs(context: Context, attrs: AttributeSet) : HorizontalScrollView(
val tempPath = context.humanizePath(fullPath)

itemsLayout.removeAllViews()
val dirs = tempPath.split("/").dropLastWhile(String::isEmpty)
for (i in dirs.indices) {
val dir = dirs[i]
if (i > 0) {
currPath += dir + "/"
tempPath.split("/")
.dropLastWhile(String::isEmpty)
.forEachIndexed { i, dir ->
if (i > 0) {
currPath += "$dir/"
}
if (dir.isEmpty()) {
return@forEachIndexed
}
currPath = "${currPath.trimEnd('/')}/"
val item = FileDirItem(currPath, dir, true, 0, 0, 0)
addBreadcrumb(item, i, i > 0)
naveensingh marked this conversation as resolved.
Show resolved Hide resolved
scrollToSelectedItem()
}
}

if (dir.isEmpty()) {
continue
}
private fun addBreadcrumb(item: FileDirItem, index: Int, isLast: Boolean) {
ItemBreadcrumbBinding.inflate(inflater, itemsLayout, false).apply {
breadcrumbText.isActivated = isLast

currPath = "${currPath.trimEnd('/')}/"
val item = FileDirItem(currPath, dir, true, 0, 0, 0)
addBreadcrumb(item, i, i > 0)
scrollToSelectedItem()
}
}
breadcrumbText.text = item.name
breadcrumbText.setTextColor(textColorStateList)
breadcrumbText.setTextSize(TypedValue.COMPLEX_UNIT_PX, fontSize)

private fun addBreadcrumb(item: FileDirItem, index: Int, addPrefix: Boolean) {
if (itemsLayout.childCount == 0) {
val firstItemBgColor = if (isShownInDialog && context.isDynamicTheme()) {
resources.getColor(R.color.you_dialog_background_color, context.theme)
itemsLayout.addView(root)
if (index > 0) {
TextViewCompat.setCompoundDrawablesRelativeWithIntrinsicBounds(breadcrumbText, R.drawable.ic_chevron_right_vector, 0, 0, 0)
TextViewCompat.setCompoundDrawableTintList(breadcrumbText, textColorStateList)
} else {
context.getProperBackgroundColor()
breadcrumbText.background = ContextCompat.getDrawable(context, R.drawable.button_background)
breadcrumbText.background.applyColorFilter(textColor)
val horizontalPadding = context.resources.getDimensionPixelSize(R.dimen.normal_margin)
breadcrumbText.updatePadding(left = horizontalPadding, right = horizontalPadding)
}


ItemBreadcrumbFirstBinding.inflate(inflater, itemsLayout, false).apply {
resources.apply {
breadcrumbText.background = ContextCompat.getDrawable(context, R.drawable.button_background)
breadcrumbText.background.applyColorFilter(textColor)
elevation = 1f
background = ColorDrawable(firstItemBgColor)
val medium = getDimension(R.dimen.medium_margin).toInt()
breadcrumbText.setPadding(medium, medium, medium, medium)
setPadding(rootStartPadding, 0, 0, 0)
}

isActivated = item.path.trimEnd('/') == lastPath.trimEnd('/')
breadcrumbText.text = item.name
breadcrumbText.setTextColor(textColorStateList)
breadcrumbText.setTextSize(TypedValue.COMPLEX_UNIT_PX, fontSize)

itemsLayout.addView(this.root)

breadcrumbText.setOnClickListener {
if (itemsLayout.getChildAt(index) != null) {
breadcrumbText.setOnClickListener { v ->
if (itemsLayout.getChildAt(index) != null && itemsLayout.getChildAt(index) == v) {
if ((v.tag as? FileDirItem)?.path?.trimEnd('/') == lastPath.trimEnd('/')) {
scrollToSelectedItem()
} else {
listener?.breadcrumbClicked(index)
}
}

root.tag = item
}
} else {
ItemBreadcrumbBinding.inflate(inflater, itemsLayout, false).apply {
var textToAdd = item.name
if (addPrefix) {
textToAdd = "> $textToAdd"
}

isActivated = item.path.trimEnd('/') == lastPath.trimEnd('/')

breadcrumbText.text = textToAdd
breadcrumbText.setTextColor(textColorStateList)
breadcrumbText.setTextSize(TypedValue.COMPLEX_UNIT_PX, fontSize)

itemsLayout.addView(root)

breadcrumbText.setOnClickListener { v ->
if (itemsLayout.getChildAt(index) != null && itemsLayout.getChildAt(index) == v) {
if ((v.tag as? FileDirItem)?.path?.trimEnd('/') == lastPath.trimEnd('/')) {
scrollToSelectedItem()
} else {
listener?.breadcrumbClicked(index)
}
}
}

root.tag = item
}
root.tag = item
}
}

Expand Down
3 changes: 1 addition & 2 deletions commons/src/main/res/layout/item_breadcrumb.xml
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,9 @@
android:id="@+id/breadcrumb_text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@drawable/selector_clickable"
android:gravity="center_vertical"
android:minHeight="@dimen/breadcrumbs_layout_height"
android:paddingLeft="@dimen/small_margin"
android:paddingTop="@dimen/medium_margin"
android:paddingRight="@dimen/small_margin"
android:paddingBottom="@dimen/medium_margin"
android:textSize="@dimen/normal_text_size" />
19 changes: 0 additions & 19 deletions commons/src/main/res/layout/item_breadcrumb_first.xml

This file was deleted.

Loading