Skip to content
This repository has been archived by the owner on Feb 20, 2023. It is now read-only.

Commit

Permalink
Small refactor before we add onboarding cards (#2541)
Browse files Browse the repository at this point in the history
* For #2390 - Cleans up the toAdapterList method before we add onboarding

* For #2514 - Hide tabs menu when no tabs are open
  • Loading branch information
boek committed May 16, 2019
1 parent c34946b commit b3a3c94
Show file tree
Hide file tree
Showing 6 changed files with 101 additions and 95 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ import org.mozilla.fenix.home.sessioncontrol.viewholders.TabInCollectionViewHold
import java.lang.IllegalStateException

sealed class AdapterItem {
object TabHeader : AdapterItem()
data class TabHeader(val isPrivate: Boolean, val hasTabs: Boolean) : AdapterItem()
object NoTabMessage : AdapterItem()
data class TabItem(val tab: Tab) : AdapterItem()
object PrivateBrowsingDescription : AdapterItem()
Expand All @@ -35,7 +35,7 @@ sealed class AdapterItem {

val viewType: Int
get() = when (this) {
TabHeader -> TabHeaderViewHolder.LAYOUT_ID
is TabHeader -> TabHeaderViewHolder.LAYOUT_ID
NoTabMessage -> NoTabMessageViewHolder.LAYOUT_ID
is TabItem -> TabViewHolder.LAYOUT_ID
SaveTabGroup -> SaveTabGroupViewHolder.LAYOUT_ID
Expand All @@ -52,7 +52,7 @@ class SessionControlAdapter(
private val actionEmitter: Observer<SessionControlAction>
) : RecyclerView.Adapter<RecyclerView.ViewHolder>() {

var items: List<AdapterItem> = listOf()
private var items: List<AdapterItem> = listOf()
private lateinit var job: Job

fun reloadData(items: List<AdapterItem>) {
Expand All @@ -69,15 +69,10 @@ class SessionControlAdapter(
NoTabMessageViewHolder.LAYOUT_ID -> NoTabMessageViewHolder(view)
TabViewHolder.LAYOUT_ID -> TabViewHolder(view, actionEmitter, job)
SaveTabGroupViewHolder.LAYOUT_ID -> SaveTabGroupViewHolder(view, actionEmitter)
PrivateBrowsingDescriptionViewHolder.LAYOUT_ID -> PrivateBrowsingDescriptionViewHolder(
view,
actionEmitter
)
PrivateBrowsingDescriptionViewHolder.LAYOUT_ID -> PrivateBrowsingDescriptionViewHolder(view, actionEmitter)
DeleteTabsViewHolder.LAYOUT_ID -> DeleteTabsViewHolder(view, actionEmitter)
CollectionHeaderViewHolder.LAYOUT_ID -> CollectionHeaderViewHolder(view)
NoCollectionMessageViewHolder.LAYOUT_ID -> NoCollectionMessageViewHolder(
view
)
NoCollectionMessageViewHolder.LAYOUT_ID -> NoCollectionMessageViewHolder(view)
CollectionViewHolder.LAYOUT_ID -> CollectionViewHolder(view, actionEmitter, job)
TabInCollectionViewHolder.LAYOUT_ID -> TabInCollectionViewHolder(view, actionEmitter, job)
else -> throw IllegalStateException()
Expand All @@ -100,14 +95,18 @@ class SessionControlAdapter(

override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
when (holder) {
is TabHeaderViewHolder -> {
val tabHeader = items[position] as AdapterItem.TabHeader
holder.bind(tabHeader.isPrivate, tabHeader.hasTabs)
}
is TabViewHolder -> holder.bindSession(
(items[position] as AdapterItem.TabItem).tab
)
is CollectionViewHolder -> holder.bindSession(
(items[position] as AdapterItem.CollectionItem).collection
)
is TabInCollectionViewHolder -> {
val item = (items[position] as AdapterItem.TabInCollectionItem)
val item = items[position] as AdapterItem.TabInCollectionItem
holder.bindSession(item.collection, item.tab, item.isLastTab)
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -58,9 +58,16 @@ data class TabCollection(
var expanded: Boolean = false
) : Parcelable

sealed class FirefoxAcocuntsState {
object SignedOut : FirefoxAcocuntsState()
data class AutoSignedIn(val email: String) : FirefoxAcocuntsState()
data class SignedIn(val email: String) : FirefoxAcocuntsState()
}

sealed class Mode {
object Normal : Mode()
object Private : Mode()
data class Onboarding(val firefoxAccountsState: FirefoxAcocuntsState) : Mode()
}

data class SessionControlState(
Expand Down Expand Up @@ -110,12 +117,9 @@ sealed class SessionControlChange : Change {
data class CollectionsChange(val collections: List<TabCollection>) : SessionControlChange()
}

class SessionControlViewModel(initialState: SessionControlState) :
UIComponentViewModelBase<SessionControlState, SessionControlChange>(
initialState,
reducer
) {

class SessionControlViewModel(
initialState: SessionControlState
) : UIComponentViewModelBase<SessionControlState, SessionControlChange>(initialState, reducer) {
companion object {
val reducer: (SessionControlState, SessionControlChange) -> SessionControlState = { state, change ->
when (change) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,60 +16,60 @@ import org.mozilla.fenix.mvi.UIView
import androidx.recyclerview.widget.ItemTouchHelper
import org.mozilla.fenix.BuildConfig

// Convert HomeState into a data structure HomeAdapter understands
@SuppressWarnings("ComplexMethod", "NestedBlockDepth")
private fun SessionControlState.toAdapterList(): List<AdapterItem> {
private fun normalModeAdapterItems(tabs: List<Tab>, collections: List<TabCollection>): List<AdapterItem> {
val items = mutableListOf<AdapterItem>()
items.add(AdapterItem.TabHeader)
items.add(AdapterItem.TabHeader(false, tabs.isNotEmpty()))

// Populate tabs
if (tabs.isNotEmpty()) {
tabs.reversed().map(AdapterItem::TabItem).forEach { items.add(it) }
if (mode == Mode.Private) {
items.add(AdapterItem.DeleteTabs)
} else if (BuildConfig.COLLECTIONS_ENABLED) {
items.addAll(tabs.reversed().map(AdapterItem::TabItem))
if (BuildConfig.COLLECTIONS_ENABLED) {
items.add(AdapterItem.SaveTabGroup)
}
} else {
val item = if (mode == Mode.Private) AdapterItem.PrivateBrowsingDescription
else AdapterItem.NoTabMessage

items.add(item)
items.add(AdapterItem.NoTabMessage)
}

// Populate collections
if (mode == Mode.Normal) {
items.add(AdapterItem.CollectionHeader)
if (collections.isNotEmpty()) {

// If the collection is expanded, we want to add all of its tabs beneath it in the adapter
collections.reversed().map(AdapterItem::CollectionItem).forEach {
if (it.collection.expanded) {
items.add(it)
addCollectionTabItems(it.collection, it.collection.tabs, items)
} else {
items.add(it)
}
items.add(AdapterItem.CollectionHeader)
if (collections.isNotEmpty()) {

// If the collection is expanded, we want to add all of its tabs beneath it in the adapter
collections.reversed().map(AdapterItem::CollectionItem).forEach {
items.add(it)
if (it.collection.expanded) {
items.addAll(collectionTabItems(it.collection))
}
} else {
items.add(AdapterItem.NoCollectionMessage)
}
} else {
items.add(AdapterItem.NoCollectionMessage)
}

return items
}

private fun addCollectionTabItems(
collection: TabCollection,
tabs: MutableList<Tab>,
itemList: MutableList<AdapterItem>
) {
for (tabIndex in 0 until tabs.size) {
itemList.add(AdapterItem.TabInCollectionItem
(collection, collection.tabs[tabIndex], tabIndex == collection.tabs.size - 1))
private fun privateModeAdapterItems(tabs: List<Tab>): List<AdapterItem> {
val items = mutableListOf<AdapterItem>()
items.add(AdapterItem.TabHeader(true, tabs.isNotEmpty()))

if (tabs.isNotEmpty()) {
items.addAll(tabs.reversed().map(AdapterItem::TabItem))
items.add(AdapterItem.DeleteTabs)
} else {
items.add(AdapterItem.PrivateBrowsingDescription)
}

return items
}

private fun SessionControlState.toAdapterList(): List<AdapterItem> = when (mode) {
is Mode.Normal -> normalModeAdapterItems(tabs, collections)
is Mode.Private -> privateModeAdapterItems(tabs)
is Mode.Onboarding -> listOf()
}

private fun collectionTabItems(collection: TabCollection) = collection.tabs.mapIndexed { index, tab ->
AdapterItem.TabInCollectionItem(collection, tab, index == collection.tabs.lastIndex)
}

class SessionControlUIView(
container: ViewGroup,
actionEmitter: Observer<SessionControlAction>,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,14 +19,14 @@ import org.mozilla.fenix.home.sessioncontrol.TabAction
import org.mozilla.fenix.home.sessioncontrol.onNext

class TabHeaderViewHolder(
view: View,
private val view: View,
private val actionEmitter: Observer<SessionControlAction>
) : RecyclerView.ViewHolder(view) {
private var isPrivate = false
private var tabsMenu: TabHeaderMenu

init {
tabsMenu = TabHeaderMenu(view.context) {
tabsMenu = TabHeaderMenu(view.context, isPrivate) {
when (it) {
is TabHeaderMenu.Item.Share -> actionEmitter.onNext(TabAction.ShareTabs)
is TabHeaderMenu.Item.CloseAll -> actionEmitter.onNext(TabAction.CloseAll(isPrivate))
Expand All @@ -37,11 +37,8 @@ class TabHeaderViewHolder(
)
}
}
view.apply {
val headerTextResourceId =
if (isPrivate) R.string.tabs_header_private_title else R.string.tab_header_label
header_text.text = context.getString(headerTextResourceId)

view.apply {
add_tab_button.run {
setOnClickListener {
actionEmitter.onNext(TabAction.Add)
Expand All @@ -58,8 +55,19 @@ class TabHeaderViewHolder(
}
}

fun bind(isPrivate: Boolean, hasTabs: Boolean) {
this.isPrivate = isPrivate
tabsMenu.isPrivate = isPrivate

val headerTextResourceId =
if (isPrivate) R.string.tabs_header_private_title else R.string.tab_header_label
view.header_text.text = view.context.getString(headerTextResourceId)
view.tabs_overflow_button.visibility = if (hasTabs) View.VISIBLE else View.GONE
}

class TabHeaderMenu(
private val context: Context,
var isPrivate: Boolean,
private val onItemTapped: (Item) -> Unit = {}
) {
sealed class Item {
Expand All @@ -81,20 +89,13 @@ class TabHeaderViewHolder(
context.getString(R.string.tabs_menu_share_tabs)
) {
onItemTapped.invoke(Item.Share)
}
).let {
val list = it.toMutableList()
if (BuildConfig.COLLECTIONS_ENABLED) {
list.add(
SimpleBrowserMenuItem(
context.getString(R.string.tabs_menu_save_to_collection)
) {
onItemTapped.invoke(Item.SaveToCollection)
}
)
}
list
}
},
SimpleBrowserMenuItem(
context.getString(R.string.tabs_menu_save_to_collection)
) {
onItemTapped.invoke(Item.SaveToCollection)
}.apply { visible = { !isPrivate && BuildConfig.COLLECTIONS_ENABLED } }
)
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,6 @@ class TabInCollectionViewHolder(
var isLastTab = false

init {

collection_tab_icon.clipToOutline = true
collection_tab_icon.outlineProvider = object : ViewOutlineProvider() {
override fun getOutline(view: View?, outline: Outline?) {
Expand Down
45 changes: 24 additions & 21 deletions app/src/main/res/layout/tab_header.xml
Original file line number Diff line number Diff line change
Expand Up @@ -21,27 +21,30 @@
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />

<ImageButton
android:id="@+id/add_tab_button"
android:layout_width="20dp"
android:layout_height="20dp"
android:layout_marginEnd="30dp"
android:background="?android:attr/selectableItemBackgroundBorderless"
android:contentDescription="@string/add_tab"
android:src="@drawable/ic_new"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toStartOf="@id/tabs_overflow_button"
app:layout_constraintTop_toTopOf="parent" />

<ImageButton
android:id="@+id/tabs_overflow_button"
android:layout_width="24dp"
android:layout_height="24dp"
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:layout_marginEnd="4.5dp"
android:background="?android:attr/selectableItemBackgroundBorderless"
android:contentDescription="@string/open_tabs_menu"
android:src="@drawable/ic_menu"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent" />
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintEnd_toEndOf="parent">
<ImageButton
android:id="@+id/add_tab_button"
android:layout_width="24dp"
android:layout_height="24dp"
android:layout_marginEnd="8dp"
android:background="?android:attr/selectableItemBackgroundBorderless"
android:contentDescription="@string/add_tab"
android:src="@drawable/ic_new"/>

<ImageButton
android:id="@+id/tabs_overflow_button"
android:layout_width="24dp"
android:layout_height="24dp"
android:layout_marginStart="8dp"
android:background="?android:attr/selectableItemBackgroundBorderless"
android:contentDescription="@string/open_tabs_menu"
android:src="@drawable/ic_menu" />
</LinearLayout>
</androidx.constraintlayout.widget.ConstraintLayout>

0 comments on commit b3a3c94

Please sign in to comment.