Untitled
unknown
plain_text
2 years ago
23 kB
10
Indexable
//Drawing Activity
package learning.android.simpledrawingapp
import android.Manifest
import android.app.AlertDialog
import android.app.Dialog
import android.content.ContentValues.TAG
import android.content.Intent
import android.content.pm.PackageManager
import android.graphics.Bitmap
import android.graphics.Canvas
import android.graphics.Color
import android.media.MediaScannerConnection
import android.media.MediaScannerConnection.OnScanCompletedListener
import android.net.Uri
import android.os.Bundle
import android.os.Environment
import android.provider.MediaStore
import android.util.Log
import android.view.View
import android.widget.FrameLayout
import android.widget.ImageButton
import android.widget.ImageView
import android.widget.LinearLayout
import android.widget.SeekBar
import android.widget.Toast
import androidx.activity.result.ActivityResultLauncher
import androidx.activity.result.contract.ActivityResultContracts
import androidx.appcompat.app.AppCompatActivity
import androidx.core.app.ActivityCompat
import androidx.core.content.ContextCompat
import androidx.core.view.get
import androidx.lifecycle.lifecycleScope
import com.karumi.dexter.Dexter
import com.karumi.dexter.MultiplePermissionsReport
import com.karumi.dexter.PermissionToken
import com.karumi.dexter.listener.PermissionRequest
import com.karumi.dexter.listener.multi.MultiplePermissionsListener
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import java.io.ByteArrayOutputStream
import java.io.File
import java.io.FileOutputStream
import java.io.IOException
class DrawingActivity : AppCompatActivity() {
private var drawingView: DrawingView? = null
private var mImageButtonCurrentPaint: ImageButton? = null
private var customProgressDialog: Dialog? = null
private var defaultColor : Int = Color.BLACK
private var fileName: String = ""
val path: File = File(Environment.getExternalStorageDirectory().absolutePath + "/myPaintings")
private val openGalleryLauncher: ActivityResultLauncher<Intent> =
registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { result ->
if (result.resultCode == RESULT_OK && result.data != null) {
val imageBackground: ImageView = findViewById(R.id.iv_background)
imageBackground.setImageURI(result.data?.data)
}
}
private var isOpenGallery: Boolean = false
private val requestPermission: ActivityResultLauncher<Array<String>> = registerForActivityResult(
ActivityResultContracts.RequestMultiplePermissions()
) { permissions ->
permissions.entries.forEach {
val permissionName = it.key
val isGranted = it.value
if (isGranted) {
val pickIntent =
Intent(Intent.ACTION_PICK, MediaStore.Images.Media.EXTERNAL_CONTENT_URI)
if (!isOpenGallery) {
Toast.makeText(
this@DrawingActivity,
"Permission granted now you can read the storage files.",
Toast.LENGTH_LONG
).show()
openGalleryLauncher.launch(pickIntent)
isOpenGallery = true
}
} else {
if (permissionName == Manifest.permission.READ_EXTERNAL_STORAGE)
Toast.makeText(
this@DrawingActivity,
"You just denied the permission.",
Toast.LENGTH_LONG
).show()
}
}
isOpenGallery = false
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_drawing);
//Print Log
Log.i(TAG, "onCreate");
drawingView = findViewById(R.id.drawing_view)
drawingView?.setSizeForBrush(20.toFloat())
val linearLayoutPaintColor = findViewById<LinearLayout>(R.id.ll_paint_colors)
mImageButtonCurrentPaint = linearLayoutPaintColor[0] as ImageButton
mImageButtonCurrentPaint!!.setImageDrawable(
ContextCompat.getDrawable(this, R.drawable.pallet_pressed)
)
val sbBrushSizeSeekBar: SeekBar = findViewById(R.id.sbBrushSizeSeekBar)
var isSeekBarVisible = false;
val ibBrush: ImageButton = findViewById(R.id.ib_brush)
ibBrush.setOnClickListener {
isSeekBarVisible = !isSeekBarVisible
sbBrushSizeSeekBar.visibility = if(isSeekBarVisible) View.VISIBLE else View.GONE
}
sbBrushSizeSeekBar.setOnSeekBarChangeListener(object : SeekBar.OnSeekBarChangeListener{
override fun onProgressChanged(seekBar: SeekBar, progress: Int, fromUser: Boolean) {
drawingView?.setSizeForBrush(progress.toFloat())
}
override fun onStartTrackingTouch(seekBar: SeekBar?) {
}
override fun onStopTrackingTouch(seekBar: SeekBar?) {
}
})
val ibRedo: ImageButton = findViewById(R.id.ib_redo)
ibRedo.setOnClickListener {
drawingView?.onClickRedo()
}
val ibUndo: ImageButton = findViewById(R.id.ib_undo)
ibUndo.setOnClickListener {
drawingView?.onClickUndo()
}
val ibSave: ImageButton = findViewById(R.id.ib_save)
ibSave.setOnClickListener {
if (isReadStorageAllowed()) {
showProgressDialog()
lifecycleScope.launch {
val flDrawingView: FrameLayout = findViewById(R.id.fl_drawing_view_container)
val myBitmap: Bitmap = getBitmapFromView(flDrawingView)
saveBitmapFile(myBitmap)
cancelProgressDialog()
}
}
}
val ibGallery: ImageButton = findViewById(R.id.ib_gallery)
ibGallery.setOnClickListener {
requestStoragePermission()
}
//askPermission();
}
private fun askPermission() {
Dexter.withContext(this)
.withPermissions(Manifest.permission.READ_EXTERNAL_STORAGE, Manifest.permission.WRITE_EXTERNAL_STORAGE)
.withListener(object : MultiplePermissionsListener{
override fun onPermissionsChecked(p0: MultiplePermissionsReport?) {
Toast.makeText(this@DrawingActivity, "Granted", Toast.LENGTH_LONG).show()
}
override fun onPermissionRationaleShouldBeShown(
permissions: MutableList<PermissionRequest>?,
token: PermissionToken
) {
token.continuePermissionRequest()
}
}).check()
}
fun paintClicked(view: View) {
//Toast.makeText(this, "clicked paint", Toast.LENGTH_LONG).show()
if (view != mImageButtonCurrentPaint) {
val imageButton = view as ImageButton
val colorTag = imageButton.tag.toString()
if(colorTag != "color_picker")
drawingView?.setColor(colorTag)
else{
//openColorPicker()
}
imageButton.setImageDrawable(
ContextCompat.getDrawable(this, R.drawable.pallet_pressed)
)
mImageButtonCurrentPaint!!.setImageDrawable(
ContextCompat.getDrawable(this, R.drawable.pallet_normal)
)
mImageButtonCurrentPaint = view
}
}
fun colorPicker(view: View){
val colorPickerDialog = ColorPickerDialog(this@DrawingActivity)
colorPickerDialog.setColorSelectedListener(object: ColorPickerDialog.OnColorSelectedListener{
override fun onColorSelected(color: Int) {
val colorString: String = String.format("#%06X", 0xFFFFFF and color)
drawingView?.setColor(colorString)
}
})
colorPickerDialog.show()
}
// fun colorPickerClicked(view: View){
// mImageButtonCurrentPaint!!.setImageDrawable(
// ContextCompat.getDrawable(this, R.drawable.pallet_normal)
// )
// openColorPicker();
// }
//
// private fun openColorPicker() {
// val ambilwarnaDialog : AmbilWarnaDialog = AmbilWarnaDialog(this, defaultColor, object : AmbilWarnaDialog.OnAmbilWarnaListener{
// override fun onCancel(dialog: AmbilWarnaDialog?) {
// TODO("Not yet implemented")
// }
//
// override fun onOk(dialog: AmbilWarnaDialog?, color: Int) {
// val colorString: String = String.format("#%06X", 0xFFFFFF and color)
// Log.d("Drawing Activity", "$colorString")
// drawingView?.setColor(colorString)
// }
// })
//
// ambilwarnaDialog.show()
// }
private fun isReadStorageAllowed(): Boolean {
val result =
ContextCompat.checkSelfPermission(this, Manifest.permission.READ_EXTERNAL_STORAGE)
return result == PackageManager.PERMISSION_GRANTED
}
private fun requestStoragePermission() {
if (ActivityCompat.shouldShowRequestPermissionRationale(
this,
Manifest.permission.READ_EXTERNAL_STORAGE
)
) {
showRationalDialog(
"Sample Drawing App",
"Sample Drawing App" + "needs to Access Your External Storage."
)
} else {
requestPermission.launch(
arrayOf(
Manifest.permission.READ_EXTERNAL_STORAGE,
Manifest.permission.WRITE_EXTERNAL_STORAGE
)
)
}
}
private fun showRationalDialog(title: String, message: String) {
val builder: AlertDialog.Builder = AlertDialog.Builder(this)
builder.setTitle(title).setMessage(message).setPositiveButton("Cancel") { dialog, _ ->
dialog.dismiss()
}
builder.create().show()
}
private fun getBitmapFromView(view: View): Bitmap {
val returnedBitmap = Bitmap.createBitmap(view.width, view.height, Bitmap.Config.ARGB_8888)
val canvas = Canvas(returnedBitmap)
val bgDrawable = view.background
if (bgDrawable != null) {
bgDrawable.draw(canvas)
} else
canvas.drawColor(Color.WHITE)
view.draw(canvas)
return returnedBitmap
}
private fun saveBitmapFile(bitmap: Bitmap): Boolean {
val directoryName = Environment.DIRECTORY_DCIM
val fileName = "DrawingApp_" + System.currentTimeMillis() / 1000 + ".png"
val directory = Environment.getExternalStoragePublicDirectory(directoryName)
if(!directory.exists()){
directory.mkdir()
}
val file = File(directory, fileName)
var outputStream : FileOutputStream? = null
try{
outputStream = FileOutputStream(file)
bitmap.compress(Bitmap.CompressFormat.PNG, 100, outputStream)
return true
}catch (e: IOException){
e.printStackTrace()
Log.e("Drawing", "Directory "+e.message)
}finally {
MediaScannerConnection.scanFile(this@DrawingActivity, arrayOf(file.absolutePath), arrayOf("image/*")
) { path, _ -> Log.d(TAG, "onScanCompleted: $path") }
try{
Toast.makeText(this@DrawingActivity, "File saved successfully: $file", Toast.LENGTH_LONG).show()
outputStream?.close()
}catch (e: IOException){
e.printStackTrace()
}
}
return false
}
private fun showProgressDialog() {
customProgressDialog = Dialog(this@DrawingActivity)
customProgressDialog?.setContentView(R.layout.dialog_custom_progress)
customProgressDialog?.show()
}
private fun cancelProgressDialog() {
if (customProgressDialog != null) {
customProgressDialog?.dismiss()
customProgressDialog = null
}
}
}
//DrawingView
package learning.android.simpledrawingapp
import android.content.ContentValues.TAG
import android.content.Context
import android.graphics.Bitmap
import android.graphics.*
import android.util.AttributeSet
import android.util.Log
import android.util.TypedValue
import android.view.MotionEvent
import android.view.View
class DrawingView(context: Context, attrs: AttributeSet) : View(context, attrs){
private var mDrawPath: CustomPath? = null
private var mCanvasBitmap: Bitmap? = null
private var mDrawPaint: Paint? = null
private var mCanvasPaint: Paint? = null
private var mBrushSize: Float = 0.toFloat()
private var color = Color.BLACK
private var canvas: Canvas? = null
private var mPaths = ArrayList<CustomPath>()
private var mUndoPaths = ArrayList<CustomPath>()
init{
setUpDrawing()
}
fun onClickUndo(){
if(mPaths.size > 0){
mUndoPaths.add(mPaths.removeAt(mPaths.size - 1))
invalidate()
}
}
fun onClickRedo(){
if(mUndoPaths.size>0){
mPaths.add(mUndoPaths.removeAt(mUndoPaths.size-1))
invalidate()
}
}
private fun setUpDrawing(){
mDrawPaint = Paint()
mDrawPath = CustomPath(color, mBrushSize)
mDrawPaint!!.color = color
mDrawPaint!!.style = Paint.Style.STROKE
mDrawPaint!!.strokeJoin = Paint.Join.ROUND
mDrawPaint!!.strokeCap = Paint.Cap.ROUND
mCanvasPaint = Paint(Paint.DITHER_FLAG)
//mBrushSize = 20.toFloat()
}
override fun onSizeChanged(w: Int, h: Int, oldw: Int, oldh: Int) {
super.onSizeChanged(w, h, oldw, oldh)
mCanvasBitmap = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888)
canvas = Canvas(mCanvasBitmap!!)
}
//Change Canvas to Canvas? if fails
override fun onDraw(canvas: Canvas) {
super.onDraw(canvas)
canvas.drawBitmap(mCanvasBitmap!!, 0f, 0f, mCanvasPaint)
Log.e(TAG, "onDraw")
//luu lai draw path sau khi MotionEvent.ACTION_UP
for(path in mPaths){
mDrawPaint!!.strokeWidth = path.brushThickness
mDrawPaint!!.color = path.color
canvas.drawPath(path, mDrawPaint!!)
}
if(!mDrawPath!!.isEmpty) {
mDrawPaint!!.strokeWidth = mDrawPath!!.brushThickness
mDrawPaint!!.color = mDrawPath!!.color
canvas.drawPath(mDrawPath!!, mDrawPaint!!)
}
}
override fun onTouchEvent(event: MotionEvent?): Boolean {
val touchX = event?.x
val touchY = event?.y
when(event?.action){
MotionEvent.ACTION_DOWN->{
mDrawPath!!.color = color
mDrawPath!!.brushThickness = mBrushSize
mDrawPath!!.reset()
if (touchX != null) {
if (touchY != null) {
mDrawPath!!.moveTo(touchX, touchY)
}
}
}
MotionEvent.ACTION_MOVE ->{
if (touchX != null) {
if (touchY != null) {
mDrawPath!!.lineTo(touchX, touchY)
}
}
}
MotionEvent.ACTION_UP ->{
mPaths.add(mDrawPath!!)
mDrawPath = CustomPath(color, mBrushSize)
}
else -> return false
}
invalidate()
return true
}
fun setSizeForBrush(newSize: Float){
mBrushSize = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, newSize, resources.displayMetrics)
mDrawPaint!!.strokeWidth = mBrushSize
}
fun setColor(newColor: String){
color = Color.parseColor(newColor)
//mDrawPaint!!.color = color
}
internal inner class CustomPath(var color: Int, var brushThickness: Float) : Path(){
}
// fun destroy(){
// mPaths.clear()
// mUndoPaths.clear()
// }
}
////SplashActivity
package learning.android.simpledrawingapp
import android.content.Intent
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import androidx.lifecycle.lifecycleScope
import kotlinx.coroutines.delay
import kotlinx.coroutines.launch
class SplashActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_splash)
lifecycleScope.launch {
delay(1000)
val intent: Intent = Intent(this@SplashActivity, DrawingActivity::class.java)
startActivity(intent)
finish()
}
}
}
//ColorPickerDialog
package learning.android.simpledrawingapp
import android.app.Dialog
import android.content.Context
import android.graphics.Color
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.view.Window
import android.widget.Button
import android.widget.SeekBar
class ColorPickerDialog(context: Context) : Dialog(context){
private var selectColor: Int = Color.BLACK
private var colorSelectedListener: OnColorSelectedListener? = null
private lateinit var colorPreview: View
private lateinit var redSeekbar: SeekBar
private lateinit var greenSeekbar: SeekBar
private lateinit var blueSeekbar: SeekBar
private lateinit var btnCancel: Button
private lateinit var btnSelect: Button
override fun onCreate(saveInstanceState: Bundle?) {
super.onCreate(saveInstanceState)
requestWindowFeature(Window.FEATURE_NO_TITLE)
setContentView(R.layout.dialog_color_picker)
//window?.setLayout(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT)
colorPreview = findViewById(R.id.color_preview)
redSeekbar = findViewById(R.id.seekbar_red)
greenSeekbar = findViewById(R.id.seekbar_green)
blueSeekbar = findViewById(R.id.seekbar_blue)
btnCancel = findViewById(R.id.btn_cancel)
btnSelect = findViewById(R.id.btn_select)
btnSelect.setOnClickListener {
colorSelectedListener?.onColorSelected(selectColor)
dismiss()
}
btnCancel.setOnClickListener{
dismiss()
}
//redSeekbar.setOnSeekBarChangeListener(createSeekbarChangeListener())
}
private fun updateColorPreview(){
colorPreview.setBackgroundColor(selectColor)
}
fun setColorSelectedListener(listener: OnColorSelectedListener){
colorSelectedListener = listener
}
interface OnColorSelectedListener{
fun onColorSelected(color: Int)
}
private fun createSeekbarChangeListener(): SeekBar.OnSeekBarChangeListener{
return object: SeekBar.OnSeekBarChangeListener{
override fun onProgressChanged(seekBar: SeekBar?, progress: Int, fromUser: Boolean) {
if(seekBar == redSeekbar){
selectColor = Color.rgb(progress, Color.green(selectColor), Color.blue(selectColor))
}
else if(seekBar == greenSeekbar){
selectColor = Color.rgb(Color.red(selectColor), progress, Color.blue(selectColor))
}
else if(seekBar == blueSeekbar){
selectColor = Color.rgb(Color.red(selectColor), Color.green(selectColor), progress)
}
updateColorPreview()
}
override fun onStartTrackingTouch(seekBar: SeekBar?) {
TODO("Not yet implemented")
}
override fun onStopTrackingTouch(seekBar: SeekBar?) {
TODO("Not yet implemented")
}
}
}
// init{
// requestWindowFeature(Window.FEATURE_NO_TITLE)
// setContentView(R.layout.dialog_color_picker)
//
// val colorPreview = findViewById<View>(R.id.color_preview)
// val redSeekbar = findViewById<SeekBar>(R.id.seekbar_red)
// val greenSeekbar = findViewById<SeekBar>(R.id.seekbar_green)
// val blueSeekBar = findViewById<SeekBar>(R.id.seekbar_blue)
//
// val btnCancel = findViewById<Button>(R.id.btn_cancel)
// val btnSelect = findViewById<Button>(R.id.btn_select)
//
// redSeekbar.progress = 0
// greenSeekbar.progress = 0
// blueSeekBar.progress = 0
//
// redSeekbar.setOnSeekBarChangeListener(object: SeekBar.OnSeekBarChangeListener{
// override fun onProgressChanged(seekBar: SeekBar?, progress: Int, fromUser: Boolean) {
// updateColorPreview(colorPreview, redSeekbar.progress, greenSeekbar.progress, blueSeekBar.progress)
// }
//
// override fun onStartTrackingTouch(seekBar: SeekBar?) {
// TODO("Not yet implemented")
// }
//
// override fun onStopTrackingTouch(seekBar: SeekBar?) {
// TODO("Not yet implemented")
// }
// })
//
// greenSeekbar.setOnSeekBarChangeListener(object: SeekBar.OnSeekBarChangeListener{
// override fun onProgressChanged(seekBar: SeekBar?, progress: Int, fromUser: Boolean) {
// updateColorPreview(colorPreview, redSeekbar.progress, greenSeekbar.progress, blueSeekBar.progress)
// }
//
// override fun onStartTrackingTouch(seekBar: SeekBar?) {
// TODO("Not yet implemented")
// }
//
// override fun onStopTrackingTouch(seekBar: SeekBar?) {
// TODO("Not yet implemented")
// }
// })
//
// blueSeekBar.setOnSeekBarChangeListener(object: SeekBar.OnSeekBarChangeListener{
// override fun onProgressChanged(seekBar: SeekBar?, progress: Int, fromUser: Boolean) {
// updateColorPreview(colorPreview, redSeekbar.progress, greenSeekbar.progress, blueSeekBar.progress)
// }
//
// override fun onStartTrackingTouch(seekBar: SeekBar?) {
// TODO("Not yet implemented")
// }
//
// override fun onStopTrackingTouch(seekBar: SeekBar?) {
// TODO("Not yet implemented")
// }
// })
//
// btnCancel.setOnClickListener{
// dismiss()
// }
//
// btnSelect.setOnClickListener {
// colorSelectedListener?.onColorSelected(selectColor)
// dismiss()
// }
//
// updateColorPreview(colorPreview, redSeekbar.progress, greenSeekbar.progress, blueSeekBar.progress)
// }
}
Editor is loading...