1
0
Fork 0

Fixes #293: Adds about settings page

Co-authored-by: Sawyer Blatz <sblatz@mozilla.com>
master
Colin Lee 2019-02-22 11:49:56 -06:00
parent 2750b65cc3
commit 3ccce1b4d2
5 changed files with 154 additions and 36 deletions

View File

@ -9,10 +9,12 @@ package org.mozilla.fenix.settings
import android.content.Context import android.content.Context
import android.content.pm.PackageManager import android.content.pm.PackageManager
import androidx.annotation.RawRes import androidx.annotation.RawRes
import org.mozilla.fenix.R
import org.mozilla.fenix.BuildConfig.BUILD_DATE import org.mozilla.fenix.BuildConfig.BUILD_DATE
import org.mozilla.fenix.R
import org.mozilla.fenix.ext.replace import org.mozilla.fenix.ext.replace
import org.mozilla.fenix.settings.SettingsFragment.Companion.wordmarkPath
import org.mozilla.geckoview.BuildConfig import org.mozilla.geckoview.BuildConfig
import java.io.File
object AboutPage { object AboutPage {
fun createAboutPage(context: Context): String { fun createAboutPage(context: Context): String {
@ -36,9 +38,12 @@ object AboutPage {
substitutionMap["%build-date%"] = BUILD_DATE substitutionMap["%build-date%"] = BUILD_DATE
context.resources.getString(R.string.about_content, appName).also { content -> context.resources.getString(R.string.about_content, appName, SupportUtils.MOZILLA_MANIFESTO_URL)
substitutionMap["%about-content%"] = content .also { content ->
} substitutionMap["%about-content%"] = content
}
substitutionMap["%wordmark%"] = File(context.filesDir, wordmarkPath).readText()
return loadResourceFile(context, R.raw.about, substitutionMap) return loadResourceFile(context, R.raw.about, substitutionMap)
} }

View File

@ -5,6 +5,8 @@
package org.mozilla.fenix.settings package org.mozilla.fenix.settings
import android.content.Intent import android.content.Intent
import android.graphics.BitmapFactory
import android.net.Uri
import android.os.Bundle import android.os.Bundle
import android.provider.Settings import android.provider.Settings
import android.widget.Toast import android.widget.Toast
@ -13,19 +15,31 @@ import androidx.navigation.Navigation
import androidx.preference.Preference import androidx.preference.Preference
import androidx.preference.Preference.OnPreferenceClickListener import androidx.preference.Preference.OnPreferenceClickListener
import androidx.preference.PreferenceFragmentCompat import androidx.preference.PreferenceFragmentCompat
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.Dispatchers.IO
import kotlinx.coroutines.Job
import kotlinx.coroutines.launch
import mozilla.components.support.ktx.android.graphics.toDataUri
import org.mozilla.fenix.BuildConfig import org.mozilla.fenix.BuildConfig
import org.mozilla.fenix.FenixApplication import org.mozilla.fenix.FenixApplication
import org.mozilla.fenix.R import org.mozilla.fenix.R
import org.mozilla.fenix.R.string.pref_key_about
import org.mozilla.fenix.R.string.pref_key_leakcanary import org.mozilla.fenix.R.string.pref_key_leakcanary
import org.mozilla.fenix.R.string.pref_key_make_default_browser import org.mozilla.fenix.R.string.pref_key_make_default_browser
import org.mozilla.fenix.ext.getPreferenceKey import org.mozilla.fenix.ext.getPreferenceKey
import org.mozilla.fenix.ext.requireComponents import org.mozilla.fenix.ext.requireComponents
import java.io.File
import kotlin.coroutines.CoroutineContext
class SettingsFragment : PreferenceFragmentCompat() { class SettingsFragment : PreferenceFragmentCompat(), CoroutineScope {
private lateinit var job: Job
override val coroutineContext: CoroutineContext
get() = Dispatchers.Main + job
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
job = Job()
(activity as AppCompatActivity).supportActionBar?.show() (activity as AppCompatActivity).supportActionBar?.show()
} }
@ -36,21 +50,70 @@ class SettingsFragment : PreferenceFragmentCompat() {
override fun onResume() { override fun onResume() {
super.onResume() super.onResume()
generateWordmark()
setupPreferences() setupPreferences()
} }
override fun onPreferenceTreeClick(preference: Preference): Boolean {
when (preference.key) {
resources.getString(R.string.pref_key_help) -> {
requireComponents.useCases.tabsUseCases.addTab
.invoke(SupportUtils.getSumoURLForTopic(context!!, SupportUtils.SumoTopic.HELP))
navigateToSettingsArticle()
}
resources.getString(R.string.pref_key_rate) -> {
startActivity(Intent(Intent.ACTION_VIEW, Uri.parse(SupportUtils.RATE_APP_URL)))
}
resources.getString(R.string.pref_key_feedback) -> {
requireComponents.useCases.tabsUseCases.addTab.invoke(SupportUtils.FEEDBACK_URL)
navigateToSettingsArticle()
}
resources.getString(R.string.pref_key_about) -> {
requireComponents.useCases.tabsUseCases.addTab.invoke(aboutURL, true)
navigateToSettingsArticle()
}
}
return super.onPreferenceTreeClick(preference)
}
override fun onDestroy() {
super.onDestroy()
job.cancel()
}
/**
* Shrinks the wordmark resolution on first run to ensure About Page loads quickly
*/
private fun generateWordmark() {
val path = context?.filesDir
val file = File(path, wordmarkPath)
path?.let {
if (!file.exists()) {
launch(IO) {
val options = BitmapFactory.Options().apply {
inSampleSize = wordmarkScalingFactor
inJustDecodeBounds = false
}
file.appendText(
BitmapFactory.decodeResource(
resources,
R.drawable.ic_logo_wordmark, options
).toDataUri()
)
}
}
}
}
private fun setupPreferences() { private fun setupPreferences() {
val makeDefaultBrowserKey = context?.getPreferenceKey(pref_key_make_default_browser) val makeDefaultBrowserKey = context?.getPreferenceKey(pref_key_make_default_browser)
val aboutKey = context?.getPreferenceKey(pref_key_about)
val leakKey = context?.getPreferenceKey(pref_key_leakcanary) val leakKey = context?.getPreferenceKey(pref_key_leakcanary)
val preferenceMakeDefaultBrowser = findPreference<Preference>(makeDefaultBrowserKey) val preferenceMakeDefaultBrowser = findPreference<Preference>(makeDefaultBrowserKey)
val preferenceAbout = findPreference<Preference>(aboutKey)
val preferenceLeakCanary = findPreference<Preference>(leakKey) val preferenceLeakCanary = findPreference<Preference>(leakKey)
preferenceMakeDefaultBrowser.onPreferenceClickListener = preferenceMakeDefaultBrowser.onPreferenceClickListener =
getClickListenerForMakeDefaultBrowser() getClickListenerForMakeDefaultBrowser()
preferenceAbout.onPreferenceClickListener = getAboutPageListener()
preferenceLeakCanary.isVisible = BuildConfig.DEBUG preferenceLeakCanary.isVisible = BuildConfig.DEBUG
if (BuildConfig.DEBUG) { if (BuildConfig.DEBUG) {
@ -81,18 +144,17 @@ class SettingsFragment : PreferenceFragmentCompat() {
} }
} }
private fun getAboutPageListener(): OnPreferenceClickListener { private fun navigateToSettingsArticle() {
return OnPreferenceClickListener { requireComponents.useCases.tabsUseCases.addTab.invoke(aboutURL, true)
requireComponents.useCases.tabsUseCases.addTab.invoke(aboutURL, true) view?.let {
view?.let { Navigation.findNavController(it)
Navigation.findNavController(it) .navigate(SettingsFragmentDirections.actionGlobalBrowser(null))
.navigate(SettingsFragmentDirections.actionGlobalBrowser(null))
}
true
} }
} }
companion object { companion object {
const val wordmarkScalingFactor = 2
const val wordmarkPath = "wordmark.b64"
const val aboutURL = "about:version" const val aboutURL = "about:version"
} }
} }

View File

@ -0,0 +1,49 @@
/* 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.settings
import android.content.Context
import android.content.pm.PackageManager
import org.mozilla.fenix.BuildConfig
import java.io.UnsupportedEncodingException
import java.net.URLEncoder
import java.util.Locale
object SupportUtils {
const val FEEDBACK_URL = "https://input.mozilla.org"
const val RATE_APP_URL = "market://details?id=" + BuildConfig.APPLICATION_ID
const val MOZILLA_MANIFESTO_URL = "https://www.mozilla.org/en-GB/about/manifesto/"
enum class SumoTopic(
internal val topicStr: String
) {
HELP("firefox-android-help")
}
fun getSumoURLForTopic(context: Context, topic: SumoTopic): String {
val escapedTopic = getEncodedTopicUTF8(topic.topicStr)
val appVersion = getAppVersion(context)
val osTarget = "Android"
val langTag = Locale.getDefault().isO3Language
return "https://support.mozilla.org/1/mobile/$appVersion/$osTarget/$langTag/$escapedTopic"
}
private fun getEncodedTopicUTF8(topic: String): String {
try {
return URLEncoder.encode(topic, "UTF-8")
} catch (e: UnsupportedEncodingException) {
throw IllegalStateException("utf-8 should always be available", e)
}
}
private fun getAppVersion(context: Context): String {
try {
return context.packageManager.getPackageInfo(context.packageName, 0).versionName
} catch (e: PackageManager.NameNotFoundException) {
// This should be impossible - we should always be able to get information about ourselves:
throw IllegalStateException("Unable find package details for Fenix", e)
}
}
}

View File

@ -4,48 +4,50 @@
- You can obtain one at http://mozilla.org/MPL/2.0/. --> - You can obtain one at http://mozilla.org/MPL/2.0/. -->
<head> <head>
<meta <meta
name="viewport" name="viewport"
charset="utf-8" charset="utf-8"
content="width=device-width, initial-scale=1"> content="width=device-width, initial-scale=1">
<style> <style>
body, html { body, html {
background: #221F1F; background: #f9f9fa;
color: #FFFFFF; color: #0C0C0D;
font-family: sans-serif; font-family: sans-serif;
line-height: 24px; line-height: 24px;
font-size: 14px; font-size: 14px;
} }
body{ body{
padding-left: 24px; padding-left: 24px;
padding-right: 24px; padding-right: 24px;
margin-left: 0px; margin-left: 0px;
margin-right: 0px; margin-right: 0px;
} }
a { a {
color: #0A9AF4; color: #0A9AF4;
} }
p.subtitle { p.subtitle {
text-align: center; text-align: center;
opacity: .7; opacity: .7;
margin: 0; margin: 0;
} }
img#wordmark {
h1#wordmark { /* We need to set the dp size here, because by default webview assumes the image is not
density specific (but since it's an android resource, we get a density specific version). */
width: 180px;
display: block;
margin-left: auto;
margin-right: auto;
padding-top: 24px; padding-top: 24px;
text-align: center; }
}
</style> </style>
</head> </head>
<html> <html>
<body <body
class="about"> class="about">
<h1 id="wordmark">Fenix</h1> <br>
<img src="%wordmark%" id="wordmark"/>
<br>
<p class="subtitle">%about-version%</p> <p class="subtitle">%about-version%</p>
%about-content% %about-content%
<p class="subtitle">Built on: %build-date%</p> <p class="subtitle">Built on: %build-date%</p>
</body> </body>
</html> </html>

View File

@ -131,10 +131,10 @@
<!-- Content description (not visible, for screen readers etc.): "Menu icon for items on a history item" --> <!-- Content description (not visible, for screen readers etc.): "Menu icon for items on a history item" -->
<string name="content_description_history_menu">History item menu</string> <string name="content_description_history_menu">History item menu</string>
<!-- About content -->
<string name="about_content"><![CDATA[ <string name="about_content"><![CDATA[
<p>%1$s puts you in control.</p> <p>%1$s is made by Mozilla: a global community that makes browsers, apps, code and tools that put
<p>%1$s is produced by Mozilla. Our mission is to foster a healthy, open Internet.<br/> people before profit. Our mission: keep the Internet open and accessible to all.<br/>
<a href="%2$s">Learn more</a></p>
]]></string> ]]></string>
<!-- Sessions --> <!-- Sessions -->