SyncedTabsController.kt 3.19 KB
Newer Older
1
2
3
4
5
6
7
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/. */

package org.mozilla.fenix.tabtray

import android.view.View
import androidx.fragment.app.FragmentManager.findFragment
9
import androidx.lifecycle.LifecycleOwner
10
11
import androidx.navigation.NavController
import androidx.navigation.fragment.findNavController
12
import androidx.recyclerview.widget.ConcatAdapter
13
14
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
15
16
17
18
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.flow.collect
import kotlinx.coroutines.flow.drop
import kotlinx.coroutines.flow.map
19
20
21
import kotlinx.coroutines.launch
import mozilla.components.browser.storage.sync.SyncedDeviceTabs
import mozilla.components.feature.syncedtabs.view.SyncedTabsView
22
23
import mozilla.components.lib.state.ext.flowScoped
import mozilla.components.support.ktx.kotlinx.coroutines.flow.ifChanged
24
25
26
27
28
29
30
import org.mozilla.fenix.sync.ListenerDelegate
import org.mozilla.fenix.sync.SyncedTabsAdapter
import org.mozilla.fenix.sync.ext.toAdapterList
import org.mozilla.fenix.sync.ext.toAdapterItem
import org.mozilla.fenix.sync.ext.toStringRes
import kotlin.coroutines.CoroutineContext

31
@OptIn(ExperimentalCoroutinesApi::class)
32
class SyncedTabsController(
33
    lifecycleOwner: LifecycleOwner,
34
    private val view: View,
35
36
    store: TabTrayDialogFragmentStore,
    private val concatAdapter: ConcatAdapter,
37
38
39
40
41
42
43
44
    coroutineContext: CoroutineContext = Dispatchers.Main
) : SyncedTabsView {
    override var listener: SyncedTabsView.Listener? = null

    val adapter = SyncedTabsAdapter(ListenerDelegate { listener })

    private val scope: CoroutineScope = CoroutineScope(coroutineContext)

45
46
47
48
49
50
51
52
    init {
        store.flowScoped(lifecycleOwner) { flow ->
            flow.map { it.mode }
                .ifChanged()
                .drop(1)
                .collect { mode ->
                    when (mode) {
                        is TabTrayDialogFragmentState.Mode.Normal -> {
53
                            concatAdapter.addAdapter(adapter)
54
55
56
57
58
59
60
61
62
                        }
                        is TabTrayDialogFragmentState.Mode.MultiSelect -> {
                            concatAdapter.removeAdapter(adapter)
                        }
                    }
                }
        }
    }

63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
    override fun displaySyncedTabs(syncedTabs: List<SyncedDeviceTabs>) {
        scope.launch {
            val tabsList = listOf(SyncedTabsAdapter.AdapterItem.Title) + syncedTabs.toAdapterList()
            // Reverse layout for TabTrayView which does things backwards.
            adapter.submitList(tabsList.reversed())
        }
    }

    override fun onError(error: SyncedTabsView.ErrorType) {
        scope.launch {
            val navController: NavController? = try {
                findFragment<TabTrayDialogFragment>(view).findNavController()
            } catch (exception: IllegalStateException) {
                null
            }

            val descriptionResId = error.toStringRes()
            val errorItem = error.toAdapterItem(descriptionResId, navController)

            adapter.submitList(listOf(errorItem))
        }
    }
}