GitLab is used only for code review, issue tracking and project management. Canonical locations for source code are still https://gitweb.torproject.org/ https://git.torproject.org/ and git-rw.torproject.org.

InstalledAddonDetailsFragment.kt 12.2 KB
Newer Older
Gabriel Luong's avatar
Gabriel Luong committed
1 2 3 4 5 6 7 8 9 10
/* 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.addons

import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
11
import androidx.core.view.isVisible
Gabriel Luong's avatar
Gabriel Luong committed
12
import androidx.fragment.app.Fragment
13
import androidx.lifecycle.lifecycleScope
Gabriel Luong's avatar
Gabriel Luong committed
14 15
import androidx.navigation.Navigation
import androidx.navigation.findNavController
16
import androidx.navigation.fragment.findNavController
17
import com.google.android.material.switchmaterial.SwitchMaterial
Gabriel Luong's avatar
Gabriel Luong committed
18
import kotlinx.android.synthetic.main.fragment_installed_add_on_details.view.*
19 20
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
Gabriel Luong's avatar
Gabriel Luong committed
21
import mozilla.components.feature.addons.Addon
22
import mozilla.components.feature.addons.AddonManagerException
Tiger Oakes's avatar
Tiger Oakes committed
23
import mozilla.components.feature.addons.ui.translatedName
24
import org.mozilla.fenix.HomeActivity
Gabriel Luong's avatar
Gabriel Luong committed
25 26 27 28 29 30 31
import org.mozilla.fenix.R
import org.mozilla.fenix.ext.components
import org.mozilla.fenix.ext.showToolbar

/**
 * An activity to show the details of a installed add-on.
 */
32
@Suppress("LargeClass", "TooManyFunctions")
Gabriel Luong's avatar
Gabriel Luong committed
33 34 35 36 37 38 39 40 41 42 43 44
class InstalledAddonDetailsFragment : Fragment() {
    private lateinit var addon: Addon

    override fun onCreateView(
        inflater: LayoutInflater,
        container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View {
        if (!::addon.isInitialized) {
            addon = AddonDetailsFragmentArgs.fromBundle(requireNotNull(arguments)).addon
        }

45 46 47
        return inflater.inflate(R.layout.fragment_installed_add_on_details, container, false).also {
            bindUI(it)
        }
48 49 50 51 52
    }

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)
        bindAddon(view)
Gabriel Luong's avatar
Gabriel Luong committed
53 54
    }

55 56 57 58 59 60 61 62 63 64 65 66 67 68
    private fun bindAddon(view: View) {
        lifecycleScope.launch(Dispatchers.IO) {
            try {
                val addons = requireContext().components.addonManager.getAddons()
                lifecycleScope.launch(Dispatchers.Main) {
                    runIfFragmentIsAttached {
                        addons.find { addon.id == it.id }.let {
                            if (it == null) {
                                throw AddonManagerException(Exception("Addon ${addon.id} not found"))
                            } else {
                                addon = it
                                bindUI(view)
                            }
                            view.add_on_progress_bar.isVisible = false
69
                            view.addon_container.isVisible = true
70 71 72
                        }
                    }
                }
73 74 75 76 77 78 79
            } catch (e: AddonManagerException) {
                lifecycleScope.launch(Dispatchers.Main) {
                    runIfFragmentIsAttached {
                        showSnackBar(
                            view,
                            getString(R.string.mozac_feature_addons_failed_to_query_add_ons)
                        )
80
                        findNavController().popBackStack()
81 82 83
                    }
                }
            }
84 85 86
        }
    }

87
    private fun bindUI(view: View) {
88
        val title = addon.translatedName
Gabriel Luong's avatar
Gabriel Luong committed
89 90 91 92 93 94
        showToolbar(title)

        bindEnableSwitch(view)
        bindSettings(view)
        bindDetails(view)
        bindPermissions(view)
95
        bindAllowInPrivateBrowsingSwitch(view)
Gabriel Luong's avatar
Gabriel Luong committed
96 97 98
        bindRemoveButton(view)
    }

99
    @SuppressWarnings("LongMethod")
Gabriel Luong's avatar
Gabriel Luong committed
100 101
    private fun bindEnableSwitch(view: View) {
        val switch = view.enable_switch
102
        val privateBrowsingSwitch = view.allow_in_private_browsing_switch
Gabriel Luong's avatar
Gabriel Luong committed
103
        switch.setState(addon.isEnabled())
Tiger Oakes's avatar
Tiger Oakes committed
104 105
        switch.setOnCheckedChangeListener { v, isChecked ->
            val addonManager = v.context.components.addonManager
106
            switch.isClickable = false
107
            view.remove_add_on.isEnabled = false
Gabriel Luong's avatar
Gabriel Luong committed
108
            if (isChecked) {
Tiger Oakes's avatar
Tiger Oakes committed
109
                addonManager.enableAddon(
Gabriel Luong's avatar
Gabriel Luong committed
110 111
                    addon,
                    onSuccess = {
112
                        runIfFragmentIsAttached {
113
                            this.addon = it
114
                            switch.isClickable = true
115
                            privateBrowsingSwitch.isVisible = false
116
                            privateBrowsingSwitch.isChecked = it.isAllowedInPrivateBrowsing()
117
                            switch.setText(R.string.mozac_feature_addons_enabled)
118
                            view.settings.isVisible = shouldSettingsBeVisible()
119
                            view.remove_add_on.isEnabled = true
120 121 122 123 124 125 126 127
                            showSnackBar(
                                view,
                                getString(
                                    R.string.mozac_feature_addons_successfully_enabled,
                                    addon.translatedName
                                )
                            )
                        }
Gabriel Luong's avatar
Gabriel Luong committed
128 129
                    },
                    onError = {
130
                        runIfFragmentIsAttached {
131
                            switch.isClickable = true
132
                            view.remove_add_on.isEnabled = true
133
                            switch.setState(addon.isEnabled())
134 135 136 137 138 139 140 141
                            showSnackBar(
                                view,
                                getString(
                                    R.string.mozac_feature_addons_failed_to_enable,
                                    addon.translatedName
                                )
                            )
                        }
Gabriel Luong's avatar
Gabriel Luong committed
142 143 144
                    }
                )
            } else {
145
                view.settings.isVisible = false
Tiger Oakes's avatar
Tiger Oakes committed
146
                addonManager.disableAddon(
Gabriel Luong's avatar
Gabriel Luong committed
147 148
                    addon,
                    onSuccess = {
149
                        runIfFragmentIsAttached {
150
                            this.addon = it
151
                            switch.isClickable = true
152
                            privateBrowsingSwitch.isVisible = it.isEnabled()
153
                            switch.setText(R.string.mozac_feature_addons_disabled)
154
                            view.remove_add_on.isEnabled = true
155 156 157 158 159 160 161 162
                            showSnackBar(
                                view,
                                getString(
                                    R.string.mozac_feature_addons_successfully_disabled,
                                    addon.translatedName
                                )
                            )
                        }
Gabriel Luong's avatar
Gabriel Luong committed
163 164
                    },
                    onError = {
165
                        runIfFragmentIsAttached {
166
                            switch.isClickable = true
167
                            privateBrowsingSwitch.isClickable = true
168
                            view.remove_add_on.isEnabled = true
169
                            switch.setState(addon.isEnabled())
170 171 172 173 174 175 176 177
                            showSnackBar(
                                view,
                                getString(
                                    R.string.mozac_feature_addons_failed_to_disable,
                                    addon.translatedName
                                )
                            )
                        }
Gabriel Luong's avatar
Gabriel Luong committed
178 179 180 181 182 183 184 185
                    }
                )
            }
        }
    }

    private fun bindSettings(view: View) {
        view.settings.apply {
186
            isVisible = shouldSettingsBeVisible()
Gabriel Luong's avatar
Gabriel Luong committed
187
            setOnClickListener {
188
                val settingUrl = addon.installedState?.optionsPageUrl ?: return@setOnClickListener
189 190 191
                val directions = if (addon.installedState?.openOptionsPageInTab == true) {
                    val components = it.context.components
                    val shouldCreatePrivateSession =
192
                        (activity as HomeActivity).browsingModeManager.mode.isPrivate
193 194

                    if (shouldCreatePrivateSession) {
195
                        components.useCases.tabsUseCases.addPrivateTab(settingUrl)
196
                    } else {
197
                        components.useCases.tabsUseCases.addTab(settingUrl)
198 199
                    }

200
                    InstalledAddonDetailsFragmentDirections.actionGlobalBrowser(null)
201 202 203 204
                } else {
                    InstalledAddonDetailsFragmentDirections
                        .actionInstalledAddonFragmentToAddonInternalSettingsFragment(addon)
                }
Gabriel Luong's avatar
Gabriel Luong committed
205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229
                Navigation.findNavController(this).navigate(directions)
            }
        }
    }

    private fun bindDetails(view: View) {
        view.details.setOnClickListener {
            val directions =
                InstalledAddonDetailsFragmentDirections.actionInstalledAddonFragmentToAddonDetailsFragment(
                    addon
                )
            Navigation.findNavController(view).navigate(directions)
        }
    }

    private fun bindPermissions(view: View) {
        view.permissions.setOnClickListener {
            val directions =
                InstalledAddonDetailsFragmentDirections.actionInstalledAddonFragmentToAddonPermissionsDetailsFragment(
                    addon
                )
            Navigation.findNavController(view).navigate(directions)
        }
    }

230 231 232
    private fun bindAllowInPrivateBrowsingSwitch(view: View) {
        val switch = view.allow_in_private_browsing_switch
        switch.isChecked = addon.isAllowedInPrivateBrowsing()
233
        switch.isVisible = false
234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249
        switch.setOnCheckedChangeListener { v, isChecked ->
            val addonManager = v.context.components.addonManager
            switch.isClickable = false
            view.remove_add_on.isEnabled = false
            addonManager.setAddonAllowedInPrivateBrowsing(
                addon,
                isChecked,
                onSuccess = {
                    runIfFragmentIsAttached {
                        this.addon = it
                        switch.isClickable = true
                        view.remove_add_on.isEnabled = true
                    }
                },
                onError = {
                    runIfFragmentIsAttached {
250
                        switch.isChecked = addon.isAllowedInPrivateBrowsing()
251 252 253 254 255 256 257
                        switch.isClickable = true
                        view.remove_add_on.isEnabled = true
                    }
                }
            )
        }
    }
Gabriel Luong's avatar
Gabriel Luong committed
258 259
    private fun bindRemoveButton(view: View) {
        view.remove_add_on.setOnClickListener {
260
            setAllInteractiveViewsClickable(view, false)
Gabriel Luong's avatar
Gabriel Luong committed
261 262 263
            requireContext().components.addonManager.uninstallAddon(
                addon,
                onSuccess = {
264
                    runIfFragmentIsAttached {
265
                        setAllInteractiveViewsClickable(view, true)
266 267 268 269 270 271 272 273 274
                        showSnackBar(
                            view,
                            getString(
                                R.string.mozac_feature_addons_successfully_uninstalled,
                                addon.translatedName
                            )
                        )
                        view.findNavController().popBackStack()
                    }
Gabriel Luong's avatar
Gabriel Luong committed
275 276
                },
                onError = { _, _ ->
277
                    runIfFragmentIsAttached {
278
                        setAllInteractiveViewsClickable(view, true)
279 280 281 282 283 284
                        showSnackBar(
                            view,
                            getString(
                                R.string.mozac_feature_addons_failed_to_uninstall,
                                addon.translatedName
                            )
Gabriel Luong's avatar
Gabriel Luong committed
285
                        )
286
                    }
Gabriel Luong's avatar
Gabriel Luong committed
287 288 289 290 291
                }
            )
        }
    }

292 293
    private fun setAllInteractiveViewsClickable(view: View, clickable: Boolean) {
        view.enable_switch.isClickable = clickable
294
        view.settings.isClickable = clickable
295 296 297 298 299
        view.details.isClickable = clickable
        view.permissions.isClickable = clickable
        view.remove_add_on.isClickable = clickable
    }

300
    private fun SwitchMaterial.setState(checked: Boolean) {
Gabriel Luong's avatar
Gabriel Luong committed
301
        val text = if (checked) {
302
            R.string.mozac_feature_addons_enabled
Gabriel Luong's avatar
Gabriel Luong committed
303
        } else {
304
            R.string.mozac_feature_addons_disabled
Gabriel Luong's avatar
Gabriel Luong committed
305 306 307 308
        }
        setText(text)
        isChecked = checked
    }
309 310

    private fun shouldSettingsBeVisible() = !addon.installedState?.optionsPageUrl.isNullOrEmpty()
Gabriel Luong's avatar
Gabriel Luong committed
311
}