* For #2648: Updates trimming of url hostname * For #2648: Fix nitsmaster
parent
7368a95d29
commit
45c509fbce
|
@ -745,21 +745,24 @@ class BrowserFragment : Fragment(), BackHandler, CoroutineScope {
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun showSaveToCollection() {
|
private fun showSaveToCollection() {
|
||||||
|
val context = context ?: return
|
||||||
getSessionById()?.let {
|
getSessionById()?.let {
|
||||||
val tabs = Tab(it.id, it.url, it.url.urlToTrimmedHost(), it.title)
|
launch(Dispatchers.Main) {
|
||||||
val viewModel = activity?.run {
|
val tabs = Tab(it.id, it.url, it.url.urlToTrimmedHost(context), it.title)
|
||||||
ViewModelProviders.of(this).get(CreateCollectionViewModel::class.java)
|
val viewModel = activity?.run {
|
||||||
}
|
ViewModelProviders.of(this).get(CreateCollectionViewModel::class.java)
|
||||||
viewModel?.tabs = listOf(tabs)
|
}
|
||||||
val selectedSet = mutableSetOf(tabs)
|
viewModel?.tabs = listOf(tabs)
|
||||||
viewModel?.selectedTabs = selectedSet
|
val selectedSet = mutableSetOf(tabs)
|
||||||
viewModel?.tabCollections = requireComponents.core.tabCollectionStorage.cachedTabCollections.reversed()
|
viewModel?.selectedTabs = selectedSet
|
||||||
viewModel?.saveCollectionStep =
|
viewModel?.tabCollections = requireComponents.core.tabCollectionStorage.cachedTabCollections.reversed()
|
||||||
viewModel?.tabCollections?.getStepForCollectionsSize() ?: SaveCollectionStep.SelectCollection
|
viewModel?.saveCollectionStep =
|
||||||
viewModel?.snackbarAnchorView = nestedScrollQuickAction
|
viewModel?.tabCollections?.getStepForCollectionsSize() ?: SaveCollectionStep.SelectCollection
|
||||||
view?.let {
|
viewModel?.snackbarAnchorView = nestedScrollQuickAction
|
||||||
val directions = BrowserFragmentDirections.actionBrowserFragmentToCreateCollectionFragment()
|
view?.let {
|
||||||
nav(R.id.browserFragment, directions)
|
val directions = BrowserFragmentDirections.actionBrowserFragmentToCreateCollectionFragment()
|
||||||
|
nav(R.id.browserFragment, directions)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -22,6 +22,10 @@ import io.reactivex.Observer
|
||||||
import io.reactivex.functions.Consumer
|
import io.reactivex.functions.Consumer
|
||||||
import kotlinx.android.synthetic.main.component_collection_creation.*
|
import kotlinx.android.synthetic.main.component_collection_creation.*
|
||||||
import kotlinx.android.synthetic.main.component_collection_creation.view.*
|
import kotlinx.android.synthetic.main.component_collection_creation.view.*
|
||||||
|
import kotlinx.coroutines.CoroutineScope
|
||||||
|
import kotlinx.coroutines.Dispatchers
|
||||||
|
import kotlinx.coroutines.Job
|
||||||
|
import kotlinx.coroutines.launch
|
||||||
import mozilla.components.support.ktx.android.view.hideKeyboard
|
import mozilla.components.support.ktx.android.view.hideKeyboard
|
||||||
import mozilla.components.support.ktx.android.view.showKeyboard
|
import mozilla.components.support.ktx.android.view.showKeyboard
|
||||||
import org.mozilla.fenix.R
|
import org.mozilla.fenix.R
|
||||||
|
@ -30,6 +34,7 @@ import org.mozilla.fenix.ext.urlToTrimmedHost
|
||||||
import org.mozilla.fenix.home.sessioncontrol.Tab
|
import org.mozilla.fenix.home.sessioncontrol.Tab
|
||||||
import org.mozilla.fenix.home.sessioncontrol.TabCollection
|
import org.mozilla.fenix.home.sessioncontrol.TabCollection
|
||||||
import org.mozilla.fenix.mvi.UIView
|
import org.mozilla.fenix.mvi.UIView
|
||||||
|
import kotlin.coroutines.CoroutineContext
|
||||||
|
|
||||||
class CollectionCreationUIView(
|
class CollectionCreationUIView(
|
||||||
container: ViewGroup,
|
container: ViewGroup,
|
||||||
|
@ -39,7 +44,11 @@ class CollectionCreationUIView(
|
||||||
container,
|
container,
|
||||||
actionEmitter,
|
actionEmitter,
|
||||||
changesObservable
|
changesObservable
|
||||||
) {
|
), CoroutineScope {
|
||||||
|
private lateinit var job: Job
|
||||||
|
override val coroutineContext: CoroutineContext
|
||||||
|
get() = Dispatchers.Main + job
|
||||||
|
|
||||||
override val view = LayoutInflater.from(container.context)
|
override val view = LayoutInflater.from(container.context)
|
||||||
.inflate(R.layout.component_collection_creation, container, true)
|
.inflate(R.layout.component_collection_creation, container, true)
|
||||||
|
|
||||||
|
@ -258,16 +267,18 @@ class CollectionCreationUIView(
|
||||||
is SaveCollectionStep.RenameCollection -> {
|
is SaveCollectionStep.RenameCollection -> {
|
||||||
view.tab_list.isClickable = false
|
view.tab_list.isClickable = false
|
||||||
|
|
||||||
it.selectedTabCollection?.let { tabCollection ->
|
launch(Dispatchers.Main) {
|
||||||
tabCollection.tabs.map { tab ->
|
it.selectedTabCollection?.let { tabCollection ->
|
||||||
Tab(
|
tabCollection.tabs.map { tab ->
|
||||||
tab.id.toString(),
|
Tab(
|
||||||
tab.url,
|
tab.id.toString(),
|
||||||
tab.url.urlToTrimmedHost(),
|
tab.url,
|
||||||
tab.title
|
tab.url.urlToTrimmedHost(view.context),
|
||||||
)
|
tab.title
|
||||||
}.let { tabs ->
|
)
|
||||||
collectionCreationTabListAdapter.updateData(tabs, tabs.toSet(), true)
|
}.let { tabs ->
|
||||||
|
collectionCreationTabListAdapter.updateData(tabs, tabs.toSet(), true)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -16,8 +16,9 @@ import kotlinx.android.synthetic.main.collections_list_item.view.collection_icon
|
||||||
import kotlinx.coroutines.CoroutineScope
|
import kotlinx.coroutines.CoroutineScope
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
import kotlinx.coroutines.Job
|
import kotlinx.coroutines.Job
|
||||||
|
import kotlinx.coroutines.launch
|
||||||
import org.mozilla.fenix.R
|
import org.mozilla.fenix.R
|
||||||
import org.mozilla.fenix.ext.urlToTrimmedHost
|
import org.mozilla.fenix.components.description
|
||||||
import org.mozilla.fenix.home.sessioncontrol.Tab
|
import org.mozilla.fenix.home.sessioncontrol.Tab
|
||||||
import org.mozilla.fenix.home.sessioncontrol.TabCollection
|
import org.mozilla.fenix.home.sessioncontrol.TabCollection
|
||||||
import kotlin.coroutines.CoroutineContext
|
import kotlin.coroutines.CoroutineContext
|
||||||
|
@ -81,36 +82,23 @@ class CollectionViewHolder(
|
||||||
|
|
||||||
fun bind(collection: TabCollection) {
|
fun bind(collection: TabCollection) {
|
||||||
this.collection = collection
|
this.collection = collection
|
||||||
view.collection_item.text = collection.title
|
launch(Dispatchers.Main) {
|
||||||
|
view.collection_item.text = collection.title
|
||||||
|
view.collection_description.text = collection.description(view.context)
|
||||||
|
|
||||||
val hostNameList = collection.tabs.map { it.url.urlToTrimmedHost().capitalize() }
|
view.collection_icon.setColorFilter(
|
||||||
|
ContextCompat.getColor(
|
||||||
var tabsDisplayed = 0
|
view.context,
|
||||||
val tabTitlesList = hostNameList.joinToString(", ") {
|
getIconColor(collection.id)
|
||||||
if (it.length > maxTitleLength) {
|
),
|
||||||
it.substring(
|
android.graphics.PorterDuff.Mode.SRC_IN
|
||||||
0,
|
)
|
||||||
maxTitleLength
|
|
||||||
) + "..."
|
|
||||||
} else {
|
|
||||||
tabsDisplayed += 1
|
|
||||||
it
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
view.collection_description.text = tabTitlesList
|
|
||||||
|
|
||||||
view.collection_icon.setColorFilter(
|
|
||||||
ContextCompat.getColor(
|
|
||||||
view.context,
|
|
||||||
getIconColor(collection.id)
|
|
||||||
),
|
|
||||||
android.graphics.PorterDuff.Mode.SRC_IN
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Suppress("ComplexMethod", "MagicNumber")
|
@Suppress("ComplexMethod", "MagicNumber")
|
||||||
private fun getIconColor(id: Long): Int {
|
private fun getIconColor(id: Long): Int {
|
||||||
return when ((id % 4).toInt()) {
|
return when ((id % 5).toInt()) {
|
||||||
0 -> R.color.collection_icon_color_violet
|
0 -> R.color.collection_icon_color_violet
|
||||||
1 -> R.color.collection_icon_color_blue
|
1 -> R.color.collection_icon_color_blue
|
||||||
2 -> R.color.collection_icon_color_pink
|
2 -> R.color.collection_icon_color_pink
|
||||||
|
|
|
@ -5,6 +5,7 @@
|
||||||
package org.mozilla.fenix.components
|
package org.mozilla.fenix.components
|
||||||
|
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
|
import mozilla.components.lib.publicsuffixlist.PublicSuffixList
|
||||||
import org.mozilla.fenix.test.Mockable
|
import org.mozilla.fenix.test.Mockable
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -21,4 +22,5 @@ class Components(private val context: Context) {
|
||||||
val useCases by lazy { UseCases(context, core.sessionManager, core.engine.settings, search.searchEngineManager) }
|
val useCases by lazy { UseCases(context, core.sessionManager, core.engine.settings, search.searchEngineManager) }
|
||||||
val utils by lazy { Utilities(context, core.sessionManager, useCases.sessionUseCases, useCases.searchUseCases) }
|
val utils by lazy { Utilities(context, core.sessionManager, useCases.sessionUseCases, useCases.searchUseCases) }
|
||||||
val analytics by lazy { Analytics(context) }
|
val analytics by lazy { Analytics(context) }
|
||||||
|
val publicSuffixList by lazy { PublicSuffixList(context) }
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,6 +14,8 @@ import mozilla.components.feature.tab.collections.TabCollection
|
||||||
import mozilla.components.feature.tab.collections.TabCollectionStorage
|
import mozilla.components.feature.tab.collections.TabCollectionStorage
|
||||||
import mozilla.components.support.base.observer.Observable
|
import mozilla.components.support.base.observer.Observable
|
||||||
import mozilla.components.support.base.observer.ObserverRegistry
|
import mozilla.components.support.base.observer.ObserverRegistry
|
||||||
|
import org.mozilla.fenix.ext.urlToTrimmedHost
|
||||||
|
import org.mozilla.fenix.home.sessioncontrol.viewholders.CollectionViewHolder
|
||||||
import org.mozilla.fenix.test.Mockable
|
import org.mozilla.fenix.test.Mockable
|
||||||
|
|
||||||
@Mockable
|
@Mockable
|
||||||
|
@ -88,3 +90,18 @@ class TabCollectionStorage(
|
||||||
notifyObservers { onCollectionRenamed(tabCollection, title) }
|
notifyObservers { onCollectionRenamed(tabCollection, title) }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
suspend fun TabCollection.description(context: Context): String {
|
||||||
|
return this.tabs
|
||||||
|
.map { it.url.urlToTrimmedHost(context).capitalize() }
|
||||||
|
.map {
|
||||||
|
if (it.length > CollectionViewHolder.maxTitleLength) {
|
||||||
|
it.substring(
|
||||||
|
0,
|
||||||
|
CollectionViewHolder.maxTitleLength
|
||||||
|
) + "…"
|
||||||
|
} else {
|
||||||
|
it
|
||||||
|
}
|
||||||
|
}.joinToString(", ")
|
||||||
|
}
|
||||||
|
|
|
@ -6,8 +6,11 @@
|
||||||
|
|
||||||
package org.mozilla.fenix.ext
|
package org.mozilla.fenix.ext
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
import java.net.MalformedURLException
|
import java.net.MalformedURLException
|
||||||
import java.net.URL
|
import java.net.URL
|
||||||
|
import mozilla.components.support.ktx.android.net.hostWithoutCommonPrefixes
|
||||||
|
import mozilla.components.support.ktx.kotlin.toUri
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Replaces the keys with the values with the map provided.
|
* Replaces the keys with the values with the map provided.
|
||||||
|
@ -28,21 +31,14 @@ fun String?.getHostFromUrl(): String? = try {
|
||||||
null
|
null
|
||||||
}
|
}
|
||||||
|
|
||||||
fun String?.urlToTrimmedHost(): String {
|
/**
|
||||||
|
* Trim a host's prefix and suffix
|
||||||
|
*/
|
||||||
|
suspend fun String.urlToTrimmedHost(context: Context): String {
|
||||||
return try {
|
return try {
|
||||||
val url = URL(this)
|
val host = this.toUri().hostWithoutCommonPrefixes ?: return this
|
||||||
val firstIndex = url.host.indexOfFirst { it == '.' } + 1
|
context.components.publicSuffixList.stripPublicSuffix(host).await()
|
||||||
val lastIndex = url.host.indexOfLast { it == '.' }
|
|
||||||
|
|
||||||
// Trim all but the title of the website from the hostname. 'www.mozilla.org' becomes 'mozilla'
|
|
||||||
when {
|
|
||||||
firstIndex - 1 == lastIndex -> url.host.substring(0, lastIndex)
|
|
||||||
firstIndex < lastIndex -> url.host.substring(firstIndex, lastIndex)
|
|
||||||
else -> url.host
|
|
||||||
}
|
|
||||||
} catch (e: MalformedURLException) {
|
} catch (e: MalformedURLException) {
|
||||||
this.getHostFromUrl() ?: ""
|
this
|
||||||
} catch (e: StringIndexOutOfBoundsException) {
|
|
||||||
this.getHostFromUrl() ?: ""
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -134,7 +134,7 @@ class HomeFragment : Fragment(), CoroutineScope, AccountObserver {
|
||||||
) {
|
) {
|
||||||
SessionControlViewModel(
|
SessionControlViewModel(
|
||||||
SessionControlState(
|
SessionControlState(
|
||||||
getListOfTabs(requireComponents.core.sessionManager),
|
listOf(),
|
||||||
setOf(),
|
setOf(),
|
||||||
requireComponents.core.tabCollectionStorage.cachedTabCollections,
|
requireComponents.core.tabCollectionStorage.cachedTabCollections,
|
||||||
mode
|
mode
|
||||||
|
@ -280,13 +280,15 @@ class HomeFragment : Fragment(), CoroutineScope, AccountObserver {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
getManagedEmitter<SessionControlChange>().onNext(
|
launch(Dispatchers.Main) {
|
||||||
SessionControlChange.Change(
|
getManagedEmitter<SessionControlChange>().onNext(
|
||||||
tabs = getListOfTabs(sessionManager = requireComponents.core.sessionManager),
|
SessionControlChange.Change(
|
||||||
mode = currentMode(),
|
tabs = getListOfTabs(sessionManager = requireComponents.core.sessionManager),
|
||||||
collections = requireComponents.core.tabCollectionStorage.cachedTabCollections
|
mode = currentMode(),
|
||||||
|
collections = requireComponents.core.tabCollectionStorage.cachedTabCollections
|
||||||
|
)
|
||||||
)
|
)
|
||||||
)
|
}
|
||||||
|
|
||||||
requireComponents.core.tabCollectionStorage.register(collectionStorageObserver, this)
|
requireComponents.core.tabCollectionStorage.register(collectionStorageObserver, this)
|
||||||
sessionObserver.onStart()
|
sessionObserver.onStart()
|
||||||
|
@ -560,82 +562,84 @@ class HomeFragment : Fragment(), CoroutineScope, AccountObserver {
|
||||||
val useCases = context?.components?.useCases?.tabsUseCases ?: return
|
val useCases = context?.components?.useCases?.tabsUseCases ?: return
|
||||||
|
|
||||||
getManagedEmitter<SessionControlChange>().onNext(SessionControlChange.TabsChange(listOf()))
|
getManagedEmitter<SessionControlChange>().onNext(SessionControlChange.TabsChange(listOf()))
|
||||||
deleteAllSessionsJob = {
|
|
||||||
|
val deleteOperation: (suspend () -> Unit) = {
|
||||||
currentFilteredSessions.forEach {
|
currentFilteredSessions.forEach {
|
||||||
useCases.removeTab.invoke(it)
|
useCases.removeTab.invoke(it)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
deleteAllSessionsJob = deleteOperation
|
||||||
|
|
||||||
allowUndo(
|
allowUndo(
|
||||||
view!!, getString(R.string.snackbar_tabs_deleted),
|
view!!, getString(R.string.snackbar_tabs_deleted),
|
||||||
getString(R.string.snackbar_deleted_undo), {
|
getString(R.string.snackbar_deleted_undo), {
|
||||||
deleteAllSessionsJob = null
|
deleteAllSessionsJob = null
|
||||||
emitSessionChanges()
|
emitSessionChanges()
|
||||||
}
|
},
|
||||||
) {
|
operation = deleteOperation
|
||||||
deleteAllSessionsJob = {
|
)
|
||||||
currentFilteredSessions.forEach {
|
|
||||||
useCases.removeTab.invoke(it)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun removeTabWithUndo(sessionId: String) {
|
private fun removeTabWithUndo(sessionId: String) {
|
||||||
val sessionManager = requireComponents.core.sessionManager
|
launch(Dispatchers.Main) {
|
||||||
|
val sessionManager = requireComponents.core.sessionManager
|
||||||
|
|
||||||
// Update the UI with the tab removed, but don't remove it from storage yet
|
// Update the UI with the tab removed, but don't remove it from storage yet
|
||||||
getManagedEmitter<SessionControlChange>().onNext(
|
getManagedEmitter<SessionControlChange>().onNext(
|
||||||
SessionControlChange.TabsChange(
|
|
||||||
sessionManager.sessions
|
SessionControlChange.TabsChange(
|
||||||
.filter { (activity as HomeActivity).browsingModeManager.isPrivate == it.private }
|
sessionManager.sessions
|
||||||
.filter { it.id != sessionId }
|
.filter { (activity as HomeActivity).browsingModeManager.isPrivate == it.private }
|
||||||
.map {
|
.filter { it.id != sessionId }
|
||||||
val selected =
|
.map {
|
||||||
it == sessionManager.selectedSession
|
val selected = it == sessionManager.selectedSession
|
||||||
Tab(
|
Tab(
|
||||||
it.id,
|
it.id,
|
||||||
it.url,
|
it.url,
|
||||||
it.url.urlToTrimmedHost(),
|
it.url.urlToTrimmedHost(context!!),
|
||||||
it.title,
|
it.title,
|
||||||
selected,
|
selected,
|
||||||
it.thumbnail
|
it.thumbnail
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
)
|
||||||
)
|
)
|
||||||
)
|
|
||||||
|
|
||||||
deleteSessionJob = {
|
val deleteOperation: (suspend () -> Unit) = {
|
||||||
sessionManager.findSessionById(sessionId)
|
sessionManager.findSessionById(sessionId)
|
||||||
?.let { session ->
|
?.let { session ->
|
||||||
sessionManager.remove(session)
|
sessionManager.remove(session)
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
allowUndo(
|
|
||||||
view!!, getString(R.string.snackbar_tab_deleted),
|
|
||||||
getString(R.string.snackbar_deleted_undo), {
|
|
||||||
deleteSessionJob = null
|
|
||||||
emitSessionChanges()
|
|
||||||
}
|
}
|
||||||
) {
|
|
||||||
sessionManager.findSessionById(sessionId)
|
deleteSessionJob = deleteOperation
|
||||||
?.let { session ->
|
|
||||||
sessionManager.remove(session)
|
allowUndo(
|
||||||
}
|
view!!, getString(R.string.snackbar_tab_deleted),
|
||||||
|
getString(R.string.snackbar_deleted_undo), {
|
||||||
|
deleteSessionJob = null
|
||||||
|
emitSessionChanges()
|
||||||
|
},
|
||||||
|
operation = deleteOperation
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun emitSessionChanges() {
|
private fun emitSessionChanges() {
|
||||||
val sessionManager = context?.components?.core?.sessionManager ?: return
|
val sessionManager = context?.components?.core?.sessionManager ?: return
|
||||||
getManagedEmitter<SessionControlChange>().onNext(
|
|
||||||
SessionControlChange.TabsChange(
|
launch(Dispatchers.Main) {
|
||||||
getListOfTabs(sessionManager)
|
getManagedEmitter<SessionControlChange>().onNext(
|
||||||
|
SessionControlChange.TabsChange(
|
||||||
|
getListOfTabs(sessionManager)
|
||||||
|
)
|
||||||
)
|
)
|
||||||
)
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun getListOfTabs(sessionManager: SessionManager): List<Tab> {
|
private suspend fun getListOfTabs(sessionManager: SessionManager): List<Tab> {
|
||||||
|
val context = context ?: return listOf()
|
||||||
return sessionManager.sessions
|
return sessionManager.sessions
|
||||||
.filter { (activity as HomeActivity).browsingModeManager.isPrivate == it.private }
|
.filter { (activity as HomeActivity).browsingModeManager.isPrivate == it.private }
|
||||||
.map {
|
.map {
|
||||||
|
@ -643,7 +647,7 @@ class HomeFragment : Fragment(), CoroutineScope, AccountObserver {
|
||||||
Tab(
|
Tab(
|
||||||
it.id,
|
it.id,
|
||||||
it.url,
|
it.url,
|
||||||
it.url.urlToTrimmedHost(),
|
it.url.urlToTrimmedHost(context),
|
||||||
it.title,
|
it.title,
|
||||||
selected,
|
selected,
|
||||||
it.thumbnail
|
it.thumbnail
|
||||||
|
@ -663,24 +667,29 @@ class HomeFragment : Fragment(), CoroutineScope, AccountObserver {
|
||||||
) {
|
) {
|
||||||
if (findNavController(this).currentDestination?.id == R.id.createCollectionFragment) return
|
if (findNavController(this).currentDestination?.id == R.id.createCollectionFragment) return
|
||||||
|
|
||||||
val tabs = requireComponents.core.sessionManager.sessions.filter { !it.private }
|
val context = context?.let { it } ?: return
|
||||||
.map { Tab(it.id, it.url, it.url.urlToTrimmedHost(), it.title) }
|
|
||||||
|
|
||||||
val viewModel = activity?.run {
|
launch(Dispatchers.Main) {
|
||||||
ViewModelProviders.of(this).get(CreateCollectionViewModel::class.java)
|
val tabs = requireComponents.core.sessionManager.sessions.filter { !it.private }
|
||||||
}
|
.map { Tab(it.id, it.url, it.url.urlToTrimmedHost(context), it.title) }
|
||||||
viewModel?.tabs = tabs
|
|
||||||
val selectedTabs = tabs.find { tab -> tab.sessionId == selectedTabId } ?: if (tabs.size == 1) tabs[0] else null
|
|
||||||
val selectedSet = if (selectedTabs == null) mutableSetOf() else mutableSetOf(selectedTabs)
|
|
||||||
viewModel?.selectedTabs = selectedSet
|
|
||||||
viewModel?.tabCollections = requireComponents.core.tabCollectionStorage.cachedTabCollections.reversed()
|
|
||||||
viewModel?.selectedTabCollection = selectedTabCollection
|
|
||||||
viewModel?.saveCollectionStep =
|
|
||||||
step ?: viewModel?.getStepForTabsAndCollectionSize() ?: SaveCollectionStep.SelectTabs
|
|
||||||
|
|
||||||
view?.let {
|
val viewModel = activity?.run {
|
||||||
val directions = HomeFragmentDirections.actionHomeFragmentToCreateCollectionFragment()
|
ViewModelProviders.of(this).get(CreateCollectionViewModel::class.java)
|
||||||
nav(R.id.homeFragment, directions)
|
}
|
||||||
|
viewModel?.tabs = tabs
|
||||||
|
val selectedTabs =
|
||||||
|
tabs.find { tab -> tab.sessionId == selectedTabId } ?: if (tabs.size == 1) tabs[0] else null
|
||||||
|
val selectedSet = if (selectedTabs == null) mutableSetOf() else mutableSetOf(selectedTabs)
|
||||||
|
viewModel?.selectedTabs = selectedSet
|
||||||
|
viewModel?.tabCollections = requireComponents.core.tabCollectionStorage.cachedTabCollections.reversed()
|
||||||
|
viewModel?.selectedTabCollection = selectedTabCollection
|
||||||
|
viewModel?.saveCollectionStep =
|
||||||
|
step ?: viewModel?.getStepForTabsAndCollectionSize() ?: SaveCollectionStep.SelectTabs
|
||||||
|
|
||||||
|
view?.let {
|
||||||
|
val directions = HomeFragmentDirections.actionHomeFragmentToCreateCollectionFragment()
|
||||||
|
nav(R.id.homeFragment, directions)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -16,13 +16,14 @@ import kotlinx.android.synthetic.main.collection_home_list_row.view.*
|
||||||
import kotlinx.coroutines.CoroutineScope
|
import kotlinx.coroutines.CoroutineScope
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
import kotlinx.coroutines.Job
|
import kotlinx.coroutines.Job
|
||||||
|
import kotlinx.coroutines.launch
|
||||||
import mozilla.components.browser.menu.BrowserMenu
|
import mozilla.components.browser.menu.BrowserMenu
|
||||||
import mozilla.components.browser.menu.BrowserMenuBuilder
|
import mozilla.components.browser.menu.BrowserMenuBuilder
|
||||||
import mozilla.components.browser.menu.item.SimpleBrowserMenuItem
|
import mozilla.components.browser.menu.item.SimpleBrowserMenuItem
|
||||||
import org.mozilla.fenix.R
|
import org.mozilla.fenix.R
|
||||||
import org.mozilla.fenix.ThemeManager
|
import org.mozilla.fenix.ThemeManager
|
||||||
|
import org.mozilla.fenix.components.description
|
||||||
import org.mozilla.fenix.ext.increaseTapArea
|
import org.mozilla.fenix.ext.increaseTapArea
|
||||||
import org.mozilla.fenix.ext.urlToTrimmedHost
|
|
||||||
import org.mozilla.fenix.home.sessioncontrol.CollectionAction
|
import org.mozilla.fenix.home.sessioncontrol.CollectionAction
|
||||||
import org.mozilla.fenix.home.sessioncontrol.SessionControlAction
|
import org.mozilla.fenix.home.sessioncontrol.SessionControlAction
|
||||||
import org.mozilla.fenix.home.sessioncontrol.TabCollection
|
import org.mozilla.fenix.home.sessioncontrol.TabCollection
|
||||||
|
@ -92,47 +93,33 @@ class CollectionViewHolder(
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun updateCollectionUI() {
|
private fun updateCollectionUI() {
|
||||||
view.collection_title.text = collection.title
|
launch(Dispatchers.Main) {
|
||||||
|
view.collection_title.text = collection.title
|
||||||
|
view.collection_description.text = collection.description(view.context)
|
||||||
|
|
||||||
val hostNameList = collection.tabs.map { it.url.urlToTrimmedHost().capitalize() }
|
if (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
|
||||||
|
|
||||||
var tabsDisplayed = 0
|
view.chevron.setBackgroundResource(R.drawable.ic_chevron_up)
|
||||||
val tabTitlesList = hostNameList.joinToString(", ") {
|
|
||||||
if (it.length > maxTitleLength) {
|
|
||||||
it.substring(
|
|
||||||
0,
|
|
||||||
maxTitleLength
|
|
||||||
) + "..."
|
|
||||||
} else {
|
} else {
|
||||||
tabsDisplayed += 1
|
(view.layoutParams as ViewGroup.MarginLayoutParams).bottomMargin = COLLAPSED_MARGIN
|
||||||
it
|
view.background = ContextCompat.getDrawable(view.context, R.drawable.rounded_all_corners)
|
||||||
|
view.collection_description.visibility = View.VISIBLE
|
||||||
|
|
||||||
|
view.chevron.setBackgroundResource(R.drawable.ic_chevron_down)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
view.collection_icon.setColorFilter(
|
||||||
|
ContextCompat.getColor(
|
||||||
|
view.context,
|
||||||
|
getIconColor(collection.id)
|
||||||
|
),
|
||||||
|
android.graphics.PorterDuff.Mode.SRC_IN
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
view.collection_description.text = tabTitlesList
|
|
||||||
|
|
||||||
if (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.chevron.setBackgroundResource(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.chevron.setBackgroundResource(R.drawable.ic_chevron_down)
|
|
||||||
}
|
|
||||||
|
|
||||||
view.collection_icon.setColorFilter(
|
|
||||||
ContextCompat.getColor(
|
|
||||||
view.context,
|
|
||||||
getIconColor(collection.id)
|
|
||||||
),
|
|
||||||
android.graphics.PorterDuff.Mode.SRC_IN
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun handleExpansion(isExpanded: Boolean) {
|
private fun handleExpansion(isExpanded: Boolean) {
|
||||||
|
@ -145,7 +132,7 @@ class CollectionViewHolder(
|
||||||
|
|
||||||
@Suppress("ComplexMethod", "MagicNumber")
|
@Suppress("ComplexMethod", "MagicNumber")
|
||||||
private fun getIconColor(id: Long): Int {
|
private fun getIconColor(id: Long): Int {
|
||||||
val sessionColorIndex = (id % 4).toInt()
|
val sessionColorIndex = (id % 5).toInt()
|
||||||
return when (sessionColorIndex) {
|
return when (sessionColorIndex) {
|
||||||
0 -> R.color.collection_icon_color_violet
|
0 -> R.color.collection_icon_color_violet
|
||||||
1 -> R.color.collection_icon_color_blue
|
1 -> R.color.collection_icon_color_blue
|
||||||
|
|
|
@ -79,7 +79,9 @@ class TabInCollectionViewHolder(
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun updateTabUI() {
|
private fun updateTabUI() {
|
||||||
collection_tab_hostname.text = tab.url.urlToTrimmedHost()
|
launch(Dispatchers.Main) {
|
||||||
|
collection_tab_hostname.text = tab.url.urlToTrimmedHost(view.context)
|
||||||
|
}
|
||||||
collection_tab_title.text = tab.title
|
collection_tab_title.text = tab.title
|
||||||
launch(Dispatchers.IO) {
|
launch(Dispatchers.IO) {
|
||||||
val bitmap = collection_tab_icon.context.components.core.icons
|
val bitmap = collection_tab_icon.context.components.core.icons
|
||||||
|
|
|
@ -24,6 +24,7 @@ import androidx.navigation.NavController
|
||||||
import androidx.navigation.Navigation
|
import androidx.navigation.Navigation
|
||||||
import kotlinx.android.synthetic.main.fragment_bookmark.view.*
|
import kotlinx.android.synthetic.main.fragment_bookmark.view.*
|
||||||
import kotlinx.coroutines.CoroutineScope
|
import kotlinx.coroutines.CoroutineScope
|
||||||
|
import kotlinx.coroutines.Dispatchers
|
||||||
import kotlinx.coroutines.Dispatchers.IO
|
import kotlinx.coroutines.Dispatchers.IO
|
||||||
import kotlinx.coroutines.Dispatchers.Main
|
import kotlinx.coroutines.Dispatchers.Main
|
||||||
import kotlinx.coroutines.Job
|
import kotlinx.coroutines.Job
|
||||||
|
@ -262,17 +263,22 @@ class BookmarkFragment : Fragment(), CoroutineScope, BackHandler, AccountObserve
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
is BookmarkAction.Delete -> {
|
is BookmarkAction.Delete -> {
|
||||||
getManagedEmitter<BookmarkChange>()
|
context?.let { context ->
|
||||||
.onNext(BookmarkChange.Change(currentRoot - it.item.guid))
|
getManagedEmitter<BookmarkChange>()
|
||||||
|
.onNext(BookmarkChange.Change(currentRoot - it.item.guid))
|
||||||
|
|
||||||
allowUndo(
|
launch(Dispatchers.Main) {
|
||||||
view!!,
|
allowUndo(
|
||||||
getString(R.string.bookmark_deletion_snackbar_message, it.item.url.urlToTrimmedHost()),
|
view!!,
|
||||||
getString(R.string.bookmark_undo_deletion), { refreshBookmarks() }
|
getString(R.string.bookmark_deletion_snackbar_message,
|
||||||
) {
|
it.item.url?.urlToTrimmedHost(context)),
|
||||||
bookmarkStorage()?.deleteNode(it.item.guid)
|
getString(R.string.bookmark_undo_deletion), { refreshBookmarks() }
|
||||||
metrics()?.track(Event.RemoveBookmark)
|
) {
|
||||||
refreshBookmarks()
|
bookmarkStorage()?.deleteNode(it.item.guid)
|
||||||
|
metrics()?.track(Event.RemoveBookmark)
|
||||||
|
refreshBookmarks()
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
is BookmarkAction.SwitchMode -> {
|
is BookmarkAction.SwitchMode -> {
|
||||||
|
|
Loading…
Reference in New Issue