Untitled

mail@pastecode.io avatar
unknown
plain_text
a year ago
23 kB
3
Indexable
Never
//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)
//    }

}