Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
A
AloqaIM-Android
Project
Project
Details
Activity
Releases
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
Administrator
AloqaIM-Android
Commits
cb560bb4
Commit
cb560bb4
authored
Oct 04, 2018
by
Lucio Maciel
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Fixes on color attachments
parent
07c5c0bf
Changes
9
Expand all
Hide whitespace changes
Inline
Side-by-side
Showing
9 changed files
with
1189 additions
and
40 deletions
+1189
-40
9.json
app/schemas/chat.rocket.android.db.RCDatabase/9.json
+1081
-0
ColorAttachmentViewHolder.kt
...ket/android/chatroom/adapter/ColorAttachmentViewHolder.kt
+18
-6
ColorAttachmentUiModel.kt
...rocket/android/chatroom/uimodel/ColorAttachmentUiModel.kt
+1
-0
UiModelMapper.kt
...ava/chat/rocket/android/chatroom/uimodel/UiModelMapper.kt
+28
-22
DatabaseManager.kt
app/src/main/java/chat/rocket/android/db/DatabaseManager.kt
+2
-2
RCDatabase.kt
app/src/main/java/chat/rocket/android/db/RCDatabase.kt
+1
-1
Attachments.kt
...src/main/java/chat/rocket/android/db/model/Attachments.kt
+23
-5
DatabaseMessageMapper.kt
...t/android/server/infraestructure/DatabaseMessageMapper.kt
+18
-1
item_color_attachment.xml
app/src/main/res/layout/item_color_attachment.xml
+17
-3
No files found.
app/schemas/chat.rocket.android.db.RCDatabase/9.json
0 → 100644
View file @
cb560bb4
This diff is collapsed.
Click to expand it.
app/src/main/java/chat/rocket/android/chatroom/adapter/ColorAttachmentViewHolder.kt
View file @
cb560bb4
package
chat.rocket.android.chatroom.adapter
package
chat.rocket.android.chatroom.adapter
import
android.graphics.drawable.ColorDrawable
import
android.graphics.drawable.Drawable
import
android.graphics.drawable.Drawable
import
androidx.core.content.ContextCompat
import
androidx.core.content.ContextCompat
import
android.text.method.LinkMovementMethod
import
android.text.method.LinkMovementMethod
import
android.view.View
import
android.view.View
import
androidx.core.view.isVisible
import
androidx.core.widget.ImageViewCompat
import
chat.rocket.android.R
import
chat.rocket.android.R
import
chat.rocket.android.chatroom.uimodel.ColorAttachmentUiModel
import
chat.rocket.android.chatroom.uimodel.ColorAttachmentUiModel
import
chat.rocket.android.emoji.EmojiReactionListener
import
chat.rocket.android.emoji.EmojiReactionListener
...
@@ -15,8 +18,7 @@ class ColorAttachmentViewHolder(itemView: View,
...
@@ -15,8 +18,7 @@ class ColorAttachmentViewHolder(itemView: View,
reactionListener
:
EmojiReactionListener
?
=
null
)
reactionListener
:
EmojiReactionListener
?
=
null
)
:
BaseViewHolder
<
ColorAttachmentUiModel
>(
itemView
,
listener
,
reactionListener
)
{
:
BaseViewHolder
<
ColorAttachmentUiModel
>(
itemView
,
listener
,
reactionListener
)
{
val
drawable
:
Drawable
?
=
ContextCompat
.
getDrawable
(
itemView
.
context
,
val
drawable
:
Drawable
=
ColorDrawable
(
ContextCompat
.
getColor
(
itemView
.
context
,
R
.
color
.
quoteBar
))
R
.
drawable
.
quote_vertical_gray_bar
)
init
{
init
{
with
(
itemView
)
{
with
(
itemView
)
{
...
@@ -27,10 +29,20 @@ class ColorAttachmentViewHolder(itemView: View,
...
@@ -27,10 +29,20 @@ class ColorAttachmentViewHolder(itemView: View,
override
fun
bindViews
(
data
:
ColorAttachmentUiModel
)
{
override
fun
bindViews
(
data
:
ColorAttachmentUiModel
)
{
with
(
itemView
)
{
with
(
itemView
)
{
drawable
?.
let
{
quote_bar
.
setColorFilter
(
data
.
color
)
quote_bar
.
background
=
drawable
.
mutate
().
apply
{
setTint
(
data
.
color
)
}
if
(
data
.
text
.
isNotEmpty
())
{
attachment_text
.
text
=
data
.
text
attachment_text
.
isVisible
=
true
}
attachment_text
.
text
=
data
.
text
}
else
{
attachment_text
.
isVisible
=
false
}
if
(
data
.
fields
.
isNullOrEmpty
())
{
text_fields
.
isVisible
=
false
}
else
{
text_fields
.
isVisible
=
true
text_fields
.
text
=
data
.
fields
}
}
}
}
}
...
...
app/src/main/java/chat/rocket/android/chatroom/uimodel/ColorAttachmentUiModel.kt
View file @
cb560bb4
...
@@ -9,6 +9,7 @@ data class ColorAttachmentUiModel(
...
@@ -9,6 +9,7 @@ data class ColorAttachmentUiModel(
val
id
:
Long
,
val
id
:
Long
,
val
color
:
Int
,
val
color
:
Int
,
val
text
:
CharSequence
,
val
text
:
CharSequence
,
val
fields
:
CharSequence
?
=
null
,
override
val
message
:
Message
,
override
val
message
:
Message
,
override
val
rawData
:
ColorAttachment
,
override
val
rawData
:
ColorAttachment
,
override
val
messageId
:
String
,
override
val
messageId
:
String
,
...
...
app/src/main/java/chat/rocket/android/chatroom/uimodel/UiModelMapper.kt
View file @
cb560bb4
...
@@ -42,6 +42,7 @@ import chat.rocket.core.model.attachment.Attachment
...
@@ -42,6 +42,7 @@ import chat.rocket.core.model.attachment.Attachment
import
chat.rocket.core.model.attachment.AudioAttachment
import
chat.rocket.core.model.attachment.AudioAttachment
import
chat.rocket.core.model.attachment.AuthorAttachment
import
chat.rocket.core.model.attachment.AuthorAttachment
import
chat.rocket.core.model.attachment.ColorAttachment
import
chat.rocket.core.model.attachment.ColorAttachment
import
chat.rocket.core.model.attachment.Field
import
chat.rocket.core.model.attachment.FileAttachment
import
chat.rocket.core.model.attachment.FileAttachment
import
chat.rocket.core.model.attachment.GenericFileAttachment
import
chat.rocket.core.model.attachment.GenericFileAttachment
import
chat.rocket.core.model.attachment.ImageAttachment
import
chat.rocket.core.model.attachment.ImageAttachment
...
@@ -129,14 +130,14 @@ class UiModelMapper @Inject constructor(
...
@@ -129,14 +130,14 @@ class UiModelMapper @Inject constructor(
withContext
(
CommonPool
)
{
withContext
(
CommonPool
)
{
val
list
=
ArrayList
<
BaseUiModel
<*>>()
val
list
=
ArrayList
<
BaseUiModel
<*>>()
message
.
urls
?.
forEach
{
message
.
urls
?.
forEach
{
url
->
val
url
=
mapUrl
(
message
,
it
)
mapUrl
(
message
,
url
)
?.
let
{
list
.
add
(
it
)
}
url
?.
let
{
list
.
add
(
url
)
}
}
}
message
.
attachments
?.
forEach
{
message
.
attachments
?.
mapNotNull
{
attachment
->
val
attachment
=
mapAttachment
(
message
,
it
)
mapAttachment
(
message
,
attachment
)
attachment
?.
let
{
list
.
add
(
attachment
)
}
}
?.
asReversed
()
?.
let
{
list
.
addAll
(
it
)
}
}
mapMessage
(
message
).
let
{
mapMessage
(
message
).
let
{
...
@@ -334,34 +335,39 @@ class UiModelMapper @Inject constructor(
...
@@ -334,34 +335,39 @@ class UiModelMapper @Inject constructor(
val
localDateTime
=
DateTimeHelper
.
getLocalDateTime
(
message
.
timestamp
)
val
localDateTime
=
DateTimeHelper
.
getLocalDateTime
(
message
.
timestamp
)
val
dayMarkerText
=
DateTimeHelper
.
getFormattedDateForMessages
(
localDateTime
,
context
)
val
dayMarkerText
=
DateTimeHelper
.
getFormattedDateForMessages
(
localDateTime
,
context
)
val
fieldsText
=
mapFields
(
fields
)
ColorAttachmentUiModel
(
attachmentUrl
=
url
,
id
=
id
,
color
=
color
.
color
,
ColorAttachmentUiModel
(
attachmentUrl
=
url
,
id
=
id
,
color
=
color
.
color
,
text
=
text
,
message
=
message
,
rawData
=
attachment
,
text
=
text
,
fields
=
fieldsText
,
message
=
message
,
rawData
=
attachment
,
messageId
=
message
.
id
,
reactions
=
getReactions
(
message
),
messageId
=
message
.
id
,
reactions
=
getReactions
(
message
),
preview
=
message
.
copy
(
message
=
content
.
message
),
unread
=
message
.
unread
,
preview
=
message
.
copy
(
message
=
content
.
message
),
unread
=
message
.
unread
,
showDayMarker
=
false
,
currentDayMarkerText
=
dayMarkerText
)
showDayMarker
=
false
,
currentDayMarkerText
=
dayMarkerText
)
}
}
}
}
private
fun
mapAuthorAttachment
(
message
:
Message
,
attachment
:
AuthorAttachment
):
AuthorAttachmentUiModel
{
private
fun
mapFields
(
fields
:
List
<
Field
>?):
CharSequence
?
{
return
with
(
attachment
)
{
return
fields
?.
let
{
val
content
=
stripMessageQuotes
(
message
)
buildSpannedString
{
it
.
forEachIndexed
{
index
,
field
->
val
fieldsText
=
fields
?.
let
{
bold
{
append
(
field
.
title
)
}
buildSpannedString
{
append
(
"\n"
)
it
.
forEachIndexed
{
index
,
field
->
if
(
field
.
value
.
isNotEmpty
())
{
bold
{
append
(
field
.
title
)
}
append
(
field
.
value
)
append
(
"\n"
)
}
if
(
field
.
value
.
isNotEmpty
())
{
append
(
field
.
value
)
}
if
(
index
!=
it
.
size
-
1
)
{
// it is not the last one, append a new line
if
(
index
!=
it
.
size
-
1
)
{
// it is not the last one, append a new line
append
(
"\n\n"
)
append
(
"\n\n"
)
}
}
}
}
}
}
}
}
}
private
fun
mapAuthorAttachment
(
message
:
Message
,
attachment
:
AuthorAttachment
):
AuthorAttachmentUiModel
{
return
with
(
attachment
)
{
val
content
=
stripMessageQuotes
(
message
)
val
fieldsText
=
mapFields
(
fields
)
val
id
=
attachmentId
(
message
,
attachment
)
val
id
=
attachmentId
(
message
,
attachment
)
val
localDateTime
=
DateTimeHelper
.
getLocalDateTime
(
message
.
timestamp
)
val
localDateTime
=
DateTimeHelper
.
getLocalDateTime
(
message
.
timestamp
)
...
...
app/src/main/java/chat/rocket/android/db/DatabaseManager.kt
View file @
cb560bb4
...
@@ -56,8 +56,8 @@ class DatabaseManager(val context: Application,
...
@@ -56,8 +56,8 @@ class DatabaseManager(val context: Application,
fun
userDao
():
UserDao
=
database
.
userDao
()
fun
userDao
():
UserDao
=
database
.
userDao
()
fun
messageDao
():
MessageDao
=
database
.
messageDao
()
fun
messageDao
():
MessageDao
=
database
.
messageDao
()
fun
clearUsersStatus
()
{
suspend
fun
clearUsersStatus
()
{
launch
(
dbContext
)
{
withContext
(
dbContext
)
{
userDao
().
clearStatus
()
userDao
().
clearStatus
()
}
}
}
}
...
...
app/src/main/java/chat/rocket/android/db/RCDatabase.kt
View file @
cb560bb4
...
@@ -23,7 +23,7 @@ import chat.rocket.android.db.model.UserEntity
...
@@ -23,7 +23,7 @@ import chat.rocket.android.db.model.UserEntity
AttachmentFieldEntity
::
class
,
AttachmentActionEntity
::
class
,
UrlEntity
::
class
,
AttachmentFieldEntity
::
class
,
AttachmentActionEntity
::
class
,
UrlEntity
::
class
,
ReactionEntity
::
class
,
MessagesSync
::
class
ReactionEntity
::
class
,
MessagesSync
::
class
],
],
version
=
8
,
version
=
9
,
exportSchema
=
true
exportSchema
=
true
)
)
abstract
class
RCDatabase
:
RoomDatabase
()
{
abstract
class
RCDatabase
:
RoomDatabase
()
{
...
...
app/src/main/java/chat/rocket/android/db/model/Attachments.kt
View file @
cb560bb4
...
@@ -69,6 +69,8 @@ data class AttachmentEntity(
...
@@ -69,6 +69,8 @@ data class AttachmentEntity(
val
timestamp
:
Long
?
=
null
,
val
timestamp
:
Long
?
=
null
,
@ColumnInfo
(
name
=
"has_actions"
)
@ColumnInfo
(
name
=
"has_actions"
)
val
hasActions
:
Boolean
=
false
,
val
hasActions
:
Boolean
=
false
,
@ColumnInfo
(
name
=
"has_fields"
)
val
hasFields
:
Boolean
=
false
,
@ColumnInfo
(
name
=
"button_alignment"
)
@ColumnInfo
(
name
=
"button_alignment"
)
val
buttonAlignment
:
String
?
=
null
val
buttonAlignment
:
String
?
=
null
)
:
BaseMessageEntity
)
:
BaseMessageEntity
...
@@ -119,7 +121,7 @@ fun Attachment.asEntity(msgId: String): List<BaseMessageEntity> {
...
@@ -119,7 +121,7 @@ fun Attachment.asEntity(msgId: String): List<BaseMessageEntity> {
is
VideoAttachment
->
listOf
(
asEntity
(
msgId
))
is
VideoAttachment
->
listOf
(
asEntity
(
msgId
))
is
AudioAttachment
->
listOf
(
asEntity
(
msgId
))
is
AudioAttachment
->
listOf
(
asEntity
(
msgId
))
is
AuthorAttachment
->
asEntity
(
msgId
)
is
AuthorAttachment
->
asEntity
(
msgId
)
is
ColorAttachment
->
listOf
(
asEntity
(
msgId
)
)
is
ColorAttachment
->
asEntity
(
msgId
)
is
MessageAttachment
->
listOf
(
asEntity
(
msgId
))
is
MessageAttachment
->
listOf
(
asEntity
(
msgId
))
is
GenericFileAttachment
->
listOf
(
asEntity
(
msgId
))
is
GenericFileAttachment
->
listOf
(
asEntity
(
msgId
))
is
ActionsAttachment
->
asEntity
(
msgId
)
is
ActionsAttachment
->
asEntity
(
msgId
)
...
@@ -179,7 +181,8 @@ fun AuthorAttachment.asEntity(msgId: String): List<BaseMessageEntity> {
...
@@ -179,7 +181,8 @@ fun AuthorAttachment.asEntity(msgId: String): List<BaseMessageEntity> {
messageId
=
msgId
,
messageId
=
msgId
,
authorLink
=
url
,
authorLink
=
url
,
authorIcon
=
authorIcon
,
authorIcon
=
authorIcon
,
authorName
=
authorName
authorName
=
authorName
,
hasFields
=
fields
?.
isNotEmpty
()
==
true
)
)
list
.
add
(
attachment
)
list
.
add
(
attachment
)
...
@@ -195,13 +198,28 @@ fun AuthorAttachment.asEntity(msgId: String): List<BaseMessageEntity> {
...
@@ -195,13 +198,28 @@ fun AuthorAttachment.asEntity(msgId: String): List<BaseMessageEntity> {
return
list
return
list
}
}
fun
ColorAttachment
.
asEntity
(
msgId
:
String
):
AttachmentEntity
=
fun
ColorAttachment
.
asEntity
(
msgId
:
String
):
List
<
BaseMessageEntity
>
{
AttachmentEntity
(
val
list
=
mutableListOf
<
BaseMessageEntity
>()
val
attachment
=
AttachmentEntity
(
_id
=
"${msgId}_${hashCode()}"
,
_id
=
"${msgId}_${hashCode()}"
,
messageId
=
msgId
,
messageId
=
msgId
,
color
=
color
.
rawColor
,
color
=
color
.
rawColor
,
fallback
=
fallback
fallback
=
fallback
,
hasFields
=
fields
?.
isNotEmpty
()
==
true
)
)
list
.
add
(
attachment
)
fields
?.
forEach
{
field
->
val
entity
=
AttachmentFieldEntity
(
attachmentId
=
attachment
.
_id
,
title
=
field
.
title
,
value
=
field
.
value
)
list
.
add
(
entity
)
}
return
list
}
// TODO - how to model An message attachment with attachments???
// TODO - how to model An message attachment with attachments???
fun
MessageAttachment
.
asEntity
(
msgId
:
String
):
AttachmentEntity
=
fun
MessageAttachment
.
asEntity
(
msgId
:
String
):
AttachmentEntity
=
...
...
app/src/main/java/chat/rocket/android/server/infraestructure/DatabaseMessageMapper.kt
View file @
cb560bb4
...
@@ -16,6 +16,7 @@ import chat.rocket.core.model.attachment.AudioAttachment
...
@@ -16,6 +16,7 @@ import chat.rocket.core.model.attachment.AudioAttachment
import
chat.rocket.core.model.attachment.AuthorAttachment
import
chat.rocket.core.model.attachment.AuthorAttachment
import
chat.rocket.core.model.attachment.Color
import
chat.rocket.core.model.attachment.Color
import
chat.rocket.core.model.attachment.ColorAttachment
import
chat.rocket.core.model.attachment.ColorAttachment
import
chat.rocket.core.model.attachment.DEFAULT_COLOR_STR
import
chat.rocket.core.model.attachment.Field
import
chat.rocket.core.model.attachment.Field
import
chat.rocket.core.model.attachment.GenericFileAttachment
import
chat.rocket.core.model.attachment.GenericFileAttachment
import
chat.rocket.core.model.attachment.ImageAttachment
import
chat.rocket.core.model.attachment.ImageAttachment
...
@@ -61,7 +62,7 @@ class DatabaseMessageMapper(private val dbManager: DatabaseManager) {
...
@@ -61,7 +62,7 @@ class DatabaseMessageMapper(private val dbManager: DatabaseManager) {
}
}
val
urls
=
this
.
urls
?.
let
{
mapUrl
(
it
)
}
val
urls
=
this
.
urls
?.
let
{
mapUrl
(
it
)
}
val
reactions
=
this
.
reactions
?.
let
{
mapReactions
(
it
)
}
val
reactions
=
this
.
reactions
?.
let
{
mapReactions
(
it
)
}
val
attachments
=
this
.
attachments
?.
let
{
mapAttachments
(
it
)
}
val
attachments
=
this
.
attachments
?.
let
{
mapAttachments
(
it
)
.
asReversed
()
}
val
messageType
=
messageTypeOf
(
this
.
message
.
type
)
val
messageType
=
messageTypeOf
(
this
.
message
.
type
)
list
.
add
(
Message
(
list
.
add
(
Message
(
...
@@ -164,6 +165,9 @@ class DatabaseMessageMapper(private val dbManager: DatabaseManager) {
...
@@ -164,6 +165,9 @@ class DatabaseMessageMapper(private val dbManager: DatabaseManager) {
authorLink
!=
null
->
{
authorLink
!=
null
->
{
mapAuthorAttachment
(
this
)
mapAuthorAttachment
(
this
)
}
}
hasFields
->
{
mapColorAttachmentWithFields
(
this
)
}
hasActions
->
{
hasActions
->
{
mapActionAttachment
(
this
)
mapActionAttachment
(
this
)
}
}
...
@@ -174,6 +178,19 @@ class DatabaseMessageMapper(private val dbManager: DatabaseManager) {
...
@@ -174,6 +178,19 @@ class DatabaseMessageMapper(private val dbManager: DatabaseManager) {
return
list
return
list
}
}
private
suspend
fun
mapColorAttachmentWithFields
(
entity
:
AttachmentEntity
):
ColorAttachment
{
val
fields
=
withContext
(
CommonPool
)
{
dbManager
.
messageDao
().
getAttachmentFields
(
entity
.
_id
)
}.
map
{
Field
(
it
.
title
,
it
.
value
)
}
return
with
(
entity
)
{
ColorAttachment
(
color
=
Color
.
Custom
(
color
?:
DEFAULT_COLOR_STR
),
text
=
text
?:
""
,
fallback
=
fallback
,
fields
=
fields
)
}
}
private
suspend
fun
mapActionAttachment
(
attachment
:
AttachmentEntity
):
ActionsAttachment
{
private
suspend
fun
mapActionAttachment
(
attachment
:
AttachmentEntity
):
ActionsAttachment
{
val
actions
=
withContext
(
CommonPool
)
{
val
actions
=
withContext
(
CommonPool
)
{
dbManager
.
messageDao
().
getAttachmentActions
(
attachment
.
_id
)
dbManager
.
messageDao
().
getAttachmentActions
(
attachment
.
_id
)
...
...
app/src/main/res/layout/item_color_attachment.xml
View file @
cb560bb4
...
@@ -13,12 +13,13 @@
...
@@ -13,12 +13,13 @@
android:paddingEnd=
"@dimen/screen_edge_left_and_right_padding"
android:paddingEnd=
"@dimen/screen_edge_left_and_right_padding"
android:paddingBottom=
"@dimen/message_item_top_and_bottom_padding"
>
android:paddingBottom=
"@dimen/message_item_top_and_bottom_padding"
>
<View
<
Image
View
android:id=
"@+id/quote_bar"
android:id=
"@+id/quote_bar"
android:layout_width=
"4dp"
android:layout_width=
"4dp"
android:layout_height=
"0dp"
android:layout_height=
"0dp"
android:layout_marginStart=
"56dp"
android:layout_marginStart=
"56dp"
android:background=
"@drawable/quote_vertical_gray_bar"
android:src=
"@drawable/quote_vertical_gray_bar"
android:scaleType=
"fitXY"
app:layout_constraintBottom_toTopOf=
"@id/recycler_view_reactions"
app:layout_constraintBottom_toTopOf=
"@id/recycler_view_reactions"
app:layout_constraintStart_toStartOf=
"parent"
app:layout_constraintStart_toStartOf=
"parent"
app:layout_constraintTop_toTopOf=
"parent"
/>
app:layout_constraintTop_toTopOf=
"parent"
/>
...
@@ -35,11 +36,24 @@
...
@@ -35,11 +36,24 @@
app:layout_constraintTop_toTopOf=
"parent"
app:layout_constraintTop_toTopOf=
"parent"
tools:text=
"#5571 - User profile from SSO must not have password change option"
/>
tools:text=
"#5571 - User profile from SSO must not have password change option"
/>
<TextView
android:id=
"@+id/text_fields"
android:layout_width=
"0dp"
android:layout_height=
"wrap_content"
android:visibility=
"gone"
android:layout_marginStart=
"8dp"
android:layout_marginTop=
"4dp"
app:layout_constraintTop_toBottomOf=
"@id/attachment_text"
app:layout_constraintStart_toEndOf=
"@id/quote_bar"
app:layout_constraintEnd_toEndOf=
"parent"
tools:visibility=
"visible"
tools:text=
"line1\nline2\n\nline3\nline4"
/>
<include
<include
layout=
"@layout/layout_reactions"
layout=
"@layout/layout_reactions"
android:layout_width=
"0dp"
android:layout_width=
"0dp"
android:layout_height=
"wrap_content"
android:layout_height=
"wrap_content"
app:layout_constraintStart_toStartOf=
"@id/quote_bar"
app:layout_constraintStart_toStartOf=
"@id/quote_bar"
app:layout_constraintTop_toBottomOf=
"@id/
attachment_text
"
/>
app:layout_constraintTop_toBottomOf=
"@id/
text_fields
"
/>
</androidx.constraintlayout.widget.ConstraintLayout>
</androidx.constraintlayout.widget.ConstraintLayout>
\ No newline at end of file
Write
Preview
Markdown
is supported
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