* For #1574: Adds collections to home view * Adds colored icons and expansion * Adds state change * Adds more styling * Adds ItsNotBrokenSnacks * Adds chevron * Improves styling of swipe to delete and adds delete action * Fix nits * Try to add real savingnightly-build-test
parent
282ad31345
commit
7d577e5953
@ -0,0 +1,17 @@
|
|||||||
|
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
|
file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
|
package org.mozilla.fenix.home.sessioncontrol.viewholders
|
||||||
|
|
||||||
|
import android.view.View
|
||||||
|
import androidx.recyclerview.widget.RecyclerView
|
||||||
|
import org.mozilla.fenix.R
|
||||||
|
|
||||||
|
class CollectionHeaderViewHolder(
|
||||||
|
view: View
|
||||||
|
) : RecyclerView.ViewHolder(view) {
|
||||||
|
companion object {
|
||||||
|
const val LAYOUT_ID = R.layout.collection_header
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,215 @@
|
|||||||
|
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
|
file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
|
package org.mozilla.fenix.home.sessioncontrol.viewholders
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
|
import android.view.View
|
||||||
|
import android.view.ViewGroup
|
||||||
|
import androidx.core.content.ContextCompat
|
||||||
|
import androidx.recyclerview.widget.RecyclerView
|
||||||
|
import io.reactivex.Observer
|
||||||
|
import kotlinx.android.extensions.LayoutContainer
|
||||||
|
import kotlinx.android.synthetic.main.collection_home_list_row.*
|
||||||
|
import kotlinx.android.synthetic.main.collection_home_list_row.view.*
|
||||||
|
import kotlinx.coroutines.CoroutineScope
|
||||||
|
import kotlinx.coroutines.Dispatchers
|
||||||
|
import kotlinx.coroutines.Job
|
||||||
|
import mozilla.components.browser.menu.BrowserMenu
|
||||||
|
import mozilla.components.browser.menu.BrowserMenuBuilder
|
||||||
|
import mozilla.components.browser.menu.item.SimpleBrowserMenuItem
|
||||||
|
import org.mozilla.fenix.DefaultThemeManager
|
||||||
|
import org.mozilla.fenix.R
|
||||||
|
import org.mozilla.fenix.ext.increaseTapArea
|
||||||
|
import org.mozilla.fenix.home.sessioncontrol.CollectionAction
|
||||||
|
import org.mozilla.fenix.home.sessioncontrol.SessionControlAction
|
||||||
|
import org.mozilla.fenix.home.sessioncontrol.TabCollection
|
||||||
|
import org.mozilla.fenix.home.sessioncontrol.onNext
|
||||||
|
import org.mozilla.fenix.utils.Settings
|
||||||
|
import kotlin.coroutines.CoroutineContext
|
||||||
|
|
||||||
|
class CollectionViewHolder(
|
||||||
|
val view: View,
|
||||||
|
val actionEmitter: Observer<SessionControlAction>,
|
||||||
|
val job: Job,
|
||||||
|
override val containerView: View? = view
|
||||||
|
) :
|
||||||
|
RecyclerView.ViewHolder(view), LayoutContainer, CoroutineScope {
|
||||||
|
|
||||||
|
override val coroutineContext: CoroutineContext
|
||||||
|
get() = Dispatchers.IO + job
|
||||||
|
|
||||||
|
private lateinit var collection: TabCollection
|
||||||
|
private var state = CollectionState.Collapsed
|
||||||
|
private var collectionMenu: CollectionItemMenu
|
||||||
|
|
||||||
|
init {
|
||||||
|
collectionMenu = CollectionItemMenu(view.context) {
|
||||||
|
when (it) {
|
||||||
|
is CollectionItemMenu.Item.DeleteCollection -> actionEmitter.onNext(CollectionAction.Delete(collection))
|
||||||
|
is CollectionItemMenu.Item.AddTab -> actionEmitter.onNext(CollectionAction.AddTab(collection))
|
||||||
|
is CollectionItemMenu.Item.RenameCollection -> actionEmitter.onNext(CollectionAction.Rename(collection))
|
||||||
|
is CollectionItemMenu.Item.OpenTabs -> actionEmitter.onNext(CollectionAction.OpenTabs(collection))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
collection_overflow_button.run {
|
||||||
|
increaseTapArea(buttonIncreaseDps)
|
||||||
|
setOnClickListener {
|
||||||
|
collectionMenu.menuBuilder
|
||||||
|
.build(view.context)
|
||||||
|
.show(anchor = it, orientation = BrowserMenu.Orientation.DOWN)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
collection_share_button.run {
|
||||||
|
increaseTapArea(buttonIncreaseDps)
|
||||||
|
setOnClickListener {
|
||||||
|
actionEmitter.onNext(CollectionAction.ShareTabs(collection))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
view.setOnClickListener {
|
||||||
|
updateState()
|
||||||
|
}
|
||||||
|
|
||||||
|
view.collection_icon.setColorFilter(ContextCompat.getColor(
|
||||||
|
view.context,
|
||||||
|
getNextIconColor()),
|
||||||
|
android.graphics.PorterDuff.Mode.SRC_IN
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun bindSession(collection: TabCollection) {
|
||||||
|
this.collection = collection
|
||||||
|
updateCollectionUI()
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun updateCollectionUI() {
|
||||||
|
view.collection_title.text = collection.title
|
||||||
|
|
||||||
|
var hostNameList = listOf<String>()
|
||||||
|
|
||||||
|
collection.tabs.forEach {
|
||||||
|
hostNameList += it.hostname.capitalize()
|
||||||
|
}
|
||||||
|
|
||||||
|
var tabsDisplayed = 0
|
||||||
|
val titleList = hostNameList.joinToString(", ") {
|
||||||
|
if (it.length > maxTitleLength) {
|
||||||
|
it.substring(0,
|
||||||
|
maxTitleLength
|
||||||
|
) + "..."
|
||||||
|
} else {
|
||||||
|
tabsDisplayed += 1
|
||||||
|
it
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
view.collection_description.text = titleList
|
||||||
|
|
||||||
|
if (collection.expanded) {
|
||||||
|
(view.layoutParams as ViewGroup.MarginLayoutParams).bottomMargin = 0
|
||||||
|
collection_title.setPadding(0, 0, 0, EXPANDED_PADDING)
|
||||||
|
view.background = ContextCompat.getDrawable(view.context, R.drawable.rounded_top_corners)
|
||||||
|
view.collection_description.visibility = View.GONE
|
||||||
|
view.expand_button.setImageDrawable(ContextCompat.getDrawable(view.context, R.drawable.ic_chevron_up))
|
||||||
|
} else {
|
||||||
|
(view.layoutParams as ViewGroup.MarginLayoutParams).bottomMargin = COLLAPSED_MARGIN
|
||||||
|
view.background = ContextCompat.getDrawable(view.context, R.drawable.rounded_all_corners)
|
||||||
|
view.collection_description.visibility = View.VISIBLE
|
||||||
|
view.expand_button.setImageDrawable(ContextCompat.getDrawable(view.context, R.drawable.ic_chevron_down))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun updateState() {
|
||||||
|
state = when (state) {
|
||||||
|
CollectionState.Expanded -> {
|
||||||
|
actionEmitter.onNext(CollectionAction.Collapse(collection))
|
||||||
|
CollectionState.Collapsed
|
||||||
|
}
|
||||||
|
CollectionState.Collapsed -> {
|
||||||
|
actionEmitter.onNext(CollectionAction.Expand(collection))
|
||||||
|
CollectionState.Expanded
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Suppress("ComplexMethod", "MagicNumber")
|
||||||
|
private fun getNextIconColor(): Int {
|
||||||
|
with(view.context) {
|
||||||
|
var sessionColorIndex = Settings.getInstance(this).preferences
|
||||||
|
.getInt(getString(R.string.pref_key_collection_color), 0)
|
||||||
|
|
||||||
|
val iconResource = when (sessionColorIndex) {
|
||||||
|
0 -> R.color.collection_icon_color_violet
|
||||||
|
1 -> R.color.collection_icon_color_blue
|
||||||
|
2 -> R.color.collection_icon_color_pink
|
||||||
|
3 -> R.color.collection_icon_color_green
|
||||||
|
4 -> R.color.collection_icon_color_yellow
|
||||||
|
else -> R.color.white_color
|
||||||
|
}
|
||||||
|
|
||||||
|
if (sessionColorIndex >= MAX_COLOR_INDEX) { sessionColorIndex = 0 } else { sessionColorIndex += 1 }
|
||||||
|
|
||||||
|
Settings.getInstance(this).preferences.edit()
|
||||||
|
.putInt(getString(R.string.pref_key_collection_color), sessionColorIndex).apply()
|
||||||
|
|
||||||
|
return iconResource
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
const val MAX_COLOR_INDEX = 4
|
||||||
|
const val EXPANDED_PADDING = 60
|
||||||
|
const val COLLAPSED_MARGIN = 12
|
||||||
|
const val LAYOUT_ID = R.layout.collection_home_list_row
|
||||||
|
const val maxTitleLength = 20
|
||||||
|
const val buttonIncreaseDps = 24
|
||||||
|
}
|
||||||
|
|
||||||
|
enum class CollectionState {
|
||||||
|
Expanded, Collapsed
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class CollectionItemMenu(
|
||||||
|
private val context: Context,
|
||||||
|
private val onItemTapped: (Item) -> Unit = {}
|
||||||
|
) {
|
||||||
|
sealed class Item {
|
||||||
|
object DeleteCollection : Item()
|
||||||
|
object AddTab : Item()
|
||||||
|
object RenameCollection : Item()
|
||||||
|
object OpenTabs : Item()
|
||||||
|
}
|
||||||
|
|
||||||
|
val menuBuilder by lazy { BrowserMenuBuilder(menuItems) }
|
||||||
|
|
||||||
|
private val menuItems by lazy {
|
||||||
|
listOf(
|
||||||
|
SimpleBrowserMenuItem(
|
||||||
|
context.getString(R.string.collection_delete),
|
||||||
|
textColorResource = DefaultThemeManager.resolveAttribute(R.attr.destructive, context)
|
||||||
|
) {
|
||||||
|
onItemTapped.invoke(Item.DeleteCollection)
|
||||||
|
},
|
||||||
|
SimpleBrowserMenuItem(
|
||||||
|
context.getString(R.string.add_tab)
|
||||||
|
) {
|
||||||
|
onItemTapped.invoke(Item.AddTab)
|
||||||
|
},
|
||||||
|
SimpleBrowserMenuItem(
|
||||||
|
context.getString(R.string.collection_rename)
|
||||||
|
) {
|
||||||
|
onItemTapped.invoke(Item.RenameCollection)
|
||||||
|
},
|
||||||
|
SimpleBrowserMenuItem(
|
||||||
|
context.getString(R.string.collection_open_tabs)
|
||||||
|
) {
|
||||||
|
onItemTapped.invoke(Item.OpenTabs)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,17 @@
|
|||||||
|
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
|
file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
|
package org.mozilla.fenix.home.sessioncontrol.viewholders
|
||||||
|
|
||||||
|
import android.view.View
|
||||||
|
import androidx.recyclerview.widget.RecyclerView
|
||||||
|
import org.mozilla.fenix.R
|
||||||
|
|
||||||
|
class NoCollectionMessageViewHolder(
|
||||||
|
view: View
|
||||||
|
) : RecyclerView.ViewHolder(view) {
|
||||||
|
companion object {
|
||||||
|
const val LAYOUT_ID = R.layout.no_collection_message
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,98 @@
|
|||||||
|
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
|
file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
|
package org.mozilla.fenix.home.sessioncontrol.viewholders
|
||||||
|
|
||||||
|
import android.graphics.Outline
|
||||||
|
import android.view.View
|
||||||
|
import android.view.ViewOutlineProvider
|
||||||
|
import androidx.core.content.ContextCompat
|
||||||
|
import androidx.recyclerview.widget.RecyclerView
|
||||||
|
import io.reactivex.Observer
|
||||||
|
import kotlinx.android.extensions.LayoutContainer
|
||||||
|
import kotlinx.android.synthetic.main.tab_in_collection.*
|
||||||
|
import kotlinx.coroutines.CoroutineScope
|
||||||
|
import kotlinx.coroutines.Dispatchers
|
||||||
|
import kotlinx.coroutines.Job
|
||||||
|
import kotlinx.coroutines.launch
|
||||||
|
import mozilla.components.browser.icons.IconRequest
|
||||||
|
import mozilla.components.support.ktx.android.content.res.pxToDp
|
||||||
|
import org.jetbrains.anko.backgroundColor
|
||||||
|
import org.mozilla.fenix.R
|
||||||
|
import org.mozilla.fenix.ext.components
|
||||||
|
import org.mozilla.fenix.ext.getColorFromAttr
|
||||||
|
import org.mozilla.fenix.home.sessioncontrol.CollectionAction
|
||||||
|
import org.mozilla.fenix.home.sessioncontrol.SessionControlAction
|
||||||
|
import org.mozilla.fenix.home.sessioncontrol.Tab
|
||||||
|
import org.mozilla.fenix.home.sessioncontrol.TabCollection
|
||||||
|
import org.mozilla.fenix.home.sessioncontrol.onNext
|
||||||
|
import kotlin.coroutines.CoroutineContext
|
||||||
|
|
||||||
|
class TabInCollectionViewHolder(
|
||||||
|
val view: View,
|
||||||
|
val actionEmitter: Observer<SessionControlAction>,
|
||||||
|
val job: Job,
|
||||||
|
override val containerView: View? = view
|
||||||
|
) : RecyclerView.ViewHolder(view), LayoutContainer, CoroutineScope {
|
||||||
|
|
||||||
|
override val coroutineContext: CoroutineContext
|
||||||
|
get() = Dispatchers.IO + job
|
||||||
|
|
||||||
|
lateinit var collection: TabCollection
|
||||||
|
private set
|
||||||
|
lateinit var tab: Tab
|
||||||
|
private set
|
||||||
|
var isLastTab = false
|
||||||
|
|
||||||
|
init {
|
||||||
|
collection_tab_icon.clipToOutline = true
|
||||||
|
collection_tab_icon.outlineProvider = object : ViewOutlineProvider() {
|
||||||
|
override fun getOutline(view: View?, outline: Outline?) {
|
||||||
|
outline?.setRoundRect(
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
view!!.width,
|
||||||
|
view.height,
|
||||||
|
view.context.resources.pxToDp(TabViewHolder.favIconBorderRadiusInPx).toFloat()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
collection_tab_close_button.setOnClickListener {
|
||||||
|
actionEmitter.onNext(CollectionAction.RemoveTab(collection, tab))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun bindSession(collection: TabCollection, tab: Tab, isLastTab: Boolean) {
|
||||||
|
this.collection = collection
|
||||||
|
this.tab = tab
|
||||||
|
this.isLastTab = isLastTab
|
||||||
|
updateTabUI()
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun updateTabUI() {
|
||||||
|
collection_tab_hostname.text = tab.hostname
|
||||||
|
collection_tab_title.text = tab.title
|
||||||
|
launch(Dispatchers.IO) {
|
||||||
|
val bitmap = collection_tab_icon.context.components.utils.icons
|
||||||
|
.loadIcon(IconRequest(tab.url)).await().bitmap
|
||||||
|
launch(Dispatchers.Main) {
|
||||||
|
collection_tab_icon.setImageBitmap(bitmap)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// If I'm the last one...
|
||||||
|
if (isLastTab) {
|
||||||
|
view.background = ContextCompat.getDrawable(view.context, R.drawable.rounded_bottom_corners)
|
||||||
|
divider_line.visibility = View.GONE
|
||||||
|
} else {
|
||||||
|
view.backgroundColor = R.attr.above.getColorFromAttr(view.context)
|
||||||
|
divider_line.visibility = View.VISIBLE
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
const val LAYOUT_ID = R.layout.tab_in_collection
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,10 @@
|
|||||||
|
<!-- This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
- License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
|
- file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
|
||||||
|
|
||||||
|
<vector android:height="6dp" android:viewportHeight="6"
|
||||||
|
android:viewportWidth="10" android:width="10dp" xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
<path android:fillColor="?primaryText" android:fillType="nonZero"
|
||||||
|
android:pathData="M5,5.6667C4.8232,5.6666 4.6537,5.5964 4.5287,5.4713L0.5287,1.4713C0.276,1.2097 0.2796,0.7939 0.5368,0.5368C0.7939,0.2796 1.2097,0.276 1.4713,0.5287L5,4.0573L8.5287,0.5287C8.7903,0.276 9.2061,0.2796 9.4632,0.5368C9.7204,0.7939 9.724,1.2097 9.4713,1.4713L5.4713,5.4713C5.3463,5.5964 5.1768,5.6666 5,5.6667Z"
|
||||||
|
android:strokeColor="#00000000" android:strokeWidth="1"/>
|
||||||
|
</vector>
|
@ -0,0 +1,10 @@
|
|||||||
|
<!-- This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
- License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
|
- file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
|
||||||
|
|
||||||
|
<vector android:height="6dp" android:viewportHeight="6"
|
||||||
|
android:viewportWidth="10" android:width="10dp" xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
<path android:fillColor="?primaryText" android:fillType="nonZero"
|
||||||
|
android:pathData="M5,0.3333C4.8232,0.3334 4.6537,0.4036 4.5287,0.5287L0.5287,4.5287C0.276,4.7903 0.2796,5.2061 0.5368,5.4632C0.7939,5.7204 1.2097,5.724 1.4713,5.4713L5,1.9427L8.5287,5.4713C8.7903,5.724 9.2061,5.7204 9.4632,5.4632C9.7204,5.2061 9.724,4.7903 9.4713,4.5287L5.4713,0.5287C5.3463,0.4036 5.1768,0.3334 5,0.3333Z"
|
||||||
|
android:strokeColor="#00000000" android:strokeWidth="1"/>
|
||||||
|
</vector>
|
@ -0,0 +1,10 @@
|
|||||||
|
<!-- This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
- License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
|
- file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
|
||||||
|
|
||||||
|
<vector android:height="20dp" android:viewportHeight="20"
|
||||||
|
android:viewportWidth="19" android:width="20dp" xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
<path android:fillColor="?primaryText" android:fillType="nonZero"
|
||||||
|
android:pathData="M6.92,12.7338C6.1902,13.5131 5.1519,14 4,14C1.7909,14 0,12.2091 0,10C0,7.7909 1.7909,6 4,6C5.0609,6 6.0783,6.4214 6.8284,7.1716C6.86,7.2031 6.8909,7.2351 6.9213,7.2676L11.1206,4.9785C11.0418,4.6654 11,4.3376 11,4C11,1.7909 12.7909,0 15,0C17.2091,0 19,1.7909 19,4C19,6.2091 17.2091,8 15,8C13.8481,8 12.8098,7.5131 12.08,6.7338L7.879,9.0237C7.9587,9.3403 8,9.668 8,10C8,10.3376 7.9582,10.6654 7.8794,10.9785L12.0787,13.2675C12.8087,12.4875 13.8474,12 15,12C17.2091,12 19,13.7909 19,16C19,18.2091 17.2091,20 15,20C12.7909,20 11,18.2091 11,16C11,15.6631 11.0417,15.3358 11.1201,15.0232L6.92,12.7338ZM15,2C13.8954,2 13,2.8954 13,4C13,5.1046 13.8954,6 15,6C16.1046,6 17,5.1046 17,4C17,2.8954 16.1046,2 15,2ZM4,8C2.8954,8 2,8.8954 2,10C2,11.1046 2.8954,12 4,12C5.1046,12 6,11.1046 6,10C6,8.8954 5.1046,8 4,8ZM15,14C13.8954,14 13,14.8954 13,16C13,17.1046 13.8954,18 15,18C16.1046,18 17,17.1046 17,16C17,14.8954 16.1046,14 15,14Z"
|
||||||
|
android:strokeColor="#00000000" android:strokeWidth="1"/>
|
||||||
|
</vector>
|
@ -0,0 +1,9 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!-- This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
- License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
|
- file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
|
||||||
|
|
||||||
|
<shape xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
<solid android:color="?above" />
|
||||||
|
<corners android:radius="@dimen/tab_corner_radius"/>
|
||||||
|
</shape>
|
@ -0,0 +1,9 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!-- This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
- License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
|
- file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
|
||||||
|
|
||||||
|
<shape xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
<solid android:color="?above" />
|
||||||
|
<corners android:bottomLeftRadius="@dimen/tab_corner_radius" android:bottomRightRadius="@dimen/tab_corner_radius" />
|
||||||
|
</shape>
|
@ -0,0 +1,9 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!-- This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
- License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
|
- file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
|
||||||
|
|
||||||
|
<shape xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
<solid android:color="?above" />
|
||||||
|
<corners android:topLeftRadius="@dimen/tab_corner_radius" android:topRightRadius="@dimen/tab_corner_radius" />
|
||||||
|
</shape>
|
@ -0,0 +1,10 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<!-- This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
- License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
|
- file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
|
||||||
|
|
||||||
|
<shape xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:shape="rectangle">
|
||||||
|
<corners android:bottomLeftRadius="@dimen/tab_corner_radius" android:bottomRightRadius="@dimen/tab_corner_radius" />
|
||||||
|
<solid android:color="@color/photonGrey30" />
|
||||||
|
</shape>
|
@ -0,0 +1,9 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<!-- This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
- License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
|
- file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
|
||||||
|
|
||||||
|
<shape xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:shape="rectangle">
|
||||||
|
<solid android:color="@color/photonGrey30" />
|
||||||
|
</shape>
|
@ -0,0 +1,33 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!-- This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
- License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
|
- file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
|
||||||
|
<androidx.constraintlayout.widget.ConstraintLayout
|
||||||
|
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
|
android:id="@+id/collections_header"
|
||||||
|
android:layout_marginTop="5dp"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content">
|
||||||
|
|
||||||
|
<View
|
||||||
|
android:id="@+id/divider_line"
|
||||||
|
android:layout_width="fill_parent"
|
||||||
|
android:layout_height="1dp"
|
||||||
|
android:background="?neutralFaded"
|
||||||
|
android:layout_marginStart="23dp"
|
||||||
|
android:layout_marginEnd="23dp"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintTop_toTopOf="parent"/>
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/collections_header_text"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="@string/collections_header"
|
||||||
|
android:textAppearance="@style/HeaderTextStyle"
|
||||||
|
android:layout_marginTop="15dp"
|
||||||
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintTop_toBottomOf="@id/divider_line" />
|
||||||
|
</androidx.constraintlayout.widget.ConstraintLayout>
|
@ -0,0 +1,95 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!-- This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
- License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
|
- file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
|
||||||
|
<LinearLayout
|
||||||
|
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
|
android:id="@+id/item_collection"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginTop="12dp"
|
||||||
|
android:clickable="true"
|
||||||
|
android:clipToPadding="false"
|
||||||
|
android:focusable="true"
|
||||||
|
android:foreground="?android:attr/selectableItemBackground"
|
||||||
|
android:background="@drawable/rounded_all_corners"
|
||||||
|
android:elevation="5dp">
|
||||||
|
|
||||||
|
<androidx.constraintlayout.widget.ConstraintLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content">
|
||||||
|
|
||||||
|
<ImageView
|
||||||
|
android:id="@+id/collection_icon"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginTop="16dp"
|
||||||
|
android:layout_marginStart="18dp"
|
||||||
|
android:tint="@null"
|
||||||
|
android:src="@drawable/ic_archive"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintTop_toTopOf="parent"/>
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/collection_title"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginTop="17dp"
|
||||||
|
android:layout_marginStart="14dp"
|
||||||
|
android:ellipsize="end"
|
||||||
|
android:maxLines="1"
|
||||||
|
android:minLines="1"
|
||||||
|
android:textAppearance="@style/Header16TextStyle"
|
||||||
|
app:layout_constraintStart_toEndOf="@id/collection_icon"
|
||||||
|
app:layout_constraintTop_toTopOf="parent"/>
|
||||||
|
|
||||||
|
<ImageView
|
||||||
|
android:id="@+id/expand_button"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginStart="8dp"
|
||||||
|
android:layout_marginTop="26dp"
|
||||||
|
android:layout_marginEnd="8dp"
|
||||||
|
android:src="@drawable/ic_chevron_down"
|
||||||
|
app:layout_constraintStart_toEndOf="@id/collection_title"
|
||||||
|
app:layout_constraintTop_toTopOf="parent"/>
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/collection_description"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginTop="8dp"
|
||||||
|
android:layout_marginBottom="16dp"
|
||||||
|
android:ellipsize="end"
|
||||||
|
android:maxLines="2"
|
||||||
|
android:minLines="2"
|
||||||
|
android:textAppearance="@style/SubtitleTextStyle"
|
||||||
|
app:layout_constraintStart_toStartOf="@id/collection_title"
|
||||||
|
app:layout_constraintTop_toBottomOf="@id/collection_share_button"
|
||||||
|
app:layout_constraintEnd_toStartOf="@id/collection_share_button"
|
||||||
|
app:layout_constraintBottom_toBottomOf="parent"/>
|
||||||
|
|
||||||
|
<ImageButton
|
||||||
|
android:id="@+id/collection_share_button"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:background="?android:attr/selectableItemBackgroundBorderless"
|
||||||
|
android:contentDescription="@string/tab_menu"
|
||||||
|
android:src="@drawable/ic_hollow_share"
|
||||||
|
android:layout_marginEnd="29dp"
|
||||||
|
app:layout_constraintEnd_toStartOf="@id/collection_overflow_button"
|
||||||
|
app:layout_constraintTop_toTopOf="@id/collection_icon"/>
|
||||||
|
|
||||||
|
<ImageButton
|
||||||
|
android:id="@+id/collection_overflow_button"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:background="?android:attr/selectableItemBackgroundBorderless"
|
||||||
|
android:contentDescription="@string/tab_menu"
|
||||||
|
android:src="@drawable/ic_menu"
|
||||||
|
android:layout_marginEnd="8dp"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
app:layout_constraintTop_toTopOf="@id/collection_icon"/>
|
||||||
|
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||||
|
</LinearLayout>
|
@ -0,0 +1,35 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!-- This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
- License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
|
- file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
|
||||||
|
<LinearLayout
|
||||||
|
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:id="@+id/no_tabs_wrapper"
|
||||||
|
android:background="@drawable/empty_session_control_background"
|
||||||
|
android:layout_marginBottom="12dp"
|
||||||
|
android:padding="16dp"
|
||||||
|
android:orientation="vertical"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/no_collection_header"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:drawableEnd="@drawable/ic_archive"
|
||||||
|
android:drawableTint="?primaryText"
|
||||||
|
android:drawablePadding="8dp"
|
||||||
|
android:text="@string/no_collections_header"
|
||||||
|
android:textAppearance="@style/HeaderTextStyle"
|
||||||
|
android:textSize="16sp" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/no_collection_description"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginTop="4dp"
|
||||||
|
android:text="@string/no_collections_description"
|
||||||
|
android:textColor="?primaryText"
|
||||||
|
android:textSize="14sp"
|
||||||
|
android:textStyle="normal" />
|
||||||
|
</LinearLayout>
|
@ -0,0 +1,84 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!-- This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
- License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
|
- file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
|
||||||
|
<LinearLayout
|
||||||
|
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
|
android:id="@+id/tab_in_collection_item"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:clickable="true"
|
||||||
|
android:clipToPadding="false"
|
||||||
|
android:focusable="true"
|
||||||
|
android:foreground="?android:attr/selectableItemBackground"
|
||||||
|
android:background="?above"
|
||||||
|
android:elevation="5dp">
|
||||||
|
|
||||||
|
<androidx.constraintlayout.widget.ConstraintLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content">
|
||||||
|
|
||||||
|
<ImageView
|
||||||
|
android:id="@+id/collection_tab_icon"
|
||||||
|
android:layout_width="24dp"
|
||||||
|
android:layout_height="24dp"
|
||||||
|
android:layout_marginTop="25dp"
|
||||||
|
android:layout_marginStart="18dp"
|
||||||
|
android:tint="@null"
|
||||||
|
android:src="@drawable/ic_archive"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintTop_toTopOf="parent"/>
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/collection_tab_hostname"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginTop="8dp"
|
||||||
|
android:layout_marginStart="14dp"
|
||||||
|
android:layout_marginEnd="48dp"
|
||||||
|
android:ellipsize="end"
|
||||||
|
android:maxLines="1"
|
||||||
|
android:minLines="1"
|
||||||
|
android:textAppearance="@style/Header12TextStyle"
|
||||||
|
app:layout_constraintStart_toEndOf="@id/collection_tab_icon"
|
||||||
|
app:layout_constraintTop_toTopOf="parent"
|
||||||
|
app:layout_constraintEnd_toStartOf="@id/collection_tab_close_button"/>
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/collection_tab_title"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginBottom="12dp"
|
||||||
|
android:ellipsize="end"
|
||||||
|
android:maxLines="2"
|
||||||
|
android:minLines="2"
|
||||||
|
android:textAppearance="@style/Body14TextStyle"
|
||||||
|
app:layout_constraintStart_toStartOf="@id/collection_tab_hostname"
|
||||||
|
app:layout_constraintTop_toBottomOf="@id/collection_tab_hostname"
|
||||||
|
app:layout_constraintEnd_toEndOf="@id/collection_tab_hostname"
|
||||||
|
app:layout_constraintBottom_toBottomOf="parent"/>
|
||||||
|
|
||||||
|
<ImageButton
|
||||||
|
android:id="@+id/collection_tab_close_button"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:background="?android:attr/selectableItemBackgroundBorderless"
|
||||||
|
android:contentDescription="@string/close_tab"
|
||||||
|
android:src="@drawable/ic_close"
|
||||||
|
android:layout_marginTop="8dp"
|
||||||
|
android:layout_marginEnd="8dp"
|
||||||
|
android:alpha="0.8"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
app:layout_constraintTop_toTopOf="parent"/>
|
||||||
|
|
||||||
|
<View
|
||||||
|
android:id="@+id/divider_line"
|
||||||
|
android:layout_width="fill_parent"
|
||||||
|
android:layout_height="1dp"
|
||||||
|
android:background="?neutralFaded"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintBottom_toBottomOf="parent"/>
|
||||||
|
|
||||||
|
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||||
|
</LinearLayout>
|
Loading…
Reference in New Issue