How to create scratch card which allows user to scratch only once

0

This code is working, I created Scratch image view through which I can scratch the image view to see the the image, but scratch image view is automatically filling with scratch pattern when I reopen the app or I move to previous activity.only once the user should scratch the image view to view image and it should not fill again when I reopen the app or move to previous activity .Can anyone help me

<com.example.swapnanadendla.scratch.ScratchImageView
                            android:id="@+id/sample_image"
                            android:layout_width="200dp"
                            android:layout_height="200dp"
                            android:layout_gravity="center"
                            android:layout_marginTop="20dp"
                            android:background="@android:color/white"
                            android:src="@drawable/image" />

.

public class ScratchImageView extends ImageView{
    public interface IRevealListener {
         void onRevealed(ScratchImageView iv);
         void onRevealPercentChangedListener(ScratchImageView siv, float percent);
    }

    public static final float STROKE_WIDTH = 12f;

    private float mX, mY;
    private static final float TOUCH_TOLERANCE = 4;

    /**
     * Bitmap holding the scratch region.
     */
    private Bitmap mScratchBitmap;

    /**
     * Drawable canvas area through which the scratchable area is drawn.
     */
    private Canvas mCanvas;

    /**
     * Path holding the erasing path done by the user.
     */
    private Path mErasePath;

    /**
     * Path to indicate where the user have touched.
     */
    private Path mTouchPath;

    /**
     * Paint properties for drawing the scratch area.
     */
    private Paint mBitmapPaint;

    /**
     * Paint properties for erasing the scratch region.
     */
    private Paint mErasePaint;

    /**
     * Gradient paint properties that lies as a background for scratch region.
     */
    private Paint mGradientBgPaint;

    /**
     * Sample Drawable bitmap having the scratch pattern.
     */
    private BitmapDrawable mDrawable;

    /**
     * Listener object callback reference to send back the callback when the image has been revealed.
     */
    private IRevealListener mRevealListener;

    /**
     * Reveal percent value.
     */
    private float mRevealPercent;

    /**
     * Thread Count
     */
    private int mThreadCount = 0;


    public ScratchImageView(Context context) {
        super(context);
        init();

    }

    public ScratchImageView(Context context, AttributeSet set) {
        super(context, set);
        init();
    }

    public ScratchImageView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        init();
    }

    /**
     * Set the strokes width based on the parameter multiplier.
     * @param multiplier can be 1,2,3 and so on to set the stroke width of the paint.
     */
    public void setStrokeWidth(int multiplier) {
        mErasePaint.setStrokeWidth(multiplier * STROKE_WIDTH);
    }

    /**
     * Initialises the paint drawing elements.
     */
    private void init() {


        mTouchPath = new Path();

        mErasePaint = new Paint();
        mErasePaint.setAntiAlias(true);
        mErasePaint.setDither(true);
        mErasePaint.setColor(0xFFFF0000);
        mErasePaint.setStyle(Paint.Style.STROKE);
        mErasePaint.setStrokeJoin(Paint.Join.BEVEL);
        mErasePaint.setStrokeCap(Paint.Cap.ROUND);
        setStrokeWidth(6);

        mGradientBgPaint = new Paint();

        mErasePath = new Path();
        mBitmapPaint = new Paint(Paint.DITHER_FLAG);

        Bitmap scratchBitmap = BitmapFactory.decodeResource(getResources(), R.drawable.ic_scratch_pattern);
        mDrawable = new BitmapDrawable(getResources(), scratchBitmap);
        mDrawable.setTileModeXY(Shader.TileMode.REPEAT, Shader.TileMode.REPEAT);

        setEraserMode();

    }

    @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        super.onSizeChanged(w, h, oldw, oldh);
        mScratchBitmap = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888);
        mCanvas = new Canvas(mScratchBitmap);

        Rect rect = new Rect(0, 0, mScratchBitmap.getWidth(), mScratchBitmap.getHeight());
        mDrawable.setBounds(rect);

        int startGradientColor = ContextCompat.getColor(getContext(), R.color.scratch_start_gradient);
        int endGradientColor = ContextCompat.getColor(getContext(), R.color.scratch_end_gradient);

        mGradientBgPaint.setShader(new LinearGradient(0, 0, 0, getHeight(), startGradientColor, endGradientColor, Shader.TileMode.MIRROR));

        mCanvas.drawRect(rect, mGradientBgPaint);
        mDrawable.draw(mCanvas);
    }

    @Override
    protected void onDraw(Canvas canvas) {

        super.onDraw(canvas);
        canvas.drawBitmap(mScratchBitmap, 0, 0, mBitmapPaint);
        canvas.drawPath(mErasePath, mErasePaint);


    }

    private void touch_start(float x, float y) {
        mErasePath.reset();
        mErasePath.moveTo(x, y);
        mX = x;
        mY = y;

    }


    /**
     * clears the scratch area to reveal the hidden image.
     */
    public void clear() {

        int[] bounds = getImageBounds();
        int left = bounds[0];
        int top = bounds[1];
        int right = bounds[2];
        int bottom = bounds[3];

        int width = right - left;
        int height = bottom - top;
        int centerX = left + width / 2;
        int centerY = top + height / 2;

        left = centerX - width / 2;
        top = centerY - height / 2;
        right = left + width;
        bottom = top + height;

        Paint paint = new Paint();
        paint.setXfermode(new PorterDuffXfermode(
                PorterDuff.Mode.CLEAR));

        mCanvas.drawRect(left, top, right, bottom, paint);
        checkRevealed();
        invalidate();
    }


    private void touch_move(float x, float y) {

        float dx = Math.abs(x - mX);
        float dy = Math.abs(y - mY);
        if (dx >= TOUCH_TOLERANCE || dy >= TOUCH_TOLERANCE) {
            mErasePath.quadTo(mX, mY, (x + mX) / 2, (y + mY) / 2);
            mX = x;
            mY = y;

            drawPath();
        }

        mTouchPath.reset();
        mTouchPath.addCircle(mX, mY, 30, Path.Direction.CW);

    }

    private void drawPath() {
        mErasePath.lineTo(mX, mY);
        // commit the path to our offscreen
        mCanvas.drawPath(mErasePath, mErasePaint);
        // kill this so we don't double draw
        mTouchPath.reset();
        mErasePath.reset();
        mErasePath.moveTo(mX, mY);

         checkRevealed();
        //reveal();
    }

    public void reveal() {
        clear();
    }

    private void touch_up() {

        drawPath();
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        float x = event.getX();
        float y = event.getY();

        switch (event.getAction()) {
            case MotionEvent.ACTION_DOWN:
                touch_start(x, y);
                invalidate();

                break;
            case MotionEvent.ACTION_MOVE:
                touch_move(x, y);
                invalidate();
                break;
            case MotionEvent.ACTION_UP:
                touch_up();
                invalidate();
                break;
            default:
                break;
        }

        return true;
    }

    public int getColor() {
        return mErasePaint.getColor();
    }


    public Paint getErasePaint() {
        return mErasePaint;
    }

    public void setEraserMode() {

        getErasePaint().setXfermode(new PorterDuffXfermode(
                PorterDuff.Mode.CLEAR));


    }

    public void setRevealListener(IRevealListener listener) {
        this.mRevealListener = listener;
    }

    public boolean isRevealed() {
        return mRevealPercent == 1;
    }

    private void checkRevealed() {

        if(! isRevealed() && mRevealListener != null) {

            int[] bounds = getImageBounds();
            int left = bounds[0];
            int top = bounds[1];
            int width = bounds[2] - left;
            int height = bounds[3] - top;

            // Do not create multiple calls to compare.
            if(mThreadCount > 1) {
                Log.d("Captcha", "Count greater than 1");
                return;
            }

            mThreadCount++;

//            new AsyncTask<Integer, Void, Float>() {
//
//                @Override
//                protected Float doInBackground(Integer... params) {
//
//                    try {
//                        int left = params[0];
//                        int top = params[1];
//                        int width = params[2];
//                        int height = params[3];
//
//                        Bitmap croppedBitmap = Bitmap.createBitmap(mScratchBitmap, left, top, width, height);
//
//                        return BitmapUtils.getTransparentPixelPercent(croppedBitmap);
//                    } finally {
//                        mThreadCount--;
//                    }
//                }
//
//                public void onPostExecute(Float percentRevealed) {
//
//                    // check if not revealed before.
//                    if( ! isRevealed()) {
//
//                        float oldValue = mRevealPercent;
//                        mRevealPercent = percentRevealed;
//
//                        if(oldValue != percentRevealed) {
//                            mRevealListener.onRevealPercentChangedListener(ScratchImageView.this, percentRevealed);
//                        }
//
//                        // if now revealed.
//                        if( isRevealed()) {
//                            mRevealListener.onRevealed(ScratchImageView.this);
//                        }
//                    }
//                }
//
// }.execute(left, top, width, height);

        }
    }

    public int[] getImageBounds() {

        int paddingLeft = getPaddingLeft();
        int paddingTop = getPaddingTop();
        int paddingRight = getPaddingRight();
        int paddingBottom = getPaddingBottom();

        int vwidth = getWidth() - paddingLeft - paddingRight;
        int vheight = getHeight() - paddingBottom - paddingTop;

        int centerX = vwidth/2;
        int centerY = vheight/2;


        Drawable drawable = getDrawable();
        Rect bounds = drawable.getBounds();

        int width = drawable.getIntrinsicWidth();
        int height = drawable.getIntrinsicHeight();

        if(width <= 0) {
            width = bounds.right - bounds.left;
        }

        if(height <= 0) {
            height = bounds.bottom - bounds.top;
        }

        int left;
        int top;

        if(height > vheight) {
            height = vheight;
        }

        if(width > vwidth) {
            width = vwidth;
        }


        ScaleType scaleType = getScaleType();

        switch (scaleType) {
            case FIT_START:
                left = paddingLeft;
                top = centerY - height / 2;
                break;
            case FIT_END:
                left = vwidth - paddingRight - width;
                top = centerY - height / 2;
                break;
            case CENTER:
                left = centerX - width / 2;
                top = centerY - height / 2;
                break;
            default:
                left = paddingLeft;
                top = paddingTop;
                width = vwidth;
                height = vheight;
                break;

        }

        return new int[] {left, top, left + width, top + height};
    }
}
android
firebase
asked on Stack Overflow May 17, 2018 by Swapna • edited May 17, 2018 by Frank van Puffelen

1 Answer

2

What you can do is store into Firebase a variable like isScratched = 1 or 0, if it's 1 it's because the user didn't scratch it yet. If the user scratch it that variable will be 0 and then in onStart you put a listener of Firebase database, if the listener finds out the value is 0 the scratch card will not be available.

I will show you some snippet here

private DatabaseReference mDatabase; //First declare your database reference

Then in init() or onCreate()

mDatabase = FirebaseDatabase.getInstance().getReference();
mDatabase.child("isScratched").setValue("1"); //here we create the isScratched and set it to 1 , meaning that the photo is not even scratched yet

Now, after the photo is scratched just set that value to 0

//After your scratch method or when the user finishes scratching the pick
mDatabase.child("isScratched").setValue("0");

Now in your onStart() or in the Activity where the image appears just attach a listener

mDatabase.child("isScratched").addSingleValueEventListener(new ValueEventListener() {
    @Override
    public void onDataChange(DataSnapshot dataSnapshot) {

            String getScratchedValue = datasnapshot.getValue(String.class);
            Log.e("IsScratched : " ,""+getScratchedValue);
            if(getScratchedValue.equals(0)){

                 //Your picture is already scratched, run the method that will show it scratched

                 }

             }

    @Override
    public void onCancelled(DatabaseError databaseError) {
        System.out.println("Database Error: "+databaseError.getDetails());
    }
});
answered on Stack Overflow May 17, 2018 by Gastón Saillén • edited Aug 17, 2019 by halfer

User contributions licensed under CC BY-SA 3.0