Skip to content
GitLab
Menu
Projects
Groups
Snippets
/
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
Menu
Open sidebar
The Tor Project
Applications
android-components
Commits
3c4477d0
Commit
3c4477d0
authored
Jul 07, 2020
by
Gabriel Luong
Browse files
Issue #7529: Add ContainerState to BrowserState
parent
27dd1be4
Changes
15
Hide whitespace changes
Inline
Side-by-side
components/browser/state/src/main/java/mozilla/components/browser/state/action/BrowserAction.kt
View file @
3c4477d0
...
...
@@ -6,6 +6,7 @@ package mozilla.components.browser.state.action
import
android.graphics.Bitmap
import
mozilla.components.browser.state.state.BrowserState
import
mozilla.components.browser.state.state.ContainerState
import
mozilla.components.browser.state.state.ContentState
import
mozilla.components.browser.state.state.CustomTabSessionState
import
mozilla.components.browser.state.state.EngineState
...
...
@@ -588,3 +589,18 @@ sealed class DownloadAction : BrowserAction() {
*/
data class
UpdateQueuedDownloadAction
(
val
download
:
DownloadState
)
:
DownloadAction
()
}
/**
* [BrowserAction] implementations related to updating [BrowserState.containers]
*/
sealed
class
ContainerAction
:
BrowserAction
()
{
/**
* Updates [BrowserState.containers] to register the given added [container].
*/
data class
AddContainerAction
(
val
container
:
ContainerState
)
:
ContainerAction
()
/**
* Removes all state of the removed container from [BrowserState.containers].
*/
data class
RemoveContainerAction
(
val
contextId
:
String
)
:
ContainerAction
()
}
components/browser/state/src/main/java/mozilla/components/browser/state/reducer/BrowserStateReducer.kt
View file @
3c4477d0
...
...
@@ -5,6 +5,7 @@
package
mozilla.components.browser.state.reducer
import
mozilla.components.browser.state.action.BrowserAction
import
mozilla.components.browser.state.action.ContainerAction
import
mozilla.components.browser.state.action.ContentAction
import
mozilla.components.browser.state.action.CustomTabListAction
import
mozilla.components.browser.state.action.DownloadAction
...
...
@@ -31,6 +32,7 @@ import mozilla.components.lib.state.Action
internal
object
BrowserStateReducer
{
fun
reduce
(
state
:
BrowserState
,
action
:
BrowserAction
):
BrowserState
{
return
when
(
action
)
{
is
ContainerAction
->
ContainerReducer
.
reduce
(
state
,
action
)
is
ContentAction
->
ContentStateReducer
.
reduce
(
state
,
action
)
is
CustomTabListAction
->
CustomTabListReducer
.
reduce
(
state
,
action
)
is
EngineAction
->
EngineStateReducer
.
reduce
(
state
,
action
)
...
...
components/browser/state/src/main/java/mozilla/components/browser/state/reducer/ContainerReducer.kt
0 → 100644
View file @
3c4477d0
/* 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
mozilla.components.browser.state.reducer
import
mozilla.components.browser.state.action.ContainerAction
import
mozilla.components.browser.state.state.BrowserState
internal
object
ContainerReducer
{
fun
reduce
(
state
:
BrowserState
,
action
:
ContainerAction
):
BrowserState
{
return
when
(
action
)
{
is
ContainerAction
.
AddContainerAction
->
{
val
existingContainer
=
state
.
containers
[
action
.
container
.
contextId
]
if
(
existingContainer
==
null
)
{
state
.
copy
(
containers
=
state
.
containers
+
(
action
.
container
.
contextId
to
action
.
container
)
)
}
else
{
state
}
}
is
ContainerAction
.
RemoveContainerAction
->
{
state
.
copy
(
containers
=
state
.
containers
-
action
.
contextId
)
}
}
}
}
components/browser/state/src/main/java/mozilla/components/browser/state/state/BrowserState.kt
View file @
3c4477d0
...
...
@@ -13,7 +13,8 @@ import mozilla.components.lib.state.State
* @property tabs the list of open tabs, defaults to an empty list.
* @property selectedTabId the ID of the currently selected (active) tab.
* @property customTabs the list of custom tabs, defaults to an empty list.
* @property extensions A map of extension ids and web extensions of all installed web extensions.
* @property containers A map of [SessionState.contextId] and their respective container [ContainerState].
* @property extensions A map of extension IDs and web extensions of all installed web extensions.
* The extensions here represent the default values for all [BrowserState.extensions] and can
* be overridden per [SessionState].
* @property media The state of all media elements and playback states for all tabs.
...
...
@@ -23,6 +24,7 @@ data class BrowserState(
val
tabs
:
List
<
TabSessionState
>
=
emptyList
(),
val
selectedTabId
:
String
?
=
null
,
val
customTabs
:
List
<
CustomTabSessionState
>
=
emptyList
(),
val
containers
:
Map
<
String
,
ContainerState
>
=
emptyMap
(),
val
extensions
:
Map
<
String
,
WebExtensionState
>
=
emptyMap
(),
val
media
:
MediaState
=
MediaState
(),
val
queuedDownloads
:
Map
<
Long
,
DownloadState
>
=
emptyMap
()
...
...
components/browser/state/src/main/java/mozilla/components/browser/state/state/ContainerState.kt
0 → 100644
View file @
3c4477d0
/* 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
mozilla.components.browser.state.state
/**
* Value type that represents the state of a container also known as a contextual identity.
*
* @property contextId The session context ID also known as cookie store ID for the container.
* @property name Name of the container.
* @property color The color for the container. This can be shown in tabs belonging to this container.
* @property icon The icon for the container.
*/
data class
ContainerState
(
val
contextId
:
String
,
val
name
:
String
,
val
color
:
Color
,
val
icon
:
Icon
)
{
/**
* Enum of container color.
*/
enum
class
Color
(
val
color
:
String
)
{
BLUE
(
"blue"
),
TURQUOISE
(
"turquoise"
),
GREEN
(
"green"
),
YELLOW
(
"yellow"
),
ORANGE
(
"orange"
),
RED
(
"red"
),
PINK
(
"pink"
),
PURPLE
(
"purple"
),
TOOLBAR
(
"toolbar"
)
}
/**
* Enum of container icon.
*/
enum
class
Icon
(
val
icon
:
String
)
{
FINGERPRINT
(
"fingerprint"
),
BRIEFCASE
(
"briefcase"
),
DOLLAR
(
"dollar"
),
CART
(
"cart"
),
CIRCLE
(
"circle"
),
GIFT
(
"gift"
),
VACATION
(
"vacation"
),
FOOD
(
"food"
),
FRUIT
(
"fruit"
),
PET
(
"pet"
),
TREE
(
"tree"
),
CHILL
(
"chill"
),
FENCE
(
"fence"
)
}
}
typealias
Container
=
ContainerState
components/browser/state/src/test/java/mozilla/components/browser/state/action/ContainerActionTest.kt
0 → 100644
View file @
3c4477d0
/* 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
mozilla.components.browser.state.action
import
mozilla.components.browser.state.state.ContainerState
import
mozilla.components.browser.state.store.BrowserStore
import
mozilla.components.support.test.ext.joinBlocking
import
org.junit.Assert.assertEquals
import
org.junit.Assert.assertFalse
import
org.junit.Assert.assertSame
import
org.junit.Assert.assertTrue
import
org.junit.Test
class
ContainerActionTest
{
@Test
fun
`AddContainerAction
-
Adds
a
container
to
the
BrowserState
containers`
()
{
val
store
=
BrowserStore
()
assertTrue
(
store
.
state
.
containers
.
isEmpty
())
val
container
=
ContainerState
(
contextId
=
"contextId"
,
name
=
"Personal"
,
color
=
ContainerState
.
Color
.
GREEN
,
icon
=
ContainerState
.
Icon
.
CART
)
store
.
dispatch
(
ContainerAction
.
AddContainerAction
(
container
)).
joinBlocking
()
assertFalse
(
store
.
state
.
containers
.
isEmpty
())
assertEquals
(
container
,
store
.
state
.
containers
.
values
.
first
())
val
state
=
store
.
state
store
.
dispatch
(
ContainerAction
.
AddContainerAction
(
container
)).
joinBlocking
()
assertSame
(
state
,
store
.
state
)
}
@Test
fun
`RemoveContainerAction
-
Removes
a
container
from
the
BrowserState
containers`
()
{
val
store
=
BrowserStore
()
assertTrue
(
store
.
state
.
containers
.
isEmpty
())
val
container1
=
ContainerState
(
contextId
=
"1"
,
name
=
"Personal"
,
color
=
ContainerState
.
Color
.
BLUE
,
icon
=
ContainerState
.
Icon
.
BRIEFCASE
)
val
container2
=
ContainerState
(
contextId
=
"2"
,
name
=
"Shopping"
,
color
=
ContainerState
.
Color
.
GREEN
,
icon
=
ContainerState
.
Icon
.
CIRCLE
)
store
.
dispatch
(
ContainerAction
.
AddContainerAction
(
container1
)).
joinBlocking
()
store
.
dispatch
(
ContainerAction
.
AddContainerAction
(
container2
)).
joinBlocking
()
assertFalse
(
store
.
state
.
containers
.
isEmpty
())
assertEquals
(
container1
,
store
.
state
.
containers
.
values
.
first
())
assertEquals
(
container2
,
store
.
state
.
containers
.
values
.
last
())
store
.
dispatch
(
ContainerAction
.
RemoveContainerAction
(
container1
.
contextId
)).
joinBlocking
()
assertEquals
(
1
,
store
.
state
.
containers
.
size
)
assertEquals
(
container2
,
store
.
state
.
containers
.
values
.
first
())
}
}
components/feature/containers/build.gradle
View file @
3c4477d0
...
...
@@ -38,6 +38,7 @@ android {
}
dependencies
{
implementation
project
(
':browser-state'
)
implementation
project
(
':support-ktx'
)
implementation
project
(
':support-base'
)
...
...
components/feature/containers/src/androidTest/java/mozilla/components/feature/containers/ContainerStorageTest.kt
View file @
3c4477d0
...
...
@@ -12,6 +12,9 @@ import androidx.test.core.app.ApplicationProvider
import
kotlinx.coroutines.ExperimentalCoroutinesApi
import
kotlinx.coroutines.flow.first
import
kotlinx.coroutines.test.runBlockingTest
import
mozilla.components.browser.state.state.Container
import
mozilla.components.browser.state.state.ContainerState.Color
import
mozilla.components.browser.state.state.ContainerState.Icon
import
mozilla.components.feature.containers.db.ContainerDatabase
import
org.junit.After
import
org.junit.Assert.assertEquals
...
...
@@ -50,25 +53,27 @@ class ContainerStorageTest {
@Test
fun
testAddingContainer
()
=
runBlockingTest
{
storage
.
addContainer
(
"Personal"
,
"red"
,
"fingerprint"
)
storage
.
addContainer
(
"Shopping"
,
"blue"
,
"cart"
)
storage
.
addContainer
(
"1"
,
"Personal"
,
Color
.
RED
,
Icon
.
FINGERPRINT
)
storage
.
addContainer
(
"2"
,
"Shopping"
,
Color
.
BLUE
,
Icon
.
CART
)
val
containers
=
getAllContainers
()
assertEquals
(
2
,
containers
.
size
)
assertEquals
(
"1"
,
containers
[
0
].
contextId
)
assertEquals
(
"Personal"
,
containers
[
0
].
name
)
assertEquals
(
"red"
,
containers
[
0
].
color
)
assertEquals
(
"fingerprint"
,
containers
[
0
].
icon
)
assertEquals
(
Color
.
RED
,
containers
[
0
].
color
)
assertEquals
(
Icon
.
FINGERPRINT
,
containers
[
0
].
icon
)
assertEquals
(
"2"
,
containers
[
1
].
contextId
)
assertEquals
(
"Shopping"
,
containers
[
1
].
name
)
assertEquals
(
"blue"
,
containers
[
1
].
color
)
assertEquals
(
"cart"
,
containers
[
1
].
icon
)
assertEquals
(
Color
.
BLUE
,
containers
[
1
].
color
)
assertEquals
(
Icon
.
CART
,
containers
[
1
].
icon
)
}
@Test
fun
testRemovingContainers
()
=
runBlockingTest
{
storage
.
addContainer
(
"Personal"
,
"red"
,
"fingerprint"
)
storage
.
addContainer
(
"Shopping"
,
"blue"
,
"cart"
)
storage
.
addContainer
(
"1"
,
"Personal"
,
Color
.
RED
,
Icon
.
FINGERPRINT
)
storage
.
addContainer
(
"2"
,
"Shopping"
,
Color
.
BLUE
,
Icon
.
CART
)
getAllContainers
().
let
{
containers
->
assertEquals
(
2
,
containers
.
size
)
...
...
@@ -79,16 +84,17 @@ class ContainerStorageTest {
getAllContainers
().
let
{
containers
->
assertEquals
(
1
,
containers
.
size
)
assertEquals
(
"2"
,
containers
[
0
].
contextId
)
assertEquals
(
"Shopping"
,
containers
[
0
].
name
)
assertEquals
(
"blue"
,
containers
[
0
].
color
)
assertEquals
(
"cart"
,
containers
[
0
].
icon
)
assertEquals
(
Color
.
BLUE
,
containers
[
0
].
color
)
assertEquals
(
Icon
.
CART
,
containers
[
0
].
icon
)
}
}
@Test
fun
testGettingContainers
()
=
runBlockingTest
{
storage
.
addContainer
(
"Personal"
,
"red"
,
"fingerprint"
)
storage
.
addContainer
(
"Shopping"
,
"blue"
,
"cart"
)
storage
.
addContainer
(
"1"
,
"Personal"
,
Color
.
RED
,
Icon
.
FINGERPRINT
)
storage
.
addContainer
(
"2"
,
"Shopping"
,
Color
.
BLUE
,
Icon
.
CART
)
val
containers
=
storage
.
getContainers
().
first
()
...
...
@@ -96,15 +102,17 @@ class ContainerStorageTest {
assertEquals
(
2
,
containers
.
size
)
with
(
containers
[
0
])
{
assertEquals
(
"1"
,
contextId
)
assertEquals
(
"Personal"
,
name
)
assertEquals
(
"red"
,
color
)
assertEquals
(
"fingerprint"
,
icon
)
assertEquals
(
Color
.
RED
,
color
)
assertEquals
(
Icon
.
FINGERPRINT
,
icon
)
}
with
(
containers
[
1
])
{
assertEquals
(
"2"
,
contextId
)
assertEquals
(
"Shopping"
,
name
)
assertEquals
(
"blue"
,
color
)
assertEquals
(
"cart"
,
icon
)
assertEquals
(
Color
.
BLUE
,
color
)
assertEquals
(
Icon
.
CART
,
icon
)
}
}
...
...
components/feature/containers/src/androidTest/java/mozilla/components/feature/containers/db/ContainerDaoTest.kt
View file @
3c4477d0
...
...
@@ -11,6 +11,8 @@ import androidx.room.Room
import
androidx.test.core.app.ApplicationProvider
import
kotlinx.coroutines.ExperimentalCoroutinesApi
import
kotlinx.coroutines.test.runBlockingTest
import
mozilla.components.browser.state.state.ContainerState.Color
import
mozilla.components.browser.state.state.ContainerState.Icon
import
org.junit.After
import
org.junit.Assert.assertEquals
import
org.junit.Before
...
...
@@ -51,8 +53,8 @@ class ContainerDaoTest {
ContainerEntity
(
contextId
=
UUID
.
randomUUID
().
toString
(),
name
=
"Personal"
,
color
=
"red"
,
icon
=
"fingerprint"
color
=
Color
.
RED
,
icon
=
Icon
.
FINGERPRINT
)
containerDao
.
insertContainer
(
container
)
...
...
@@ -73,15 +75,15 @@ class ContainerDaoTest {
ContainerEntity
(
contextId
=
UUID
.
randomUUID
().
toString
(),
name
=
"Personal"
,
color
=
"red"
,
icon
=
"fingerprint"
color
=
Color
.
RED
,
icon
=
Icon
.
FINGERPRINT
)
val
container2
=
ContainerEntity
(
contextId
=
UUID
.
randomUUID
().
toString
(),
name
=
"Shopping"
,
color
=
"blue"
,
icon
=
"cart"
color
=
Color
.
BLUE
,
icon
=
Icon
.
CART
)
containerDao
.
insertContainer
(
container1
)
...
...
components/feature/containers/src/main/java/mozilla/components/feature/containers/Container.kt
deleted
100644 → 0
View file @
27dd1be4
/* 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
mozilla.components.feature.containers
/**
* A container also known as a contextual identity.
*/
interface
Container
{
/**
* The session context ID also known as cookie store ID for the container.
*/
val
contextId
:
String
/**
* Name of the container.
*/
val
name
:
String
/**
* The color for the container. This can be shown in tabs belonging to this container.
*/
val
color
:
String
/**
* The name of an icon for the container.
*/
val
icon
:
String
}
components/feature/containers/src/main/java/mozilla/components/feature/containers/ContainerStorage.kt
View file @
3c4477d0
...
...
@@ -9,15 +9,18 @@ import androidx.annotation.VisibleForTesting
import
androidx.paging.DataSource
import
kotlinx.coroutines.flow.Flow
import
kotlinx.coroutines.flow.map
import
mozilla.components.feature.containers.adapter.ContainerAdapter
import
mozilla.components.browser.state.state.Container
import
mozilla.components.browser.state.state.ContainerState.Color
import
mozilla.components.browser.state.state.ContainerState.Icon
import
mozilla.components.feature.containers.db.ContainerDatabase
import
mozilla.components.feature.containers.db.ContainerEntity
import
mozilla.components.feature.containers.db.toContainerEntity
import
java.util.UUID
/**
* A storage implementation for organizing containers (contextual identities).
*/
class
ContainerStorage
(
context
:
Context
)
{
internal
class
ContainerStorage
(
context
:
Context
)
{
@VisibleForTesting
internal
var
database
:
Lazy
<
ContainerDatabase
>
=
...
...
@@ -27,10 +30,15 @@ class ContainerStorage(context: Context) {
/**
* Adds a new [Container].
*/
suspend
fun
addContainer
(
name
:
String
,
color
:
String
,
icon
:
String
)
{
database
.
value
.
containerDao
().
insertContainer
(
suspend
fun
addContainer
(
contextId
:
String
=
UUID
.
randomUUID
().
toString
(),
name
:
String
,
color
:
Color
,
icon
:
Icon
)
{
containerDao
.
insertContainer
(
ContainerEntity
(
contextId
=
UUID
.
randomUUID
().
toString
()
,
contextId
=
contextId
,
name
=
name
,
color
=
color
,
icon
=
icon
...
...
@@ -43,7 +51,7 @@ class ContainerStorage(context: Context) {
*/
fun
getContainers
():
Flow
<
List
<
Container
>>
{
return
containerDao
.
getContainers
().
map
{
list
->
list
.
map
{
entity
->
ContainerAdapter
(
entity
)
}
list
.
map
{
entity
->
entity
.
toContainer
(
)
}
}
}
...
...
@@ -53,16 +61,13 @@ class ContainerStorage(context: Context) {
fun
getContainersPaged
():
DataSource
.
Factory
<
Int
,
Container
>
=
containerDao
.
getContainersPaged
()
.
map
{
entity
->
ContainerAdapter
(
entity
)
entity
.
toContainer
()
}
/**
* Removes the given [Container].
*/
suspend
fun
removeContainer
(
container
:
Container
)
{
val
containerEntity
=
(
container
as
ContainerAdapter
).
entity
containerDao
.
deleteContainer
(
containerEntity
)
containerDao
.
deleteContainer
(
container
.
toContainerEntity
())
}
}
components/feature/containers/src/main/java/mozilla/components/feature/containers/adapter/ContainerAdapter.kt
deleted
100644 → 0
View file @
27dd1be4
/* 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
mozilla.components.feature.containers.adapter
import
mozilla.components.feature.containers.Container
import
mozilla.components.feature.containers.db.ContainerEntity
internal
class
ContainerAdapter
(
internal
val
entity
:
ContainerEntity
)
:
Container
{
override
val
contextId
:
String
get
()
=
entity
.
contextId
override
val
name
:
String
get
()
=
entity
.
name
override
val
color
:
String
get
()
=
entity
.
color
override
val
icon
:
String
get
()
=
entity
.
icon
override
fun
equals
(
other
:
Any
?):
Boolean
{
if
(
other
!
is
ContainerAdapter
)
{
return
false
}
return
entity
==
other
.
entity
}
override
fun
hashCode
():
Int
{
return
entity
.
hashCode
()
}
}
components/feature/containers/src/main/java/mozilla/components/feature/containers/db/ContainerDatabase.kt
View file @
3c4477d0
...
...
@@ -8,11 +8,16 @@ import android.content.Context
import
androidx.room.Database
import
androidx.room.Room
import
androidx.room.RoomDatabase
import
androidx.room.TypeConverter
import
androidx.room.TypeConverters
import
mozilla.components.browser.state.state.ContainerState.Color
import
mozilla.components.browser.state.state.ContainerState.Icon
/**
* Internal database for storing containers (contextual identities).
*/
@Database
(
entities
=
[
ContainerEntity
::
class
],
version
=
1
)
@TypeConverters
(
Converter
::
class
)
internal
abstract
class
ContainerDatabase
:
RoomDatabase
()
{
abstract
fun
containerDao
():
ContainerDao
...
...
@@ -34,3 +39,25 @@ internal abstract class ContainerDatabase : RoomDatabase() {
}
}
}
internal
class
Converter
{
@TypeConverter
fun
toColorString
(
color
:
Color
):
String
{
return
color
.
color
}
@TypeConverter
fun
toColor
(
color
:
String
):
Color
?
{
return
Color
.
values
().
find
{
it
.
color
==
color
}
}
@TypeConverter
fun
toIconString
(
icon
:
Icon
):
String
{
return
icon
.
icon
}
@TypeConverter
fun
toIcon
(
icon
:
String
):
Icon
?
{
return
Icon
.
values
().
find
{
it
.
icon
==
icon
}
}
}
components/feature/containers/src/main/java/mozilla/components/feature/containers/db/ContainerEntity.kt
View file @
3c4477d0
...
...
@@ -7,6 +7,9 @@ package mozilla.components.feature.containers.db
import
androidx.room.ColumnInfo
import
androidx.room.Entity
import
androidx.room.PrimaryKey
import
mozilla.components.browser.state.state.Container
import
mozilla.components.browser.state.state.Container.Color
import
mozilla.components.browser.state.state.Container.Icon
/**
* Internal entity representing a container (contextual identity).
...
...
@@ -21,8 +24,26 @@ internal data class ContainerEntity(
var
name
:
String
,
@ColumnInfo
(
name
=
"color"
)
var
color
:
String
,
var
color
:
Color
,
@ColumnInfo
(
name
=
"icon"
)