void display(T container, String uri) {
98 | ImageLoader.getInstance(mContext).display(container, uri);
99 | }
100 |
101 |
102 | private class ViewHolder {
103 | ImageView mImage;
104 | ImageView mImageSelected;
105 | }
106 | }
107 |
--------------------------------------------------------------------------------
/app/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 | Anki Doodle
3 |
4 | You have denied this app\'s access to external storage, so we cannot make occlusion cards for you.\n
5 | Please grant this permission manually at application settings page.\n
6 |
7 |
8 |
9 | No access to ankidroid\'s API. You have to ensure that:\n
10 | You have Ankidroid installed.\n
11 | In the advanced settings of Ankidroid, You have \"Enable Ankidroid API\" checked.\n
12 | You have grant the permission "Read And Write Ankidroid Database" in this app\' settings page.
13 |
14 | Deck
15 | Mode
16 | Note of Front Side
17 | Note of Back Side
18 | delete selected occlusion
19 | create card(s)
20 | Error when read deck list, you may have to open Ankidroid first:
21 | No deck named %s found!
22 | Error When add model, you may have to open Ankidroid first:
23 | Error when write image file:
24 | Error generating json data:
25 | Error write cards, you may have to open Ankidroid first:
26 | No selected occlusion to delete!
27 | Card(s) added
28 | Add Card(s) to Ankidroid
29 | Illegal Operation; Crop the image first!
30 | Rectangle Color
31 | Rectangle Highlight Color
32 | Choose
33 | Cancel
34 | Settings
35 | https://github.com/mmjang/Ankillusion/blob/master/documentation-en.md
36 | About
37 |
38 | Author: mmjang\n
39 | Source Code: Github Repo\n
40 | Email: pheiztu@foxmail.com\n
41 | WeChat: Cc966200\n\n
42 | Acknowledgements\n
43 | 1993hzw\'s Doodle\n
44 | duanhong169\'s ColorPicker
45 |
46 | Donate
47 | For users in China:
48 | For international users:
49 | Exit after card(s) creation
50 | Tags(separated by blanks)
51 |
52 |
--------------------------------------------------------------------------------
/app/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
50 |
53 |
54 |
59 |
62 |
63 |
64 |
68 |
72 |
76 |
77 |
78 |
--------------------------------------------------------------------------------
/frontend/test_canvas.html:
--------------------------------------------------------------------------------
1 |
2 |
3 | Canvas tutorial
4 |
50 |
58 |
59 |
60 |
61 | {
62 | "version": 1,
63 | "image_file": "xxx.jpg",
64 | "width": 200,
65 | "height": 200,
66 | "shape_list_front":[
67 | {
68 | "type": "rect",
69 | "color": "#ff0000",
70 | "data":
71 | [[94, 593],
72 | [13, 683],
73 | [137, 794],
74 | [218, 704]]
75 | }
76 | ],
77 | "shape_list_back":[
78 | {
79 | "type": "rect",
80 | "color": "#00ff00",
81 | "data": [[94, 593],
82 | [13, 683],
83 | [137, 794],
84 | [218, 704]]
85 | }
86 | ]
87 | }
88 |
89 |
90 |
92 |
93 |
--------------------------------------------------------------------------------
/app/src/main/java/com/mmjang/ankillusion/anki/OcclusionCardModel.java:
--------------------------------------------------------------------------------
1 | package com.mmjang.ankillusion.anki;
2 |
3 | import android.content.Context;
4 |
5 | import com.mmjang.ankillusion.data.Constant;
6 | import com.mmjang.ankillusion.data.Settings;
7 |
8 | import java.io.IOException;
9 | import java.io.InputStream;
10 |
11 | public class OcclusionCardModel {
12 | private final AnkiDroidHelper mAnkidroid;
13 | private Context context;
14 |
15 | private final String defaultModelName = Constant.OCCLUSION_MODEL_NAME;
16 | private final String MODEL_FILE = "occlusion_model.html";
17 | private final String MODEL_SPLITTER = "@@@";
18 | private final String CODING = "UTF-8";
19 | private final int NUMBER_OF_MODEL_STRING = 3;
20 |
21 | private String[] front = new String[1];
22 | private String css = "";
23 | private String[] back = new String[1];
24 |
25 | String[] QFMT = new String[1];
26 | String[] AFMT = new String[1];
27 | String[] Cards = {"card1"};
28 | String CSS;
29 | public static final String [] FILEDS = {
30 | "Image",
31 | "Data",
32 | "Front",
33 | "Back"
34 | };
35 |
36 | public OcclusionCardModel(Context ct, AnkiDroidHelper ankiDroidHelper){
37 |
38 | context = ct;
39 | mAnkidroid = ankiDroidHelper;
40 | try {
41 | InputStream ips = ct.getResources().getAssets().open(MODEL_FILE);
42 | byte[] data = new byte[ips.available()];
43 | ips.read(data);
44 | String defaultModelStr = new String(data, CODING);
45 | String[] defaultModelSplitted = defaultModelStr.split(MODEL_SPLITTER);
46 | if(defaultModelSplitted.length == NUMBER_OF_MODEL_STRING) {
47 | front[0] = defaultModelSplitted[0];
48 | back[0] = defaultModelSplitted[1];
49 | css = defaultModelSplitted[2];
50 | }
51 | else{
52 | ;
53 | }
54 | QFMT[0] = front[0];
55 | AFMT[0] = back[0];
56 | CSS = css;
57 |
58 | }
59 | catch(IOException e) {
60 | e.printStackTrace();
61 | return;
62 | }
63 | }
64 |
65 | public boolean needAddModel(){
66 | long storedModelId = Settings.getInstance(context).getModelId();
67 | if(storedModelId > 0){
68 | String modelName = mAnkidroid.getApi().getModelName(storedModelId);
69 | if(modelName == null || !modelName.equals(Constant.OCCLUSION_MODEL_NAME)){
70 | return true;
71 | }else{
72 | return false;
73 | }
74 | }else{
75 | Long mid = mAnkidroid.findModelIdByName(defaultModelName, FILEDS.length);
76 | if(mid == null){
77 | return true;
78 | }else{
79 | Settings.getInstance(context).setModelId(mid);
80 | return false;
81 | }
82 | }
83 | }
84 |
85 | public boolean addModel(){
86 | Long mid = mAnkidroid.getApi().addNewCustomModel(
87 | defaultModelName,
88 | FILEDS,
89 | Cards,
90 | QFMT,
91 | AFMT,
92 | CSS,
93 | null,
94 | null
95 | );
96 | if(mid != null){
97 | Settings.getInstance(context).setModelId(mid);
98 | return true;
99 | }else{
100 | return false;
101 | }
102 | }
103 | }
104 |
105 |
106 |
--------------------------------------------------------------------------------
/Doodle/app/src/main/java/cn/hzw/doodledemo/guide/SimpleDoodleView.java:
--------------------------------------------------------------------------------
1 | package cn.hzw.doodledemo.guide;
2 |
3 | import android.content.Context;
4 | import android.graphics.Canvas;
5 | import android.graphics.Color;
6 | import android.graphics.Paint;
7 | import android.graphics.Path;
8 | import android.util.Log;
9 | import android.view.MotionEvent;
10 | import android.view.View;
11 |
12 | import java.util.ArrayList;
13 | import java.util.List;
14 |
15 | import cn.forward.androids.TouchGestureDetector;
16 |
17 | /**
18 | * 初级涂鸦
19 | * 没有图片 仅支持 手绘
20 | * Created on 24/06/2018.
21 | */
22 | public class SimpleDoodleView extends View {
23 |
24 | private final static String TAG = "SimpleDoodleView";
25 |
26 | private Paint mPaint = new Paint();
27 | private List mPathList = new ArrayList<>(); // 保存涂鸦轨迹的集合
28 | private TouchGestureDetector mTouchGestureDetector; // 触摸手势监听
29 | private float mLastX, mLastY;
30 | private Path mCurrentPath; // 当前的涂鸦轨迹
31 |
32 | public SimpleDoodleView(Context context) {
33 | super(context);
34 | // 设置画笔
35 | mPaint.setColor(Color.RED);
36 | mPaint.setStyle(Paint.Style.STROKE);
37 | mPaint.setStrokeWidth(20);
38 | mPaint.setAntiAlias(true);
39 | mPaint.setStrokeCap(Paint.Cap.ROUND);
40 |
41 | // 由手势识别器处理手势
42 | mTouchGestureDetector = new TouchGestureDetector(getContext(), new TouchGestureDetector.OnTouchGestureListener() {
43 |
44 | @Override
45 | public void onScrollBegin(MotionEvent e) { // 滑动开始
46 | Log.d(TAG, "onScrollBegin: ");
47 | mCurrentPath = new Path(); // 新的涂鸦
48 | mPathList.add(mCurrentPath); // 添加的集合中
49 | mCurrentPath.moveTo(e.getX(), e.getY());
50 | mLastX = e.getX();
51 | mLastY = e.getY();
52 | invalidate(); // 刷新
53 | }
54 |
55 | @Override
56 | public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) { // 滑动中
57 | Log.d(TAG, "onScroll: " + e2.getX() + " " + e2.getY());
58 | mCurrentPath.quadTo(
59 | mLastX,
60 | mLastY,
61 | (e2.getX() + mLastX) / 2,
62 | (e2.getY() + mLastY) / 2); // 使用贝塞尔曲线 让涂鸦轨迹更圆滑
63 | mLastX = e2.getX();
64 | mLastY = e2.getY();
65 | invalidate(); // 刷新
66 | return true;
67 | }
68 |
69 | @Override
70 | public void onScrollEnd(MotionEvent e) { // 滑动结束
71 | Log.d(TAG, "onScrollEnd: ");
72 | mCurrentPath.quadTo(
73 | mLastX,
74 | mLastY,
75 | (e.getX() + mLastX) / 2,
76 | (e.getY() + mLastY) / 2); // 使用贝塞尔曲线 让涂鸦轨迹更圆滑
77 | mCurrentPath = null; // 轨迹结束
78 | invalidate(); // 刷新
79 | }
80 |
81 | });
82 | }
83 |
84 | @Override
85 | public boolean dispatchTouchEvent(MotionEvent event) {
86 | boolean consumed = mTouchGestureDetector.onTouchEvent(event); // 由手势识别器处理手势
87 | if (!consumed) {
88 | return super.dispatchTouchEvent(event);
89 | }
90 | return true;
91 | }
92 |
93 | @Override
94 | protected void onDraw(Canvas canvas) {
95 | for (Path path : mPathList) { // 绘制涂鸦轨迹
96 | canvas.drawPath(path, mPaint);
97 | }
98 | }
99 | }
100 |
--------------------------------------------------------------------------------
/frontend/test_canvas - 副本.html:
--------------------------------------------------------------------------------
1 |
2 |
3 | Canvas tutorial
4 |
5 |
18 |
19 |
20 | {{Front}}
21 |
22 | {
23 | "version": 1,
24 | "image_file": "xxx.jpg",
25 | "width": 200,
26 | "height": 200,
27 | "shape_list_front":[
28 | {
29 | "type": "rect",
30 | "color": "#ff0000",
31 | "data":
32 | [[94, 593],
33 | [13, 683],
34 | [137, 794],
35 | [218, 704]]
36 | }
37 | ],
38 | "shape_list_back":[
39 | {
40 | "type": "rect",
41 | "color": "#00ff00",
42 | "data": [[94, 593],
43 | [13, 683],
44 | [137, 794],
45 | [218, 704]]
46 | }
47 | ]
48 | }
49 |
50 |
51 |
52 |
54 |
55 |
98 |
99 |
--------------------------------------------------------------------------------
/Doodle/doodle/src/main/java/cn/hzw/doodle/core/IDoodleItem.java:
--------------------------------------------------------------------------------
1 | package cn.hzw.doodle.core;
2 |
3 | import android.graphics.Canvas;
4 | import android.graphics.PointF;
5 |
6 | /**
7 | * Created on 27/06/2018.
8 | */
9 |
10 | public interface IDoodleItem {
11 |
12 | public void setDoodle(IDoodle doodle);
13 |
14 | public IDoodle getDoodle();
15 |
16 | /**
17 | * 获取画笔
18 | *
19 | * @return
20 | */
21 | public IDoodlePen getPen();
22 |
23 | /**
24 | * 设置画笔
25 | *
26 | * @param pen
27 | */
28 | public void setPen(IDoodlePen pen);
29 |
30 | /**
31 | * 获取画笔形状
32 | *
33 | * @return
34 | */
35 | public IDoodleShape getShape();
36 |
37 | /**
38 | * 设置画笔形状
39 | *
40 | * @param shape
41 | */
42 | public void setShape(IDoodleShape shape);
43 |
44 | /**
45 | * 获取大小
46 | *
47 | * @return
48 | */
49 | public float getSize();
50 |
51 | /**
52 | * 设置大小
53 | *
54 | * @param size
55 | */
56 | public void setSize(float size);
57 |
58 | /**
59 | * 获取颜色
60 | *
61 | * @return
62 | */
63 | public IDoodleColor getColor();
64 |
65 | /**
66 | * 设置颜色
67 | *
68 | * @param color
69 | */
70 | public void setColor(IDoodleColor color);
71 |
72 | /**
73 | * 绘制item
74 | *
75 | * @param canvas
76 | */
77 | public void draw(Canvas canvas);
78 |
79 | /**
80 | * 画在所有item的上面
81 | * @param canvas
82 | */
83 | void drawAtTheTop(Canvas canvas);
84 |
85 | /**
86 | * 设置在当前涂鸦中的左上角位置
87 | *
88 | * @param x
89 | * @param y
90 | */
91 | public void setLocation(float x, float y);
92 |
93 | /**
94 | * 获取当前涂鸦中的起始坐标
95 | */
96 | public PointF getLocation();
97 |
98 | /**
99 | * item中心点x
100 | *
101 | * @param pivotX
102 | */
103 | public void setPivotX(float pivotX);
104 |
105 | /**
106 | * item中心点x
107 | */
108 | public float getPivotX();
109 |
110 | /**
111 | * item中心点y
112 | *
113 | * @param pivotY
114 | */
115 | public void setPivotY(float pivotY);
116 |
117 | /**
118 | * item中心点y
119 | */
120 | public float getPivotY();
121 |
122 | /**
123 | * 设置item的旋转值,围绕中心点Pivot旋转
124 | *
125 | * @param degree
126 | */
127 | public void setItemRotate(float degree);
128 |
129 | /**
130 | * 获取item的旋转值
131 | *
132 | * @return
133 | */
134 | public float getItemRotate();
135 |
136 | /**
137 | * 是否需要裁剪图片区域外的部分
138 | *
139 | * @return
140 | */
141 | public boolean isNeedClipOutside();
142 |
143 | /**
144 | * 设置是否需要裁剪图片区域外的部分
145 | *
146 | * @param clip
147 | */
148 | public void setNeedClipOutside(boolean clip);
149 |
150 | /**
151 | * 添加进涂鸦时回调
152 | */
153 | public void onAdd();
154 |
155 | /**
156 | * 移除涂鸦时回调
157 | */
158 | public void onRemove();
159 |
160 | /**
161 | * 刷新
162 | */
163 | public void refresh();
164 |
165 | /**
166 | * item是否可以编辑。用于编辑模式下对item的操作
167 | * @return
168 | */
169 | public boolean isDoodleEditable();
170 |
171 | /**
172 | * 缩放倍数,围绕(PivotX,PivotY)旋转
173 | */
174 | public void setScale(float scale);
175 |
176 | public float getScale();
177 |
178 | /**
179 | * 监听器
180 | * @param listener
181 | */
182 | public void addItemListener(IDoodleItemListener listener);
183 |
184 | public void removeItemListener(IDoodleItemListener listener);
185 | }
186 |
--------------------------------------------------------------------------------
/Doodle/doodle/src/main/res/layout/doodle_title_bar.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
14 |
15 |
25 |
26 |
32 |
33 |
47 |
48 |
49 |
60 |
61 |
72 |
73 |
83 |
84 |
85 |
--------------------------------------------------------------------------------
/app/src/main/java/com/mmjang/ankillusion/ui/AboutActivity.java:
--------------------------------------------------------------------------------
1 | package com.mmjang.ankillusion.ui;
2 |
3 | import android.content.Intent;
4 | import android.net.Uri;
5 | import android.support.v4.app.NavUtils;
6 | import android.support.v7.app.AppCompatActivity;
7 | import android.os.Bundle;
8 | import android.text.method.LinkMovementMethod;
9 | import android.view.Menu;
10 | import android.view.MenuInflater;
11 | import android.view.MenuItem;
12 | import android.view.View;
13 | import android.widget.ImageView;
14 | import android.widget.TextView;
15 | import android.widget.Toast;
16 |
17 | import com.mmjang.ankillusion.BuildConfig;
18 | import com.mmjang.ankillusion.R;
19 |
20 | public class AboutActivity extends AppCompatActivity {
21 |
22 | TextView mTextViewAboutInformation;
23 | @Override
24 | protected void onCreate(Bundle savedInstanceState) {
25 | super.onCreate(savedInstanceState);
26 | setContentView(R.layout.activity_about);
27 | getSupportActionBar().setDisplayHomeAsUpEnabled(true);
28 | setAppNameAndVersion();
29 |
30 | mTextViewAboutInformation = findViewById(R.id.textview_about_information);
31 | mTextViewAboutInformation.setMovementMethod(LinkMovementMethod.getInstance());
32 |
33 | ImageView btnBuymeacoffee = findViewById(R.id.btn_buymeacoffee);
34 | ImageView btnAlipay = findViewById(R.id.btn_alipay);
35 |
36 | btnBuymeacoffee.setOnClickListener(
37 | new View.OnClickListener() {
38 | @Override
39 | public void onClick(View v) {
40 | String url = "https://www.buymeacoffee.com/w05dHCN";
41 | Intent i = new Intent(Intent.ACTION_VIEW);
42 | i.setData(Uri.parse(url));
43 | startActivity(i);
44 | }
45 | }
46 | );
47 |
48 | btnAlipay.setOnClickListener(
49 | new View.OnClickListener() {
50 | @Override
51 | public void onClick(View v) {
52 | Intent intent = new Intent();
53 | intent.setAction("android.intent.action.VIEW");
54 | //intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
55 | String payUrl = "HTTPS://QR.ALIPAY.COM/FKX011406PTCIHXZJPW7A1";
56 | //String payUrl = "HTTPS://QR.ALIPAY.COM/A6X00376AFOZWZUHWTDNDF4"; //any
57 | intent.setData(Uri.parse("alipayqr://platformapi/startapp?saId=10000007&clientVersion=3.7.0.0718&qrcode=" + payUrl));
58 | if (intent.resolveActivity(getPackageManager()) != null) {
59 | startActivity(intent);
60 | } else {
61 | intent.setData(Uri.parse(payUrl.toLowerCase()));
62 | startActivity(intent);
63 | }
64 | }
65 | }
66 | );
67 | }
68 |
69 | private TextView mAppNameAndVersion;
70 | private void setAppNameAndVersion(){
71 | if(mAppNameAndVersion == null){
72 | mAppNameAndVersion = findViewById(R.id.textview_app_name_and_version);
73 | }
74 | mAppNameAndVersion.setText(
75 | getText(R.string.app_name) + " ver: " + BuildConfig.VERSION_NAME);
76 | }
77 |
78 | @Override
79 | public boolean onOptionsItemSelected(MenuItem item) {
80 | switch (item.getItemId()) {
81 | // Respond to the action bar's Up/Home button
82 | case android.R.id.home:
83 | NavUtils.navigateUpFromSameTask(this);
84 | return true;
85 | }
86 | return super.onOptionsItemSelected(item);
87 | }
88 | }
89 |
--------------------------------------------------------------------------------
/Doodle/app/src/main/res/layout/activity_main.xml:
--------------------------------------------------------------------------------
1 |
2 |
12 |
13 |
18 |
19 |
30 |
31 |
36 |
37 |
42 |
43 |
50 |
51 |
52 |
58 |
59 |
70 |
71 |
77 |
78 |
83 |
84 |
89 |
94 |
95 |
96 |
--------------------------------------------------------------------------------
/app/src/main/java/com/ichi2/anki/api/NoteInfo.java:
--------------------------------------------------------------------------------
1 | /***************************************************************************************
2 | * *
3 | * Copyright (c) 2016 Timothy Rae *
4 | * *
5 | * This program is free software; you can redistribute it and/or modify it under *
6 | * the terms of the GNU Lesser General Public License as published by the Free Software *
7 | * Foundation; either version 3 of the License, or (at your option) any later *
8 | * version. *
9 | * *
10 | * This program is distributed in the hope that it will be useful, but WITHOUT ANY *
11 | * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A *
12 | * PARTICULAR PURPOSE. See the GNU General Public License for more details. *
13 | * *
14 | * You should have received a copy of the GNU Lesser General Public License along with *
15 | * this program. If not, see . *
16 | ****************************************************************************************/
17 |
18 | package com.ichi2.anki.api;
19 |
20 | import android.database.Cursor;
21 | import com.ichi2.anki.FlashCardsContract;
22 | import java.util.Arrays;
23 | import java.util.HashSet;
24 | import java.util.Set;
25 |
26 |
27 | /**
28 | * Representation of the contents of a note in AnkiDroid.
29 | */
30 | public final class NoteInfo {
31 | private final long mId;
32 | private final String[] mFields;
33 | private final Set mTags;
34 |
35 | /**
36 | * Static initializer method to build a NoteInfo object from a Cursor
37 | * @param cursor from a query to FlashCardsContract.Note.CONTENT_URI
38 | * @return a NoteInfo object or null if the cursor was not valid
39 | */
40 | static NoteInfo buildFromCursor(Cursor cursor) {
41 | try {
42 | int idIndex = cursor.getColumnIndexOrThrow(FlashCardsContract.Note._ID);
43 | int fldsIndex = cursor.getColumnIndexOrThrow(FlashCardsContract.Note.FLDS);
44 | int tagsIndex = cursor.getColumnIndexOrThrow(FlashCardsContract.Note.TAGS);
45 | String[] fields = Utils.splitFields(cursor.getString(fldsIndex));
46 | long id = cursor.getLong(idIndex);
47 | Set tags = new HashSet<>(Arrays.asList(Utils.splitTags(cursor.getString(tagsIndex))));
48 | return new NoteInfo(id, fields, tags);
49 | } catch (Exception e) {
50 | return null;
51 | }
52 | }
53 |
54 | private NoteInfo(long id, String[] fields, Set tags) {
55 | mId = id;
56 | mFields = fields;
57 | mTags = tags;
58 | }
59 |
60 | /**
61 | * Clone a NoteInfo object
62 | * @param parent the object to clone
63 | */
64 | public NoteInfo(NoteInfo parent) {
65 | mId = parent.getId();
66 | mFields = parent.getFields().clone();
67 | mTags = new HashSet<>(parent.getTags());
68 | }
69 |
70 | /** Note ID */
71 | public long getId() {
72 | return mId;
73 | }
74 |
75 | /** The array of fields */
76 | public String[] getFields() {
77 | return mFields;
78 | }
79 |
80 | /** The set of tags */
81 | public Set getTags() {
82 | return mTags;
83 | }
84 |
85 | /** The first field **/
86 | public String getKey() {
87 | return getFields()[0];
88 | }
89 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/mmjang/ankillusion/data/OcclusionObject.java:
--------------------------------------------------------------------------------
1 | package com.mmjang.ankillusion.data;
2 |
3 | import org.json.JSONArray;
4 | import org.json.JSONException;
5 | import org.json.JSONObject;
6 |
7 | import java.util.ArrayList;
8 | import java.util.List;
9 |
10 | import cn.hzw.doodle.occlusion.OcclusionItem;
11 |
12 | public class OcclusionObject{
13 | private int version;
14 | private String imageFile;
15 | private int width;
16 | private int height;
17 | private List shapeListFront;
18 | private List shapeListBack;
19 |
20 | public OcclusionObject(int version, String imageFile, int width, int height,
21 | List shapeListFront, List shapeListBack) {
22 | this.version = version;
23 | this.imageFile = imageFile;
24 | this.width = width;
25 | this.height = height;
26 | this.shapeListFront = shapeListFront;
27 | this.shapeListBack = shapeListBack;
28 | }
29 |
30 | public String toJsonString() throws JSONException{
31 | JSONObject occlusionJson = new JSONObject();
32 | occlusionJson.put("version", version);
33 | occlusionJson.put("image_file", imageFile);
34 | occlusionJson.put("width", width);
35 | occlusionJson.put("height", height);
36 | JSONArray frontJson = new JSONArray();
37 | for(OcclusionItem item : shapeListFront){
38 | frontJson.put(item.toJsonObject());
39 | }
40 | occlusionJson.put("shape_list_front", frontJson);
41 | JSONArray backJson = new JSONArray();
42 | for(OcclusionItem item : shapeListBack){
43 | backJson.put(item.toJsonObject());
44 | }
45 | occlusionJson.put("shape_list_back", backJson);
46 | return occlusionJson.toString(4);//indent the exported string
47 | }
48 |
49 | public OcclusionObject clone(){
50 | List newFront = new ArrayList<>();
51 | List newBack = new ArrayList<>();
52 | for(OcclusionItem item : shapeListFront){
53 | newFront.add(item.clone());
54 | }
55 | for(OcclusionItem item : shapeListBack){
56 | newBack.add(item.clone());
57 | }
58 | OcclusionObject newObj = new OcclusionObject(
59 | version,
60 | imageFile + "",
61 | width,
62 | height,
63 | newFront,
64 | newBack
65 | );
66 | return newObj;
67 | }
68 |
69 | public int getVersion() {
70 | return version;
71 | }
72 |
73 | public void setVersion(int version) {
74 | this.version = version;
75 | }
76 |
77 | public String getImageFile() {
78 | return imageFile;
79 | }
80 |
81 | public void setImageFile(String imageFile) {
82 | this.imageFile = imageFile;
83 | }
84 |
85 | public int getWidth() {
86 | return width;
87 | }
88 |
89 | public void setWidth(int width) {
90 | this.width = width;
91 | }
92 |
93 | public int getHeight() {
94 | return height;
95 | }
96 |
97 | public void setHeight(int height) {
98 | this.height = height;
99 | }
100 |
101 | public List getShapeListFront() {
102 | return shapeListFront;
103 | }
104 |
105 | public void setShapeListFront(List shapeListFront) {
106 | this.shapeListFront = shapeListFront;
107 | }
108 |
109 | public List getShapeListBack() {
110 | return shapeListBack;
111 | }
112 |
113 | public void setShapeListBack(List shapeListBack) {
114 | this.shapeListBack = shapeListBack;
115 | }
116 | }
117 |
--------------------------------------------------------------------------------
/Doodle/doodle/src/main/java/cn/hzw/doodle/DoodleColor.java:
--------------------------------------------------------------------------------
1 | package cn.hzw.doodle;
2 |
3 | import android.graphics.Bitmap;
4 | import android.graphics.BitmapShader;
5 | import android.graphics.Matrix;
6 | import android.graphics.Paint;
7 | import android.graphics.Shader;
8 |
9 | import cn.hzw.doodle.core.IDoodleColor;
10 | import cn.hzw.doodle.core.IDoodleItem;
11 |
12 | /**
13 | * 涂鸦画笔颜色,用于手绘
14 | */
15 | public class DoodleColor implements IDoodleColor {
16 |
17 | public enum Type {
18 | COLOR, // 颜色值
19 | BITMAP // 图片
20 | }
21 |
22 | private int mColor;
23 | private Bitmap mBitmap;
24 | private Type mType;
25 | private Matrix mMatrix;
26 |
27 | private int mLevel = 1;
28 |
29 | // bitmap相关
30 | private Shader.TileMode mTileX = Shader.TileMode.MIRROR;
31 | private Shader.TileMode mTileY = Shader.TileMode.MIRROR; // 镜像
32 |
33 | public DoodleColor(int color) {
34 | mType = Type.COLOR;
35 | mColor = color;
36 | }
37 |
38 | public DoodleColor(Bitmap bitmap) {
39 | this(bitmap, null);
40 | }
41 |
42 | public DoodleColor(Bitmap bitmap, Matrix matrix) {
43 | this(bitmap, matrix, Shader.TileMode.MIRROR, Shader.TileMode.MIRROR);
44 | }
45 |
46 | public DoodleColor(Bitmap bitmap, Matrix matrix, Shader.TileMode tileX, Shader.TileMode tileY) {
47 | mType = Type.BITMAP;
48 | mMatrix = matrix;
49 | mBitmap = bitmap;
50 | mTileX = tileX;
51 | mTileY = tileY;
52 | }
53 |
54 | @Override
55 | public void config(IDoodleItem item, Paint paint) {
56 | DoodleItemBase doodleItem = (DoodleItemBase) item;
57 | if (mType == Type.COLOR) {
58 | paint.setColor(mColor);
59 | paint.setShader(null);
60 | } else if (mType == Type.BITMAP) {
61 | BitmapShader shader = new BitmapShader(mBitmap, mTileX, mTileY);
62 | shader.setLocalMatrix(mMatrix);
63 | paint.setShader(shader);
64 | }
65 | }
66 |
67 | public void setColor(int color) {
68 | mType = Type.COLOR;
69 | mColor = color;
70 | }
71 |
72 | public void setColor(Bitmap bitmap) {
73 | mType = Type.BITMAP;
74 | mBitmap = bitmap;
75 | }
76 |
77 | public void setColor(Bitmap bitmap, Matrix matrix) {
78 | mType = Type.BITMAP;
79 | mMatrix = matrix;
80 | mBitmap = bitmap;
81 | }
82 |
83 | public void setColor(Bitmap bitmap, Matrix matrix, Shader.TileMode tileX, Shader.TileMode tileY) {
84 | mType = Type.BITMAP;
85 | mBitmap = bitmap;
86 | mMatrix = matrix;
87 | mTileX = tileX;
88 | mTileY = tileY;
89 | }
90 |
91 | public void setMatrix(Matrix matrix) {
92 | mMatrix = matrix;
93 | }
94 |
95 | public Matrix getMatrix() {
96 | return mMatrix;
97 | }
98 |
99 | public int getColor() {
100 | return mColor;
101 | }
102 |
103 | public Bitmap getBitmap() {
104 | return mBitmap;
105 | }
106 |
107 | public Type getType() {
108 | return mType;
109 | }
110 |
111 | @Override
112 | public IDoodleColor copy() {
113 | DoodleColor color = null;
114 | if (mType == Type.COLOR) {
115 | color = new DoodleColor(mColor);
116 | } else {
117 | color = new DoodleColor(mBitmap);
118 | }
119 | color.mTileX = mTileX;
120 | color.mTileY = mTileY;
121 | color.mMatrix = new Matrix(mMatrix);
122 | color.mLevel = mLevel;
123 | return color;
124 | }
125 |
126 | public void setLevel(int level) {
127 | mLevel = level;
128 | }
129 |
130 | public int getLevel() {
131 | return mLevel;
132 | }
133 | }
134 |
135 |
136 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_main.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
13 |
20 |
21 |
22 |
23 |
34 |
35 |
41 |
52 |
63 |
75 |
76 |
77 |
78 |
88 |
89 |
--------------------------------------------------------------------------------
/Doodle/doodle/src/main/res/layout/doodle_dialog.xml:
--------------------------------------------------------------------------------
1 |
2 |
12 |
13 |
25 |
26 |
41 |
42 |
48 |
49 |
60 |
61 |
62 |
67 |
68 |
81 |
82 |
95 |
96 |
97 |
--------------------------------------------------------------------------------
/Doodle/doodle/src/main/java/cn/hzw/doodle/CopyLocation.java:
--------------------------------------------------------------------------------
1 | package cn.hzw.doodle;
2 |
3 | import android.graphics.Canvas;
4 | import android.graphics.Paint;
5 | import android.graphics.PointF;
6 |
7 | import static cn.hzw.doodle.util.DrawUtil.drawCircle;
8 |
9 | /**
10 | * 仿制的定位器
11 | */
12 | public class CopyLocation {
13 |
14 | private float mCopyStartX, mCopyStartY; // 仿制的坐标
15 | private float mTouchStartX, mTouchStartY; // 开始触摸的坐标
16 | private float mX, mY; // 当前位置
17 |
18 | private Paint mPaint;
19 |
20 | private boolean mIsRelocating = true; // 正在定位中
21 | private boolean mIsCopying = false; // 正在仿制绘图中
22 |
23 | private PointF mTemp = new PointF();
24 |
25 | public CopyLocation() {
26 | mPaint = new Paint();
27 | mPaint.setAntiAlias(true);
28 | mPaint.setStyle(Paint.Style.FILL);
29 | mPaint.setStrokeJoin(Paint.Join.ROUND);
30 | }
31 |
32 | public float getTouchStartX() {
33 | return mTouchStartX;
34 | }
35 |
36 | public float getTouchStartY() {
37 | return mTouchStartY;
38 | }
39 |
40 | public float getCopyStartX() {
41 | return mCopyStartX;
42 | }
43 |
44 | public float getCopyStartY() {
45 | return mCopyStartY;
46 | }
47 |
48 | public float getX() {
49 | return mX;
50 | }
51 |
52 | public float getY() {
53 | return mY;
54 | }
55 |
56 | public boolean isCopying() {
57 | return mIsCopying;
58 | }
59 |
60 | public boolean isRelocating() {
61 | return mIsRelocating;
62 | }
63 |
64 | public void setCopying(boolean copying) {
65 | mIsCopying = copying;
66 | }
67 |
68 | public void setRelocating(boolean relocating) {
69 | mIsRelocating = relocating;
70 | }
71 |
72 | public void updateLocation(float x, float y) {
73 | mX = x;
74 | mY = y;
75 | }
76 |
77 | public void setStartPosition(float touchStartX, float touchStartY) {
78 | setStartPosition(touchStartX, touchStartY, mX, mY);
79 | }
80 |
81 | public void setStartPosition( float touchStartX, float touchStartY, float copyStartX, float copyStartY) {
82 | mCopyStartX = copyStartX;
83 | mCopyStartY = copyStartY;
84 | mTouchStartX = touchStartX;
85 | mTouchStartY = touchStartY;
86 | }
87 |
88 | public void drawItSelf(Canvas canvas, float size) {
89 | mPaint.setStrokeWidth(size / 4);
90 | mPaint.setStyle(Paint.Style.STROKE);
91 | mPaint.setColor(0xaa666666); // 灰色
92 | drawCircle(canvas, mX, mY, size / 2 + size / 8, mPaint);
93 |
94 | mPaint.setStrokeWidth(size / 16);
95 | mPaint.setStyle(Paint.Style.STROKE);
96 | mPaint.setColor(0xaaffffff); // 白色
97 | drawCircle(canvas, mX, mY, size / 2 + size / 32, mPaint);
98 |
99 | mPaint.setStyle(Paint.Style.FILL);
100 | if (!mIsCopying) {
101 | mPaint.setColor(0x44ff0000); // 红色
102 | drawCircle(canvas, mX, mY, size / 2, mPaint);
103 | } else {
104 | mPaint.setColor(0x44000088); // 蓝色
105 | drawCircle(canvas, mX, mY, size / 2, mPaint);
106 | }
107 | }
108 |
109 | /**
110 | * 判断是否点中
111 | */
112 | public boolean contains(float x, float y, float mPaintSize) {
113 | return (mX - x) * (mX - x) + (mY - y) * (mY - y) <= mPaintSize * mPaintSize;
114 | }
115 |
116 | public CopyLocation copy() {
117 | CopyLocation copyLocation = new CopyLocation();
118 | copyLocation.mCopyStartX = mCopyStartX;
119 | copyLocation.mCopyStartY = mCopyStartY;
120 | copyLocation.mTouchStartX = mTouchStartX;
121 | copyLocation.mTouchStartY = mTouchStartY;
122 | copyLocation.mX = mX;
123 | copyLocation.mY = mY;
124 | return copyLocation;
125 | }
126 |
127 | public void reset() {
128 | mCopyStartX = mCopyStartY = mTouchStartX = mTouchStartY = mX = mY = 0;
129 | mIsRelocating = true; // 正在定位中
130 | mIsCopying = false; // 正在仿制绘图中
131 | }
132 |
133 | }
134 |
135 |
--------------------------------------------------------------------------------
/Doodle/app/src/main/java/cn/hzw/doodledemo/MosaicDemo.java:
--------------------------------------------------------------------------------
1 | package cn.hzw.doodledemo;
2 |
3 | import android.app.Activity;
4 | import android.graphics.Bitmap;
5 | import android.graphics.BitmapFactory;
6 | import android.graphics.Canvas;
7 | import android.graphics.Color;
8 | import android.graphics.Matrix;
9 | import android.graphics.Paint;
10 | import android.os.Bundle;
11 | import android.view.View;
12 | import android.view.ViewGroup;
13 | import android.widget.Toast;
14 |
15 | import cn.hzw.doodle.DoodleColor;
16 | import cn.hzw.doodle.DoodleOnTouchGestureListener;
17 | import cn.hzw.doodle.DoodleShape;
18 | import cn.hzw.doodle.DoodleTouchDetector;
19 | import cn.hzw.doodle.DoodleView;
20 | import cn.hzw.doodle.IDoodleListener;
21 | import cn.hzw.doodle.core.IDoodle;
22 | import cn.hzw.doodle.core.IDoodleItem;
23 | import cn.hzw.doodle.core.IDoodlePen;
24 |
25 | /**
26 | * Mosaic effect
27 | */
28 | public class MosaicDemo extends Activity {
29 | private DoodleView doodleView;
30 |
31 | @Override
32 | protected void onCreate(Bundle savedInstanceState) {
33 | super.onCreate(savedInstanceState);
34 | setContentView(R.layout.activity_mosaic);
35 |
36 | // step 1
37 | Bitmap bitmap = BitmapFactory.decodeResource(getResources(), R.drawable.thelittleprince2);
38 | doodleView = new DoodleView(this, bitmap, new IDoodleListener() {
39 | @Override
40 | public void onSaved(IDoodle doodle, Bitmap doodleBitmap, Runnable callback) {
41 | Toast.makeText(MosaicDemo.this, "onSaved", Toast.LENGTH_SHORT).show();
42 | }
43 |
44 | @Override
45 | public void onReady(IDoodle doodle) {
46 | doodle.setSize(30 * doodle.getUnitSize());
47 | }
48 | });
49 |
50 | // step 2
51 | DoodleOnTouchGestureListener touchGestureListener = new DoodleOnTouchGestureListener(doodleView, null);
52 | DoodleTouchDetector touchDetector = new DoodleTouchDetector(this, touchGestureListener);
53 | doodleView.setDefaultTouchDetector(touchDetector);
54 |
55 | // step 3
56 | doodleView.setPen(new MosaicPen());
57 | //doodleView.setShape(DoodleShape.HAND_WRITE);
58 | doodleView.setShape(DoodleShape.FILL_RECT);
59 | doodleView.setColor(new DoodleColor(Color.RED));
60 | // setColor
61 | //findViewById(R.id.btn_mosaic_x3).performClick(); // see setMosaicLevel(View view)
62 |
63 | // step 4
64 | ViewGroup container = (ViewGroup) findViewById(R.id.doodle_container);
65 | container.addView(doodleView);
66 | }
67 |
68 | private DoodleColor getMosaicColor(int level) {
69 | Matrix matrix = new Matrix();
70 | matrix.setScale(1f / level, 1f / level);
71 | Bitmap mosaicBitmap = Bitmap.createBitmap(doodleView.getBitmap(),
72 | 0, 0, doodleView.getBitmap().getWidth(), doodleView.getBitmap().getHeight(), matrix, true);
73 | matrix.reset();
74 | matrix.setScale(level, level);
75 | DoodleColor doodleColor = new DoodleColor(mosaicBitmap, matrix);
76 | doodleColor.setLevel(level);
77 | return doodleColor;
78 | }
79 |
80 | public void setMosaicLevel(View view) {
81 | if (view.getId() == R.id.btn_mosaic_x1) {
82 | doodleView.setColor(getMosaicColor(5));
83 | } else if (view.getId() == R.id.btn_mosaic_x2) {
84 | doodleView.setColor(getMosaicColor(20));
85 | } else if (view.getId() == R.id.btn_mosaic_x3) {
86 | doodleView.setColor(getMosaicColor(50));
87 | }
88 | }
89 |
90 | /*
91 | Though setting a new pen here is not necessary, the design-based specification should do this.
92 | 虽然这里设置新的画笔不是必要的,但是基于设计的规范应该这样做。马赛克画笔在概念上不同于其他画笔,
93 | */
94 | private static class MosaicPen implements IDoodlePen {
95 | @Override
96 | public void config(IDoodleItem doodleItem, Paint paint) {
97 | }
98 |
99 | @Override
100 | public void drawHelpers(Canvas canvas, IDoodle doodle) {
101 | }
102 |
103 | @Override
104 | public IDoodlePen copy() {
105 | return this;
106 | }
107 | }
108 | }
109 |
--------------------------------------------------------------------------------
/Doodle/app/src/main/java/cn/hzw/doodledemo/MainActivity.java:
--------------------------------------------------------------------------------
1 | package cn.hzw.doodledemo;
2 |
3 | import android.app.Activity;
4 | import android.content.Intent;
5 | import android.graphics.Color;
6 | import android.os.Bundle;
7 | import android.text.TextUtils;
8 | import android.view.View;
9 | import android.widget.TextView;
10 | import android.widget.Toast;
11 |
12 | import java.util.ArrayList;
13 |
14 | import cn.forward.androids.utils.LogUtil;
15 | import cn.hzw.doodle.DoodleActivity;
16 | import cn.hzw.doodle.DoodleParams;
17 | import cn.hzw.doodle.DoodleView;
18 | import cn.hzw.doodledemo.guide.DoodleGuideActivity;
19 | import cn.hzw.imageselector.ImageLoader;
20 | import cn.hzw.imageselector.ImageSelectorActivity;
21 |
22 | public class MainActivity extends Activity {
23 |
24 | public static final int REQ_CODE_SELECT_IMAGE = 100;
25 | public static final int REQ_CODE_DOODLE = 101;
26 | private TextView mPath;
27 |
28 | @Override
29 | protected void onCreate(Bundle savedInstanceState) {
30 | super.onCreate(savedInstanceState);
31 | setContentView(R.layout.activity_main);
32 |
33 | findViewById(R.id.btn_select_image).setOnClickListener(new View.OnClickListener() {
34 | @Override
35 | public void onClick(View v) {
36 | ImageSelectorActivity.startActivityForResult(REQ_CODE_SELECT_IMAGE, MainActivity.this, null, false);
37 | }
38 | });
39 |
40 | findViewById(R.id.btn_guide).setOnClickListener(new View.OnClickListener() {
41 | @Override
42 | public void onClick(View v) {
43 | startActivity(new Intent(getApplicationContext(), DoodleGuideActivity.class));
44 | }
45 | });
46 |
47 | findViewById(R.id.btn_mosaic).setOnClickListener(new View.OnClickListener() {
48 | @Override
49 | public void onClick(View v) {
50 | startActivity(new Intent(getApplicationContext(), MosaicDemo.class));
51 | }
52 | });
53 | findViewById(R.id.btn_scale_gesture).setOnClickListener(new View.OnClickListener() {
54 | @Override
55 | public void onClick(View v) {
56 | startActivity(new Intent(getApplicationContext(), ScaleGestureItemDemo.class));
57 | }
58 | });
59 | mPath = (TextView) findViewById(R.id.img_path);
60 | }
61 |
62 | @Override
63 | protected void onActivityResult(int requestCode, int resultCode, Intent data) {
64 | super.onActivityResult(requestCode, resultCode, data);
65 | if (requestCode == REQ_CODE_SELECT_IMAGE) {
66 | if (data == null) {
67 | return;
68 | }
69 | ArrayList list = data.getStringArrayListExtra(ImageSelectorActivity.KEY_PATH_LIST);
70 | if (list != null && list.size() > 0) {
71 | LogUtil.d("Doodle", list.get(0));
72 |
73 | // 涂鸦参数
74 | DoodleParams params = new DoodleParams();
75 | params.mIsFullScreen = true;
76 | // 图片路径
77 | params.mImagePath = list.get(0);
78 | // 初始画笔大小
79 | params.mPaintUnitSize = DoodleView.DEFAULT_SIZE;
80 | // 画笔颜色
81 | params.mPaintColor = Color.RED;
82 | // 是否支持缩放item
83 | params.mSupportScaleItem = true;
84 | // 启动涂鸦页面
85 | DoodleActivity.startActivityForResult(MainActivity.this, params, REQ_CODE_DOODLE);
86 | }
87 | } else if (requestCode == REQ_CODE_DOODLE) {
88 | if (data == null) {
89 | return;
90 | }
91 | if (resultCode == DoodleActivity.RESULT_OK) {
92 | String path = data.getStringExtra(DoodleActivity.KEY_IMAGE_PATH);
93 | if (TextUtils.isEmpty(path)) {
94 | return;
95 | }
96 | ImageLoader.getInstance(this).display(findViewById(R.id.img), path);
97 | mPath.setText(path);
98 | } else if (resultCode == DoodleActivity.RESULT_ERROR) {
99 | Toast.makeText(getApplicationContext(), "error", Toast.LENGTH_SHORT).show();
100 | }
101 | }
102 | }
103 | }
104 |
--------------------------------------------------------------------------------
/app/src/main/res/layout/activity_about.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
11 |
18 |
26 |
33 |
34 |
46 |
47 |
56 |
57 |
68 |
69 |
76 |
77 |
89 |
90 |
98 |
99 |
100 |
101 |
102 |
--------------------------------------------------------------------------------
/privacy_policy.md:
--------------------------------------------------------------------------------
1 | ## Privacy Policy
2 |
3 | mmjang built the Anki Doodle app as an Open Source app. This SERVICE is provided by mmjang at no cost and is intended for use as is.
4 |
5 | This page is used to inform visitors regarding my policies with the collection, use, and disclosure of Personal Information if anyone decided to use my Service.
6 |
7 | If you choose to use my Service, then you agree to the collection and use of information in relation to this policy. The Personal Information that I collect is used for providing and improving the Service. I will not use or share your information with anyone except as described in this Privacy Policy.
8 |
9 | The terms used in this Privacy Policy have the same meanings as in our Terms and Conditions, which is accessible at Anki Doodle unless otherwise defined in this Privacy Policy.
10 |
11 | **Information Collection and Use**
12 |
13 | For a better experience, while using our Service, I may require you to provide us with certain personally identifiable information, including but not limited to Device Name, Operation System, Crash Logs. The information that I request will be retained on your device and is not collected by me in any way.
14 |
15 | The app does use third party services that may collect information used to identify you.
16 |
17 | Link to privacy policy of third party service providers used by the app
18 |
19 | **Log Data**
20 |
21 | I want to inform you that whenever you use my Service, in a case of an error in the app I collect data and information (through third party products) on your phone called Log Data. This Log Data may include information such as your device Internet Protocol (“IP”) address, device name, operating system version, the configuration of the app when utilizing my Service, the time and date of your use of the Service, and other statistics.
22 |
23 | **Cookies**
24 |
25 | Cookies are files with a small amount of data that are commonly used as anonymous unique identifiers. These are sent to your browser from the websites that you visit and are stored on your device's internal memory.
26 |
27 | This Service does not use these “cookies” explicitly. However, the app may use third party code and libraries that use “cookies” to collect information and improve their services. You have the option to either accept or refuse these cookies and know when a cookie is being sent to your device. If you choose to refuse our cookies, you may not be able to use some portions of this Service.
28 |
29 | **Service Providers**
30 |
31 | I may employ third-party companies and individuals due to the following reasons:
32 |
33 | * To facilitate our Service;
34 | * To provide the Service on our behalf;
35 | * To perform Service-related services; or
36 | * To assist us in analyzing how our Service is used.
37 |
38 | I want to inform users of this Service that these third parties have access to your Personal Information. The reason is to perform the tasks assigned to them on our behalf. However, they are obligated not to disclose or use the information for any other purpose.
39 |
40 | **Security**
41 |
42 | I value your trust in providing us your Personal Information, thus we are striving to use commercially acceptable means of protecting it. But remember that no method of transmission over the internet, or method of electronic storage is 100% secure and reliable, and I cannot guarantee its absolute security.
43 |
44 | **Links to Other Sites**
45 |
46 | This Service may contain links to other sites. If you click on a third-party link, you will be directed to that site. Note that these external sites are not operated by me. Therefore, I strongly advise you to review the Privacy Policy of these websites. I have no control over and assume no responsibility for the content, privacy policies, or practices of any third-party sites or services.
47 |
48 | **Children’s Privacy**
49 |
50 | These Services do not address anyone under the age of 13\. I do not knowingly collect personally identifiable information from children under 13\. In the case I discover that a child under 13 has provided me with personal information, I immediately delete this from our servers. If you are a parent or guardian and you are aware that your child has provided us with personal information, please contact me so that I will be able to do necessary actions.
51 |
52 | **Changes to This Privacy Policy**
53 |
54 | I may update our Privacy Policy from time to time. Thus, you are advised to review this page periodically for any changes. I will notify you of any changes by posting the new Privacy Policy on this page. These changes are effective immediately after they are posted on this page.
55 |
56 | **Contact Us**
57 |
58 | If you have any questions or suggestions about my Privacy Policy, do not hesitate to contact me at pheiztu@foxmail.com.
59 |
60 | This privacy policy page was created at [privacypolicytemplate.net](https://privacypolicytemplate.net) and modified/generated by [App Privacy Policy Generator](https://app-privacy-policy-generator.firebaseapp.com/)
--------------------------------------------------------------------------------
/app/src/main/java/com/mmjang/ankillusion/data/OcclusionObjectListGenerator.java:
--------------------------------------------------------------------------------
1 | package com.mmjang.ankillusion.data;
2 |
3 | import com.mmjang.ankillusion.MyApplication;
4 |
5 | import java.util.ArrayList;
6 | import java.util.List;
7 |
8 | import cn.hzw.doodle.occlusion.OcclusionItem;
9 |
10 | public class OcclusionObjectListGenerator {
11 | public static List gen(
12 | int version,
13 | String img,
14 | int width,
15 | int height,
16 | List occlusionItemList,
17 | OcclusionExportType expType
18 | ){
19 | Settings mySettings = Settings.getInstance(MyApplication.getContext());
20 | List occlusionObjectList = new ArrayList<>();
21 | if(expType == OcclusionExportType.HIDE_ALL_REVEAL_ALL){
22 | for(OcclusionItem occlusionItem : occlusionItemList){
23 | occlusionItem.highlight = true;
24 | occlusionItem.color = mySettings.getOcclusionColorHighlight();
25 | }
26 | List frontList = occlusionItemList;
27 | List backList = new ArrayList<>();
28 | OcclusionObject occlusionObject = new OcclusionObject(
29 | version,
30 | img,
31 | width,
32 | height,
33 | frontList,
34 | backList
35 | );
36 | occlusionObjectList.add(occlusionObject);
37 | }
38 | if(expType == OcclusionExportType.HIDE_ONE_REVEAL_ONE){
39 | //when no occlusion, make one card.
40 | if(occlusionItemList.size() == 0){
41 | List frontList = new ArrayList<>();
42 | List backList = new ArrayList<>();
43 | OcclusionObject occlusionObject = new OcclusionObject(
44 | version,
45 | img,
46 | width,
47 | height,
48 | frontList,
49 | backList
50 | );
51 | occlusionObjectList.add(occlusionObject);
52 | }
53 |
54 | for(OcclusionItem occlusionItem : occlusionItemList){
55 | occlusionItem.highlight = true;
56 | occlusionItem.color = mySettings.getOcclusionColorHighlight();
57 | List frontList = new ArrayList<>();
58 | frontList.add(occlusionItem);
59 | List backList = new ArrayList<>();
60 | OcclusionObject occlusionObject = new OcclusionObject(
61 | version,
62 | img,
63 | width,
64 | height,
65 | frontList,
66 | backList
67 | );
68 | occlusionObjectList.add(occlusionObject);
69 | }
70 | }
71 | if(expType == OcclusionExportType.HIDE_ALL_REVEAL_ONE){
72 |
73 | //when no occlusion, make one card.
74 | if(occlusionItemList.size() == 0){
75 | List frontList = new ArrayList<>();
76 | List backList = new ArrayList<>();
77 | OcclusionObject occlusionObject = new OcclusionObject(
78 | version,
79 | img,
80 | width,
81 | height,
82 | frontList,
83 | backList
84 | );
85 | occlusionObjectList.add(occlusionObject);
86 | }
87 |
88 | for(int i = 0; i < occlusionItemList.size(); i ++){
89 | List frontList = new ArrayList<>();
90 | List backList = new ArrayList<>();
91 | for(int j = 0; j < occlusionItemList.size(); j ++){
92 | OcclusionItem copiedItem = occlusionItemList.get(j).clone();
93 | if(j == i){//this is the item to hide
94 | copiedItem.highlight = true;
95 | copiedItem.color = mySettings.getOcclusionColorHighlight();
96 | frontList.add(copiedItem);
97 | }else{
98 | frontList.add(copiedItem);
99 | backList.add(copiedItem.clone());
100 | }
101 | }
102 | OcclusionObject occlusionObject = new OcclusionObject(
103 | version,
104 | img,
105 | width,
106 | height,
107 | frontList,
108 | backList
109 | );
110 | occlusionObjectList.add(occlusionObject);
111 | }
112 | }
113 |
114 | return occlusionObjectList;
115 | }
116 | }
117 |
--------------------------------------------------------------------------------
/Doodle/doodle/src/main/java/cn/hzw/doodle/DoodleParams.java:
--------------------------------------------------------------------------------
1 | package cn.hzw.doodle;
2 |
3 |
4 | import android.app.Activity;
5 | import android.graphics.Color;
6 | import android.os.Parcel;
7 | import android.os.Parcelable;
8 |
9 | import cn.hzw.doodle.core.IDoodle;
10 |
11 | /**
12 | * 涂鸦参数
13 | */
14 | public class DoodleParams implements Parcelable {
15 |
16 | /**
17 | * 图片路径
18 | */
19 | public String mImagePath;
20 | /**
21 | * 保存路径,如果为null,则图片保存在根目录下/DCIM/Doodle/
22 | */
23 | public String mSavePath;
24 | /**
25 | * 保存路径是否为目录,如果为目录,则在该目录生成由时间戳组成的图片名称
26 | */
27 | public boolean mSavePathIsDir;
28 |
29 | /**
30 | * 触摸时,图片区域外是否绘制涂鸦轨迹
31 | */
32 | public boolean mIsDrawableOutside;
33 |
34 | /**
35 | * 涂鸦时(手指按下)隐藏设置面板的延长时间(ms),当小于等于0时则为不尝试隐藏面板(即保持面板当前状态不变);当大于0时表示需要触摸屏幕超过一定时间后才隐藏
36 | * 或者手指抬起时展示面板的延长时间(ms),或者表示需要离开屏幕超过一定时间后才展示
37 | * 默认为200ms
38 | */
39 | public long mChangePanelVisibilityDelay = 200; //ms
40 |
41 | /**
42 | * 设置放大镜的倍数,当小于等于0时表示不使用放大器功能
43 | * 放大器只有在设置面板被隐藏的时候才会出现
44 | * 默认为2.5倍
45 | */
46 | public float mZoomerScale = 2.5f;
47 |
48 | /**
49 | * 是否全屏显示,即是否隐藏状态栏
50 | * 默认为false,表示状态栏继承应用样式
51 | */
52 | public boolean mIsFullScreen = false;
53 |
54 | /**
55 | * 初始化的画笔大小,单位为像素
56 | */
57 | public float mPaintPixelSize = -1;
58 |
59 | /**
60 | * 初始化的画笔大小,单位为涂鸦坐标系中的单位大小,该单位参考dp,独立于图片
61 | * mPaintUnitSize值优先于mPaintPixelSize
62 | */
63 | public float mPaintUnitSize = -1;
64 |
65 | /**
66 | * 画布的最小/最大缩放倍数
67 | */
68 | public float mMinScale = DoodleView.MIN_SCALE;
69 | public float mMaxScale = DoodleView.MAX_SCALE;
70 |
71 | /**
72 | * 初始的画笔颜色
73 | */
74 | public int mPaintColor = Color.RED;
75 |
76 | /**
77 | * 是否支持缩放item
78 | */
79 | public boolean mSupportScaleItem = true;
80 |
81 | /**
82 | *
83 | * 是否优化绘制,开启后涂鸦会及时绘制在图片上,以此优化绘制速度和性能.
84 | *
85 | * {@link DoodleView#mOptimizeDrawing}
86 | */
87 | public boolean mOptimizeDrawing = true;
88 |
89 | public static final Creator CREATOR = new Creator() {
90 | @Override
91 | public DoodleParams createFromParcel(Parcel in) {
92 | DoodleParams params = new DoodleParams();
93 | params.mImagePath = in.readString();
94 | params.mSavePath = in.readString();
95 | params.mSavePathIsDir = in.readInt() == 1;
96 | params.mIsDrawableOutside = in.readInt() == 1;
97 | params.mChangePanelVisibilityDelay = in.readLong();
98 | params.mZoomerScale = in.readFloat();
99 | params.mIsFullScreen = in.readInt() == 1;
100 | params.mPaintPixelSize = in.readFloat();
101 | params.mPaintUnitSize = in.readFloat();
102 | params.mMinScale = in.readFloat();
103 | params.mMaxScale = in.readFloat();
104 | params.mPaintColor = in.readInt();
105 | params.mSupportScaleItem = in.readInt() == 1;
106 | params.mOptimizeDrawing = in.readInt() == 1;
107 |
108 | return params;
109 | }
110 |
111 | @Override
112 | public DoodleParams[] newArray(int size) {
113 | return new DoodleParams[size];
114 | }
115 | };
116 |
117 | @Override
118 | public void writeToParcel(Parcel dest, int flags) {
119 | dest.writeString(mImagePath);
120 | dest.writeString(mSavePath);
121 | dest.writeInt(mSavePathIsDir ? 1 : 0);
122 | dest.writeInt(mIsDrawableOutside ? 1 : 0);
123 | dest.writeLong(mChangePanelVisibilityDelay);
124 | dest.writeFloat(mZoomerScale);
125 | dest.writeInt(mIsFullScreen ? 1 : 0);
126 | dest.writeFloat(mPaintPixelSize);
127 | dest.writeFloat(mPaintUnitSize);
128 | dest.writeFloat(mMinScale);
129 | dest.writeFloat(mMaxScale);
130 | dest.writeInt(mPaintColor);
131 | dest.writeInt(mSupportScaleItem ? 1 : 0);
132 | dest.writeInt(mOptimizeDrawing ? 1 : 0);
133 |
134 | }
135 |
136 | @Override
137 | public int describeContents() {
138 | return 0;
139 | }
140 |
141 | private static DialogInterceptor sDialogInterceptor;
142 |
143 | /**
144 | * 设置涂鸦中对话框的拦截器,如点击返回按钮(或返回键)弹出保存对话框,可以进行拦截,弹出自定义的对话框
145 | * 切记:需要自行处理内存泄漏的问题!!!
146 | */
147 | public static void setDialogInterceptor(DialogInterceptor interceptor) {
148 | sDialogInterceptor = interceptor;
149 | }
150 |
151 | public static DialogInterceptor getDialogInterceptor() {
152 | return sDialogInterceptor;
153 | }
154 |
155 | public enum DialogType {
156 | SAVE, CLEAR_ALL, COLOR_PICKER;
157 | }
158 |
159 | public interface DialogInterceptor {
160 | /**
161 | * @param activity
162 | * @param doodle
163 | * @param dialogType 对话框类型
164 | * @return 返回true表示拦截
165 | */
166 | boolean onShow(Activity activity, IDoodle doodle, DialogType dialogType);
167 | }
168 | }
169 |
--------------------------------------------------------------------------------