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
0835821a
Commit
0835821a
authored
Apr 02, 2019
by
Sawyer Blatz
Committed by
Sebastian Kaspari
Apr 12, 2019
Browse files
Closes #2615: Adds titleView to DisplayToolbar
parent
caaf992d
Changes
12
Hide whitespace changes
Inline
Side-by-side
components/browser/toolbar/src/main/java/mozilla/components/browser/toolbar/BrowserToolbar.kt
View file @
0835821a
...
...
@@ -192,6 +192,15 @@ class BrowserToolbar @JvmOverloads constructor(
displayToolbar
.
progressBarGravity
=
value
}
/**
* Sets the colour of the text for title displayed in the toolbar.
*/
var
titleColor
:
Int
get
()
=
displayToolbar
.
urlView
.
currentTextColor
set
(
value
)
{
displayToolbar
.
titleView
.
setTextColor
(
value
)
}
/**
* Sets the colour of the text for the URL/search term displayed in the toolbar.
*/
...
...
@@ -202,6 +211,15 @@ class BrowserToolbar @JvmOverloads constructor(
editToolbar
.
urlView
.
setTextColor
(
value
)
}
/**
* Sets the size of the text for the title displayed in the toolbar.
*/
var
titleTextSize
:
Float
get
()
=
displayToolbar
.
titleView
.
textSize
set
(
value
)
{
displayToolbar
.
titleView
.
textSize
=
value
}
/**
* Sets the size of the text for the URL/search term displayed in the toolbar.
*/
...
...
@@ -296,6 +314,13 @@ class BrowserToolbar @JvmOverloads constructor(
private
var
searchTerms
:
String
=
""
private
var
urlCommitListener
:
((
String
)
->
Boolean
)?
=
null
override
var
title
:
String
=
""
set
(
value
)
{
displayToolbar
.
updateTitle
(
value
)
field
=
value
}
override
var
url
:
CharSequence
=
""
set
(
value
)
{
// We update the display toolbar immediately. We do not do that for the edit toolbar to not
...
...
components/browser/toolbar/src/main/java/mozilla/components/browser/toolbar/display/DisplayToolbar.kt
View file @
0835821a
...
...
@@ -10,6 +10,7 @@ import android.support.v4.content.ContextCompat
import
android.support.v7.widget.AppCompatImageButton
import
android.support.v7.widget.AppCompatImageView
import
android.support.v7.widget.AppCompatTextView
import
android.text.TextUtils
import
android.util.TypedValue
import
android.view.Gravity
import
android.view.View
...
...
@@ -66,7 +67,7 @@ import mozilla.components.ui.icons.R.drawable.mozac_ic_lock
*
*/
@SuppressLint
(
"ViewConstructor"
)
// This view is only instantiated in code
@Suppress
(
"LargeClass"
)
@Suppress
(
"LargeClass"
,
"TooManyFunctions"
)
internal
class
DisplayToolbar
(
context
:
Context
,
val
toolbar
:
BrowserToolbar
...
...
@@ -89,6 +90,16 @@ internal class DisplayToolbar(
setOnClickListener
(
null
)
}
internal
val
titleView
=
AppCompatTextView
(
context
).
apply
{
id
=
R
.
id
.
mozac_browser_toolbar_title_view
gravity
=
Gravity
.
CENTER_VERTICAL
textSize
=
URL_TEXT_SIZE
visibility
=
View
.
GONE
ellipsize
=
TextUtils
.
TruncateAt
.
END
setSingleLine
(
true
)
}
internal
val
urlView
=
AppCompatTextView
(
context
).
apply
{
id
=
R
.
id
.
mozac_browser_toolbar_url_view
gravity
=
Gravity
.
CENTER_VERTICAL
...
...
@@ -195,11 +206,20 @@ internal class DisplayToolbar(
init
{
addView
(
siteSecurityIconView
)
addView
(
titleView
)
addView
(
urlView
)
addView
(
menuView
)
addView
(
progressView
)
}
/**
* Updates the title to be displayed.
*/
fun
updateTitle
(
title
:
String
)
{
titleView
.
text
=
title
titleView
.
visibility
=
if
(
title
.
isEmpty
())
View
.
GONE
else
View
.
VISIBLE
}
/**
* Updates the URL to be displayed.
*/
...
...
@@ -306,7 +326,8 @@ internal class DisplayToolbar(
val
height
=
MeasureSpec
.
getSize
(
heightMeasureSpec
)
val
fixedHeightSpec
=
MeasureSpec
.
makeMeasureSpec
(
height
,
MeasureSpec
.
EXACTLY
)
val
halfFixedHeightSpec
=
MeasureSpec
.
makeMeasureSpec
(
height
/
MEASURED_HEIGHT_DENOMINATOR
,
MeasureSpec
.
EXACTLY
)
setMeasuredDimension
(
width
,
height
)
// The icon and menu fill the whole height and have a square shape
...
...
@@ -325,7 +346,15 @@ internal class DisplayToolbar(
val
urlWidth
=
(
width
-
iconSize
-
browserActionsWidth
-
pageActionsWidth
-
menuWidth
-
navigationActionsWidth
-
2
*
urlBoxMargin
)
val
urlWidthSpec
=
MeasureSpec
.
makeMeasureSpec
(
urlWidth
,
MeasureSpec
.
EXACTLY
)
urlView
.
measure
(
urlWidthSpec
,
fixedHeightSpec
)
if
(
titleView
.
isVisible
())
{
// With a title view, the url and title split the rest of the space vertically
titleView
.
measure
(
urlWidthSpec
,
halfFixedHeightSpec
)
urlView
.
measure
(
urlWidthSpec
,
halfFixedHeightSpec
)
}
else
{
// With no title view, the url view takes up the rest of the space
urlView
.
measure
(
urlWidthSpec
,
fixedHeightSpec
)
}
val
progressHeightSpec
=
MeasureSpec
.
makeMeasureSpec
(
resources
.
pxToDp
(
PROGRESS_BAR_HEIGHT_DP
),
MeasureSpec
.
EXACTLY
)
...
...
@@ -427,10 +456,32 @@ internal class DisplayToolbar(
// | navigation | icon | url [ page ] | browser | menu |
// | actions | | [ actions ] | actions | |
// +-------------+------+-----------------------+----------+------+
val
iconWidth
=
if
(
siteSecurityIconView
.
isVisible
())
siteSecurityIconView
.
measuredWidth
else
0
val
urlLeft
=
navigationActionsWidth
+
iconWidth
+
urlBoxMargin
urlView
.
layout
(
urlLeft
,
0
,
urlLeft
+
urlView
.
measuredWidth
,
measuredHeight
)
// If the titleView is visible, it will appear above the URL:
// +-------------+------+-----------------------+----------+------+
// | navigation | icon | title [ page ] | browser | menu |
// | actions | | url [ actions ] | actions | |
// +-------------+------+-----------------------+----------+------+
if
(
titleView
.
isVisible
())
{
val
totalTextHeights
=
urlView
.
measuredHeight
+
titleView
.
measuredHeight
val
totalAvailablePadding
=
height
-
totalTextHeights
val
padding
=
totalAvailablePadding
/
MEASURED_HEIGHT_DENOMINATOR
titleView
.
layout
(
urlLeft
,
padding
,
urlLeft
+
titleView
.
measuredWidth
,
padding
+
titleView
.
measuredHeight
)
urlView
.
layout
(
urlLeft
,
padding
+
titleView
.
measuredHeight
,
urlLeft
+
urlView
.
measuredWidth
,
padding
+
titleView
.
measuredHeight
+
urlView
.
measuredHeight
)
}
else
{
urlView
.
layout
(
urlLeft
,
0
,
urlLeft
+
urlView
.
measuredWidth
,
measuredHeight
)
}
// The progress bar by default is going to be drawn at the bottom of the toolbar, top if defined:
progressView
.
layout
(
...
...
@@ -449,6 +500,7 @@ internal class DisplayToolbar(
}
companion
object
{
internal
const
val
MEASURED_HEIGHT_DENOMINATOR
=
2
internal
const
val
URL_FADING_EDGE_SIZE_DP
=
24
const
val
BOTTOM_PROGRESS_BAR
=
0
...
...
components/browser/toolbar/src/main/res/values/ids.xml
View file @
0835821a
...
...
@@ -6,6 +6,7 @@
-->
<resources>
<item
name=
"mozac_browser_toolbar_title_view"
type=
"id"
/>
<item
name=
"mozac_browser_toolbar_url_view"
type=
"id"
/>
<item
name=
"mozac_browser_toolbar_edit_url_view"
type=
"id"
/>
<item
name=
"mozac_browser_toolbar_clear_view"
type=
"id"
/>
...
...
components/browser/toolbar/src/test/java/mozilla/components/browser/toolbar/BrowserToolbarTest.kt
View file @
0835821a
...
...
@@ -742,6 +742,45 @@ class BrowserToolbarTest {
assertEquals
(
12f
,
toolbar
.
editToolbar
.
urlView
.
textSize
)
}
@Test
fun
`titleTextSize
changes
display
titleView`
()
{
val
toolbar
=
BrowserToolbar
(
context
)
assertTrue
(
toolbar
.
displayToolbar
.
titleView
.
textSize
!=
12f
)
toolbar
.
titleTextSize
=
12f
assertEquals
(
12f
,
toolbar
.
displayToolbar
.
titleView
.
textSize
)
}
@Test
fun
`titleTextColor
changes
display
titleView`
()
{
val
toolbar
=
BrowserToolbar
(
context
)
toolbar
.
titleColor
=
R
.
color
.
photonBlue40
assertEquals
(
R
.
color
.
photonBlue40
,
toolbar
.
displayToolbar
.
titleView
.
currentTextColor
)
}
@Test
fun
`titleView
visibility
is
based
on
being
set
`
()
{
val
toolbar
=
BrowserToolbar
(
context
)
assertEquals
(
toolbar
.
displayToolbar
.
titleView
.
visibility
,
View
.
GONE
)
toolbar
.
title
=
"Mozilla"
assertEquals
(
toolbar
.
displayToolbar
.
titleView
.
visibility
,
View
.
VISIBLE
)
toolbar
.
title
=
""
assertEquals
(
toolbar
.
displayToolbar
.
titleView
.
visibility
,
View
.
GONE
)
}
@Test
fun
`titleView
text
is
set
properly`
()
{
val
toolbar
=
BrowserToolbar
(
context
)
toolbar
.
title
=
"Mozilla"
assertEquals
(
toolbar
.
displayToolbar
.
titleView
.
text
,
"Mozilla"
)
}
@Test
fun
`typeface
changes
edit
and
display
urlView`
()
{
val
toolbar
=
BrowserToolbar
(
context
)
...
...
components/browser/toolbar/src/test/java/mozilla/components/browser/toolbar/display/DisplayToolbarTest.kt
View file @
0835821a
...
...
@@ -605,6 +605,102 @@ class DisplayToolbarTest {
assertEquals
(
624
,
viewRect
.
width
())
}
@Test
fun
`titleView
does
not
display
when
there
is
no
title
text`
()
{
val
toolbar
=
mock
(
BrowserToolbar
::
class
.
java
)
val
displayToolbar
=
DisplayToolbar
(
context
,
toolbar
)
val
widthSpec
=
View
.
MeasureSpec
.
makeMeasureSpec
(
1024
,
View
.
MeasureSpec
.
AT_MOST
)
val
heightSpec
=
View
.
MeasureSpec
.
makeMeasureSpec
(
200
,
View
.
MeasureSpec
.
AT_MOST
)
displayToolbar
.
measure
(
widthSpec
,
heightSpec
)
displayToolbar
.
layout
(
0
,
0
,
1024
,
200
)
val
urlView
=
displayToolbar
.
urlView
val
titleView
=
displayToolbar
.
titleView
val
urlViewRect
=
Rect
(
urlView
.
left
,
urlView
.
top
,
urlView
.
right
,
urlView
.
bottom
)
val
titleViewRect
=
Rect
(
titleView
.
left
,
titleView
.
top
,
titleView
.
right
,
titleView
.
bottom
)
assertTrue
(
urlViewRect
.
width
()
>
0
)
assertTrue
(
urlViewRect
.
height
()
>
0
)
assertTrue
(
titleViewRect
.
width
()
==
0
)
assertTrue
(
titleViewRect
.
height
()
==
0
)
assertEquals
(
titleView
.
visibility
,
View
.
GONE
)
}
@Test
fun
`titleView
is
properly
laid
out
when
there
is
title
text`
()
{
val
toolbar
=
mock
(
BrowserToolbar
::
class
.
java
)
val
displayToolbar
=
DisplayToolbar
(
context
,
toolbar
)
displayToolbar
.
updateTitle
(
"Mozilla"
)
assertEquals
(
displayToolbar
.
titleView
.
visibility
,
View
.
VISIBLE
)
val
widthSpec
=
View
.
MeasureSpec
.
makeMeasureSpec
(
1024
,
View
.
MeasureSpec
.
AT_MOST
)
val
heightSpec
=
View
.
MeasureSpec
.
makeMeasureSpec
(
200
,
View
.
MeasureSpec
.
AT_MOST
)
displayToolbar
.
measure
(
widthSpec
,
heightSpec
)
displayToolbar
.
layout
(
0
,
0
,
1024
,
200
)
val
urlView
=
displayToolbar
.
urlView
val
titleView
=
displayToolbar
.
titleView
val
urlViewRect
=
Rect
(
urlView
.
left
,
urlView
.
top
,
urlView
.
right
,
urlView
.
bottom
)
val
titleViewRect
=
Rect
(
titleView
.
left
,
titleView
.
top
,
titleView
.
right
,
titleView
.
bottom
)
assertTrue
(
urlViewRect
.
width
()
>
0
)
assertTrue
(
urlViewRect
.
height
()
>
0
)
assertTrue
(
titleViewRect
.
width
()
>
0
)
assertTrue
(
titleViewRect
.
height
()
>
0
)
val
totalTextHeights
=
urlViewRect
.
height
()
+
titleViewRect
.
height
()
val
totalAvailablePadding
=
200
-
totalTextHeights
val
padding
=
totalAvailablePadding
/
DisplayToolbar
.
MEASURED_HEIGHT_DENOMINATOR
assertTrue
(
titleViewRect
.
left
==
urlViewRect
.
left
)
assertTrue
(
titleViewRect
.
top
==
padding
)
assertTrue
(
titleViewRect
.
right
==
urlViewRect
.
right
)
assertTrue
(
titleViewRect
.
bottom
==
padding
+
titleViewRect
.
height
())
}
@Test
fun
`urlView
is
properly
laid
out
when
a
title
is
shown`
()
{
val
toolbar
=
mock
(
BrowserToolbar
::
class
.
java
)
val
displayToolbar
=
DisplayToolbar
(
context
,
toolbar
)
displayToolbar
.
updateTitle
(
"Mozilla"
)
val
widthSpec
=
View
.
MeasureSpec
.
makeMeasureSpec
(
1024
,
View
.
MeasureSpec
.
AT_MOST
)
val
heightSpec
=
View
.
MeasureSpec
.
makeMeasureSpec
(
200
,
View
.
MeasureSpec
.
AT_MOST
)
displayToolbar
.
measure
(
widthSpec
,
heightSpec
)
displayToolbar
.
layout
(
0
,
0
,
1024
,
200
)
val
urlView
=
displayToolbar
.
urlView
val
titleView
=
displayToolbar
.
titleView
val
titleViewRect
=
Rect
(
titleView
.
left
,
titleView
.
top
,
titleView
.
right
,
titleView
.
bottom
)
val
urlViewRect
=
Rect
(
urlView
.
left
,
urlView
.
top
,
urlView
.
right
,
urlView
.
bottom
)
val
totalTextHeights
=
urlViewRect
.
height
()
+
titleViewRect
.
height
()
val
totalAvailablePadding
=
200
-
totalTextHeights
val
padding
=
totalAvailablePadding
/
DisplayToolbar
.
MEASURED_HEIGHT_DENOMINATOR
assertTrue
(
urlViewRect
.
width
()
>
0
)
assertTrue
(
urlViewRect
.
height
()
>
0
)
assertTrue
(
titleViewRect
.
width
()
>
0
)
assertTrue
(
titleViewRect
.
height
()
>
0
)
assertTrue
(
urlViewRect
.
left
==
titleViewRect
.
left
)
assertTrue
(
urlViewRect
.
top
==
padding
+
titleViewRect
.
height
())
assertTrue
(
urlViewRect
.
right
==
titleView
.
right
)
assertTrue
(
urlViewRect
.
bottom
==
padding
+
titleViewRect
.
height
()
+
urlViewRect
.
height
())
}
@Test
fun
`toolbar
only
switches
to
editing
mode
if
onUrlClicked
returns
true
`
()
{
val
toolbar
=
mock
(
BrowserToolbar
::
class
.
java
)
...
...
components/concept/toolbar/src/main/java/mozilla/components/concept/toolbar/Toolbar.kt
View file @
0835821a
...
...
@@ -21,6 +21,11 @@ import java.lang.ref.WeakReference
*/
@Suppress
(
"TooManyFunctions"
)
interface
Toolbar
{
/**
* Sets/Gets the title to be displayed on the toolbar.
*/
var
title
:
String
/**
* Sets/Gets the URL to be displayed on the toolbar.
*/
...
...
components/feature/customtabs/src/main/java/mozilla/components/feature/customtabs/CustomTabsToolbarFeature.kt
View file @
0835821a
...
...
@@ -43,7 +43,10 @@ class CustomTabsToolbarFeature(
if
(
initialized
)
{
return
}
initialized
=
sessionManager
.
runWithSession
(
sessionId
)
{
initialize
(
it
)
}
initialized
=
sessionManager
.
runWithSession
(
sessionId
)
{
it
.
register
(
sessionObserver
)
initialize
(
it
)
}
}
@VisibleForTesting
...
...
@@ -65,6 +68,10 @@ class CustomTabsToolbarFeature(
if
(
config
.
showShareMenuItem
)
addShareButton
(
session
)
// Add menu items
if
(
config
.
menuItems
.
isNotEmpty
())
addMenuItems
(
config
.
menuItems
)
// Explicitly set the title regardless of the customTabConfig settings
toolbar
.
titleTextSize
=
TITLE_TEXT_SIZE
return
true
}
return
false
...
...
@@ -75,6 +82,7 @@ class CustomTabsToolbarFeature(
toolbarColor
?.
let
{
color
->
toolbar
.
setBackgroundColor
(
color
)
toolbar
.
textColor
=
readableColor
toolbar
.
titleColor
=
readableColor
toolbar
.
siteSecurityColor
=
Pair
(
readableColor
,
readableColor
)
toolbar
.
menuViewColor
=
readableColor
}
...
...
@@ -134,7 +142,20 @@ class CustomTabsToolbarFeature(
}
}
override
fun
stop
()
{}
private
val
sessionObserver
=
object
:
Session
.
Observer
{
override
fun
onTitleChanged
(
session
:
Session
,
title
:
String
)
{
// Only shrink the urlTextSize if a title is displayed
toolbar
.
textSize
=
URL_TEXT_SIZE
toolbar
.
title
=
title
}
}
override
fun
stop
()
{
sessionManager
.
runWithSession
(
sessionId
)
{
it
.
unregister
(
sessionObserver
)
true
}
}
/**
* When the back button is pressed if not initialized returns false,
...
...
@@ -154,6 +175,8 @@ class CustomTabsToolbarFeature(
}
companion
object
{
const
val
TITLE_TEXT_SIZE
=
16f
const
val
URL_TEXT_SIZE
=
12f
@Suppress
(
"MagicNumber"
)
internal
fun
getReadableTextColor
(
backgroundColor
:
Int
):
Int
{
val
greyValue
=
greyscaleFromRGB
(
backgroundColor
)
...
...
components/feature/toolbar/src/main/java/mozilla/components/feature/toolbar/ToolbarFeature.kt
View file @
0835821a
...
...
@@ -63,10 +63,25 @@ class ToolbarFeature(
* @property registrableDomainColor Text color that should be used for the registrable domain of the URL (see
* [PublicSuffixList.getPublicSuffixPlusOne] for an explanation of "registrable domain".
* @property urlColor Optional text color used for the URL.
* @property renderStyle Sealed class that controls the style of the url to be displayed
*/
data class
UrlRenderConfiguration
(
internal
val
publicSuffixList
:
PublicSuffixList
,
@ColorInt
internal
val
registrableDomainColor
:
Int
,
@ColorInt
internal
val
urlColor
:
Int
?
=
null
@ColorInt
internal
val
urlColor
:
Int
?
=
null
,
internal
val
renderStyle
:
RenderStyle
=
RenderStyle
.
ColoredUrl
)
/**
* Controls how the url should be styled
*
* RegistrableDomain: displays only the url, uncolored
* ColoredUrl: displays the registrableDomain with color and url with another color
* UncoloredUrl: displays the full url, uncolored
*/
sealed
class
RenderStyle
{
object
RegistrableDomain
:
RenderStyle
()
object
ColoredUrl
:
RenderStyle
()
object
UncoloredUrl
:
RenderStyle
()
}
}
components/feature/toolbar/src/main/java/mozilla/components/feature/toolbar/internal/URLRenderer.kt
View file @
0835821a
...
...
@@ -59,8 +59,23 @@ internal class URLRenderer(
internal
suspend
fun
updateUrl
(
url
:
String
)
{
if
(
url
.
isEmpty
()
||
configuration
==
null
)
{
setUncoloredUrl
(
url
)
return
}
when
(
configuration
.
renderStyle
)
{
ToolbarFeature
.
RenderStyle
.
UncoloredUrl
->
setUncoloredUrl
(
url
)
ToolbarFeature
.
RenderStyle
.
ColoredUrl
->
setColoredUrl
(
url
,
configuration
)
ToolbarFeature
.
RenderStyle
.
RegistrableDomain
->
setRegistrableDomainUrl
(
url
)
}
}
private
suspend
fun
setRegistrableDomainUrl
(
url
:
String
)
{
val
host
=
url
.
toUri
().
host
if
(!
host
.
isNullOrEmpty
())
{
toolbar
.
url
=
getRegistrableDomain
(
host
)
?:
url
}
else
{
setColoredUrl
(
url
,
configuration
)
toolbar
.
url
=
url
}
}
...
...
@@ -76,6 +91,10 @@ internal class URLRenderer(
private
fun
setUncoloredUrl
(
url
:
String
)
{
toolbar
.
url
=
url
}
private
suspend
fun
getRegistrableDomain
(
host
:
String
):
CharSequence
?
{
return
configuration
?.
publicSuffixList
?.
getPublicSuffixPlusOne
(
host
)
?.
await
()
}
}
private
suspend
fun
SpannableStringBuilder
.
colorRegistrableDomain
(
...
...
components/feature/toolbar/src/test/java/mozilla/components/feature/toolbar/ToolbarAutocompleteFeatureTest.kt
View file @
0835821a
...
...
@@ -30,6 +30,7 @@ import org.robolectric.RobolectricTestRunner
@RunWith
(
RobolectricTestRunner
::
class
)
class
ToolbarAutocompleteFeatureTest
{
class
TestToolbar
:
Toolbar
{
override
var
title
:
String
=
""
override
var
url
:
CharSequence
=
""
override
var
siteSecure
:
Toolbar
.
SiteSecurity
=
Toolbar
.
SiteSecurity
.
INSECURE
override
var
private
:
Boolean
=
false
...
...
components/feature/toolbar/src/test/java/mozilla/components/feature/toolbar/ToolbarInteractorTest.kt
View file @
0835821a
...
...
@@ -23,6 +23,7 @@ class ToolbarInteractorTest {
override
var
url
:
CharSequence
=
""
override
var
siteSecure
:
Toolbar
.
SiteSecurity
=
Toolbar
.
SiteSecurity
.
INSECURE
override
var
private
:
Boolean
=
false
override
var
title
:
String
=
""
override
fun
setSearchTerms
(
searchTerms
:
String
)
{
fail
()
...
...
docs/changelog.md
View file @
0835821a
...
...
@@ -12,6 +12,11 @@ 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-toolbar**
*
Added
`titleView`
to
`DisplayToolbar`
which displays the title of the page. Various options are able to modified such as
`titleTextSize`
,
`titleColor`
, and
`displayTitle`
. In custom tabs, the URL will now only display the hostname.
*
Changed
`UrlRenderConfiguration`
to include a
`RenderStyle`
parameter where you can specify how the URL renders
*
**support-ktx**
*
Added extension property
`Uri.isHttpOrHttps`
.
...
...
Write
Preview
Supports
Markdown
0%
Try again
or
attach a new file
.
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment