Skip to content
GitLab
Projects
Groups
Snippets
/
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
Menu
Open sidebar
Matthew Finkel
fenix
Commits
232247fd
Commit
232247fd
authored
Sep 10, 2020
by
Matthew Finkel
Browse files
Bug 40028: Implement Tor connect and logger screens
parent
f39de0b6
Changes
19
Hide whitespace changes
Inline
Side-by-side
app/src/main/java/org/mozilla/fenix/home/HomeFragment.kt
View file @
232247fd
...
...
@@ -253,7 +253,8 @@ class HomeFragment : Fragment() {
handleSwipedItemDeletionCancel
=
::
handleSwipedItemDeletionCancel
,
handleTorBootstrapConnect
=
::
handleTorBootstrapConnect
,
cancelTorBootstrap
=
::
cancelTorBootstrap
,
initiateTorBootstrap
=
::
initiateTorBootstrap
initiateTorBootstrap
=
::
initiateTorBootstrap
,
openTorNetworkSettings
=
::
openTorNetworkSettings
)
)
...
...
@@ -1062,6 +1063,9 @@ class HomeFragment : Fragment() {
requireComponents
.
torController
.
initiateTorBootstrap
(
lifecycleScope
,
withDebugLogging
)
}
private
fun
openTorNetworkSettings
()
{
}
companion
object
{
const
val
ALL_NORMAL_TABS
=
"all_normal"
const
val
ALL_PRIVATE_TABS
=
"all_private"
...
...
app/src/main/java/org/mozilla/fenix/home/sessioncontrol/SessionControlAdapter.kt
View file @
232247fd
...
...
@@ -21,6 +21,7 @@ import org.mozilla.fenix.home.sessioncontrol.viewholders.CollectionHeaderViewHol
import
org.mozilla.fenix.home.sessioncontrol.viewholders.CollectionViewHolder
import
org.mozilla.fenix.home.sessioncontrol.viewholders.NoCollectionsMessageViewHolder
import
org.mozilla.fenix.home.sessioncontrol.viewholders.PrivateBrowsingDescriptionViewHolder
import
org.mozilla.fenix.home.sessioncontrol.viewholders.TorBootstrapPagerViewHolder
import
org.mozilla.fenix.home.sessioncontrol.viewholders.TabInCollectionViewHolder
import
org.mozilla.fenix.home.sessioncontrol.viewholders.TopSitePagerViewHolder
import
org.mozilla.fenix.home.sessioncontrol.viewholders.onboarding.OnboardingAutomaticSignInViewHolder
...
...
@@ -60,6 +61,8 @@ sealed class AdapterItem(@LayoutRes val viewType: Int) {
object
PrivateBrowsingDescription
:
AdapterItem
(
PrivateBrowsingDescriptionViewHolder
.
LAYOUT_ID
)
object
NoCollectionsMessage
:
AdapterItem
(
NoCollectionsMessageViewHolder
.
LAYOUT_ID
)
object
TorBootstrap
:
AdapterItem
(
TorBootstrapPagerViewHolder
.
LAYOUT_ID
)
object
CollectionHeader
:
AdapterItem
(
CollectionHeaderViewHolder
.
LAYOUT_ID
)
data class
CollectionItem
(
val
collection
:
TabCollection
,
...
...
@@ -152,6 +155,11 @@ class SessionControlAdapter(
view
,
interactor
)
TorBootstrapPagerViewHolder
.
LAYOUT_ID
->
TorBootstrapPagerViewHolder
(
view
,
components
,
interactor
)
NoCollectionsMessageViewHolder
.
LAYOUT_ID
->
NoCollectionsMessageViewHolder
(
view
,
...
...
app/src/main/java/org/mozilla/fenix/home/sessioncontrol/SessionControlController.kt
View file @
232247fd
...
...
@@ -156,9 +156,9 @@ interface SessionControlController {
fun
handleTorBootstrapConnectClicked
()
/**
* @see [TorBootstrapInteractor.onTorBootstrap
ConnectingClicked
]
* @see [TorBootstrapInteractor.onTor
Stop
Bootstrap
ping
]
*/
fun
handleTorBootstrap
ConnectingClicked
()
fun
handleTor
Stop
Bootstrap
ping
()
/**
* @see [TorBootstrapInteractor.onTorStartBootstrapping]
...
...
@@ -169,6 +169,11 @@ interface SessionControlController {
* @see [TorBootstrapInteractor.onTorStartDebugBootstrapping]
*/
fun
handleTorStartDebugBootstrapping
()
/**
* @see [TorBootstrapInteractor.onTorBootstrapNetworkSettingsClicked]
*/
fun
handleTorNetworkSettingsClicked
()
}
@Suppress
(
"TooManyFunctions"
,
"LargeClass"
)
...
...
@@ -196,7 +201,8 @@ class DefaultSessionControlController(
private
val
handleSwipedItemDeletionCancel
:
()
->
Unit
,
private
val
handleTorBootstrapConnect
:
()
->
Unit
,
private
val
initiateTorBootstrap
:
(
Boolean
)
->
Unit
,
private
val
cancelTorBootstrap
:
()
->
Unit
private
val
cancelTorBootstrap
:
()
->
Unit
,
private
val
openTorNetworkSettings
:
()
->
Unit
)
:
SessionControlController
{
override
fun
handleCollectionAddTabTapped
(
collection
:
TabCollection
)
{
...
...
@@ -462,7 +468,7 @@ class DefaultSessionControlController(
handleTorBootstrapConnect
()
}
override
fun
handleTorBootstrap
ConnectingClicked
()
{
override
fun
handleTor
Stop
Bootstrap
ping
()
{
cancelTorBootstrap
()
}
...
...
@@ -473,4 +479,8 @@ class DefaultSessionControlController(
override
fun
handleTorStartDebugBootstrapping
()
{
initiateTorBootstrap
(
true
)
}
override
fun
handleTorNetworkSettingsClicked
()
{
openTorNetworkSettings
()
}
}
app/src/main/java/org/mozilla/fenix/home/sessioncontrol/SessionControlInteractor.kt
View file @
232247fd
...
...
@@ -144,6 +144,34 @@ interface TipInteractor {
fun
onCloseTip
(
tip
:
Tip
)
}
interface
TorBootstrapInteractor
{
/**
* Initiates Tor bootstrapping. Called when a user clicks on the "Connect" button.
*/
fun
onTorBootstrapConnectClicked
()
/**
* Initiates Tor bootstrapping. Called when a user clicks on the "Connect" button.
*/
fun
onTorStartBootstrapping
()
/**
* Stop Tor bootstrapping. Called when a user clicks on the "settings" cog/button.
*/
fun
onTorStopBootstrapping
()
/**
* Initiates Tor bootstrapping with debug logging. Called when bootstrapping fails with
* the control.txt file not existing.
*/
fun
onTorStartDebugBootstrapping
()
/**
* Open Tor Network Settings preference screen
*/
fun
onTorBootstrapNetworkSettingsClicked
()
}
/**
* Interface for top site related actions in the [SessionControlInteractor].
*/
...
...
@@ -181,7 +209,7 @@ interface TopSiteInteractor {
class
SessionControlInteractor
(
private
val
controller
:
SessionControlController
)
:
CollectionInteractor
,
OnboardingInteractor
,
TopSiteInteractor
,
TipInteractor
,
TabSessionInteractor
,
ToolbarInteractor
{
TabSessionInteractor
,
ToolbarInteractor
,
TorBootstrapInteractor
{
override
fun
onCollectionAddTabTapped
(
collection
:
TabCollection
)
{
controller
.
handleCollectionAddTabTapped
(
collection
)
}
...
...
@@ -265,4 +293,24 @@ class SessionControlInteractor(
override
fun
onRemoveCollectionsPlaceholder
()
{
controller
.
handleRemoveCollectionsPlaceholder
()
}
override
fun
onTorBootstrapConnectClicked
()
{
controller
.
handleTorBootstrapConnectClicked
()
}
override
fun
onTorStopBootstrapping
()
{
controller
.
handleTorStopBootstrapping
()
}
override
fun
onTorStartBootstrapping
()
{
controller
.
handleTorStartBootstrapping
()
}
override
fun
onTorStartDebugBootstrapping
()
{
controller
.
handleTorStartDebugBootstrapping
()
}
override
fun
onTorBootstrapNetworkSettingsClicked
()
{
controller
.
handleTorNetworkSettingsClicked
()
}
}
app/src/main/java/org/mozilla/fenix/home/sessioncontrol/SessionControlView.kt
View file @
232247fd
...
...
@@ -68,6 +68,8 @@ private fun showCollections(
private
fun
privateModeAdapterItems
()
=
listOf
(
AdapterItem
.
PrivateBrowsingDescription
)
private
fun
bootstrapAdapterItems
()
=
listOf
(
AdapterItem
.
TorBootstrap
)
private
fun
onboardingAdapterItems
(
onboardingState
:
OnboardingState
):
List
<
AdapterItem
>
{
val
items
:
MutableList
<
AdapterItem
>
=
mutableListOf
(
AdapterItem
.
OnboardingHeader
)
...
...
@@ -117,6 +119,7 @@ private fun HomeFragmentState.toAdapterList(): List<AdapterItem> = when (mode) {
)
is
Mode
.
Private
->
privateModeAdapterItems
()
is
Mode
.
Onboarding
->
onboardingAdapterItems
(
mode
.
state
)
is
Mode
.
Bootstrap
->
bootstrapAdapterItems
()
}
private
fun
collectionTabItems
(
collection
:
TabCollection
)
=
...
...
app/src/main/java/org/mozilla/fenix/home/sessioncontrol/viewholders/TorBootstrapConnectViewHolder.kt
0 → 100644
View file @
232247fd
/* 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.home.sessioncontrol.viewholders
import
android.view.View
import
androidx.appcompat.widget.SwitchCompat
import
androidx.recyclerview.widget.RecyclerView
import
kotlinx.android.synthetic.main.tor_bootstrap_connect.view.*
import
org.mozilla.fenix.R
import
org.mozilla.fenix.tor.TorEvents
import
org.mozilla.fenix.tor.bootstrap.TorQuickStart
import
org.mozilla.fenix.components.Components
import
org.mozilla.fenix.home.sessioncontrol.TorBootstrapInteractor
class
TorBootstrapConnectViewHolder
(
private
val
view
:
View
,
private
val
components
:
Components
,
private
val
interactor
:
TorBootstrapInteractor
)
:
RecyclerView
.
ViewHolder
(
view
),
TorEvents
{
init
{
val
torQuickStart
=
TorQuickStart
(
view
.
context
)
setQuickStartDescription
(
view
,
torQuickStart
)
with
(
view
.
quick_start_toggle
as
SwitchCompat
)
{
setOnCheckedChangeListener
{
_
,
isChecked
->
torQuickStart
.
setQuickStartTor
(
isChecked
)
setQuickStartDescription
(
view
,
torQuickStart
)
}
isChecked
=
torQuickStart
.
quickStartTor
()
}
with
(
view
.
tor_bootstrap_network_settings_button
)
{
setOnClickListener
{
interactor
.
onTorStopBootstrapping
()
interactor
.
onTorBootstrapNetworkSettingsClicked
()
with
(
view
.
tor_bootstrap_progress
)
{
visibility
=
View
.
INVISIBLE
}
with
(
view
.
tor_bootstrap_connect_button
)
{
visibility
=
View
.
VISIBLE
}
}
}
with
(
view
.
tor_bootstrap_connect_button
)
{
setOnClickListener
{
interactor
.
onTorBootstrapConnectClicked
()
interactor
.
onTorStartBootstrapping
()
visibility
=
View
.
INVISIBLE
with
(
view
.
tor_bootstrap_progress
)
{
visibility
=
View
.
VISIBLE
}
}
}
components
.
torController
.
registerTorListener
(
this
)
}
private
fun
setQuickStartDescription
(
view
:
View
,
torQuickStart
:
TorQuickStart
)
{
val
resources
=
view
.
context
.
resources
val
appName
=
resources
.
getString
(
R
.
string
.
app_name
)
if
(
torQuickStart
.
quickStartTor
())
{
view
.
tor_bootstrap_quick_start_description
.
text
=
resources
.
getString
(
R
.
string
.
tor_bootstrap_quick_start_enabled
,
appName
)
}
else
{
view
.
tor_bootstrap_quick_start_description
.
text
=
resources
.
getString
(
R
.
string
.
tor_bootstrap_quick_start_disabled
)
}
}
@SuppressWarnings
(
"EmptyFunctionBlock"
)
override
fun
onTorConnecting
()
{
}
override
fun
onTorConnected
()
{
components
.
torController
.
unregisterTorListener
(
this
)
}
@SuppressWarnings
(
"EmptyFunctionBlock"
)
override
fun
onTorStopped
()
{
}
override
fun
onTorStatusUpdate
(
entry
:
String
?,
status
:
String
?)
{
if
(
entry
==
null
)
return
view
.
tor_bootstrap_status_message
.
text
=
entry
if
(
entry
.
startsWith
(
BOOTSTRAPPED_PREFIX
))
{
val
percentIdx
=
entry
.
indexOf
(
"%"
)
val
percent
=
entry
.
substring
(
BOOTSTRAPPED_PREFIX
.
length
,
percentIdx
)
with
(
view
.
tor_bootstrap_progress
)
{
progress
=
percent
.
toInt
()
}
}
}
companion
object
{
const
val
LAYOUT_ID
=
R
.
layout
.
tor_bootstrap_connect
const
val
BOOTSTRAPPED_PREFIX
=
"NOTICE: Bootstrapped "
}
}
app/src/main/java/org/mozilla/fenix/home/sessioncontrol/viewholders/TorBootstrapLoggerViewHolder.kt
0 → 100644
View file @
232247fd
/* 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.home.sessioncontrol.viewholders
import
android.text.method.ScrollingMovementMethod
import
android.view.View
import
androidx.recyclerview.widget.RecyclerView
import
kotlinx.android.synthetic.main.tor_bootstrap_logger.view.*
import
org.mozilla.fenix.R
import
org.mozilla.fenix.tor.TorEvents
import
org.mozilla.fenix.components.Components
class
TorBootstrapLoggerViewHolder
(
private
val
view
:
View
,
private
val
components
:
Components
)
:
RecyclerView
.
ViewHolder
(
view
),
TorEvents
{
private
var
entries
=
mutableListOf
<
String
>()
init
{
components
.
torController
.
registerTorListener
(
this
)
val
currentEntries
=
components
.
torController
.
logEntries
.
filter
{
it
.
first
!=
null
}
.
filter
{
!(
it
.
first
!!
.
startsWith
(
"Circuit"
)
&&
it
.
second
==
"ON"
)
}
// Keep synchronized with format in onTorStatusUpdate
.
flatMap
{
listOf
(
"(${it.second}) '${it.first}'"
)
}
val
entriesLen
=
currentEntries
.
size
val
subListOffset
=
if
(
entriesLen
>
MAX_NEW_ENTRIES
)
MAX_NEW_ENTRIES
else
entriesLen
entries
=
currentEntries
.
subList
((
entriesLen
-
subListOffset
),
entriesLen
)
as
MutableList
<
String
>
val
initLog
=
"---------------"
+
view
.
resources
.
getString
(
R
.
string
.
tor_initializing_log
)
+
"---------------"
entries
.
add
(
0
,
initLog
)
with
(
view
.
tor_bootstrap_log_entries
)
{
movementMethod
=
ScrollingMovementMethod
()
text
=
formatLogEntries
(
entries
)
}
}
private
fun
formatLogEntries
(
entries
:
List
<
String
>)
=
entries
.
joinToString
(
"\n"
)
@SuppressWarnings
(
"EmptyFunctionBlock"
)
override
fun
onTorConnecting
()
{
}
override
fun
onTorConnected
()
{
components
.
torController
.
unregisterTorListener
(
this
)
}
@SuppressWarnings
(
"EmptyFunctionBlock"
)
override
fun
onTorStopped
()
{
}
override
fun
onTorStatusUpdate
(
entry
:
String
?,
status
:
String
?)
{
if
(
status
==
null
||
entry
==
null
)
return
if
(
status
==
"ON"
&&
entry
.
startsWith
(
"Circuit"
))
return
if
(
entries
.
size
>
MAX_LINES
)
{
entries
=
entries
.
drop
(
1
)
as
MutableList
<
String
>
}
entries
.
add
(
"($status) '$entry'"
)
view
.
tor_bootstrap_log_entries
.
text
=
formatLogEntries
(
entries
)
}
companion
object
{
const
val
LAYOUT_ID
=
R
.
layout
.
tor_bootstrap_logger
const
val
MAX_NEW_ENTRIES
=
24
const
val
MAX_LINES
=
25
}
}
app/src/main/java/org/mozilla/fenix/home/sessioncontrol/viewholders/TorBootstrapPagerViewHolder.kt
0 → 100644
View file @
232247fd
/* 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.home.sessioncontrol.viewholders
import
android.view.View
import
androidx.recyclerview.widget.RecyclerView
import
kotlinx.android.synthetic.main.tor_bootstrap_pager.view.*
import
org.mozilla.fenix.R
import
org.mozilla.fenix.components.Components
import
org.mozilla.fenix.home.sessioncontrol.TorBootstrapInteractor
import
org.mozilla.fenix.home.sessioncontrol.viewholders.torbootstrap.BootstrapPagerAdapter
class
TorBootstrapPagerViewHolder
(
view
:
View
,
components
:
Components
,
interactor
:
TorBootstrapInteractor
)
:
RecyclerView
.
ViewHolder
(
view
)
{
private
val
bootstrapPagerAdapter
=
BootstrapPagerAdapter
(
components
,
interactor
)
init
{
view
.
bootstrap_pager
.
apply
{
adapter
=
bootstrapPagerAdapter
}
}
companion
object
{
const
val
LAYOUT_ID
=
R
.
layout
.
tor_bootstrap_pager
}
}
app/src/main/java/org/mozilla/fenix/home/sessioncontrol/viewholders/torbootstrap/BootstrapPagerAdapter.kt
0 → 100644
View file @
232247fd
/* 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.home.sessioncontrol.viewholders.torbootstrap
import
android.view.LayoutInflater
import
android.view.ViewGroup
import
androidx.recyclerview.widget.RecyclerView
import
androidx.recyclerview.widget.RecyclerView.ViewHolder
import
org.mozilla.fenix.components.Components
import
org.mozilla.fenix.home.sessioncontrol.TorBootstrapInteractor
import
org.mozilla.fenix.home.sessioncontrol.viewholders.TorBootstrapConnectViewHolder
import
org.mozilla.fenix.home.sessioncontrol.viewholders.TorBootstrapLoggerViewHolder
class
BootstrapPagerAdapter
(
private
val
components
:
Components
,
private
val
interactor
:
TorBootstrapInteractor
)
:
RecyclerView
.
Adapter
<
RecyclerView
.
ViewHolder
>()
{
override
fun
onCreateViewHolder
(
parent
:
ViewGroup
,
viewType
:
Int
):
RecyclerView
.
ViewHolder
{
if
(
viewType
==
BOOTSTRAP_UI_PAGE_TYPE
)
{
val
viewDVH
=
LayoutInflater
.
from
(
parent
.
context
)
.
inflate
(
TorBootstrapConnectViewHolder
.
LAYOUT_ID
,
parent
,
false
)
return
TorBootstrapConnectViewHolder
(
viewDVH
,
components
,
interactor
)
}
else
{
val
viewLVH
=
LayoutInflater
.
from
(
parent
.
context
)
.
inflate
(
TorBootstrapLoggerViewHolder
.
LAYOUT_ID
,
parent
,
false
)
return
TorBootstrapLoggerViewHolder
(
viewLVH
,
components
)
}
}
@SuppressWarnings
(
"EmptyFunctionBlock"
)
override
fun
onBindViewHolder
(
holder
:
RecyclerView
.
ViewHolder
,
position
:
Int
)
{
}
override
fun
getItemViewType
(
position
:
Int
):
Int
=
position
override
fun
getItemCount
():
Int
=
BOOTSTRAP_PAGE_COUNT
companion
object
{
const
val
BOOTSTRAP_UI_PAGE_TYPE
=
0
const
val
BOOTSTRAP_LOG_PAGE_TYPE
=
1
const
val
BOOTSTRAP_PAGE_COUNT
=
2
}
}
app/src/main/res/drawable/connectoncropped.png
0 → 100644
View file @
232247fd
44.9 KB
app/src/main/res/drawable/ic_tor_connect_computer_graphic.xml
0 → 100644
View file @
232247fd
<vector
xmlns:android=
"http://schemas.android.com/apk/res/android"
xmlns:aapt=
"http://schemas.android.com/aapt"
android:width=
"302dp"
android:height=
"263dp"
android:viewportWidth=
"302"
android:viewportHeight=
"263"
>
<path
android:pathData=
"M279.49,222.64l-94.22,-0l-0,-79.61l94.22,-0z"
android:strokeWidth=
"1"
android:fillType=
"nonZero"
android:strokeColor=
"#00000000"
>
<aapt:attr
name=
"android:fillColor"
>
<gradient
android:startY=
"203.70642"
android:startX=
"231.9"
android:endY=
"160.04314"
android:endX=
"232.90999"
android:type=
"linear"
>
<item
android:offset=
"0.08"
android:color=
"#FF7E4696"
/>
<item
android:offset=
"0.39"
android:color=
"#9B7E4696"
/>
<item
android:offset=
"0.85"
android:color=
"#007E4696"
/>
</gradient>
</aapt:attr>
</path>
<path
android:pathData=
"M112.74,217.05l-102.32,-0l-0,-102.32l102.32,-0z"
android:strokeWidth=
"1"
android:fillType=
"nonZero"
android:strokeColor=
"#00000000"
>
<aapt:attr
name=
"android:fillColor"
>
<gradient
android:startY=
"203.36"
android:startX=
"60.96"
android:endY=
"124.990005"
android:endX=
"62.249996"
android:type=
"linear"
>
<item
android:offset=
"0.08"
android:color=
"#FF00D9B5"
/>
<item
android:offset=
"0.3"
android:color=
"#BA00D9B5"
/>
<item
android:offset=
"0.8"
android:color=
"#1100D9B5"
/>
<item
android:offset=
"0.85"
android:color=
"#0000D9B5"
/>
</gradient>
</aapt:attr>
</path>
<path
android:pathData=
"M58,1L183.49,1C186.526,1.016 188.984,3.474 189,6.51L189,100.25L52.47,100.25L52.47,6.51C52.486,3.466 54.956,1.005 58,1Z"
android:strokeLineJoin=
"round"
android:strokeWidth=
"1.76"
android:fillColor=
"#F0D4FD"
android:strokeColor=
"#65318E"
android:fillType=
"nonZero"
android:strokeLineCap=
"round"
/>
<path
android:pathData=
"M60.55,8.87h120.41v108.53h-120.41z"
android:strokeLineJoin=
"round"
android:strokeWidth=
"1.76"
android:fillColor=
"#FFFFFF"
android:strokeColor=
"#490260"
android:fillType=
"nonZero"
android:strokeLineCap=
"round"
/>
<path
android:pathData=
"M60.55,8.87h120.41v108.53h-120.41z"
android:strokeWidth=
"1"
android:fillType=
"nonZero"
android:strokeColor=
"#00000000"
>
<aapt:attr
name=
"android:fillColor"
>
<gradient
android:startY=
"-56.010002"
android:startX=
"120.75"
android:endY=
"120.520004"
android:endX=
"120.75"
android:type=
"linear"
>
<item
android:offset=
"0.08"
android:color=
"#FF00D9B5"
/>
<item
android:offset=
"0.12"
android:color=
"#F700D9B5"
/>
<item
android:offset=
"0.19"
android:color=
"#E200D9B5"
/>
<item
android:offset=
"0.26"
android:color=
"#BF00D9B5"
/>
<item
android:offset=
"0.35"
android:color=
"#8E00D9B5"
/>
<item
android:offset=
"0.44"
android:color=
"#5100D9B5"
/>
<item
android:offset=
"0.54"
android:color=
"#0700D9B5"
/>
<item
android:offset=
"0.54"
android:color=
"#0000D9B5"
/>
</gradient>
</aapt:attr>
</path>
<path
android:pathData=
"M77.5,120.83h134.33v10.38h-134.33z"
android:strokeLineJoin=
"round"
android:strokeWidth=
"1.76"
android:fillColor=
"#F0D4FD"
android:strokeColor=
"#65318E"
android:fillType=
"nonZero"
android:strokeLineCap=
"round"
/>
<path
android:pathData=
"M52.47,100.25l0,10.29l25.03,20.67l0,-10.38z"
android:strokeLineJoin=
"round"
android:strokeWidth=
"1.76"
android:fillColor=
"#65318E"
android:strokeColor=
"#F0D4FD"
android:fillType=
"nonZero"
android:strokeLineCap=
"round"
/>
<path
android:pathData=
"M60.33,33.17h43.89v37.87h-43.89z"
android:strokeWidth=
"1.76"
android:fillColor=
"#FFFFFF"
android:strokeColor=
"#65318E"
android:fillType=
"nonZero"
/>
<path
android:pathData=
"M178.05,170.61L61.43,170.61L61.43,87C61.43,85.895 62.325,85 63.43,85L176,85C177.105,85 178,85.895 178,87L178.05,170.61Z"
android:strokeLineJoin=
"round"
android:strokeWidth=
"1.76"
android:fillColor=
"#00D9B5"
android:strokeColor=
"#490260"
android:fillType=
"nonZero"
android:strokeLineCap=
"round"
/>
<path
android:pathData=
"M66.88,89.57h105.71v76.37h-105.71z"
android:strokeLineJoin=
"round"
android:strokeWidth=
"1.76"