SessionControlController.kt 10.7 KB
Newer Older
1
2
3
4
5
6
7
8
9
10
11
12
13
/* 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

import androidx.navigation.NavController
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import mozilla.components.browser.session.SessionManager
import mozilla.components.concept.engine.prompt.ShareData
import mozilla.components.feature.tab.collections.TabCollection
14
import mozilla.components.feature.tab.collections.ext.restore
15
import mozilla.components.feature.top.sites.TopSite
16
17
18
import org.mozilla.fenix.BrowserDirection
import org.mozilla.fenix.HomeActivity
import org.mozilla.fenix.R
19
import org.mozilla.fenix.browser.browsingmode.BrowsingMode
20
21
import org.mozilla.fenix.collections.SaveCollectionStep
import org.mozilla.fenix.components.TabCollectionStorage
22
import org.mozilla.fenix.components.TopSiteStorage
23
24
import org.mozilla.fenix.components.metrics.Event
import org.mozilla.fenix.components.metrics.MetricController
25
import org.mozilla.fenix.components.tips.Tip
ekager's avatar
ekager committed
26
import org.mozilla.fenix.ext.components
27
28
29
30
31
32
33
import org.mozilla.fenix.ext.nav
import org.mozilla.fenix.home.HomeFragment
import org.mozilla.fenix.home.HomeFragmentAction
import org.mozilla.fenix.home.HomeFragmentDirections
import org.mozilla.fenix.home.HomeFragmentStore
import org.mozilla.fenix.home.Tab
import org.mozilla.fenix.settings.SupportUtils
ekager's avatar
ekager committed
34
import mozilla.components.feature.tab.collections.Tab as ComponentTab
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71

/**
 * [HomeFragment] controller. An interface that handles the view manipulation of the Tabs triggered
 * by the Interactor.
 */
@SuppressWarnings("TooManyFunctions")
interface SessionControlController {
    /**
     * @see [CollectionInteractor.onCollectionAddTabTapped]
     */
    fun handleCollectionAddTabTapped(collection: TabCollection)

    /**
     * @see [CollectionInteractor.onCollectionOpenTabClicked]
     */
    fun handleCollectionOpenTabClicked(tab: ComponentTab)

    /**
     * @see [CollectionInteractor.onCollectionOpenTabsTapped]
     */
    fun handleCollectionOpenTabsTapped(collection: TabCollection)

    /**
     * @see [CollectionInteractor.onCollectionRemoveTab]
     */
    fun handleCollectionRemoveTab(collection: TabCollection, tab: ComponentTab)

    /**
     * @see [CollectionInteractor.onCollectionShareTabsClicked]
     */
    fun handleCollectionShareTabsClicked(collection: TabCollection)

    /**
     * @see [CollectionInteractor.onDeleteCollectionTapped]
     */
    fun handleDeleteCollectionTapped(collection: TabCollection)

72
73
74
75
76
    /**
     * @see [TopSiteInteractor.onOpenInPrivateTabClicked]
     */
    fun handleOpenInPrivateTabClicked(topSite: TopSite)

77
78
79
80
81
    /**
     * @see [TabSessionInteractor.onPrivateBrowsingLearnMoreClicked]
     */
    fun handlePrivateBrowsingLearnMoreClicked()

82
83
84
85
86
    /**
     * @see [TopSiteInteractor.onRemoveTopSiteClicked]
     */
    fun handleRemoveTopSiteClicked(topSite: TopSite)

87
88
89
90
91
    /**
     * @see [CollectionInteractor.onRenameCollectionTapped]
     */
    fun handleRenameCollectionTapped(collection: TabCollection)

92
93
94
    /**
     * @see [TopSiteInteractor.onSelectTopSite]
     */
95
    fun handleSelectTopSite(url: String, isDefault: Boolean)
96

97
98
99
100
101
    /**
     * @see [OnboardingInteractor.onStartBrowsingClicked]
     */
    fun handleStartBrowsingClicked()

102
103
104
105
106
    /**
     * @see [OnboardingInteractor.onOpenSettingsClicked]
     */
    fun handleOpenSettingsClicked()

107
108
109
110
111
112
113
114
115
116
    /**
     * @see [OnboardingInteractor.onWhatsNewGetAnswersClicked]
     */
    fun handleWhatsNewGetAnswersClicked()

    /**
     * @see [OnboardingInteractor.onReadPrivacyNoticeClicked]
     */
    fun handleReadPrivacyNoticeClicked()

117
118
119
120
    /**
     * @see [CollectionInteractor.onToggleCollectionExpanded]
     */
    fun handleToggleCollectionExpanded(collection: TabCollection, expand: Boolean)
121

122
    fun handleCloseTip(tip: Tip)
123
124
125
126
127

    /**
     * @see [CollectionInteractor.onAddTabsToCollectionTapped]
     */
    fun handleCreateCollection()
128
129
}

130
@SuppressWarnings("TooManyFunctions", "LargeClass")
131
132
class DefaultSessionControlController(
    private val activity: HomeActivity,
133
    private val fragmentStore: HomeFragmentStore,
134
    private val navController: NavController,
135
    private val viewLifecycleScope: CoroutineScope,
136
137
138
    private val getListOfTabs: () -> List<Tab>,
    private val hideOnboarding: () -> Unit,
    private val registerCollectionStorageObserver: () -> Unit,
139
    private val showDeleteCollectionPrompt: (tabCollection: TabCollection) -> Unit,
140
    private val openSettingsScreen: () -> Unit,
141
    private val openWhatsNewLink: () -> Unit,
142
143
    private val openPrivacyNotice: () -> Unit,
    private val showTabTray: () -> Unit
144
145
146
147
148
149
150
) : SessionControlController {
    private val metrics: MetricController
        get() = activity.components.analytics.metrics
    private val sessionManager: SessionManager
        get() = activity.components.core.sessionManager
    private val tabCollectionStorage: TabCollectionStorage
        get() = activity.components.core.tabCollectionStorage
151
152
    private val topSiteStorage: TopSiteStorage
        get() = activity.components.core.topSiteStorage
153
154
155
156
157
158
159
160
161
162

    override fun handleCollectionAddTabTapped(collection: TabCollection) {
        metrics.track(Event.CollectionAddTabPressed)
        showCollectionCreationFragment(
            step = SaveCollectionStep.SelectTabs,
            selectedTabCollectionId = collection.id
        )
    }

    override fun handleCollectionOpenTabClicked(tab: ComponentTab) {
163
164
165
166
167
168
169
170
171
172
173
174
175
176
        sessionManager.restore(
            activity,
            activity.components.core.engine,
            tab,
            onTabRestored = {
                activity.openToBrowser(BrowserDirection.FromHome)
            },
            onFailure = {
                activity.openToBrowserAndLoad(
                    searchTermOrURL = tab.url,
                    newTab = true,
                    from = BrowserDirection.FromHome
                )
            }
177
178
179
180
181
182
        )

        metrics.track(Event.CollectionTabRestored)
    }

    override fun handleCollectionOpenTabsTapped(collection: TabCollection) {
183
184
185
186
187
188
        sessionManager.restore(
            activity,
            activity.components.core.engine,
            collection,
            onFailure = { url ->
                activity.components.useCases.tabsUseCases.addTab.invoke(url)
189
            }
190
        )
191

192
        showTabTray()
193
194
195
196
197
198
        metrics.track(Event.CollectionAllTabsRestored)
    }

    override fun handleCollectionRemoveTab(collection: TabCollection, tab: ComponentTab) {
        metrics.track(Event.CollectionTabRemoved)

199
        viewLifecycleScope.launch(Dispatchers.IO) {
200
201
202
203
204
205
206
207
208
209
210
211
212
            tabCollectionStorage.removeTabFromCollection(collection, tab)
        }
    }

    override fun handleCollectionShareTabsClicked(collection: TabCollection) {
        showShareFragment(collection.tabs.map { ShareData(url = it.url, title = it.title) })
        metrics.track(Event.CollectionShared)
    }

    override fun handleDeleteCollectionTapped(collection: TabCollection) {
        showDeleteCollectionPrompt(collection)
    }

213
    override fun handleOpenInPrivateTabClicked(topSite: TopSite) {
214
        metrics.track(Event.TopSiteOpenInPrivateTab)
215
216
217
218
219
220
221
222
223
224
        with(activity) {
            browsingModeManager.mode = BrowsingMode.Private
            openToBrowserAndLoad(
                searchTermOrURL = topSite.url,
                newTab = true,
                from = BrowserDirection.FromHome
            )
        }
    }

225
226
227
228
229
230
231
232
233
    override fun handlePrivateBrowsingLearnMoreClicked() {
        activity.openToBrowserAndLoad(
            searchTermOrURL = SupportUtils.getGenericSumoURLForTopic
                (SupportUtils.SumoTopic.PRIVATE_BROWSING_MYTHS),
            newTab = true,
            from = BrowserDirection.FromHome
        )
    }

234
    override fun handleRemoveTopSiteClicked(topSite: TopSite) {
235
        metrics.track(Event.TopSiteRemoved)
ekager's avatar
ekager committed
236
237
238
        if (topSite.url == SupportUtils.POCKET_TRENDING_URL) {
            metrics.track(Event.PocketTopSiteRemoved)
        }
239

240
        viewLifecycleScope.launch(Dispatchers.IO) {
241
242
243
244
            topSiteStorage.removeTopSite(topSite)
        }
    }

245
246
247
248
249
250
251
252
    override fun handleRenameCollectionTapped(collection: TabCollection) {
        showCollectionCreationFragment(
            step = SaveCollectionStep.RenameCollection,
            selectedTabCollectionId = collection.id
        )
        metrics.track(Event.CollectionRenamePressed)
    }

253
    override fun handleSelectTopSite(url: String, isDefault: Boolean) {
254
        metrics.track(Event.TopSiteOpenInNewTab)
255
        if (isDefault) { metrics.track(Event.TopSiteOpenDefault) }
256
257
258
259
260
        if (url == SupportUtils.POCKET_TRENDING_URL) { metrics.track(Event.PocketTopSiteClicked) }
        activity.components.useCases.tabsUseCases.addTab.invoke(
            url = url,
            selectTab = true,
            startLoading = true
261
        )
262
        activity.openToBrowser(BrowserDirection.FromHome)
263
264
    }

265
266
267
268
    override fun handleStartBrowsingClicked() {
        hideOnboarding()
    }

269
270
271
272
    override fun handleOpenSettingsClicked() {
        openSettingsScreen()
    }

273
274
275
276
277
278
279
280
    override fun handleWhatsNewGetAnswersClicked() {
        openWhatsNewLink()
    }

    override fun handleReadPrivacyNoticeClicked() {
        openPrivacyNotice()
    }

281
    override fun handleToggleCollectionExpanded(collection: TabCollection, expand: Boolean) {
282
        fragmentStore.dispatch(HomeFragmentAction.CollectionExpanded(collection, expand))
283
284
    }

285
286
287
288
    override fun handleCloseTip(tip: Tip) {
        fragmentStore.dispatch(HomeFragmentAction.RemoveTip(tip))
    }

289
290
291
292
293
294
295
296
297
298
299
    private fun showCollectionCreationFragment(
        step: SaveCollectionStep,
        selectedTabIds: Array<String>? = null,
        selectedTabCollectionId: Long? = null
    ) {
        if (navController.currentDestination?.id == R.id.collectionCreationFragment) return

        // Only register the observer right before moving to collection creation
        registerCollectionStorageObserver()

        val tabIds = getListOfTabs().map { it.sessionId }.toTypedArray()
300
        val directions = HomeFragmentDirections.actionGlobalCollectionCreationFragment(
301
302
303
304
305
306
307
308
            tabIds = tabIds,
            saveCollectionStep = step,
            selectedTabIds = selectedTabIds,
            selectedTabCollectionId = selectedTabCollectionId ?: -1
        )
        navController.nav(R.id.homeFragment, directions)
    }

309
310
311
312
    override fun handleCreateCollection() {
        showCollectionCreationFragment(step = SaveCollectionStep.SelectTabs)
    }

313
    private fun showShareFragment(data: List<ShareData>) {
Jeff Boek's avatar
Jeff Boek committed
314
        val directions = HomeFragmentDirections.actionGlobalShareFragment(
315
316
317
318
319
            data = data.toTypedArray()
        )
        navController.nav(R.id.homeFragment, directions)
    }
}