Commit 6543e2c0 authored by MozLando's avatar MozLando
Browse files

Merge #6652 #6694



6652: Closes #6651 - Don't restore session source in SnapshotSerializer r=pocmo a=ekager



6694: Adds UI Widgets component with Button styling r=pocmo,Amejia481 a=sblatz
Co-authored-by: default avatarekager <ekager@mozilla.com>
Co-authored-by: default avatarSawyer Blatz <sdblatz@gmail.com>
......@@ -224,6 +224,10 @@ projects:
path: components/ui/colors
description: 'The standard set of Photon colors.'
publish: true
ui-widgets:
path: components/ui/widgets
description: 'The standard set of Mozilla widgets.'
publish: true
ui-fonts:
path: components/ui/fonts
description: 'Convenience accessor for fonts used by Mozilla.'
......
......@@ -174,7 +174,12 @@ class Session(
/**
* User entered a URL or search term
*/
USER_ENTERED
USER_ENTERED,
/**
* This session was restored
*/
RESTORED
}
/**
......
......@@ -83,10 +83,12 @@ class SnapshotSerializer(
fun itemFromJSON(engine: Engine, json: JSONObject): SessionManager.Snapshot.Item {
val sessionJson = json.getJSONObject(Keys.SESSION_KEY)
val session = deserializeSession(sessionJson, restoreSessionIds, restoreParentIds)
val readerState = ReaderState(active = sessionJson.optBoolean(Keys.SESSION_READER_MODE_KEY, false))
val readerState =
ReaderState(active = sessionJson.optBoolean(Keys.SESSION_READER_MODE_KEY, false))
val engineState = engine.createSessionState(sessionJson)
return SessionManager.Snapshot.Item(session,
return SessionManager.Snapshot.Item(
session,
engineSession = null,
engineSessionState = engineState,
readerState = readerState
......@@ -99,7 +101,6 @@ class SnapshotSerializer(
internal fun serializeSession(session: Session): JSONObject {
return JSONObject().apply {
put(Keys.SESSION_URL_KEY, session.url)
put(Keys.SESSION_SOURCE_KEY, session.source.name)
put(Keys.SESSION_UUID_KEY, session.id)
put(Keys.SESSION_PARENT_UUID_KEY, session.parentId ?: "")
put(Keys.SESSION_TITLE, session.title)
......@@ -109,17 +110,16 @@ internal fun serializeSession(session: Session): JSONObject {
@Throws(JSONException::class)
@VisibleForTesting(otherwise = VisibleForTesting.PRIVATE)
internal fun deserializeSession(json: JSONObject, restoreId: Boolean, restoreParentId: Boolean): Session {
val source = try {
Session.Source.valueOf(json.getString(Keys.SESSION_SOURCE_KEY))
} catch (e: IllegalArgumentException) {
Session.Source.NONE
}
internal fun deserializeSession(
json: JSONObject,
restoreId: Boolean,
restoreParentId: Boolean
): Session {
val session = Session(
json.getString(Keys.SESSION_URL_KEY),
// Currently, snapshot cannot contain private sessions.
false,
source,
Session.Source.RESTORED,
if (restoreId) {
json.getString(Keys.SESSION_UUID_KEY)
} else {
......@@ -138,7 +138,6 @@ private object Keys {
const val SELECTED_SESSION_INDEX_KEY = "selectedSessionIndex"
const val SESSION_STATE_TUPLES_KEY = "sessionStateTuples"
const val SESSION_SOURCE_KEY = "source"
const val SESSION_URL_KEY = "url"
const val SESSION_UUID_KEY = "uuid"
const val SESSION_CONTEXT_ID_KEY = "contextId"
......
......@@ -452,14 +452,20 @@ class SessionStorageTest {
json.put("url", "testUrl")
json.put("source", Source.NEW_TAB.name)
json.put("parentUuid", "")
assertEquals(Source.NEW_TAB, deserializeSession(json, restoreId = true, restoreParentId = true).source)
assertEquals(
Source.RESTORED,
deserializeSession(json, restoreId = true, restoreParentId = true).source
)
val jsonInvalid = JSONObject()
jsonInvalid.put("uuid", "testId")
jsonInvalid.put("url", "testUrl")
jsonInvalid.put("source", "invalidSource")
jsonInvalid.put("parentUuid", "")
assertEquals(Source.NONE, deserializeSession(jsonInvalid, restoreId = true, restoreParentId = true).source)
assertEquals(
Source.RESTORED,
deserializeSession(jsonInvalid, restoreId = true, restoreParentId = true).source
)
}
@Suppress("UNCHECKED_CAST")
......
......@@ -29,7 +29,8 @@ class SnapshotSerializerTest {
"https://www.mozilla.org",
source = Session.Source.ACTION_VIEW,
id = "test-id",
contextId = "test-context-id").apply {
contextId = "test-context-id"
).apply {
title = "Hello World"
}
......@@ -37,7 +38,7 @@ class SnapshotSerializerTest {
val restoredSession = deserializeSession(json, restoreId = true, restoreParentId = false)
assertEquals("https://www.mozilla.org", restoredSession.url)
assertEquals(Session.Source.ACTION_VIEW, restoredSession.source)
assertEquals(Session.Source.RESTORED, restoredSession.source)
assertEquals("test-id", restoredSession.id)
assertEquals("test-context-id", restoredSession.contextId)
assertEquals("Hello World", restoredSession.title)
......@@ -51,16 +52,22 @@ class SnapshotSerializerTest {
"https://www.mozilla.org",
source = Session.Source.ACTION_VIEW,
id = "test-id",
contextId = "test-context-id").apply {
contextId = "test-context-id"
).apply {
title = "Hello World"
}
val serializer = SnapshotSerializer()
val json = serializer.itemToJSON(Snapshot.Item(originalSession, readerState = ReaderState(active = true)))
val json = serializer.itemToJSON(
Snapshot.Item(
originalSession,
readerState = ReaderState(active = true)
)
)
val restoredItem = serializer.itemFromJSON(engine, json)
assertEquals("https://www.mozilla.org", restoredItem.session.url)
assertEquals(Session.Source.ACTION_VIEW, restoredItem.session.source)
assertEquals(Session.Source.RESTORED, restoredItem.session.source)
assertEquals("test-id", restoredItem.session.id)
assertEquals("test-context-id", restoredItem.session.contextId)
assertEquals("Hello World", restoredItem.session.title)
......@@ -76,10 +83,14 @@ class SnapshotSerializerTest {
put("parentUuid", "")
}
val restoredSession = deserializeSession(json, restoreId = true, restoreParentId = false)
val restoredSession = deserializeSession(
json,
restoreId = true,
restoreParentId = false
)
assertEquals("https://www.mozilla.org", restoredSession.url)
assertEquals(Session.Source.ACTION_VIEW, restoredSession.source)
assertEquals(Session.Source.RESTORED, restoredSession.source)
assertEquals("test-id", restoredSession.id)
}
......@@ -102,7 +113,8 @@ class SnapshotSerializerTest {
val originalSession = Session(
"https://www.mozilla.org",
source = Session.Source.ACTION_VIEW,
id = "test-id").apply {
id = "test-id"
).apply {
title = "Hello World"
}
......@@ -110,12 +122,13 @@ class SnapshotSerializerTest {
val restoredSession = deserializeSession(json, restoreId = false, restoreParentId = false)
assertEquals("https://www.mozilla.org", restoredSession.url)
assertEquals(Session.Source.ACTION_VIEW, restoredSession.source)
assertEquals(Session.Source.RESTORED, restoredSession.source)
assertNotEquals("test-id", restoredSession.id)
assertTrue(restoredSession.id.isNotBlank())
assertEquals("Hello World", restoredSession.title)
val restoredSessionAgain = deserializeSession(json, restoreId = false, restoreParentId = false)
val restoredSessionAgain =
deserializeSession(json, restoreId = false, restoreParentId = false)
assertNotEquals("test-id", restoredSessionAgain.id)
assertNotEquals(restoredSession.id, restoredSessionAgain.id)
assertTrue(restoredSessionAgain.id.isNotBlank())
......@@ -124,9 +137,10 @@ class SnapshotSerializerTest {
@Test
fun `Deserialize session without restoring parent id`() {
val originalSession = Session(
"https://www.mozilla.org",
source = Session.Source.ACTION_VIEW,
id = "test-id").apply {
"https://www.mozilla.org",
source = Session.Source.ACTION_VIEW,
id = "test-id"
).apply {
parentId = "test-parent-id"
title = "Hello World"
}
......@@ -134,13 +148,14 @@ class SnapshotSerializerTest {
val json = serializeSession(originalSession)
val restoredSession = deserializeSession(json, restoreId = true, restoreParentId = true)
assertEquals("https://www.mozilla.org", restoredSession.url)
assertEquals(Session.Source.ACTION_VIEW, restoredSession.source)
assertEquals(Session.Source.RESTORED, restoredSession.source)
assertEquals("test-id", restoredSession.id)
assertEquals("test-parent-id", restoredSession.parentId)
assertTrue(restoredSession.id.isNotBlank())
assertEquals("Hello World", restoredSession.title)
val restoredSessionAgain = deserializeSession(json, restoreId = true, restoreParentId = false)
val restoredSessionAgain =
deserializeSession(json, restoreId = true, restoreParentId = false)
assertEquals("test-id", restoredSessionAgain.id)
assertNull(restoredSessionAgain.parentId)
}
......
# [Android Components](../../../README.md) > UI > Widgets
The standard set of Mozilla widgets.
## Usage
### Setting up the dependency
Use Gradle to download the library from [maven.mozilla.org](https://maven.mozilla.org/) ([Setup repository](../../../README.md#maven-repository)):
```Groovy
implementation "org.mozilla.components:ui-widgets:{latest-version}"
```
## License
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/
/* 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/. */
apply plugin: 'com.android.library'
android {
compileSdkVersion config.compileSdkVersion
defaultConfig {
minSdkVersion config.minSdkVersion
targetSdkVersion config.targetSdkVersion
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
}
dependencies {
implementation Dependencies.google_material
}
apply from: '../../../publish.gradle'
ext.configurePublish(config.componentsGroupId, archivesBaseName, project.ext.description)
\ No newline at end of file
# Add project specific ProGuard rules here.
# You can control the set of applied configuration files using the
# proguardFiles setting in build.gradle.
#
# For more details, see
# http://developer.android.com/guide/developing/tools/proguard.html
# If your project uses WebView with JS, uncomment the following
# and specify the fully qualified class name to the JavaScript interface
# class:
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
# public *;
#}
# Uncomment this to preserve the line number information for
# debugging stack traces.
#-keepattributes SourceFile,LineNumberTable
# If you keep the line number information, uncomment this to
# hide the original source file name.
#-renamesourcefileattribute SourceFile
<!-- 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/. -->
<manifest package="mozilla.components.ui.widgets" />
<?xml version="1.0" encoding="utf-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/. -->
<ripple xmlns:android="http://schemas.android.com/apk/res/android"
android:color="?android:attr/colorControlHighlight">
<item android:id="@android:id/mask">
<shape>
<solid android:color="#000000" />
<corners android:radius="4dp" />
</shape>
</item>
<item>
<shape android:shape="rectangle">
<corners android:radius="4dp" />
</shape>
</item>
</ripple>
<?xml version="1.0" encoding="utf-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/. -->
<resources>
<attr name="mozac_font_semibold" format="reference" />
<attr name="mozac_accent" format="reference" />
<attr name="mozac_contrast_text" format="reference" />
</resources>
<?xml version="1.0" encoding="utf-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/. -->
<resources>
<!-- Button Colors -->
<color name="mozac_grey_button_color">#E0E0E6</color>
<color name="mozac_destructive_button_text_color">#C50042</color>
<color name="mozac_grey_button_text_color">#312A65</color>
</resources>
<?xml version="1.0" encoding="utf-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/. -->
<resources xmlns:android="http://schemas.android.com/apk/res/android">
<!-- Button styling -->
<style name="Mozac.Widgets.NeutralButton" parent="Widget.MaterialComponents.Button.TextButton">
<item name="iconTint">@color/mozac_grey_button_text_color</item>
<item name="iconPadding">8dp</item>
<item name="iconGravity">textStart</item>
<item name="android:textAlignment">center</item>
<item name="android:background">@drawable/rounded_button_background</item>
<item name="android:layout_width">match_parent</item>
<item name="android:layout_height">48dp</item>
<item name="android:textStyle">bold</item>
<item name="android:textAllCaps">false</item>
<item name="backgroundTint">@color/mozac_grey_button_color</item>
<item name="android:textColor">@color/mozac_grey_button_text_color</item>
<item name="android:letterSpacing">0</item>
<item name="fontFamily">?mozac_font_semibold</item>
</style>
<style name="Mozac.Widgets.DestructiveButton" parent="Mozac.Widgets.NeutralButton">
<item name="iconTint">@color/mozac_destructive_button_text_color</item>
<item name="android:textColor">@color/mozac_destructive_button_text_color</item>
</style>
<style name="Mozac.Widgets.PositiveButton" parent="Mozac.Widgets.NeutralButton">
<item name="backgroundTint">?mozac_accent</item>
<item name="iconTint">?mozac_contrast_text</item>
<item name="android:textColor">?mozac_contrast_text</item>
</style>
</resources>
......@@ -12,6 +12,9 @@ permalink: /changelog/
* [Gecko](https://github.com/mozilla-mobile/android-components/blob/master/buildSrc/src/main/java/Gecko.kt)
* [Configuration](https://github.com/mozilla-mobile/android-components/blob/master/buildSrc/src/main/java/Config.kt)
* **browser-session**
* `SnapshotSerializer` no longer restores source of a `Session`, added `Session.Source.RESTORED`
* **feature-downloads**
* Fixed issue [#6764](https://github.com/mozilla-mobile/android-components/issues/6764).
......@@ -21,6 +24,10 @@ permalink: /changelog/
* **feature-sitepermissions**
* ⚠️ **This is a breaking change**: The `SitePermissionsFeature`'s constructor, now requires a new parameter `onShouldShowRequestPermissionRationale` a lambda to allow the feature to query [ActivityCompat.shouldShowRequestPermissionRationale](https://developer.android.com/reference/androidx/core/app/ActivityCompat#shouldShowRequestPermissionRationale(android.app.Activity,%20java.lang.String)) or [Fragment.shouldShowRequestPermissionRationale](https://developer.android.com/reference/androidx/fragment/app/Fragment#shouldShowRequestPermissionRationale(java.lang.String)). This allows the `SitePermissionsFeature` to handle when a user clicks "Deny & don't ask again" button in a system permission dialog, for more information see [issue #6565](https://github.com/mozilla-mobile/android-components/issues/6565).
* **ui-widgets**
* 🆕 New component for standardized Mozilla widgets and styles. A living style guide will be published soon that helps explain design choices made.
* First version includes styling for buttons: `NeutralButton`, `PositiveButton`, and `DestructiveButton`
* **feature-addons**
* Added `AddonsManagerAdapter.updateAddon` and `AddonsManagerAdapter.updateAddons` to allow partial updates.
* ⚠️ **This is a breaking change**: `AddonsManagerAdapterDelegate.onNotYetSupportedSectionClicked(unsupportedAddons: ArrayList<Addon>)` is changed to `AddonsManagerAdapterDelegate.onNotYetSupportedSectionClicked(unsupportedAddons: List<Addon>)`.
......@@ -52,7 +59,7 @@ permalink: /changelog/
* **browser-tabstray**
* The iconView is no longer required in the template.
* The URL text for items may be styled.
* **service-glean**
* Glean was updated to v28.0.0
* The baseline ping is now sent when the application goes to foreground, in addition to background and dirty-startup.
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment