Untitled
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) // } }