<file_sep># sketch-app
Paint style application for Android. 
<file_sep>package com.just.sketchapp

import android.app.Application
import com.just.sketchapp.dialog.BitmapExportManager
import com.just.sketchapp.dialog.ColorPickerManager
import com.just.sketchapp.ui.ViewModelFactory
import com.todo.shakeit.core.ShakeIt
import org.kodein.di.Kodein
import org.kodein.di.KodeinAware
import org.kodein.di.android.x.androidXModule
import org.kodein.di.generic.bind
import org.kodein.di.generic.instance
import org.kodein.di.generic.provider
import org.kodein.di.generic.singleton

class SketchApp: Application(), KodeinAware {
    override val kodein = Kodein.lazy {
        import(androidXModule(this@SketchApp))
        bind () from provider { ViewModelFactory() }
        bind() from singleton { ColorPickerManager() }
        bind() from singleton { BitmapExportManager() }

    }

    override fun onCreate() {
        super.onCreate()
        ShakeIt.init(this)
    }
}
<file_sep>package com.just.sketchapp.ui

import android.Manifest
import android.content.Context
import android.content.DialogInterface
import android.content.pm.PackageManager
import android.graphics.Bitmap
import android.graphics.Canvas
import android.hardware.Sensor
import android.hardware.SensorEventListener
import android.hardware.SensorListener
import android.hardware.SensorManager
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.util.Log
import android.widget.ImageButton
import androidx.databinding.DataBindingUtil
import androidx.lifecycle.ViewModelProviders
import com.just.sketchapp.databinding.ActivityMainBinding
import org.kodein.di.KodeinAware
import org.kodein.di.android.kodein
import org.kodein.di.generic.instance
import android.util.DisplayMetrics
import android.view.View
import android.widget.Toast
import androidx.appcompat.app.AlertDialog
import androidx.core.app.ActivityCompat
import androidx.core.content.ContextCompat
import androidx.databinding.library.baseAdapters.BR
import com.just.sketchapp.R
import com.just.sketchapp.dialog.BitmapExportManager
import com.just.sketchapp.dialog.ColorPickerManager
import com.todo.shakeit.core.ShakeDetector
import com.todo.shakeit.core.ShakeListener
import kotlinx.android.synthetic.main.activity_main.*


private const val MY_PERMISSION_WRITE_EXTERNAL_STORAGE = 1


class MainActivity : AppCompatActivity(), KodeinAware,  ShakeListener {


    override val kodein by kodein()
    private val viewModelFactory: ViewModelFactory by instance()
    private lateinit var mainViewModel: MainViewModel
    private val colorPickerManager: ColorPickerManager by instance()
    private val bitmapExportManager: BitmapExportManager by instance()
    private lateinit var dialog: AlertDialog

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        //init viewmodel and data binding
        mainViewModel = ViewModelProviders.of(this, viewModelFactory).get(MainViewModel::class.java)
        DataBindingUtil.setContentView<ActivityMainBinding>(
            this, R.layout.activity_main
        ).apply {
            this.lifecycleOwner = this@MainActivity
            this.viewModel = mainViewModel
            this.setVariable(BR.viewModel, mainViewModel)
            this.executePendingBindings()
        }

        //init button listener
        val colorButton = findViewById<ImageButton>(R.id.color)
        colorButton?.setOnClickListener {
            colorPickerManager.showColorPicker(this) {
                mainViewModel.setColor(it)
            }
        }
        val cancelButton = findViewById<ImageButton>(R.id.cancel)
        cancelButton?.setOnClickListener {
            mainViewModel.clearPaths()
        }
        val downloadButton = findViewById<ImageButton>(R.id.download)
        downloadButton?.setOnClickListener {
            val pics = findViewById<CanvasView>(R.id.canvasView)
            requestWritePermission() // need to refactor requests
            if (hasFilePermission()) {
                if(bitmapExportManager.saveBitmap(this, canvasView))
                    Toast.makeText(this, "Saved successfully", Toast.LENGTH_SHORT).show()
            }
        }


    }

    private fun requestWritePermission() {
        ActivityCompat.requestPermissions(
            this,
            arrayOf(Manifest.permission.READ_EXTERNAL_STORAGE),
            1
        )
    }

    private fun hasFilePermission(): Boolean {
        return ContextCompat.checkSelfPermission(
            this,
            Manifest.permission.WRITE_EXTERNAL_STORAGE
        ) == PackageManager.PERMISSION_GRANTED
    }


    override fun onShake() {
        ShakeDetector.unRegisterForShakeEvent(this)
        showDialog()
    }

    private fun showDialog() {
        // Initialize a new instance of alert dialog builder object
        var builder = AlertDialog.Builder(this).setMessage("Are you sure you want to delete your work permamently? ")

        val dialogClickListener = DialogInterface.OnClickListener { _, which ->
            when (which) {
               DialogInterface.BUTTON_POSITIVE -> {mainViewModel.clearPaths()
                ShakeDetector.registerForShakeEvent(this)}
                DialogInterface.BUTTON_NEUTRAL -> ShakeDetector.registerForShakeEvent(this)
            }
        }
        builder.setPositiveButton("YES", dialogClickListener)
        builder.setNeutralButton("CANCEL", dialogClickListener)
        dialog = builder.create()
        dialog.show()
    }

    override fun onPause() {
        ShakeDetector.unRegisterForShakeEvent(this)
        super.onPause()
    }

    override fun onResume() {
        ShakeDetector.registerForShakeEvent(this)
        super.onResume()
    }
}
<file_sep>package com.just.sketchapp.dialog

import android.content.Context
import android.content.DialogInterface
import com.just.sketchapp.R
import com.skydoves.colorpickerview.ColorEnvelope
import com.skydoves.colorpickerview.ColorPickerDialog
import com.skydoves.colorpickerview.listeners.ColorEnvelopeListener

class ColorPickerManager {

    fun showColorPicker(context: Context, onConfirmButton: (Int) -> Unit) {

        ColorPickerDialog.Builder(context, R.style.Theme_AppCompat_Dialog_Alert)
            .setTitle("Choose your brush color")
            .setPositiveButton("ok", object: ColorEnvelopeListener{
                override fun onColorSelected(envelope: ColorEnvelope?, fromUser: Boolean) {
                    onConfirmButton(envelope!!.color)
                }
            })
            .setNegativeButton("cancel", object: DialogInterface.OnClickListener{
                override fun onClick(dialog: DialogInterface?, which: Int) {
                    dialog?.dismiss()
                }
            })
            .setPreferenceName("MyColorPicker")
            .show()
    }

}<file_sep>package com.just.sketchapp.ui

import androidx.lifecycle.ViewModel
import androidx.lifecycle.ViewModelProvider

class ViewModelFactory : ViewModelProvider.NewInstanceFactory(){

}<file_sep>package com.just.sketchapp.data

import android.graphics.Path

data class FingerPath(val color:Int, val brushSize: Int, val path: Path)
<file_sep>package com.just.sketchapp.ui

import android.content.Context
import android.graphics.*
import android.view.View
import android.util.AttributeSet
import android.view.MotionEvent
import com.just.sketchapp.data.FingerPath
import kotlin.math.absoluteValue
import android.graphics.Bitmap
import androidx.annotation.ColorInt


class CanvasView(context: Context, attr: AttributeSet?): View(context, attr){

    private var brushSize: Int = 0
    private var brushColor : Int  = Color.WHITE
    private val backgroundColor: Int = Color.WHITE
    private val touchTolerance:Float = 4.0f
    private var mX :Float? = null
    private var mY :Float? = null
    private var paths  = mutableListOf<FingerPath>()
    private lateinit var path: Path
    private var paint: Paint
    private lateinit var bitmap: Bitmap
    private val mCanvas: Canvas
    private var bitmapPaint: Paint = Paint(Paint.DITHER_FLAG)



    fun setColor(@ColorInt color: Int) {
        brushColor = color
        paint.color = brushColor

    }

    fun setSize(size: Int) {
        brushSize = size
    }

    fun setPaths(path: MutableList<FingerPath>) {
        paths = path
        invalidate()
    }



    init{

        paint= Paint()
        paint.isAntiAlias = true
        paint.isDither = true
        paint.color = brushColor
        paint.style = Paint.Style.STROKE
        paint.strokeJoin = Paint.Join.ROUND
        paint.strokeCap = Paint.Cap.ROUND
        paint.xfermode = null
        paint.alpha = 0xff

        bitmap = Bitmap.createBitmap(context.resources.displayMetrics.widthPixels, context.resources.displayMetrics.heightPixels, Bitmap.Config.ARGB_8888)
        mCanvas = Canvas(bitmap)

    }


    private fun touchStart(x: Float, y: Float){
        path = Path()
        val fp = FingerPath(brushColor, brushSize, path)
        paths.add(fp)
        path.reset()
        path.moveTo(x,y)
        mX = x
        mY = y
    }

    private fun touchMove(x: Float, y:Float) {
        (mX != null && mY != null).let {
            val dx = (x - mX!!).absoluteValue
            val dy = (y - mY!!).absoluteValue

            if (dx >= touchTolerance && dy >= touchTolerance) {
                path.quadTo(mX!!, mY!!, (x + mX!!) / 2, (y + mY!!) / 2)
                mX = x
                mY = y
            }
        }
    }

    private fun touchUp(){
        (mX != null && mY != null ).let {
            path.lineTo(mX!!, mY!!)
        }
    }


    override fun onDraw(canvas: Canvas) {
        canvas.save()
        mCanvas.drawColor(backgroundColor)

        paths.forEach {
            paint.color = it.color
            paint.strokeWidth = it.brushSize.toFloat()
            paint.maskFilter = null

            mCanvas.drawPath(it.path, paint)
        }
     canvas.drawBitmap(bitmap, 0.0f, 0.0f,  bitmapPaint)
    }

    override fun onTouchEvent(event: MotionEvent): Boolean {
       val x  = event.x
       val y = event.y
        when(event.action){
            MotionEvent.ACTION_DOWN -> {
                touchStart(x, y)
                invalidate()}
            MotionEvent.ACTION_MOVE -> {
                touchMove(x, y)
                invalidate() }
            MotionEvent.ACTION_UP -> {
                touchUp()
                invalidate()
            }
        }
        return true
    }


}<file_sep>package com.just.sketchapp.dialog

import android.content.Context
import android.graphics.Bitmap
import android.graphics.Canvas
import android.graphics.Color
import android.graphics.Paint
import android.provider.MediaStore
import android.util.Log
import android.view.View
import com.just.sketchapp.data.FingerPath

class BitmapExportManager{

    private fun createBitmapFromView(canvas: View): Bitmap {
        val bitmap = Bitmap.createBitmap(canvas.measuredWidth, canvas.measuredHeight, Bitmap.Config.ARGB_8888)
        canvas.draw(Canvas(bitmap))
        return bitmap
    }
    fun saveBitmap(context: Context, canvas: View): Boolean {


        val bitmap = createBitmapFromView(canvas)
        try {
            MediaStore.Images.Media.insertImage(context.contentResolver, bitmap, "new", null)
        } catch (e: Exception) {
            Log.d("EXPORT ERROR", e.message)
            return false
        }
        return true
    }


}

<file_sep>package com.just.sketchapp.ui
import android.graphics.Color
import android.widget.SeekBar
import androidx.lifecycle.*
import com.just.sketchapp.data.FingerPath

class MainViewModel: ViewModel() {

    private var _paths  = MutableLiveData<MutableList<FingerPath>?>()
    private val _color = MutableLiveData<Int?>()
    private val _size = MutableLiveData<Int?>()
    init{
        _color.value = Color.RED
        _paths.value = mutableListOf()
         _size.value =30

    }

    fun getColor(): LiveData<Int?> = _color
    fun setColor(color: Int){
        _color.value = color
    }


    fun setPaths(paths: MutableList<FingerPath>){
        _paths.value = paths
    }

    fun  getPaths(): LiveData<MutableList<FingerPath>?> = _paths


    fun getSize(): LiveData<Int?> = _size

    fun  onSizeChanged(seekBar: SeekBar, progressValue: Int, fromUser: Boolean) {
        _size.value = progressValue
    }
    fun clearPaths(){
            setPaths(mutableListOf<FingerPath>())
    }


}

<file_sep>package com.just.sketchapp.data



class DrawingRepo {}