1
0
Fork 0

For #1696 - Removes sessions from session control

master
Jeff Boek 2019-04-17 16:47:38 -07:00
parent 6183e82264
commit 5ca9040702
10 changed files with 8 additions and 230 deletions

View File

@ -23,7 +23,6 @@ import mozilla.components.concept.engine.EngineSession.TrackingProtectionPolicy
import mozilla.components.concept.engine.mediaquery.PreferredColorScheme
import mozilla.components.concept.fetch.Client
import mozilla.components.feature.session.HistoryDelegate
import mozilla.components.feature.session.bundling.SessionBundleStorage
import mozilla.components.lib.crash.handler.CrashHandlerService
import org.mozilla.fenix.AppRequestInterceptor
import org.mozilla.fenix.utils.Settings

View File

@ -17,15 +17,12 @@ import android.view.View
import android.view.ViewGroup
import androidx.appcompat.app.AppCompatActivity
import androidx.fragment.app.Fragment
import androidx.lifecycle.Observer
import androidx.navigation.Navigation
import kotlinx.android.synthetic.main.fragment_home.*
import kotlinx.android.synthetic.main.fragment_home.view.*
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.Dispatchers.IO
import kotlinx.coroutines.Job
import kotlinx.coroutines.launch
import mozilla.components.browser.menu.BrowserMenu
import mozilla.components.browser.session.Session
import mozilla.components.browser.session.SessionManager
@ -35,12 +32,8 @@ import org.mozilla.fenix.BrowsingModeManager
import org.mozilla.fenix.DefaultThemeManager
import org.mozilla.fenix.HomeActivity
import org.mozilla.fenix.R
import org.mozilla.fenix.utils.ItsNotBrokenSnack
import org.mozilla.fenix.components.metrics.Event
import org.mozilla.fenix.ext.archive
import org.mozilla.fenix.ext.requireComponents
import org.mozilla.fenix.home.sessioncontrol.ArchivedSession
import org.mozilla.fenix.home.sessioncontrol.ArchivedSessionAction
import org.mozilla.fenix.home.sessioncontrol.Mode
import org.mozilla.fenix.home.sessioncontrol.SessionControlAction
import org.mozilla.fenix.home.sessioncontrol.SessionControlChange
@ -77,7 +70,7 @@ class HomeFragment : Fragment(), CoroutineScope {
sessionControlComponent = SessionControlComponent(
view.homeLayout,
bus,
SessionControlState(listOf(), listOf(), mode)
SessionControlState(listOf(), mode)
)
view.homeLayout.applyConstraintSet {

View File

@ -16,8 +16,6 @@ import kotlinx.android.synthetic.main.session_bottom_sheet.view.*
import org.mozilla.fenix.DefaultThemeManager
import org.mozilla.fenix.utils.ItsNotBrokenSnack
import org.mozilla.fenix.R
import org.mozilla.fenix.home.sessioncontrol.ArchivedSession
import org.mozilla.fenix.home.sessioncontrol.viewholders.formattedSavedAt
class SessionBottomSheetFragment : BottomSheetDialogFragment(), LayoutContainer {
sealed class SessionType {

View File

@ -12,9 +12,6 @@ import kotlinx.coroutines.Job
import org.mozilla.fenix.home.sessioncontrol.viewholders.ArchiveTabsViewHolder
import org.mozilla.fenix.home.sessioncontrol.viewholders.DeleteTabsViewHolder
import org.mozilla.fenix.home.sessioncontrol.viewholders.PrivateBrowsingDescriptionViewHolder
import org.mozilla.fenix.home.sessioncontrol.viewholders.SessionHeaderViewHolder
import org.mozilla.fenix.home.sessioncontrol.viewholders.SessionViewHolder
import org.mozilla.fenix.home.sessioncontrol.viewholders.SessionPlaceholderViewHolder
import org.mozilla.fenix.home.sessioncontrol.viewholders.TabHeaderViewHolder
import org.mozilla.fenix.home.sessioncontrol.viewholders.TabViewHolder
import java.lang.IllegalStateException
@ -25,9 +22,6 @@ sealed class AdapterItem {
object PrivateBrowsingDescription : AdapterItem()
object ArchiveTabs : AdapterItem()
object DeleteTabs : AdapterItem()
object SessionHeader : AdapterItem()
object SessionPlaceholder : AdapterItem()
data class SessionItem(val session: ArchivedSession) : AdapterItem()
val viewType: Int
get() = when (this) {
@ -36,9 +30,6 @@ sealed class AdapterItem {
ArchiveTabs -> ArchiveTabsViewHolder.LAYOUT_ID
PrivateBrowsingDescription -> PrivateBrowsingDescriptionViewHolder.LAYOUT_ID
DeleteTabs -> DeleteTabsViewHolder.LAYOUT_ID
SessionHeader -> SessionHeaderViewHolder.LAYOUT_ID
SessionPlaceholder -> SessionPlaceholderViewHolder.LAYOUT_ID
is SessionItem -> SessionViewHolder.LAYOUT_ID
}
}
@ -67,9 +58,6 @@ class SessionControlAdapter(
actionEmitter
)
DeleteTabsViewHolder.LAYOUT_ID -> DeleteTabsViewHolder(view, actionEmitter)
SessionHeaderViewHolder.LAYOUT_ID -> SessionHeaderViewHolder(view)
SessionPlaceholderViewHolder.LAYOUT_ID -> SessionPlaceholderViewHolder(view)
SessionViewHolder.LAYOUT_ID -> SessionViewHolder(view, actionEmitter)
else -> throw IllegalStateException()
}
}
@ -94,7 +82,6 @@ class SessionControlAdapter(
(items[position] as AdapterItem.TabItem).tab,
position
)
is SessionViewHolder -> holder.bind((items[position] as AdapterItem.SessionItem).session)
}
}
}

View File

@ -7,7 +7,6 @@ package org.mozilla.fenix.home.sessioncontrol
import android.graphics.Bitmap
import android.view.ViewGroup
import androidx.recyclerview.widget.RecyclerView
import mozilla.components.feature.session.bundling.SessionBundle
import io.reactivex.Observer
import org.mozilla.fenix.mvi.Action
import org.mozilla.fenix.mvi.ActionBusFactory
@ -18,7 +17,7 @@ import org.mozilla.fenix.mvi.ViewState
class SessionControlComponent(
private val container: ViewGroup,
bus: ActionBusFactory,
override var initialState: SessionControlState = SessionControlState(emptyList(), emptyList(), Mode.Normal)
override var initialState: SessionControlState = SessionControlState(emptyList(), Mode.Normal)
) :
UIComponent<SessionControlState, SessionControlAction, SessionControlChange>(
bus.getManagedEmitter(SessionControlAction::class.java),
@ -28,8 +27,6 @@ class SessionControlComponent(
override val reducer: (SessionControlState, SessionControlChange) -> SessionControlState = { state, change ->
when (change) {
is SessionControlChange.TabsChange -> state.copy(tabs = change.tabs)
is SessionControlChange.ArchivedSessionsChange ->
state.copy(archivedSessions = change.archivedSessions)
is SessionControlChange.ModeChange -> state.copy(mode = change.mode)
}
}
@ -44,7 +41,6 @@ class SessionControlComponent(
}
data class Tab(val sessionId: String, val url: String, val selected: Boolean, val thumbnail: Bitmap? = null)
data class ArchivedSession(val id: Long, val bundle: SessionBundle, val savedAt: Long, val urls: List<String>)
sealed class Mode {
object Normal : Mode()
object Private : Mode()
@ -52,17 +48,9 @@ sealed class Mode {
data class SessionControlState(
val tabs: List<Tab>,
val archivedSessions: List<ArchivedSession>,
val mode: Mode
) : ViewState
sealed class ArchivedSessionAction : Action {
data class Select(val session: ArchivedSession) : ArchivedSessionAction()
data class Delete(val session: ArchivedSession) : ArchivedSessionAction()
data class MenuTapped(val session: ArchivedSession) : ArchivedSessionAction()
data class ShareTapped(val session: ArchivedSession) : ArchivedSessionAction()
}
sealed class TabAction : Action {
object Archive : TabAction()
object MenuTapped : TabAction()
@ -75,19 +63,13 @@ sealed class TabAction : Action {
sealed class SessionControlAction : Action {
data class Tab(val action: TabAction) : SessionControlAction()
data class Session(val action: ArchivedSessionAction) : SessionControlAction()
}
fun Observer<SessionControlAction>.onNext(tabAction: TabAction) {
onNext(SessionControlAction.Tab(tabAction))
}
fun Observer<SessionControlAction>.onNext(archivedSessionAction: ArchivedSessionAction) {
onNext(SessionControlAction.Session(archivedSessionAction))
}
sealed class SessionControlChange : Change {
data class ArchivedSessionsChange(val archivedSessions: List<ArchivedSession>) : SessionControlChange()
data class TabsChange(val tabs: List<Tab>) : SessionControlChange()
data class ModeChange(val mode: Mode) : SessionControlChange()
}

View File

@ -23,22 +23,15 @@ private fun SessionControlState.toAdapterList(): List<AdapterItem> {
if (tabs.isNotEmpty()) {
items.add(AdapterItem.TabHeader)
tabs.reversed().map(AdapterItem::TabItem).forEach { items.add(it) }
items.add(if (mode == Mode.Private) AdapterItem.DeleteTabs else AdapterItem.ArchiveTabs)
if (mode == Mode.Private) {
items.add(AdapterItem.DeleteTabs)
}
} else {
if (mode == Mode.Private) {
items.add(AdapterItem.PrivateBrowsingDescription)
}
}
if (mode == Mode.Private) { return items }
if (archivedSessions.isNotEmpty()) {
items.add(AdapterItem.SessionHeader)
archivedSessions.map(AdapterItem::SessionItem).forEach { items.add(it) }
} else {
items.add(AdapterItem.SessionPlaceholder)
}
return items
}

View File

@ -13,7 +13,6 @@ import androidx.recyclerview.widget.ItemTouchHelper
import androidx.recyclerview.widget.RecyclerView
import io.reactivex.Observer
import org.mozilla.fenix.R
import org.mozilla.fenix.home.sessioncontrol.viewholders.SessionViewHolder
import org.mozilla.fenix.home.sessioncontrol.viewholders.TabViewHolder
import android.graphics.drawable.Drawable
@ -33,9 +32,6 @@ class SwipeToDeleteCallback(
if (viewHolder is TabViewHolder) {
actionEmitter.onNext(TabAction.Close(viewHolder.tab?.sessionId!!))
}
if (viewHolder is SessionViewHolder) {
viewHolder.session?.apply { actionEmitter.onNext(ArchivedSessionAction.Delete(this)) }
}
}
override fun onChildDraw(
@ -101,10 +97,9 @@ class SwipeToDeleteCallback(
recyclerView: RecyclerView,
viewHolder: RecyclerView.ViewHolder
): Int {
return if (viewHolder is TabViewHolder || viewHolder is SessionViewHolder) super.getSwipeDirs(
recyclerView,
viewHolder
) else 0
return if (viewHolder is TabViewHolder) {
super.getSwipeDirs(recyclerView, viewHolder)
} else 0
}
companion object {

View File

@ -1,22 +0,0 @@
/* 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 kotlinx.android.synthetic.main.session_list_header.view.*
import org.mozilla.fenix.R
class SessionHeaderViewHolder(view: View) : RecyclerView.ViewHolder(view) {
val headerText = view.header_text
init {
headerText.text = "Today"
}
companion object {
const val LAYOUT_ID = R.layout.session_list_header
}
}

View File

@ -1,15 +0,0 @@
/* 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 SessionPlaceholderViewHolder(view: View) : RecyclerView.ViewHolder(view) {
companion object {
const val LAYOUT_ID = R.layout.session_list_empty
}
}

View File

@ -1,132 +0,0 @@
/* 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.Color
import android.graphics.LightingColorFilter
import android.view.View
import androidx.core.content.ContextCompat
import androidx.recyclerview.widget.RecyclerView
import io.reactivex.Observer
import kotlinx.android.extensions.LayoutContainer
import kotlinx.android.synthetic.main.session_item.*
import org.mozilla.fenix.R
import org.mozilla.fenix.home.sessioncontrol.ArchivedSession
import org.mozilla.fenix.home.sessioncontrol.ArchivedSessionAction
import org.mozilla.fenix.home.sessioncontrol.SessionControlAction
import org.mozilla.fenix.home.sessioncontrol.onNext
import java.net.URL
import java.text.SimpleDateFormat
import java.util.Locale
import java.util.Calendar
import java.util.Date
private const val NUMBER_OF_URLS_TO_DISPLAY = 5
private const val LONGEST_HOST_ON_INTERNET_LENGTH = 64
private val timeFormatter = SimpleDateFormat("h:mm a", Locale.US)
private val monthFormatter = SimpleDateFormat("M", Locale.US)
private val dayFormatter = SimpleDateFormat("d", Locale.US)
private val dayOfWeekFormatter = SimpleDateFormat("EEEE", Locale.US)
val ArchivedSession.formattedSavedAt: String
get() = {
val isSameDay: (Calendar, Calendar) -> Boolean = { a, b ->
a.get(Calendar.ERA) == b.get(Calendar.ERA) &&
a.get(Calendar.YEAR) == b.get(Calendar.YEAR) &&
a.get(Calendar.DAY_OF_YEAR) == b.get(Calendar.DAY_OF_YEAR)
}
val parse: (Date) -> String = { date ->
val dateCal = Calendar.getInstance().apply { time = date }
val today = Calendar.getInstance()
val yesterday = Calendar.getInstance().apply { add(Calendar.DAY_OF_YEAR, -1) }
val time = timeFormatter.format(date)
val month = monthFormatter.format(date)
val day = dayFormatter.format(date)
val dayOfWeek = dayOfWeekFormatter.format(date)
when {
isSameDay(dateCal, today) -> "Today @ $time"
isSameDay(dateCal, yesterday) -> "Yesterday @ $time"
else -> "$dayOfWeek $month/$day @ $time"
}
}
parse(Date(savedAt))
}()
val ArchivedSession.titles: String
get() = {
// Until we resolve (https://github.com/mozilla-mobile/fenix/issues/532) we
// just want to grab the host from the URL
@SuppressWarnings("TooGenericExceptionCaught")
val urlFormatter: (String) -> String = { url ->
var formattedURL = try {
URL(url).host
} catch (e: Exception) {
url
}
if (formattedURL.length > LONGEST_HOST_ON_INTERNET_LENGTH) {
formattedURL = formattedURL.take(LONGEST_HOST_ON_INTERNET_LENGTH).plus("...")
}
formattedURL
}
urls
.take(NUMBER_OF_URLS_TO_DISPLAY)
.joinToString(", ", transform = urlFormatter)
}()
val ArchivedSession.extrasLabel: Int
get() = maxOf(urls.size - NUMBER_OF_URLS_TO_DISPLAY, 0)
class SessionViewHolder(
view: View,
private val actionEmitter: Observer<SessionControlAction>,
override val containerView: View? = view
) : RecyclerView.ViewHolder(view), LayoutContainer {
internal var session: ArchivedSession? = null
init {
session_item.setOnClickListener {
session?.apply { actionEmitter.onNext(ArchivedSessionAction.Select(this)) }
}
session_card_overflow_button.setOnClickListener {
session?.apply { actionEmitter.onNext(ArchivedSessionAction.MenuTapped(this)) }
}
session_card_share_button.setOnClickListener {
session?.apply { actionEmitter.onNext(ArchivedSessionAction.ShareTapped(this)) }
}
}
fun bind(session: ArchivedSession) {
this.session = session
val color = availableColors[(session.id % availableColors.size).toInt()]
session_card_thumbnail.colorFilter =
LightingColorFilter(ContextCompat.getColor(itemView.context, color), Color.BLACK)
session_card_timestamp.text = session.formattedSavedAt
session_card_titles.text = session.titles
session_card_extras.text = if (session.extrasLabel > 0) {
"+${session.extrasLabel} sites..."
} else { "" }
}
companion object {
private val availableColors =
listOf(
R.color.session_placeholder_blue,
R.color.session_placeholder_green,
R.color.session_placeholder_orange,
R.color.session_placeholder_purple,
R.color.session_placeholder_pink
)
const val LAYOUT_ID = R.layout.session_item
}
}