Commit 9926e3c9 authored by divyanshu's avatar divyanshu

Merge branch 'develop-2.x' into send-msg-attachments

# Conflicts:
#	app/src/main/java/chat/rocket/android/chatroom/ui/ChatRoomFragment.kt
parents fad3e0c2 4d7ea29a
...@@ -62,6 +62,7 @@ dependencies { ...@@ -62,6 +62,7 @@ dependencies {
implementation project(':player') implementation project(':player')
implementation project(':emoji') implementation project(':emoji')
implementation project(':draw')
implementation libraries.kotlin implementation libraries.kotlin
implementation libraries.coroutines implementation libraries.coroutines
......
...@@ -28,6 +28,8 @@ class ImageAttachmentViewHolder( ...@@ -28,6 +28,8 @@ class ImageAttachmentViewHolder(
}.build() }.build()
image_attachment.controller = controller image_attachment.controller = controller
file_name.text = data.attachmentTitle file_name.text = data.attachmentTitle
file_description.text = data.attachmentDescription
file_text.text = data.attachmentText
image_attachment.setOnClickListener { image_attachment.setOnClickListener {
ImageHelper.openImage( ImageHelper.openImage(
context, context,
......
...@@ -3,6 +3,7 @@ package chat.rocket.android.chatroom.domain ...@@ -3,6 +3,7 @@ package chat.rocket.android.chatroom.domain
import android.content.Context import android.content.Context
import android.net.Uri import android.net.Uri
import chat.rocket.android.util.extensions.* import chat.rocket.android.util.extensions.*
import java.io.File
import javax.inject.Inject import javax.inject.Inject
class UriInteractor @Inject constructor(private val context: Context) { class UriInteractor @Inject constructor(private val context: Context) {
...@@ -33,4 +34,9 @@ class UriInteractor @Inject constructor(private val context: Context) { ...@@ -33,4 +34,9 @@ class UriInteractor @Inject constructor(private val context: Context) {
* Note: It should be an image. * Note: It should be an image.
*/ */
fun getBitmap(uri: Uri) = uri.getBitmpap(context) fun getBitmap(uri: Uri) = uri.getBitmpap(context)
/**
* Returns the Uri from the [File].
*/
fun getUri(file: File) = Uri.fromFile(file)
} }
\ No newline at end of file
package chat.rocket.android.chatroom.presentation package chat.rocket.android.chatroom.presentation
import android.graphics.Bitmap
import android.graphics.BitmapFactory
import android.net.Uri import android.net.Uri
import android.os.Environment
import chat.rocket.android.R import chat.rocket.android.R
import chat.rocket.android.chatroom.adapter.AutoCompleteType import chat.rocket.android.chatroom.adapter.AutoCompleteType
import chat.rocket.android.chatroom.adapter.PEOPLE import chat.rocket.android.chatroom.adapter.PEOPLE
...@@ -77,6 +80,8 @@ import timber.log.Timber ...@@ -77,6 +80,8 @@ import timber.log.Timber
import java.io.ByteArrayInputStream import java.io.ByteArrayInputStream
import java.io.ByteArrayOutputStream import java.io.ByteArrayOutputStream
import java.io.InputStream import java.io.InputStream
import java.io.File
import java.io.FileOutputStream
import java.util.* import java.util.*
import javax.inject.Inject import javax.inject.Inject
...@@ -898,6 +903,12 @@ class ChatRoomPresenter @Inject constructor( ...@@ -898,6 +903,12 @@ class ChatRoomPresenter @Inject constructor(
} }
} }
fun getDrawingImageUri(byteArray: ByteArray): Uri {
val bitmap = BitmapFactory.decodeByteArray(byteArray, 0, byteArray.size)
val file = saveDrawingImage(bitmap)
return uriInteractor.getUri(file)
}
private suspend fun subscribeTypingStatus() { private suspend fun subscribeTypingStatus() {
launch(CommonPool + strategy.jobs) { launch(CommonPool + strategy.jobs) {
client.subscribeTypingStatus(chatRoomId.toString()) { _, id -> client.subscribeTypingStatus(chatRoomId.toString()) { _, id ->
...@@ -963,4 +974,17 @@ class ChatRoomPresenter @Inject constructor( ...@@ -963,4 +974,17 @@ class ChatRoomPresenter @Inject constructor(
} }
} }
} }
private fun saveDrawingImage(bitmap: Bitmap): File {
val imageDir = "${Environment.DIRECTORY_PICTURES}/Rocket.Chat Images/"
val path = Environment.getExternalStoragePublicDirectory(imageDir)
val file = File(path, UUID.randomUUID().toString()+".png")
path.mkdirs()
file.createNewFile()
val outputStream = FileOutputStream(file)
bitmap.compress(Bitmap.CompressFormat.PNG,70, outputStream)
outputStream.flush()
outputStream.close()
return file
}
} }
\ No newline at end of file
package chat.rocket.android.chatroom.ui package chat.rocket.android.chatroom.ui
import android.app.Activity import android.app.Activity
import android.app.AlertDialog
import android.content.ClipData import android.content.ClipData
import android.content.ClipboardManager import android.content.ClipboardManager
import android.content.Context import android.content.Context
...@@ -13,14 +12,10 @@ import android.text.SpannableStringBuilder ...@@ -13,14 +12,10 @@ import android.text.SpannableStringBuilder
import android.view.KeyEvent import android.view.KeyEvent
import android.view.LayoutInflater import android.view.LayoutInflater
import android.view.Menu import android.view.Menu
import android.view.MenuInflater
import android.view.MenuItem import android.view.MenuItem
import android.view.View import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
import android.widget.EditText
import android.widget.Button
import android.widget.FrameLayout
import android.widget.ImageView
import android.widget.TextView
import androidx.annotation.DrawableRes import androidx.annotation.DrawableRes
import androidx.core.text.bold import androidx.core.text.bold
import androidx.core.view.isVisible import androidx.core.view.isVisible
...@@ -61,8 +56,6 @@ import chat.rocket.android.util.extensions.rotateBy ...@@ -61,8 +56,6 @@ import chat.rocket.android.util.extensions.rotateBy
import chat.rocket.android.util.extensions.showToast import chat.rocket.android.util.extensions.showToast
import chat.rocket.android.util.extensions.textContent import chat.rocket.android.util.extensions.textContent
import chat.rocket.android.util.extensions.ui import chat.rocket.android.util.extensions.ui
import chat.rocket.android.util.extensions.getMimeType
import chat.rocket.android.util.extensions.getFileName
import chat.rocket.common.model.RoomType import chat.rocket.common.model.RoomType
import chat.rocket.common.model.roomTypeOf import chat.rocket.common.model.roomTypeOf
import chat.rocket.core.internal.realtime.socket.model.State import chat.rocket.core.internal.realtime.socket.model.State
...@@ -235,53 +228,11 @@ class ChatRoomFragment : Fragment(), ChatRoomView, EmojiKeyboardListener, EmojiR ...@@ -235,53 +228,11 @@ class ChatRoomFragment : Fragment(), ChatRoomView, EmojiKeyboardListener, EmojiR
override fun onActivityResult(requestCode: Int, resultCode: Int, resultData: Intent?) { override fun onActivityResult(requestCode: Int, resultCode: Int, resultData: Intent?) {
if (requestCode == REQUEST_CODE_FOR_PERFORM_SAF && resultCode == Activity.RESULT_OK) { if (requestCode == REQUEST_CODE_FOR_PERFORM_SAF && resultCode == Activity.RESULT_OK) {
if (resultData != null) { if (resultData != null) {
fileAttachmentDialog(resultData.data) uploadFile(resultData.data)
} }
} }
} }
private fun fileAttachmentDialog(data: Uri) {
val builder = AlertDialog.Builder(activity)
val dialogView = View.inflate(context, R.layout.file_attachments_dialog, null)
builder.setView(dialogView)
val alertDialog = builder.create()
dialogView?.let {
val imagePreview = it.findViewById<ImageView>(R.id.image_preview)
val sendButton = it.findViewById<Button>(R.id.button_send)
val cancelButton: Button = it.findViewById(R.id.button_cancel)
val description = it.findViewById<EditText>(R.id.text_file_description)
val audioVideoAttachment = it.findViewById<FrameLayout>(R.id.audio_video_attachment)
val textFile = it.findViewById<TextView>(R.id.text_file_name)
activity?.let {
data.getMimeType(it).apply {
when {
this.startsWith("image") -> {
imagePreview.isVisible = true
imagePreview.setImageURI(data)
}
this.startsWith("video") -> {
audioVideoAttachment.isVisible = true
}
else -> {
textFile.isVisible = true
textFile.text = data.getFileName(it)
}
}
}
}
sendButton.setOnClickListener {
uploadFile(data, description.text.toString())
alertDialog.dismiss()
}
cancelButton.setOnClickListener {
alertDialog.dismiss()
}
}
alertDialog.show()
}
override fun onPrepareOptionsMenu(menu: Menu) { override fun onPrepareOptionsMenu(menu: Menu) {
menu.clear() menu.clear()
if (isFavorite) { if (isFavorite) {
...@@ -526,8 +477,9 @@ class ChatRoomFragment : Fragment(), ChatRoomView, EmojiKeyboardListener, EmojiR ...@@ -526,8 +477,9 @@ class ChatRoomFragment : Fragment(), ChatRoomView, EmojiKeyboardListener, EmojiR
} }
} }
override fun uploadFile(uri: Uri, msg: String) { override fun uploadFile(uri: Uri) {
presenter.uploadFile(chatRoomId, uri, msg) // TODO Just leaving a blank message that comes with the file for now. In the future lets add the possibility to add a message with the file to be uploaded.
presenter.uploadFile(chatRoomId, uri, "")
} }
override fun showInvalidFileMessage() { override fun showInvalidFileMessage() {
......
...@@ -10,6 +10,8 @@ data class ImageAttachmentUiModel( ...@@ -10,6 +10,8 @@ data class ImageAttachmentUiModel(
override val messageId: String, override val messageId: String,
override val attachmentUrl: String, override val attachmentUrl: String,
override val attachmentTitle: CharSequence, override val attachmentTitle: CharSequence,
val attachmentText: String?,
val attachmentDescription: String?,
override val id: Long, override val id: Long,
override var reactions: List<ReactionUiModel>, override var reactions: List<ReactionUiModel>,
override var nextDownStreamMessage: BaseUiModel<*>? = null, override var nextDownStreamMessage: BaseUiModel<*>? = null,
......
...@@ -13,6 +13,7 @@ import androidx.core.text.buildSpannedString ...@@ -13,6 +13,7 @@ import androidx.core.text.buildSpannedString
import androidx.core.text.color import androidx.core.text.color
import androidx.core.text.scale import androidx.core.text.scale
import chat.rocket.android.R import chat.rocket.android.R
import chat.rocket.android.app.RocketChatApplication.Companion.context
import chat.rocket.android.chatroom.domain.MessageReply import chat.rocket.android.chatroom.domain.MessageReply
import chat.rocket.android.dagger.scope.PerFragment import chat.rocket.android.dagger.scope.PerFragment
import chat.rocket.android.helper.MessageHelper import chat.rocket.android.helper.MessageHelper
...@@ -45,6 +46,8 @@ import kotlinx.coroutines.experimental.CommonPool ...@@ -45,6 +46,8 @@ import kotlinx.coroutines.experimental.CommonPool
import kotlinx.coroutines.experimental.withContext import kotlinx.coroutines.experimental.withContext
import okhttp3.HttpUrl import okhttp3.HttpUrl
import java.security.InvalidParameterException import java.security.InvalidParameterException
import java.util.*
import java.util.Collections.emptyList
import javax.inject.Inject import javax.inject.Inject
@PerFragment @PerFragment
...@@ -285,10 +288,12 @@ class UiModelMapper @Inject constructor( ...@@ -285,10 +288,12 @@ class UiModelMapper @Inject constructor(
private fun mapFileAttachment(message: Message, attachment: FileAttachment): BaseUiModel<*>? { private fun mapFileAttachment(message: Message, attachment: FileAttachment): BaseUiModel<*>? {
val attachmentUrl = attachmentUrl(attachment) val attachmentUrl = attachmentUrl(attachment)
val attachmentTitle = attachmentTitle(attachment) val attachmentTitle = attachmentTitle(attachment)
val attachmentText = attachmentText(attachment)
val attachmentDescription = attachmentDescription(attachment)
val id = attachmentId(message, attachment) val id = attachmentId(message, attachment)
return when (attachment) { return when (attachment) {
is ImageAttachment -> ImageAttachmentUiModel(message, attachment, message.id, is ImageAttachment -> ImageAttachmentUiModel(message, attachment, message.id,
attachmentUrl, attachmentTitle, id, getReactions(message), attachmentUrl, attachmentTitle, attachmentText, attachmentDescription, id, getReactions(message),
preview = message.copy(message = context.getString(R.string.msg_preview_photo))) preview = message.copy(message = context.getString(R.string.msg_preview_photo)))
is VideoAttachment -> VideoAttachmentUiModel(message, attachment, message.id, is VideoAttachment -> VideoAttachmentUiModel(message, attachment, message.id,
attachmentUrl, attachmentTitle, id, getReactions(message), attachmentUrl, attachmentTitle, id, getReactions(message),
...@@ -338,6 +343,14 @@ class UiModelMapper @Inject constructor( ...@@ -338,6 +343,14 @@ class UiModelMapper @Inject constructor(
} }
} }
private fun attachmentText(attachment: FileAttachment): String? {
return attachment.text
}
private fun attachmentDescription(attachment: FileAttachment): String? {
return attachment.description
}
private suspend fun mapMessage(message: Message): MessageUiModel = withContext(CommonPool) { private suspend fun mapMessage(message: Message): MessageUiModel = withContext(CommonPool) {
val sender = getSenderName(message) val sender = getSenderName(message)
val time = getTime(message.timestamp) val time = getTime(message.timestamp)
......
...@@ -147,16 +147,16 @@ object ImageHelper { ...@@ -147,16 +147,16 @@ object ImageHelper {
return true return true
} }
private fun canWriteToExternalStorage(context: Context): Boolean { fun canWriteToExternalStorage(context: Context): Boolean {
return AndroidPermissionsHelper.checkPermission( return AndroidPermissionsHelper.checkPermission(
context, context,
Manifest.permission.WRITE_EXTERNAL_STORAGE Manifest.permission.WRITE_EXTERNAL_STORAGE
) )
} }
private fun checkWritingPermission(context: Context) { fun checkWritingPermission(context: Context) {
if (context is ContextThemeWrapper && context.baseContext is Activity) { if (context is ContextThemeWrapper) {
val activity = context.baseContext as Activity val activity = if (context.baseContext is Activity) context.baseContext as Activity else context as Activity
AndroidPermissionsHelper.requestPermission( AndroidPermissionsHelper.requestPermission(
activity, activity,
Manifest.permission.WRITE_EXTERNAL_STORAGE, Manifest.permission.WRITE_EXTERNAL_STORAGE,
......
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24.0"
android:viewportHeight="24.0">
<path
android:fillColor="#FF1D74F5"
android:pathData="M4.59,6.89c0.7,-0.71 1.4,-1.35 1.71,-1.22 0.5,0.2 0,1.03 -0.3,1.52 -0.25,0.42 -2.86,3.89 -2.86,6.31 0,1.28 0.48,2.34 1.34,2.98 0.75,0.56 1.74,0.73 2.64,0.46 1.07,-0.31 1.95,-1.4 3.06,-2.77 1.21,-1.49 2.83,-3.44 4.08,-3.44 1.63,0 1.65,1.01 1.76,1.79 -3.78,0.64 -5.38,3.67 -5.38,5.37 0,1.7 1.44,3.09 3.21,3.09 1.63,0 4.29,-1.33 4.69,-6.1L21,14.88v-2.5h-2.47c-0.15,-1.65 -1.09,-4.2 -4.03,-4.2 -2.25,0 -4.18,1.91 -4.94,2.84 -0.58,0.73 -2.06,2.48 -2.29,2.72 -0.25,0.3 -0.68,0.84 -1.11,0.84 -0.45,0 -0.72,-0.83 -0.36,-1.92 0.35,-1.09 1.4,-2.86 1.85,-3.52 0.78,-1.14 1.3,-1.92 1.3,-3.28C8.95,3.69 7.31,3 6.44,3 5.12,3 3.97,4 3.72,4.25c-0.36,0.36 -0.66,0.66 -0.88,0.93l1.75,1.71zM13.88,18.55c-0.31,0 -0.74,-0.26 -0.74,-0.72 0,-0.6 0.73,-2.2 2.87,-2.76 -0.3,2.69 -1.43,3.48 -2.13,3.48z"/>
</vector>
...@@ -10,6 +10,20 @@ ...@@ -10,6 +10,20 @@
android:paddingEnd="@dimen/screen_edge_left_and_right_margins" android:paddingEnd="@dimen/screen_edge_left_and_right_margins"
android:paddingStart="72dp"> android:paddingStart="72dp">
<TextView
android:id="@+id/file_name"
style="@style/Message.TextView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
tools:text="Filename.png" />
<TextView
android:id="@+id/file_description"
android:layout_width="match_parent"
android:layout_height="wrap_content"
tools:text="Some description" />
<com.facebook.drawee.view.SimpleDraweeView <com.facebook.drawee.view.SimpleDraweeView
android:id="@+id/image_attachment" android:id="@+id/image_attachment"
android:layout_width="match_parent" android:layout_width="match_parent"
...@@ -34,10 +48,10 @@ ...@@ -34,10 +48,10 @@
</FrameLayout> </FrameLayout>
<TextView <TextView
android:id="@+id/file_name" android:id="@+id/file_text"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
tools:text="Filename.png" /> tools:text="Some text" />
<include <include
layout="@layout/layout_reactions" layout="@layout/layout_reactions"
......
...@@ -15,4 +15,14 @@ ...@@ -15,4 +15,14 @@
android:gravity="start|center" android:gravity="start|center"
android:text="@string/action_files" /> android:text="@string/action_files" />
<Button
android:id="@+id/button_drawing"
style="?android:attr/borderlessButtonStyle"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:drawablePadding="20dp"
android:drawableStart="@drawable/ic_gesture_black_24dp"
android:gravity="start|center"
android:text="@string/action_drawing" />
</LinearLayout> </LinearLayout>
\ No newline at end of file
...@@ -6,5 +6,5 @@ ...@@ -6,5 +6,5 @@
android:id="@+id/action_save_image" android:id="@+id/action_save_image"
android:icon="@drawable/ic_file_download_white_24dp" android:icon="@drawable/ic_file_download_white_24dp"
android:title="@string/action_save_to_gallery" android:title="@string/action_save_to_gallery"
android:showAsAction="always" /> app:showAsAction="always" />
</menu> </menu>
\ No newline at end of file
...@@ -39,6 +39,7 @@ ...@@ -39,6 +39,7 @@
<string name="action_away">Ausente</string> <string name="action_away">Ausente</string>
<string name="action_busy">Ocupado</string> <string name="action_busy">Ocupado</string>
<string name="action_invisible">Invisible</string> <string name="action_invisible">Invisible</string>
<string name="action_drawing">Dibujo</string>
// TODO: Add proper translation. // TODO: Add proper translation.
<string name="action_save_to_gallery">Save to gallery</string> <string name="action_save_to_gallery">Save to gallery</string>
......
...@@ -39,6 +39,7 @@ ...@@ -39,6 +39,7 @@
<string name="action_away">Loin</string> <string name="action_away">Loin</string>
<string name="action_busy">Occupé</string> <string name="action_busy">Occupé</string>
<string name="action_invisible">Invisible</string> <string name="action_invisible">Invisible</string>
<string name="action_drawing">Dessin</string>
// TODO: Add proper translation. // TODO: Add proper translation.
<string name="action_save_to_gallery">Save to gallery</string> <string name="action_save_to_gallery">Save to gallery</string>
......
...@@ -40,6 +40,7 @@ ...@@ -40,6 +40,7 @@
<string name="action_busy">व्यस्त</string> <string name="action_busy">व्यस्त</string>
<string name="action_invisible">अदृश्य</string> <string name="action_invisible">अदृश्य</string>
<string name="action_save_to_gallery">गैलरी में सहेजें</string> <string name="action_save_to_gallery">गैलरी में सहेजें</string>
<string name="action_drawing">चित्रकारी</string>
<!-- Settings List --> <!-- Settings List -->
<string-array name="settings_actions"> <string-array name="settings_actions">
......
...@@ -37,6 +37,7 @@ ...@@ -37,6 +37,7 @@
<string name="action_away">Ausente</string> <string name="action_away">Ausente</string>
<string name="action_busy">Ocupado</string> <string name="action_busy">Ocupado</string>
<string name="action_invisible">Invisível</string> <string name="action_invisible">Invisível</string>
<string name="action_drawing">Desenhando</string>
<string name="action_save_to_gallery">Salvar na galeria</string> <string name="action_save_to_gallery">Salvar na galeria</string>
<!-- Settings List --> <!-- Settings List -->
......
...@@ -172,9 +172,8 @@ ...@@ -172,9 +172,8 @@
<string name="permission_starring_not_allowed">Отмечивание запрещено</string> <string name="permission_starring_not_allowed">Отмечивание запрещено</string>
<!-- Favorite/Unfavorite chat room --> <!-- Favorite/Unfavorite chat room -->
<!-- TODO Add proper translation--> <string name="title_favorite_chat">Добавить чат в избранное</string>
<string name="title_favorite_chat">Favorite chat</string> <string name="title_unfavorite_chat">Удалить чат из избранного</string>
<string name="title_unfavorite_chat">Unfavorite chat</string>
<!-- Members List --> <!-- Members List -->
<string name="title_members_list">Пользователи</string> <string name="title_members_list">Пользователи</string>
......
...@@ -38,6 +38,7 @@ ...@@ -38,6 +38,7 @@
<string name="action_away">Away</string> <string name="action_away">Away</string>
<string name="action_busy">Busy</string> <string name="action_busy">Busy</string>
<string name="action_invisible">Invisible</string> <string name="action_invisible">Invisible</string>
<string name="action_drawing">Drawing</string>
<string name="action_save_to_gallery">Save to gallery</string> <string name="action_save_to_gallery">Save to gallery</string>
<!-- Settings List --> <!-- Settings List -->
......
apply plugin: 'com.android.library'
android {
compileSdkVersion versions.compileSdk
buildToolsVersion versions.buildTools
defaultConfig {
minSdkVersion 21
targetSdkVersion versions.targetSdk
versionCode 1
versionName "1.0"
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
}
dependencies {
implementation fileTree(dir: 'libs', include: ['*.jar'])
implementation libraries.appCompat
implementation libraries.kotlin
implementation libraries.constraintlayout
implementation libraries.androidKtx
testImplementation 'junit:junit:4.12'
androidTestImplementation 'com.android.support.test:runner:1.0.2'
androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2'
}
apply plugin: 'kotlin-android'
apply plugin: 'kotlin-android-extensions'
\ 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
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="chat.rocket.android.draw">
<application>
<activity
android:name=".DrawingActivity"
android:theme="@style/Theme.AppCompat.Light.NoActionBar" />
</application>
</manifest>
\ No newline at end of file
package chat.rocket.android.draw
import android.app.Activity
import android.content.Intent
import android.content.res.Resources
import android.graphics.Bitmap
import android.os.Bundle
import android.view.View
import android.widget.SeekBar
import androidx.appcompat.app.AppCompatActivity
import androidx.core.content.res.ResourcesCompat
import androidx.core.view.isVisible
import kotlinx.android.synthetic.main.activity_drawing.*
import kotlinx.android.synthetic.main.color_palette_view.*
import java.io.ByteArrayOutputStream
class DrawingActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_drawing)
image_close_drawing.setOnClickListener {
finish()
}
image_send_drawing.setOnClickListener {
val bStream = ByteArrayOutputStream()
val bitmap = custom_draw_view.getBitmap()
bitmap.compress(Bitmap.CompressFormat.PNG, 70, bStream)
val byteArray = bStream.toByteArray()
val returnIntent = Intent()
returnIntent.putExtra("bitmap", byteArray)
setResult(Activity.RESULT_OK,returnIntent)
finish()
}
setUpDrawTools()
colorSelector()
setPaintAlpha()
setPaintWidth()
}
private fun setUpDrawTools() {
image_draw_eraser.setOnClickListener {
custom_draw_view.clearCanvas()
toggleDrawTools(draw_tools,false)
}
image_draw_width.setOnClickListener {
if (draw_tools.translationY == (56).toPx){
toggleDrawTools(draw_tools,true)
}else if (draw_tools.translationY == (0).toPx && seekBar_width.isVisible){
toggleDrawTools(draw_tools,false)
}
seekBar_width.isVisible = true
seekBar_opacity.isVisible = false
draw_color_palette.isVisible = false
}
image_draw_opacity.setOnClickListener {
if (draw_tools.translationY == (56).toPx){
toggleDrawTools(draw_tools,true)
}else if (draw_tools.translationY == (0).toPx && seekBar_opacity.isVisible){
toggleDrawTools(draw_tools,false)
}
seekBar_width.isVisible = false
seekBar_opacity.isVisible = true
draw_color_palette.isVisible = false
}
image_draw_color.setOnClickListener {
if (draw_tools.translationY == (56).toPx){
toggleDrawTools(draw_tools,true)
}else if (draw_tools.translationY == (0).toPx && draw_color_palette.isVisible){
toggleDrawTools(draw_tools,false)
}
seekBar_width.isVisible = false
seekBar_opacity.isVisible = false
draw_color_palette.isVisible = true
}
image_draw_undo.setOnClickListener {
custom_draw_view.undo()
toggleDrawTools(draw_tools,false)
}
image_draw_redo.setOnClickListener {
custom_draw_view.redo()
toggleDrawTools(draw_tools,false)
}
}
private fun toggleDrawTools(view: View, showView: Boolean = true) {
if (showView){
view.animate().translationY((0).toPx)
}else{
view.animate().translationY((56).toPx)
}
}
private fun colorSelector() {
image_color_black.setOnClickListener {
custom_draw_view.setColor(ResourcesCompat.getColor(resources, R.color.color_black,null))
scaleColorView(image_color_black)
}
image_color_red.setOnClickListener {
custom_draw_view.setColor(ResourcesCompat.getColor(resources, R.color.color_red,null))
scaleColorView(image_color_red)
}
image_color_yellow.setOnClickListener {
custom_draw_view.setColor(ResourcesCompat.getColor(resources, R.color.color_yellow,null))
scaleColorView(image_color_yellow)
}
image_color_green.setOnClickListener {
custom_draw_view.setColor(ResourcesCompat.getColor(resources, R.color.color_green,null))
scaleColorView(image_color_green)
}
image_color_blue.setOnClickListener {
custom_draw_view.setColor(ResourcesCompat.getColor(resources, R.color.color_blue,null))
scaleColorView(image_color_blue)
}
image_color_pink.setOnClickListener {
custom_draw_view.setColor(ResourcesCompat.getColor(resources, R.color.color_pink,null))
scaleColorView(image_color_pink)
}
image_color_brown.setOnClickListener {
custom_draw_view.setColor(ResourcesCompat.getColor(resources, R.color.color_brown,null))
scaleColorView(image_color_brown)
}
}
private fun scaleColorView(view: View) {
//reset scale of all views
image_color_black.scaleX = 1f
image_color_black.scaleY = 1f
image_color_red.scaleX = 1f
image_color_red.scaleY = 1f
image_color_yellow.scaleX = 1f
image_color_yellow.scaleY = 1f
image_color_green.scaleX = 1f
image_color_green.scaleY = 1f
image_color_blue.scaleX = 1f
image_color_blue.scaleY = 1f
image_color_pink.scaleX = 1f
image_color_pink.scaleY = 1f
image_color_brown.scaleX = 1f
image_color_brown.scaleY = 1f
//set scale of selected view
view.scaleX = 1.5f
view.scaleY = 1.5f
}
private fun setPaintWidth() {
seekBar_width.setOnSeekBarChangeListener(object: SeekBar.OnSeekBarChangeListener{
override fun onProgressChanged(seekBar: SeekBar?, progress: Int, fromUser: Boolean) {
custom_draw_view.setStrokeWidth(progress.toFloat())
}
override fun onStartTrackingTouch(seekBar: SeekBar?) {}
override fun onStopTrackingTouch(seekBar: SeekBar?) {}
})
}
private fun setPaintAlpha() {
seekBar_opacity.setOnSeekBarChangeListener(object: SeekBar.OnSeekBarChangeListener{
override fun onProgressChanged(seekBar: SeekBar?, progress: Int, fromUser: Boolean) {
custom_draw_view.setAlpha(progress)
}
override fun onStartTrackingTouch(seekBar: SeekBar?) {}
override fun onStopTrackingTouch(seekBar: SeekBar?) {}
})
}
private val Int.toPx: Float
get() = (this * Resources.getSystem().displayMetrics.density)
}
package chat.rocket.android.draw.widget
import android.graphics.Path
import java.io.Serializable
interface Action : Serializable {
fun perform(path: Path)
}
package chat.rocket.android.draw.widget
import android.content.Context
import android.graphics.Bitmap
import android.graphics.Canvas
import android.graphics.Color
import android.graphics.Paint
import android.util.AttributeSet
import android.view.MotionEvent
import android.view.View
import androidx.annotation.ColorInt
import androidx.core.graphics.ColorUtils
class CustomDrawView(context: Context, attrs: AttributeSet) : View(context, attrs) {
var mPaths = LinkedHashMap<MyPath, PaintOptions>()
private var mLastPaths = LinkedHashMap<MyPath, PaintOptions>()
private var mUndonePaths = LinkedHashMap<MyPath, PaintOptions>()
private var mPaint = Paint()
private var mPath = MyPath()
private var mPaintOptions = PaintOptions()
private var mCurX = 0f
private var mCurY = 0f
private var mStartX = 0f
private var mStartY = 0f
private var mIsSaving = false
private var mIsStrokeWidthBarEnabled = false
init {
mPaint.apply {
color = mPaintOptions.color
style = Paint.Style.STROKE
strokeJoin = Paint.Join.ROUND
strokeCap = Paint.Cap.ROUND
strokeWidth = mPaintOptions.strokeWidth
isAntiAlias = true
}
}
fun undo() {
if (mPaths.isEmpty() && mLastPaths.isNotEmpty()) {
mPaths = mLastPaths.clone() as LinkedHashMap<MyPath, PaintOptions>
mLastPaths.clear()
invalidate()
return
}
if (mPaths.isEmpty()) {
return
}
val lastPath = mPaths.values.lastOrNull()
val lastKey = mPaths.keys.lastOrNull()
mPaths.remove(lastKey)
if (lastPath != null && lastKey != null) {
mUndonePaths[lastKey] = lastPath
}
invalidate()
}
fun redo() {
if (mUndonePaths.keys.isEmpty()) {
return
}
val lastKey = mUndonePaths.keys.last()
addPath(lastKey, mUndonePaths.values.last())
mUndonePaths.remove(lastKey)
invalidate()
}
fun setColor(newColor: Int) {
@ColorInt
val alphaColor = ColorUtils.setAlphaComponent(newColor, mPaintOptions.alpha)
mPaintOptions.color = alphaColor
if (mIsStrokeWidthBarEnabled) {
invalidate()
}
}
fun setAlpha(newAlpha: Int) {
val alpha = (newAlpha*255)/100
mPaintOptions.alpha = alpha
setColor(mPaintOptions.color)
}
fun setStrokeWidth(newStrokeWidth: Float) {
mPaintOptions.strokeWidth = newStrokeWidth
if (mIsStrokeWidthBarEnabled) {
invalidate()
}
}
fun getBitmap(): Bitmap {
val bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888)
val canvas = Canvas(bitmap)
canvas.drawColor(Color.WHITE)
mIsSaving = true
draw(canvas)
mIsSaving = false
return bitmap
}
fun addPath(path: MyPath, options: PaintOptions) {
mPaths[path] = options
}
override fun onDraw(canvas: Canvas) {
super.onDraw(canvas)
for ((key, value) in mPaths) {
changePaint(value)
canvas.drawPath(key, mPaint)
}
changePaint(mPaintOptions)
canvas.drawPath(mPath, mPaint)
}
private fun changePaint(paintOptions: PaintOptions) {
mPaint.color = paintOptions.color
mPaint.strokeWidth = paintOptions.strokeWidth
}
fun clearCanvas() {
mLastPaths = mPaths.clone() as LinkedHashMap<MyPath, PaintOptions>
mPath.reset()
mPaths.clear()
invalidate()
}
private fun actionDown(x: Float, y: Float) {
mPath.reset()
mPath.moveTo(x, y)
mCurX = x
mCurY = y
}
private fun actionMove(x: Float, y: Float) {
mPath.quadTo(mCurX, mCurY, (x + mCurX) / 2, (y + mCurY) / 2)
mCurX = x
mCurY = y
}
private fun actionUp() {
mPath.lineTo(mCurX, mCurY)
// draw a dot on click
if (mStartX == mCurX && mStartY == mCurY) {
mPath.lineTo(mCurX, mCurY + 2)
mPath.lineTo(mCurX + 1, mCurY + 2)
mPath.lineTo(mCurX + 1, mCurY)
}
mPaths.put(mPath, mPaintOptions)
mPath = MyPath()
mPaintOptions = PaintOptions(mPaintOptions.color, mPaintOptions.strokeWidth, mPaintOptions.alpha)
}
override fun onTouchEvent(event: MotionEvent): Boolean {
val x = event.x
val y = event.y
when (event.action) {
MotionEvent.ACTION_DOWN -> {
mStartX = x
mStartY = y
actionDown(x, y)
mUndonePaths.clear()
}
MotionEvent.ACTION_MOVE -> actionMove(x, y)
MotionEvent.ACTION_UP -> actionUp()
}
invalidate()
return true
}
}
\ No newline at end of file
package chat.rocket.android.draw.widget
import android.graphics.Path
class Line(val x: Float, val y: Float) : Action {
override fun perform(path: Path) {
path.lineTo(x, y)
}
}
\ No newline at end of file
package chat.rocket.android.draw.widget
import android.graphics.Path
class Move(val x: Float, val y: Float) : Action {
override fun perform(path: Path) {
path.moveTo(x, y)
}
}
\ No newline at end of file
package chat.rocket.android.draw.widget
import android.graphics.Path
import java.io.Serializable
import java.util.*
class MyPath : Path(), Serializable {
val actions = LinkedList<Action>()
override fun reset() {
actions.clear()
super.reset()
}
override fun moveTo(x: Float, y: Float) {
actions.add(Move(x, y))
super.moveTo(x, y)
}
override fun lineTo(x: Float, y: Float) {
actions.add(Line(x, y))
super.lineTo(x, y)
}
override fun quadTo(x1: Float, y1: Float, x2: Float, y2: Float) {
actions.add(Quad(x1, y1, x2, y2))
super.quadTo(x1, y1, x2, y2)
}
}
\ No newline at end of file
package chat.rocket.android.draw.widget
import android.graphics.Color
data class PaintOptions(var color: Int = Color.BLACK, var strokeWidth: Float = 8f, var alpha: Int = 255)
package chat.rocket.android.draw.widget
import android.graphics.Path
class Quad(private val x1: Float, private val y1: Float, private val x2: Float, private val y2: Float) : Action {
override fun perform(path: Path) {
path.quadTo(x1, y1, x2, y2)
}
}
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="oval">
<solid android:color="@color/color_black" />
<corners android:radius="50dp" />
</shape>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="oval">
<solid android:color="@color/color_blue" />
<corners android:radius="50dp" />
</shape>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="oval">
<solid android:color="@color/color_brown" />
<corners android:radius="50dp" />
</shape>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="oval">
<solid android:color="@color/color_green" />
<corners android:radius="50dp" />
</shape>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="oval">
<solid android:color="@color/color_pink" />
<corners android:radius="50dp" />
</shape>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="oval">
<solid android:color="@color/color_red" />
<corners android:radius="50dp" />
</shape>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="oval">
<solid android:color="@color/color_yellow" />
<corners android:radius="50dp" />
</shape>
\ No newline at end of file
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24.0"
android:viewportHeight="24.0">
<path
android:fillColor="#FF000000"
android:pathData="M12,2C6.49,2 2,6.49 2,12s4.49,10 10,10 10,-4.49 10,-10S17.51,2 12,2zM12,20c-4.41,0 -8,-3.59 -8,-8s3.59,-8 8,-8 8,3.59 8,8 -3.59,8 -8,8zM15,12c0,1.66 -1.34,3 -3,3s-3,-1.34 -3,-3 1.34,-3 3,-3 3,1.34 3,3z"/>
</vector>
\ No newline at end of file
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24.0"
android:viewportHeight="24.0">
<path
android:fillColor="#FF000000"
android:pathData="M19,6.41L17.59,5 12,10.59 6.41,5 5,6.41 10.59,12 5,17.59 6.41,19 12,13.41 17.59,19 19,17.59 13.41,12z"/>
</vector>
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24.0"
android:viewportHeight="24.0">
<path
android:fillColor="#FF000000"
android:pathData="M12,3c-4.97,0 -9,4.03 -9,9s4.03,9 9,9c0.83,0 1.5,-0.67 1.5,-1.5 0,-0.39 -0.15,-0.74 -0.39,-1.01 -0.23,-0.26 -0.38,-0.61 -0.38,-0.99 0,-0.83 0.67,-1.5 1.5,-1.5L16,16c2.76,0 5,-2.24 5,-5 0,-4.42 -4.03,-8 -9,-8zM6.5,12c-0.83,0 -1.5,-0.67 -1.5,-1.5S5.67,9 6.5,9 8,9.67 8,10.5 7.33,12 6.5,12zM9.5,8C8.67,8 8,7.33 8,6.5S8.67,5 9.5,5s1.5,0.67 1.5,1.5S10.33,8 9.5,8zM14.5,8c-0.83,0 -1.5,-0.67 -1.5,-1.5S13.67,5 14.5,5s1.5,0.67 1.5,1.5S15.33,8 14.5,8zM17.5,12c-0.83,0 -1.5,-0.67 -1.5,-1.5S16.67,9 17.5,9s1.5,0.67 1.5,1.5 -0.67,1.5 -1.5,1.5z"/>
</vector>
\ No newline at end of file
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24.0"
android:viewportHeight="24.0">
<path
android:fillColor="#FF000000"
android:pathData="M15.14,3C14.63,3 14.12,3.2 13.73,3.59L2.59,14.73C1.81,15.5 1.81,16.77 2.59,17.56L5.03,20H12.69L21.41,11.27C22.2,10.5 22.2,9.23 21.41,8.44L16.56,3.59C16.17,3.2 15.65,3 15.14,3M17,18L15,20H22V18"/>
</vector>
\ No newline at end of file
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24.0"
android:viewportHeight="24.0">
<path
android:fillColor="#FF000000"
android:pathData="M17.66,8L12,2.35 6.34,8C4.78,9.56 4,11.64 4,13.64s0.78,4.11 2.34,5.67 3.61,2.35 5.66,2.35 4.1,-0.79 5.66,-2.35S20,15.64 20,13.64 19.22,9.56 17.66,8zM6,14c0.01,-2 0.62,-3.27 1.76,-4.4L12,5.27l4.24,4.38C17.38,10.77 17.99,12 18,14H6z"/>
</vector>
\ No newline at end of file
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24.0"
android:viewportHeight="24.0">
<path
android:fillColor="#FF000000"
android:pathData="M18.4,10.6C16.55,8.99 14.15,8 11.5,8c-4.65,0 -8.58,3.03 -9.96,7.22L3.9,16c1.05,-3.19 4.05,-5.5 7.6,-5.5 1.95,0 3.73,0.72 5.12,1.88L13,16h9V7l-3.6,3.6z"/>
</vector>
\ No newline at end of file
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24.0"
android:viewportHeight="24.0">
<path
android:fillColor="#FF000000"
android:pathData="M2.01,21L23,12 2.01,3 2,10l15,2 -15,2z"/>
</vector>
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24.0"
android:viewportHeight="24.0">
<path
android:fillColor="#FF000000"
android:pathData="M12.5,8c-2.65,0 -5.05,0.99 -6.9,2.6L2,7v9h9l-3.62,-3.62c1.39,-1.16 3.16,-1.88 5.12,-1.88 3.54,0 6.55,2.31 7.6,5.5l2.37,-0.78C21.08,11.03 17.15,8 12.5,8z"/>
</vector>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".DrawingActivity">
<chat.rocket.android.draw.widget.CustomDrawView
android:id="@+id/custom_draw_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/color_white" />
<ImageView
android:id="@+id/image_close_drawing"
android:layout_width="56dp"
android:layout_height="56dp"
android:src="@drawable/ic_close_black_24dp"
android:tint="@color/icon_color"
android:padding="16dp"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
android:background="@color/color_white"
android:foreground="?selectableItemBackgroundBorderless" />
<ImageView
android:id="@+id/image_send_drawing"
android:layout_width="56dp"
android:layout_height="56dp"
android:src="@drawable/ic_send_black_24dp"
android:padding="16dp"
android:tint="@color/colorAccent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent"
android:background="@color/color_white"
android:foreground="?selectableItemBackgroundBorderless" />
<androidx.constraintlayout.widget.ConstraintLayout
android:id="@+id/draw_tools"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
android:background="@color/color_white"
android:elevation="4dp"
android:translationY="56dp" >
<ImageView
android:id="@+id/image_draw_eraser"
android:layout_width="56dp"
android:layout_height="56dp"
android:src="@drawable/ic_eraser_black_24dp"
android:padding="16dp"
android:tint="@color/icon_color"
android:foreground="?selectableItemBackground"
app:layout_constraintHorizontal_chainStyle="packed"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toStartOf="@id/image_draw_width"
app:layout_constraintTop_toTopOf="parent"/>
<ImageView
android:id="@+id/image_draw_width"
android:layout_width="56dp"
android:layout_height="56dp"
android:src="@drawable/ic_adjust_black_24dp"
android:padding="16dp"
android:tint="@color/icon_color"
android:foreground="?selectableItemBackground"
app:layout_constraintStart_toEndOf="@id/image_draw_eraser"
app:layout_constraintEnd_toStartOf="@id/image_draw_color"
app:layout_constraintTop_toTopOf="parent"/>
<ImageView
android:id="@+id/image_draw_color"
android:layout_width="56dp"
android:layout_height="56dp"
android:src="@drawable/ic_color_lens_black_24dp"
android:padding="16dp"
android:tint="@color/icon_color"
android:foreground="?selectableItemBackground"
app:layout_constraintStart_toEndOf="@id/image_draw_width"
app:layout_constraintEnd_toStartOf="@id/image_draw_opacity"
app:layout_constraintTop_toTopOf="parent"/>
<ImageView
android:id="@+id/image_draw_opacity"
android:layout_width="56dp"
android:layout_height="56dp"
android:src="@drawable/ic_opacity_black_24dp"
android:padding="16dp"
android:tint="@color/icon_color"
android:foreground="?selectableItemBackground"
app:layout_constraintStart_toEndOf="@id/image_draw_color"
app:layout_constraintEnd_toStartOf="@id/image_draw_undo"
app:layout_constraintTop_toTopOf="parent"/>
<ImageView
android:id="@+id/image_draw_undo"
android:layout_width="56dp"
android:layout_height="56dp"
android:src="@drawable/ic_undo_black_24dp"
android:padding="16dp"
android:tint="@color/icon_color"
android:foreground="?selectableItemBackground"
app:layout_constraintStart_toEndOf="@id/image_draw_opacity"
app:layout_constraintEnd_toStartOf="@id/image_draw_redo"
app:layout_constraintTop_toTopOf="parent" />
<ImageView
android:id="@+id/image_draw_redo"
android:layout_width="56dp"
android:layout_height="56dp"
android:src="@drawable/ic_redo_black_24dp"
android:padding="16dp"
android:tint="@color/icon_color"
android:foreground="?selectableItemBackground"
app:layout_constraintStart_toEndOf="@id/image_draw_undo"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<SeekBar
android:id="@+id/seekBar_width"
android:layout_width="0dp"
android:layout_height="56dp"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toBottomOf="@id/image_draw_eraser"
android:progressTint="@color/colorAccent"
android:thumbTint="@color/colorAccent"
android:progress="8"
android:paddingStart="16dp"
android:paddingEnd="16dp" />
<SeekBar
android:id="@+id/seekBar_opacity"
android:layout_width="0dp"
android:layout_height="56dp"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toBottomOf="@id/image_draw_eraser"
android:progress="100"
android:progressTint="@color/colorAccent"
android:thumbTint="@color/colorAccent"
android:paddingStart="16dp"
android:paddingEnd="16dp" />
<include
android:id="@+id/draw_color_palette"
layout="@layout/color_palette_view"
android:layout_width="0dp"
android:layout_height="56dp"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toBottomOf="@id/image_draw_eraser" />
</androidx.constraintlayout.widget.ConstraintLayout>
</androidx.constraintlayout.widget.ConstraintLayout>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="56dp"
android:orientation="horizontal">
<ImageView
android:id="@+id/image_color_black"
android:layout_width="48dp"
android:layout_height="match_parent"
android:src="@drawable/circle_black"
android:paddingTop="16dp"
android:paddingBottom="16dp"
android:paddingStart="12dp"
android:paddingEnd="12dp"
android:scaleY="1.5"
android:scaleX="1.5"/>
<ImageView
android:id="@+id/image_color_red"
android:layout_width="48dp"
android:layout_height="match_parent"
android:src="@drawable/circle_red"
android:paddingTop="16dp"
android:paddingBottom="16dp"
android:paddingStart="12dp"
android:paddingEnd="12dp" />
<ImageView
android:id="@+id/image_color_yellow"
android:layout_width="48dp"
android:layout_height="match_parent"
android:src="@drawable/circle_yellow"
android:paddingTop="16dp"
android:paddingBottom="16dp"
android:paddingStart="12dp"
android:paddingEnd="12dp" />
<ImageView
android:id="@+id/image_color_green"
android:layout_width="48dp"
android:layout_height="match_parent"
android:src="@drawable/circle_green"
android:paddingTop="16dp"
android:paddingBottom="16dp"
android:paddingStart="12dp"
android:paddingEnd="12dp" />
<ImageView
android:id="@+id/image_color_blue"
android:layout_width="48dp"
android:layout_height="match_parent"
android:src="@drawable/circle_blue"
android:paddingTop="16dp"
android:paddingBottom="16dp"
android:paddingStart="12dp"
android:paddingEnd="12dp" />
<ImageView
android:id="@+id/image_color_pink"
android:layout_width="48dp"
android:layout_height="match_parent"
android:src="@drawable/circle_pink"
android:paddingTop="16dp"
android:paddingBottom="16dp"
android:paddingStart="12dp"
android:paddingEnd="12dp" />
<ImageView
android:id="@+id/image_color_brown"
android:layout_width="48dp"
android:layout_height="match_parent"
android:src="@drawable/circle_brown"
android:paddingTop="16dp"
android:paddingBottom="16dp"
android:paddingStart="12dp"
android:paddingEnd="12dp" />
</LinearLayout>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<resources>
<color name="colorAccent">#FF1976D2</color>
<color name="icon_color">#C2C2C2</color>
<color name="color_white">#FFFFFF</color>
<color name="color_black">#000</color>
<color name="color_red">#FF5252</color>
<color name="color_yellow">#FFEB3B</color>
<color name="color_green">#00C853</color>
<color name="color_blue">#00B0FF</color>
<color name="color_pink">#D500F9</color>
<color name="color_brown">#8D6E63</color>
</resources>
\ No newline at end of file
<resources>
<string name="app_name">Draw</string>
</resources>
include ':app', ':player', ':emoji' //, ':wear' include ':app', ':player', ':emoji', ':draw' //, ':wear'
\ No newline at end of file \ No newline at end of file
Markdown is supported
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