[
  {
    "path": ".gitignore",
    "content": "#Android generated\nbin\ngen\nlint.xml\nlint\n\n#Eclipse\n.project\n.classpath\n.settings\n.checkstyle\n\n#IntelliJ IDEA\n.idea\n*.iml\n*.ipr\n*.iws\nclasses\ngen-external-apklibs\n\n#gradle\n.gradle\nlocal.properties\ngradlew\ngradlew.bat\ngradle/\nbuild/\n\n#vi\n*.swp\n\n#other editors\n*.bak\n\n#Maven\ntarget\nrelease.properties\npom.xml.*\n\n#Ant\nbuild.xml\nant.properties\nlocal.properties\nproguard.cfg\nproguard-project.txt\n\n#Other\n.DS_Store\nThumbs.db\ntmp\n*.tgz\n*.lock\n*.lck\ncom_crashlytics_export_strings.xml"
  },
  {
    "path": "README.md",
    "content": "# WhiteBoard\n\n- 1、涂鸦功能：包括画笔粗细选择、颜色选择、橡皮擦等；\n- 2、文字输入：包括颜色选择、增、删、改等；\n- 3、白板功能：包括撤销、重做、新增、锁屏、切换、保存为图片、保存到本地等功能\n\n![](https://github.com/guanpy/WhiteBoard/blob/master/screenshot/main.jpg)  \n\n## 预览\n![](https://github.com/guanpy/WhiteBoard/blob/master/screenshot/main_pen.gif)  \n\n![](https://github.com/guanpy/WhiteBoard/blob/master/screenshot/main_text.gif)\n## TODO\n- 1、DrawTextView的接口化\n- 2、白板数据结构重定义\n- 3、markId的重新加载问题\n"
  },
  {
    "path": "app/.gitignore",
    "content": "/build\n"
  },
  {
    "path": "app/build.gradle",
    "content": "apply plugin: 'com.android.application'\n\nandroid {\n    compileSdkVersion 23\n    buildToolsVersion \"23.0.2\"\n\n    defaultConfig {\n        applicationId \"com.example.gpy.whiteboard\"\n        minSdkVersion 14\n        targetSdkVersion 23\n        versionCode 1\n        versionName \"1.0\"\n    }\n    buildTypes {\n        release {\n            minifyEnabled false\n            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'\n        }\n    }\n}\n\ndependencies {\n    compile fileTree(dir: 'libs', include: ['*.jar'])\n    compile project(':wblib')\n    compile 'com.android.support:appcompat-v7:23.1.1'\n    compile'com.squareup.retrofit:converter-jackson:1.9.0'\n    compile 'com.jakewharton:butterknife:6.1.0'\n}\n"
  },
  {
    "path": "app/proguard-rules.pro",
    "content": "# Add project specific ProGuard rules here.\n# By default, the flags in this file are appended to flags specified\n# in D:\\software\\Java\\Android\\sdk_studio/tools/proguard/proguard-android.txt\n# You can edit the include path and order by changing the proguardFiles\n# directive in build.gradle.\n#\n# For more details, see\n#   http://developer.android.com/guide/developing/tools/proguard.html\n\n# Add any project specific keep options here:\n\n# If your project uses WebView with JS, uncomment the following\n# and specify the fully qualified class name to the JavaScript interface\n# class:\n#-keepclassmembers class fqcn.of.javascript.interface.for.webview {\n#   public *;\n#}\n"
  },
  {
    "path": "app/src/androidTest/java/com/example/gpy/whiteboard/ApplicationTest.java",
    "content": "package com.example.gpy.whiteboard;\n\nimport android.app.Application;\nimport android.test.ApplicationTestCase;\n\n/**\n * <a href=\"http://d.android.com/tools/testing/testing_android.html\">Testing Fundamentals</a>\n */\npublic class ApplicationTest extends ApplicationTestCase<Application> {\n    public ApplicationTest() {\n        super(Application.class);\n    }\n}"
  },
  {
    "path": "app/src/main/AndroidManifest.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<manifest xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    package=\"com.example.gpy.whiteboard\">\n\n    <uses-permission android:name=\"android.permission.WRITE_EXTERNAL_STORAGE\"/>\n\n    <application\n        android:allowBackup=\"true\"\n        android:icon=\"@mipmap/ic_launcher\"\n        android:label=\"@string/app_name\"\n        android:supportsRtl=\"true\"\n        android:name=\".SelfApplication\"\n        android:theme=\"@style/AppTheme\">\n        <activity android:name=\".MainActivity\">\n            <intent-filter>\n                <action android:name=\"android.intent.action.MAIN\" />\n                <category android:name=\"android.intent.category.LAUNCHER\" />\n            </intent-filter>\n        </activity>\n        <activity\n            android:name=\".view.WhiteBoardActivity\"\n            android:windowSoftInputMode=\"stateHidden|adjustResize\"\n            android:screenOrientation=\"landscape\">\n        </activity>\n    </application>\n\n</manifest>\n"
  },
  {
    "path": "app/src/main/java/com/example/gpy/whiteboard/MainActivity.java",
    "content": "package com.example.gpy.whiteboard;\n\nimport android.os.Bundle;\nimport android.view.LayoutInflater;\nimport android.view.View;\nimport android.view.ViewGroup;\nimport android.widget.BaseAdapter;\nimport android.widget.ImageView;\nimport android.widget.ListView;\nimport android.widget.TextView;\n\nimport com.example.gpy.whiteboard.utils.FileUtil;\nimport com.example.gpy.whiteboard.utils.StoreUtil;\nimport com.example.gpy.whiteboard.utils.ToastUtils;\nimport com.example.gpy.whiteboard.view.WhiteBoardActivity;\nimport com.example.gpy.whiteboard.view.base.BaseActivity;\nimport com.github.guanpy.wblib.utils.OperationUtils;\n\nimport java.io.File;\nimport java.util.ArrayList;\n\nimport butterknife.InjectView;\n\npublic class MainActivity extends BaseActivity {\n\n    @InjectView(R.id.lv_wb)\n    ListView mLv;\n    @InjectView(R.id.iv_wb_add)\n    ImageView mIvAdd;\n\n\n    private WbAdapter mWbAdapter;\n    ArrayList<String> filenames;\n    ArrayList<String> filepaths;\n    private long mBackPressedTime;\n    @Override\n    protected int getLayoutId() {\n        return R.layout.activity_main;\n    }\n\n    @Override\n    protected void afterCreate(Bundle savedInstanceState) {\n        loadData();\n        initView();\n    }\n\n    private void loadData() {\n        File folder = new File(StoreUtil.getWbPath());\n        if (!folder.exists()) {\n            folder.mkdirs();\n        }\n        final File[] files = folder.listFiles();\n        if (files.length > 0) {\n            filenames = new ArrayList<String>();\n            filepaths = new ArrayList<String>();\n            for (File f : files) {\n                filenames.add(FileUtil.getFileName(f));\n                filepaths.add(f.getAbsolutePath());\n            }\n        }\n//        mWbAdapter.notifyDataSetChanged();\n\n    }\n\n    private void initView() {\n        mWbAdapter = new WbAdapter();\n        mLv.setAdapter(mWbAdapter);\n        mIvAdd.setOnClickListener(new View.OnClickListener() {\n            @Override\n            public void onClick(View v) {\n                OperationUtils.getInstance().initDrawPointList();\n                navi2Page(WhiteBoardActivity.class);\n            }\n        });\n    }\n\n    @Override\n    public void onBackPressed() {\n        final long mCurrentTime = System.currentTimeMillis();\n        if (mCurrentTime - this.mBackPressedTime > 1000) {\n            ToastUtils.showToast(this, R.string.app_logout);\n            this.mBackPressedTime = mCurrentTime;\n            return;\n        }\n        super.onBackPressed();\n        System.exit(0);\n    }\n\n    private class WbAdapter extends BaseAdapter {\n        @Override\n        public int getCount() {\n            return filenames != null ? filenames.size() : 0;\n        }\n\n        @Override\n        public Object getItem(int position) {\n            return null;\n        }\n\n        @Override\n        public long getItemId(int position) {\n            return 0;\n        }\n\n        @Override\n        public View getView(final int position, View convertView, ViewGroup parent) {\n            WbViewHolder holder = null;\n            if (convertView != null) {\n                holder = (WbViewHolder) convertView.getTag();\n            } else {\n                convertView = LayoutInflater.from(MainActivity.this).inflate(R.layout.wb_item, null);\n                if (convertView != null) {\n                    convertView.setTag(\n                            holder = new WbViewHolder(convertView)\n                    );\n                }\n                if (holder != null) {\n                    holder.nWbName.setText(filenames.get(position));\n                    convertView.setOnClickListener(new View.OnClickListener() {\n                        @Override\n                        public void onClick(final View v) {\n                            StoreUtil.readWhiteBoardPoints(filepaths.get(position));\n                            navi2Page(WhiteBoardActivity.class);\n                        }\n                    });\n                }\n            }\n            return convertView;\n        }\n    }\n\n    private final class WbViewHolder {\n        final TextView nWbName;\n\n        public WbViewHolder(final View view) {\n            this.nWbName = (TextView) view.findViewById(R.id.tv_wb_name);\n        }\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/com/example/gpy/whiteboard/SelfApplication.java",
    "content": "package com.example.gpy.whiteboard;\n\nimport android.app.Application;\n\nimport com.example.gpy.whiteboard.utils.SdCardStatus;\nimport com.example.gpy.whiteboard.utils.StoreUtil;\nimport com.github.guanpy.wblib.utils.AppContextUtil;\nimport com.github.guanpy.wblib.utils.OperationUtils;\n\n/**\n * Created by gpy on 2015/8/17.\n */\npublic class SelfApplication extends Application{\n\n    @Override\n    public void onCreate() {\n        super.onCreate();\n        AppContextUtil.init(this);\n        SdCardStatus.init(StoreUtil.CACHE_DIR);\n        OperationUtils.getInstance().init();\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/com/example/gpy/whiteboard/bean/WbInfo.java",
    "content": "package com.example.gpy.whiteboard.bean;\n\nimport java.io.File;\n\n/**\n * Created by gpy on 2016/4/22.\n */\npublic class WbInfo {\n\n    /**\n     * 文件名\n     */\n    private String mName;\n    /**\n     * 文件\n     */\n    private File mFile;\n\n    /**\n     * 获得文件名\n     * Created 2016-3-22 18:30:34\n     *\n     * @return 文件名\n     * @author gpy\n     */\n    public String getName() {\n        return mName;\n    }\n\n    /**\n     * 设置文件名\n     * Created 2016-3-22 18:30:34\n     *\n     * @param name 文件名\n     * @author gpy\n     */\n    public void setName(String name) {\n        this.mName = name;\n    }\n\n    /**\n     * 获得文件\n     * Created 2016-3-22 18:30:34\n     *\n     * @return 文件\n     * @author gpy\n     */\n    public File getFile() {\n        return mFile;\n    }\n\n    /**\n     * 设置文件\n     * Created 2016-3-22 18:30:34\n     *\n     * @param file 文件\n     * @author gpy\n     */\n    public void setFile(File file) {\n        this.mFile = file;\n    }\n\n\n}\n"
  },
  {
    "path": "app/src/main/java/com/example/gpy/whiteboard/utils/FileUtil.java",
    "content": "package com.example.gpy.whiteboard.utils;\n\nimport android.text.TextUtils;\nimport android.util.Log;\n\nimport java.io.File;\nimport java.io.FileInputStream;\nimport java.text.DecimalFormat;\n\n/**\n * Created by gpy on 2016/4/6.\n */\npublic class FileUtil {\n    public static final int SIZETYPE_B = 1;// 获取文件大小单位为B的double值\n    public static final int SIZETYPE_KB = 2;// 获取文件大小单位为KB的double值\n    public static final int SIZETYPE_MB = 3;// 获取文件大小单位为MB的double值\n    public static final int SIZETYPE_GB = 4;// 获取文件大小单位为GB的double值\n\n    /**\n     * 获取指定文件名字\n     *\n     * @param file\n     * @return\n     */\n    public static String getFileName(File file) {\n        final String name = file.getName();\n        if (!TextUtils.isEmpty(name)) {\n            final int ext = name.lastIndexOf(\".\");\n            if (ext > 0) {\n                return name.substring(0, ext);\n            }\n        }\n        return name;\n    }\n\n    /**\n     * 调用此方法自动计算指定文件或指定文件夹的大小\n     *\n     * @param filePath 文件路径\n     * @return 计算好的带B、KB、MB、GB的字符串\n     */\n    public static String getAutoFileOrFilesSize(String filePath) {\n        File file = new File(filePath);\n        long blockSize = 0;\n        try {\n            if (file.isDirectory()) {\n                blockSize = getFileSizes(file);\n            } else {\n                blockSize = getFileSize(file);\n            }\n        } catch (Exception e) {\n            e.printStackTrace();\n            Log.e(\"获取文件大小\", \"获取失败!\");\n        }\n        return FormetFileSize(blockSize);\n    }\n\n    /**\n     * 获取文件指定文件的指定单位的大小\n     *\n     * @param filePath 文件路径\n     * @param sizeType 获取大小的类型1为B、2为KB、3为MB、4为GB\n     * @return double值的大小\n     */\n    public static double getFileOrFilesSize(String filePath, int sizeType) {\n        File file = new File(filePath);\n        long blockSize = 0;\n        try {\n            if (file.isDirectory()) {\n                blockSize = getFileSizes(file);\n            } else {\n                blockSize = getFileSize(file);\n            }\n        } catch (Exception e) {\n            e.printStackTrace();\n            Log.e(\"获取文件大小\", \"获取失败!\");\n        }\n        return FormetFileSize(blockSize, sizeType);\n    }\n\n    /**\n     * 获取指定文件大小\n     *\n     * @param file\n     * @return\n     * @throws Exception\n     */\n    private static long getFileSize(File file) throws Exception {\n        long size = 0;\n        if (file.exists()) {\n            FileInputStream fis = null;\n            fis = new FileInputStream(file);\n            size = fis.available();\n        } else {\n            file.createNewFile();\n            Log.e(\"获取文件大小\", \"文件不存在!\");\n        }\n        return size;\n    }\n\n    /**\n     * 获取指定文件夹\n     *\n     * @param f\n     * @return\n     * @throws Exception\n     */\n    private static long getFileSizes(File f) throws Exception {\n        long size = 0;\n        File flist[] = f.listFiles();\n        for (int i = 0; i < flist.length; i++) {\n            if (flist[i].isDirectory()) {\n                size = size + getFileSizes(flist[i]);\n            } else {\n                size = size + getFileSize(flist[i]);\n            }\n        }\n        return size;\n    }\n\n    /**\n     * 转换文件大小\n     *\n     * @param fileS\n     * @return\n     */\n    private static String FormetFileSize(long fileS) {\n        DecimalFormat df = new DecimalFormat(\"#.00\");\n        String fileSizeString = \"\";\n        String wrongSize = \"0B\";\n        if (fileS == 0) {\n            return wrongSize;\n        }\n        if (fileS < 1024) {\n            fileSizeString = df.format((double) fileS) + \"B\";\n        } else if (fileS < 1048576) {\n            fileSizeString = df.format((double) fileS / 1024) + \"KB\";\n        } else if (fileS < 1073741824) {\n            fileSizeString = df.format((double) fileS / 1048576) + \"MB\";\n        } else {\n            fileSizeString = df.format((double) fileS / 1073741824) + \"GB\";\n        }\n        return fileSizeString;\n    }\n\n    /**\n     * 转换文件大小,指定转换的类型\n     *\n     * @param fileS\n     * @param sizeType\n     * @return\n     */\n    private static double FormetFileSize(long fileS, int sizeType) {\n        DecimalFormat df = new DecimalFormat(\"#.00\");\n        double fileSizeLong = 0;\n        switch (sizeType) {\n            case SIZETYPE_B:\n                fileSizeLong = Double.valueOf(df.format((double) fileS));\n                break;\n            case SIZETYPE_KB:\n                fileSizeLong = Double.valueOf(df.format((double) fileS / 1024));\n                break;\n            case SIZETYPE_MB:\n                fileSizeLong = Double.valueOf(df.format((double) fileS / 1048576));\n                break;\n            case SIZETYPE_GB:\n                fileSizeLong = Double.valueOf(df\n                        .format((double) fileS / 1073741824));\n                break;\n            default:\n                break;\n        }\n        return fileSizeLong;\n    }\n}"
  },
  {
    "path": "app/src/main/java/com/example/gpy/whiteboard/utils/SdCardStatus.java",
    "content": "package com.example.gpy.whiteboard.utils;\n\nimport android.os.Environment;\n\nimport java.io.File;\n\n/**\n * Created by gpy on 2015/10/20.\n */\npublic class SdCardStatus {\n    private static String CACHE_FOLDER_NAME;\n    private static String NONE_SD_CARD_PROMPT = \"您的手机中sd卡不存在\";\n\n    public static void init(String cacheFolderName) {\n        CACHE_FOLDER_NAME = cacheFolderName;\n    }\n    public static String getDefaulstCacheDirInSdCard() throws IllegalStateException {\n        String sdCardPath = null;\n        sdCardPath = getSDPath();\n        if (null == sdCardPath) {\n            throw new IllegalStateException(NONE_SD_CARD_PROMPT);\n        }\n        return sdCardPath + File.separator + CACHE_FOLDER_NAME;\n    }\n\n    /**\n     * when not exist sd card,return null.\n     *\n     * @return\n     */\n    public static String getSDPath() {\n        boolean sdCardExist = Environment.getExternalStorageState().equals(\n                Environment.MEDIA_MOUNTED);\n        if (sdCardExist) {\n            return Environment.getExternalStorageDirectory().getAbsolutePath();\n        } else {\n                return null;\n        }\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/com/example/gpy/whiteboard/utils/StoreUtil.java",
    "content": "package com.example.gpy.whiteboard.utils;\n\nimport android.graphics.Paint;\nimport android.graphics.Path;\nimport android.graphics.PorterDuff;\nimport android.graphics.PorterDuffXfermode;\nimport android.text.TextUtils;\nimport android.util.Log;\n\nimport com.example.gpy.whiteboard.R;\nimport com.github.guanpy.wblib.bean.DrawPenPoint;\nimport com.github.guanpy.wblib.bean.DrawPenStr;\nimport com.github.guanpy.wblib.bean.DrawPoint;\nimport com.github.guanpy.wblib.bean.Point;\nimport com.github.guanpy.wblib.bean.WhiteBoardPoint;\nimport com.github.guanpy.wblib.bean.WhiteBoardPoints;\nimport com.github.guanpy.wblib.utils.AppContextUtil;\nimport com.github.guanpy.wblib.utils.OperationUtils;\nimport com.google.gson.Gson;\n\nimport java.io.File;\nimport java.io.FileInputStream;\nimport java.io.FileNotFoundException;\nimport java.io.FileOutputStream;\nimport java.io.IOException;\nimport java.io.OutputStream;\nimport java.util.UUID;\n\n/**\n * 存储空间工具类\n * Created by gpy on 2015/8/2.\n */\npublic class StoreUtil {\n    private static final String TAG = \"StoreUtil\";\n    private static final String CHARSET = \"UTF-8\";\n    public static final String CACHE_DIR = \"WhiteBoard\";\n    private static final String CACHE_DIR_PHOTO = \"photo\";\n    private static final String PHOTO_FORMAT_PNG = \".png\";\n    private static final String CACHE_DIR_WB = \"wb\";\n    private static final String WB_FORMAT = \".wb\";\n\n    /**\n     * 获取保存路径\n     */\n    public static String getPhotoSavePath() {\n        return getPhotoPath() + File.separator + UUID.randomUUID().toString() + PHOTO_FORMAT_PNG;\n    }\n\n    public static String getPhotoPath() {\n        return SdCardStatus.getDefaulstCacheDirInSdCard() + File.separator + CACHE_DIR_PHOTO;\n    }\n    /**\n     * 获取保存路径\n     */\n    public static String getWbSavePath() {\n        return getWbPath() + File.separator + UUID.randomUUID().toString() + WB_FORMAT;\n    }\n\n    public static String getWbPath() {\n        return SdCardStatus.getDefaulstCacheDirInSdCard() + File.separator + CACHE_DIR_WB;\n    }\n    /**\n     * 存储白板集\n     */\n    public static void saveWhiteBoardPoints() {\n        WhiteBoardPoints whiteBoardPoints = OperationUtils.getInstance().getWhiteBoardPoints();\n        if (whiteBoardPoints == null || whiteBoardPoints.getWhiteBoardPoints() == null || whiteBoardPoints.getWhiteBoardPoints().isEmpty()) {\n            return;\n        }\n        for (WhiteBoardPoint whiteBoardPoint : whiteBoardPoints.getWhiteBoardPoints()) {//清除绘画路径，保留字符串形式就行\n            for (DrawPoint drawPoint : whiteBoardPoint.getSavePoints()) {\n                if (drawPoint.getType() == OperationUtils.DRAW_PEN) {\n                    drawPoint.setDrawPen(null);\n\n                }\n            }\n        }\n        String strJson = new Gson().toJson(whiteBoardPoints);\n        StoreUtil.write(strJson, getWbSavePath());\n        convertWhiteBoardPoints(whiteBoardPoints);\n        OperationUtils.getInstance().setWhiteBoardPoints(whiteBoardPoints);\n        ToastUtils.showToast(AppContextUtil.getContext(), AppContextUtil.getContext().getString(R.string.white_board_save_sucess));\n    }\n\n    /**\n     * 读取白板集\n     */\n    public static void readWhiteBoardPoints(String filePath) {\n        String strJson = StoreUtil.read(filePath);\n        if (!TextUtils.isEmpty(strJson)) {\n            WhiteBoardPoints whiteBoardPoints = new Gson().fromJson(strJson, WhiteBoardPoints.class);\n            convertWhiteBoardPoints(whiteBoardPoints);\n            OperationUtils.getInstance().setWhiteBoardPoints(whiteBoardPoints);\n        }\n\n    }\n\n    /**\n     * 从json字符中将Path、Paint系统类转换出来\n     */\n    public static void convertWhiteBoardPoints(WhiteBoardPoints whiteBoardPoints) {\n        for (WhiteBoardPoint whiteBoardPoint : whiteBoardPoints.getWhiteBoardPoints()) {\n            whiteBoardPoint.getDeletePoints().clear();\n            for (DrawPoint drawPoint : whiteBoardPoint.getSavePoints()) {\n                if (drawPoint.getType() == OperationUtils.DRAW_PEN) {\n                    DrawPenStr drawPenStr = drawPoint.getDrawPenStr();\n                    Paint paint = new Paint();\n                    paint.setAntiAlias(true);//是否使用抗锯齿功能,会消耗较大资源，绘制图形速度会变慢\n                    paint.setDither(true);// 设定是否使用图像抖动处理，会使绘制出来的图片颜色更加平滑和饱满，图像更加清晰\n                    paint.setColor(drawPenStr.getColor());//设置绘制的颜色\n                    paint.setStyle(Paint.Style.STROKE);//设置画笔的样式\n                    paint.setStrokeJoin(Paint.Join.ROUND);//设置绘制时各图形的结合方式，如平滑效果等\n                    paint.setStrokeCap(Paint.Cap.ROUND);//当画笔样式为STROKE或FILL_OR_STROKE时，设置笔刷的图形样式，如圆形样式    Cap.ROUND,或方形样式Cap.SQUARE\n                    paint.setStrokeWidth(drawPenStr.getStrokeWidth());//当画笔样式为STROKE或FILL_OR_STROKE时，设置笔刷的粗细度\n                    if (drawPenStr.getIsEraser()) {\n                        paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR));//擦除模式\n                    }\n                    Path path = new Path();\n                    path.moveTo(drawPenStr.getMoveTo().getX(), drawPenStr.getMoveTo().getY());\n                    for (int i = 0; i < drawPenStr.getQuadToA().size(); i++) {\n                        Point pointA = drawPenStr.getQuadToA().get(i);\n                        Point pointB = drawPenStr.getQuadToB().get(i);\n                        path.quadTo(pointA.getX(), pointA.getY(), pointB.getX(), pointB.getY());\n                    }\n                    path.lineTo(drawPenStr.getLineTo().getX(), drawPenStr.getLineTo().getY());\n                    path.offset(drawPenStr.getOffset().getX(), drawPenStr.getOffset().getY());\n\n                    DrawPenPoint drawPenPoint = new DrawPenPoint();\n                    drawPenPoint.setPaint(paint);\n                    drawPenPoint.setPath(path);\n                    drawPoint.setDrawPen(drawPenPoint);\n                }\n\n            }\n        }\n    }\n\n    /**\n     * 保存内容到文件中\n     */\n    public static void write(String strWb, String path) {\n        if (TextUtils.isEmpty(strWb) || TextUtils.isEmpty(path)) {\n            Log.d(TAG, \"Trying to save null or 0 length strWb or path\");\n            return;\n        }\n        File toFile = new File(path);\n        if (!toFile.getParentFile().exists()) {\n            toFile.getParentFile().mkdirs();\n        }\n        if (toFile.exists()) {\n            toFile.delete();\n        }\n        try {\n            toFile.createNewFile();\n        } catch (IOException e) {\n            Log.e(TAG, \"IOException：\" + e.getMessage());\n            toFile = null;\n        } finally {\n            if (null != toFile && null != strWb) {\n                OutputStream outStream = null;\n                try {\n                    outStream = new FileOutputStream(toFile);\n                } catch (FileNotFoundException e) {\n                    Log.d(TAG, \"FileNotFoundException：\" + e.getMessage());\n                    outStream = null;\n                } finally {\n                    if (null != outStream) {\n                        try {\n                            outStream.write(strWb.getBytes(\"utf-8\"));\n                            outStream.flush();\n                        } catch (IOException e) {\n                            Log.e(TAG, \"IOException：\" + e.getMessage());\n                        } finally {\n                            try {\n                                if (null != outStream) {\n                                    outStream.close();\n                                }\n                            } catch (IOException e) {\n                                Log.d(TAG, \"IOException\" + e.getMessage());\n                            }\n                        }\n                    }\n                }\n            }\n        }\n    }\n\n    /**\n     * 加载文件内容\n     */\n    public static String read(String wbPath) {\n        File file = new File(wbPath);\n        if (file.exists()) {\n            FileInputStream fis = null;\n            try {\n                fis = new FileInputStream(file);\n                int len = fis.available();\n                if (len > 0) {\n                    byte[] buf = new byte[len];\n                    fis.read(buf);\n                    String string = new String(buf, CHARSET);\n                    return string;\n                }\n            } catch (Exception e) {\n                e.printStackTrace();\n            } catch (OutOfMemoryError e) {\n                e.printStackTrace();\n            } finally {\n                if (fis != null)\n                    try {\n                        fis.close();\n                    } catch (IOException e) {\n                        e.printStackTrace();\n                    }\n            }\n        }\n        return null;\n    }\n\n\n}\n"
  },
  {
    "path": "app/src/main/java/com/example/gpy/whiteboard/utils/ToastUtils.java",
    "content": "package com.example.gpy.whiteboard.utils;\n\nimport android.content.Context;\nimport android.widget.Toast;\n\n/**\n * Created by gpy on 2016/4/11.\n */\npublic class ToastUtils {\n\n    public static void showToast(Context context, String string) {\n        Toast.makeText(context, string, Toast.LENGTH_SHORT).show();\n    }\n\n    public static void showToast(Context context, int intStr) {\n        Toast.makeText(context, intStr, Toast.LENGTH_SHORT).show();\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/com/example/gpy/whiteboard/view/WhiteBoardActivity.java",
    "content": "package com.example.gpy.whiteboard.view;\n\nimport android.content.Intent;\nimport android.graphics.Bitmap;\nimport android.net.Uri;\nimport android.os.Bundle;\nimport android.os.Handler;\nimport android.util.Log;\nimport android.view.View;\nimport android.widget.FrameLayout;\nimport android.widget.ImageView;\nimport android.widget.LinearLayout;\nimport android.widget.RelativeLayout;\nimport android.widget.TextView;\n\nimport com.example.gpy.whiteboard.R;\nimport com.example.gpy.whiteboard.utils.StoreUtil;\nimport com.example.gpy.whiteboard.view.base.BaseActivity;\nimport com.example.gpy.whiteboard.view.widget.floatingactionmenu.FloatingActionsMenu;\nimport com.example.gpy.whiteboard.view.widget.floatingactionmenu.FloatingImageButton;\nimport com.github.guanpy.library.ann.ReceiveEvents;\nimport com.github.guanpy.wblib.bean.DrawPoint;\nimport com.github.guanpy.wblib.utils.Events;\nimport com.github.guanpy.wblib.utils.OperationUtils;\nimport com.github.guanpy.wblib.utils.WhiteBoardVariable;\nimport com.github.guanpy.wblib.widget.DrawPenView;\nimport com.github.guanpy.wblib.widget.DrawTextLayout;\nimport com.github.guanpy.wblib.widget.DrawTextView;\n\nimport java.io.File;\nimport java.io.FileOutputStream;\n\nimport butterknife.InjectView;\n\n/**\n * 白板工具\n * Created by gpy on 2015/6/2.\n */\npublic class WhiteBoardActivity extends BaseActivity implements View.OnClickListener {\n    @InjectView(R.id.iv_white_board_book)\n    ImageView mIvWhiteBoardBook;\n    @InjectView(R.id.rl_head)\n    RelativeLayout mRlHead;\n    @InjectView(R.id.iv_white_board_back)\n    ImageView mIvWhiteBoardBack;\n    @InjectView(R.id.tv_white_board_head)\n    TextView mTvWhiteBoardHead;\n    @InjectView(R.id.iv_white_board_export)\n    ImageView mIvWhiteBoardExport;\n    @InjectView(R.id.iv_white_board_save)\n    ImageView mIvWhiteBoardSave;\n    @InjectView(R.id.fl_view)\n    FrameLayout mFlView;\n    @InjectView(R.id.db_view)\n    DrawPenView mDbView;\n    @InjectView(R.id.dt_view)\n    DrawTextLayout mDtView;\n    @InjectView(R.id.fab_menu_size)\n    FloatingActionsMenu mFabMenuSize;\n    @InjectView(R.id.bt_size_large)\n    FloatingImageButton mBtSizeLarge;\n    @InjectView(R.id.bt_size_middle)\n    FloatingImageButton mBtSizeMiddle;\n    @InjectView(R.id.bt_size_mini)\n    FloatingImageButton mBtSizeMini;\n    @InjectView(R.id.fab_menu_color)\n    FloatingActionsMenu mFabMenuColor;\n    @InjectView(R.id.bt_color_green)\n    FloatingImageButton mBtColorGreen;\n    @InjectView(R.id.bt_color_purple)\n    FloatingImageButton mBtColorPurple;\n    @InjectView(R.id.bt_color_pink)\n    FloatingImageButton mBtColorPink;\n    @InjectView(R.id.bt_color_orange)\n    FloatingImageButton mBtColorOrange;\n    @InjectView(R.id.bt_color_black)\n    FloatingImageButton mBtColorBlack;\n    @InjectView(R.id.fab_menu_text)\n    FloatingActionsMenu mFabMenuText;\n    @InjectView(R.id.bt_text_underline)\n    FloatingImageButton mBtTextUnderline;\n    @InjectView(R.id.bt_text_italics)\n    FloatingImageButton mBtTextItalics;\n    @InjectView(R.id.bt_text_bold)\n    FloatingImageButton mBtTextBold;\n    @InjectView(R.id.fab_menu_eraser)\n    FloatingActionsMenu mFabMenuEraser;\n    @InjectView(R.id.bt_eraser_large)\n    FloatingImageButton mBtEraserLarge;\n    @InjectView(R.id.bt_eraser_middle)\n    FloatingImageButton mBtEraserMiddle;\n    @InjectView(R.id.bt_eraser_mini)\n    FloatingImageButton mBtEraserMini;\n    @InjectView(R.id.iv_white_board_undo)\n    ImageView mIvWhiteBoardUndo;\n    @InjectView(R.id.iv_white_board_redo)\n    ImageView mIvWhiteBoardRedo;\n    @InjectView(R.id.ll_white_board_page)\n    LinearLayout mLlWhiteBoardPage;\n    @InjectView(R.id.iv_white_board_pre)\n    ImageView mIvWhiteBoardPre;\n    @InjectView(R.id.tv_white_board_page)\n    TextView mTvWhiteBoardPage;\n    @InjectView(R.id.iv_white_board_next)\n    ImageView mIvWhiteBoardNext;\n    @InjectView(R.id.iv_white_board_add)\n    ImageView mIvWhiteBoardAdd;\n    @InjectView(R.id.iv_white_board_disable)\n    ImageView mIvWhiteBoardDisable;\n    @InjectView(R.id.iv_white_board_quit)\n    ImageView mIvWhiteBoardQuit;\n    @InjectView(R.id.iv_white_board_confirm)\n    ImageView mIvWhiteBoardConfirm;\n    @InjectView(R.id.rl_content)\n    RelativeLayout mRlContent;\n    @InjectView(R.id.rl_bottom)\n    RelativeLayout mRlBottom;\n    @InjectView(R.id.v_bottom_back)\n    View mVBottomBack;\n    @InjectView(R.id.ll_white_board_pre)\n    LinearLayout mLlWhiteBoardPre;\n    @InjectView(R.id.ll_white_board_next)\n    LinearLayout mLlWhiteBoardNext;\n\n\n\n\n    @Override\n    protected void afterCreate(Bundle bundle) {\n        initView();\n        initEvent();\n\n    }\n    private void initView() {\n        changePenBack();\n        changeColorBack();\n        changeEraserBack();\n        ToolsOperation(WhiteBoardVariable.Operation.PEN_NORMAL);\n        mDbView.post(new Runnable() {\n            @Override\n            public void run() {\n                showPoints();\n            }\n        });\n    }\n\n    private void initEvent() {\n        //头部\n        mIvWhiteBoardBack.setOnClickListener(this);\n        mIvWhiteBoardExport.setOnClickListener(this);\n        mIvWhiteBoardSave.setOnClickListener(this);\n        mIvWhiteBoardQuit.setOnClickListener(this);\n        mIvWhiteBoardConfirm.setOnClickListener(this);\n        mVBottomBack.setOnClickListener(this);\n        //画笔尺寸大小\n        mFabMenuSize.setOnFloatingActionsMenuClickListener(new FloatingActionsMenu.OnFloatingActionsMenuClickListener() {\n            @Override\n            public void addButtonLister() {\n                ToolsOperation(WhiteBoardVariable.Operation.PEN_CLICK);\n            }\n        });\n        mBtSizeLarge.setOnClickListener(this);\n        mBtSizeMiddle.setOnClickListener(this);\n        mBtSizeMini.setOnClickListener(this);\n        //画笔或者文字颜色\n        mFabMenuColor.setOnFloatingActionsMenuClickListener(new FloatingActionsMenu.OnFloatingActionsMenuClickListener() {\n            @Override\n            public void addButtonLister() {\n                ToolsOperation(WhiteBoardVariable.Operation.COLOR_CLICK);\n            }\n        });\n        mBtColorGreen.setOnClickListener(this);\n        mBtColorPurple.setOnClickListener(this);\n        mBtColorPink.setOnClickListener(this);\n        mBtColorOrange.setOnClickListener(this);\n        mBtColorBlack.setOnClickListener(this);\n        //文字样式\n        mFabMenuText.setOnFloatingActionsMenuClickListener(new FloatingActionsMenu.OnFloatingActionsMenuClickListener() {\n            @Override\n            public void addButtonLister() {\n                ToolsOperation(WhiteBoardVariable.Operation.TEXT_CLICK);\n            }\n        });\n        mBtTextUnderline.setOnClickListener(this);\n        mBtTextItalics.setOnClickListener(this);\n        mBtTextBold.setOnClickListener(this);\n        //橡皮擦尺寸大小\n        mFabMenuEraser.setOnFloatingActionsMenuClickListener(new FloatingActionsMenu.OnFloatingActionsMenuClickListener() {\n            @Override\n            public void addButtonLister() {\n                ToolsOperation(WhiteBoardVariable.Operation.ERASER_CLICK);\n            }\n        });\n        mBtEraserLarge.setOnClickListener(this);\n        mBtEraserMiddle.setOnClickListener(this);\n        mBtEraserMini.setOnClickListener(this);\n\n        mIvWhiteBoardUndo.setOnClickListener(this);\n        mIvWhiteBoardRedo.setOnClickListener(this);\n\n        mLlWhiteBoardPre.setOnClickListener(this);\n        mIvWhiteBoardPre.setOnClickListener(this);\n        mLlWhiteBoardNext.setOnClickListener(this);\n        mIvWhiteBoardNext.setOnClickListener(this);\n        mIvWhiteBoardAdd.setOnClickListener(this);\n        mIvWhiteBoardDisable.setOnClickListener(this);\n\n    }\n\n    @Override\n    public void onClick(View view) {\n        switch (view.getId()) {\n            case R.id.iv_white_board_back://返回键\n                onBackPressed();\n                break;\n            case R.id.iv_white_board_quit://退出文字编辑\n                afterEdit(false);\n                break;\n            case R.id.iv_white_board_confirm://保存文字编辑\n                afterEdit(true);\n                break;\n            case R.id.iv_white_board_export://保存白板操作集到本地\n                ToolsOperation(WhiteBoardVariable.Operation.OUTSIDE_CLICK);\n                StoreUtil.saveWhiteBoardPoints();\n                break;\n            case R.id.iv_white_board_save://保存白板为图片\n                ToolsOperation(WhiteBoardVariable.Operation.OUTSIDE_CLICK);\n                saveImage();\n                break;\n            case R.id.v_bottom_back://点击挡板\n                ToolsOperation(WhiteBoardVariable.Operation.OUTSIDE_CLICK);\n                break;\n            case R.id.bt_size_large://设置画笔尺寸-大号\n                setPenSize(WhiteBoardVariable.PenSize.LARRGE);\n                break;\n            case R.id.bt_size_middle://设置画笔尺寸-中号\n                setPenSize(WhiteBoardVariable.PenSize.MIDDLE);\n                break;\n            case R.id.bt_size_mini://设置画笔尺寸-小号\n                setPenSize(WhiteBoardVariable.PenSize.MINI);\n                break;\n\n            case R.id.bt_color_green://设置颜色-绿色\n                setColor(WhiteBoardVariable.Color.GREEN);\n                break;\n            case R.id.bt_color_purple://设置颜色-紫色\n                setColor(WhiteBoardVariable.Color.PURPLE);\n                break;\n            case R.id.bt_color_pink://设置颜色-粉色\n                setColor(WhiteBoardVariable.Color.PINK);\n                break;\n            case R.id.bt_color_orange://设置颜色-橙色\n                setColor(WhiteBoardVariable.Color.ORANGE);\n                break;\n            case R.id.bt_color_black://设置颜色-黑色\n                setColor(WhiteBoardVariable.Color.BLACK);\n                break;\n\n            case R.id.bt_text_underline://设置文字样式-下划线\n                setTextStyle(WhiteBoardVariable.TextStyle.CHANGE_UNDERLINE);\n                break;\n            case R.id.bt_text_italics://设置文字样式-斜体\n                setTextStyle(WhiteBoardVariable.TextStyle.CHANGE_ITALICS);\n                break;\n            case R.id.bt_text_bold://设置文字样式-粗体\n                setTextStyle(WhiteBoardVariable.TextStyle.CHANGE_BOLD);\n                break;\n\n            case R.id.bt_eraser_large://设置橡皮擦尺寸-大号\n                setEraserSize(WhiteBoardVariable.EraserSize.LARRGE);\n                break;\n            case R.id.bt_eraser_middle://设置橡皮擦尺寸-中号\n                setEraserSize(WhiteBoardVariable.EraserSize.MIDDLE);\n                break;\n            case R.id.bt_eraser_mini://设置橡皮擦尺寸-小号\n                setEraserSize(WhiteBoardVariable.EraserSize.MINI);\n                break;\n\n            case R.id.iv_white_board_undo://撤销\n                ToolsOperation(WhiteBoardVariable.Operation.OUTSIDE_CLICK);\n                if (OperationUtils.getInstance().DISABLE) {\n                    undo();\n                }\n                break;\n            case R.id.iv_white_board_redo://重做\n                ToolsOperation(WhiteBoardVariable.Operation.OUTSIDE_CLICK);\n                if (OperationUtils.getInstance().DISABLE) {\n                    redo();\n                }\n                break;\n            case R.id.ll_white_board_pre:\n            case R.id.iv_white_board_pre://上一页\n                ToolsOperation(WhiteBoardVariable.Operation.OUTSIDE_CLICK);\n                prePage();\n                break;\n            case R.id.ll_white_board_next:\n            case R.id.iv_white_board_next://下一页\n                ToolsOperation(WhiteBoardVariable.Operation.OUTSIDE_CLICK);\n                nextPage();\n                break;\n            case R.id.iv_white_board_add://新建白板\n                ToolsOperation(WhiteBoardVariable.Operation.OUTSIDE_CLICK);\n                newPage();\n                break;\n            case R.id.iv_white_board_disable://禁止/解禁按钮\n                ToolsOperation(WhiteBoardVariable.Operation.OUTSIDE_CLICK);\n                if (OperationUtils.getInstance().DISABLE) {\n                    OperationUtils.getInstance().DISABLE = false;\n                    mIvWhiteBoardDisable.setImageResource(R.drawable.white_board_undisable_selector);\n                    mRlBottom.setVisibility(View.GONE);\n                } else {\n                    OperationUtils.getInstance().DISABLE = true;\n                    mIvWhiteBoardDisable.setImageResource(R.drawable.white_board_disable_selector);\n                    mRlBottom.setVisibility(View.VISIBLE);\n                }\n                break;\n\n        }\n    }\n\n    /**\n     * 设置画笔尺寸\n     */\n    private void setPenSize(int size) {\n        OperationUtils.getInstance().mCurrentPenSize = size;\n        changePenBack();\n        mDbView.setPenSize();\n    }\n\n    /**\n     * 切换画笔尺寸按按钮背景\n     */\n    private void changePenBack() {\n        if (OperationUtils.getInstance().mCurrentPenSize == WhiteBoardVariable.PenSize.LARRGE) {\n            mBtSizeLarge.drawCircleAndRing(WhiteBoardVariable.PenSize.LARRGE, OperationUtils.getInstance().mCurrentColor);\n            mBtSizeMiddle.drawCircle(WhiteBoardVariable.PenSize.MIDDLE);\n            mBtSizeMini.drawCircle(WhiteBoardVariable.PenSize.MINI);\n        } else if (OperationUtils.getInstance().mCurrentPenSize == WhiteBoardVariable.PenSize.MIDDLE) {\n            mBtSizeLarge.drawCircle(WhiteBoardVariable.PenSize.LARRGE);\n            mBtSizeMiddle.drawCircleAndRing(WhiteBoardVariable.PenSize.MIDDLE, OperationUtils.getInstance().mCurrentColor);\n            mBtSizeMini.drawCircle(WhiteBoardVariable.PenSize.MINI);\n        } else if (OperationUtils.getInstance().mCurrentPenSize == WhiteBoardVariable.PenSize.MINI) {\n            mBtSizeLarge.drawCircle(WhiteBoardVariable.PenSize.LARRGE);\n            mBtSizeMiddle.drawCircle(WhiteBoardVariable.PenSize.MIDDLE);\n            mBtSizeMini.drawCircleAndRing(WhiteBoardVariable.PenSize.MINI, OperationUtils.getInstance().mCurrentColor);\n\n        }\n    }\n\n    /**\n     * 设置颜色\n     */\n    private void setColor(int color) {\n        OperationUtils.getInstance().mCurrentColor = color;\n        changeColorBack();\n        setPenSize(OperationUtils.getInstance().mCurrentPenSize);\n        mDbView.setPenColor();\n        mDtView.setTextColor();\n    }\n\n    /**\n     * 切换颜色控制按钮背景\n     */\n    private void changeColorBack() {\n        if (OperationUtils.getInstance().mCurrentColor == WhiteBoardVariable.Color.BLACK) {\n            mFabMenuColor.setAddButtonBackground(R.drawable.white_board_color_black_selector);\n        } else if (OperationUtils.getInstance().mCurrentColor == WhiteBoardVariable.Color.ORANGE) {\n            mFabMenuColor.setAddButtonBackground(R.drawable.white_board_color_orange_selector);\n        } else if (OperationUtils.getInstance().mCurrentColor == WhiteBoardVariable.Color.PINK) {\n            mFabMenuColor.setAddButtonBackground(R.drawable.white_board_color_pink_selector);\n        } else if (OperationUtils.getInstance().mCurrentColor == WhiteBoardVariable.Color.PURPLE) {\n            mFabMenuColor.setAddButtonBackground(R.drawable.white_board_color_purple_selector);\n        } else if (OperationUtils.getInstance().mCurrentColor == WhiteBoardVariable.Color.GREEN) {\n            mFabMenuColor.setAddButtonBackground(R.drawable.white_board_color_green_selector);\n        }\n    }\n\n    /**\n     * 设置文字风格\n     */\n    private void setTextStyle(int textStyle) {\n        mDtView.setTextStyle(textStyle);\n        changeTextBack();\n    }\n\n    /**\n     * 切换文字相关按钮背景\n     */\n    private void changeTextBack() {\n        int size = OperationUtils.getInstance().getSavePoints().size();\n        if (size < 1) {\n            return;\n        }\n        DrawPoint dp = OperationUtils.getInstance().getSavePoints().get(size - 1);\n        if (dp.getType() != OperationUtils.DRAW_TEXT) {\n            return;\n        }\n        if (dp.getDrawText().getIsUnderline()) {\n            mBtTextUnderline.setBackgroundResource(R.drawable.white_board_text_underline_selected_selector);\n        } else {\n            mBtTextUnderline.setBackgroundResource(R.drawable.white_board_text_underline_selector);\n        }\n\n        if (dp.getDrawText().getIsItalics()) {\n            mBtTextItalics.setBackgroundResource(R.drawable.white_board_text_italics_selected_selector);\n        } else {\n            mBtTextItalics.setBackgroundResource(R.drawable.white_board_text_italics_selector);\n        }\n\n        if (dp.getDrawText().getIsBold()) {\n            mBtTextBold.setBackgroundResource(R.drawable.white_board_text_bold_selected_selector);\n        } else {\n            mBtTextBold.setBackgroundResource(R.drawable.white_board_text_bold_selector);\n        }\n    }\n\n    /**\n     * 设置橡皮擦尺寸\n     */\n    private void setEraserSize(int size) {\n        OperationUtils.getInstance().mCurrentEraserSize = size;\n        changeEraserBack();\n        mDbView.setEraserSize();\n\n    }\n\n    /**\n     * 切换橡皮擦尺寸按钮背景\n     */\n    private void changeEraserBack() {\n        if (OperationUtils.getInstance().mCurrentEraserSize == WhiteBoardVariable.EraserSize.LARRGE) {\n            mBtEraserLarge.drawCircleAndRing(WhiteBoardVariable.EraserSize.LARRGE, WhiteBoardVariable.Color.BLACK);\n            mBtEraserMiddle.drawCircle(WhiteBoardVariable.EraserSize.MIDDLE, WhiteBoardVariable.Color.BLACK);\n            mBtEraserMini.drawCircle(WhiteBoardVariable.EraserSize.MINI, WhiteBoardVariable.Color.BLACK);\n        } else if (OperationUtils.getInstance().mCurrentEraserSize == WhiteBoardVariable.EraserSize.MIDDLE) {\n            mBtEraserLarge.drawCircle(WhiteBoardVariable.EraserSize.LARRGE, WhiteBoardVariable.Color.BLACK);\n            mBtEraserMiddle.drawCircleAndRing(WhiteBoardVariable.EraserSize.MIDDLE, WhiteBoardVariable.Color.BLACK);\n            mBtEraserMini.drawCircle(WhiteBoardVariable.EraserSize.MINI, WhiteBoardVariable.Color.BLACK);\n        } else if (OperationUtils.getInstance().mCurrentEraserSize == WhiteBoardVariable.EraserSize.MINI) {\n            mBtEraserLarge.drawCircle(WhiteBoardVariable.EraserSize.LARRGE, WhiteBoardVariable.Color.BLACK);\n            mBtEraserMiddle.drawCircle(WhiteBoardVariable.EraserSize.MIDDLE, WhiteBoardVariable.Color.BLACK);\n            mBtEraserMini.drawCircleAndRing(WhiteBoardVariable.EraserSize.MINI, WhiteBoardVariable.Color.BLACK);\n\n        }\n    }\n\n    /**\n     * 新建白板\n     */\n    private void newPage() {\n        OperationUtils.getInstance().newPage();\n        showPoints();\n    }\n\n    /**\n     * 上一页\n     */\n    private void prePage() {\n        if (OperationUtils.getInstance().mCurrentIndex > 0) {\n            OperationUtils.getInstance().mCurrentIndex--;\n            showPoints();\n        }\n    }\n\n    /**\n     * 下一页\n     */\n    private void nextPage() {\n        if (OperationUtils.getInstance().mCurrentIndex + 1 < OperationUtils.getInstance().getDrawPointSize()) {\n            OperationUtils.getInstance().mCurrentIndex++;\n            showPoints();\n        }\n    }\n\n    /**\n     * 重新显示白板\n     */\n    private void showPoints() {\n        mDbView.showPoints();\n        mDtView.showPoints();\n        mTvWhiteBoardPage.setText(\"\" + (OperationUtils.getInstance().mCurrentIndex + 1) + \"/\" + OperationUtils.getInstance().getDrawPointSize());\n        showPage();\n        showUndoRedo();\n    }\n\n    /**\n     * 显示上下页是否可点击\n     */\n    private void showPage() {\n        if (OperationUtils.getInstance().mCurrentIndex + 1 == OperationUtils.getInstance().getDrawPointSize()) {\n            mIvWhiteBoardNext.setImageResource(R.drawable.white_board_next_page_click);\n        } else {\n            mIvWhiteBoardNext.setImageResource(R.drawable.white_board_next_page_selector);\n        }\n        if (OperationUtils.getInstance().mCurrentIndex == 0) {\n            mIvWhiteBoardPre.setImageResource(R.drawable.white_board_pre_page_click);\n        } else {\n            mIvWhiteBoardPre.setImageResource(R.drawable.white_board_pre_page_selector);\n        }\n\n    }\n\n    /**\n     * 撤销\n     */\n    private void undo() {\n        int size = OperationUtils.getInstance().getSavePoints().size();\n        if (size == 0) {\n            return;\n        } else {\n            OperationUtils.getInstance().getDeletePoints().add(OperationUtils.getInstance().getSavePoints().get(size - 1));\n            OperationUtils.getInstance().getSavePoints().remove(size - 1);\n            size = OperationUtils.getInstance().getDeletePoints().size();\n            if (OperationUtils.getInstance().getDeletePoints().get(size - 1).getType() == OperationUtils.DRAW_PEN) {\n                mDbView.undo();\n            } else if (OperationUtils.getInstance().getDeletePoints().get(size - 1).getType() == OperationUtils.DRAW_TEXT) {\n                mDtView.undo();\n            }\n            showUndoRedo();\n        }\n\n    }\n\n    /**\n     * 重做\n     */\n    private void redo() {\n        int size = OperationUtils.getInstance().getDeletePoints().size();\n        if (size == 0) {\n            return;\n        } else {\n            OperationUtils.getInstance().getSavePoints().add(OperationUtils.getInstance().getDeletePoints().get(size - 1));\n            OperationUtils.getInstance().getDeletePoints().remove(size - 1);\n            size = OperationUtils.getInstance().getSavePoints().size();\n            if (OperationUtils.getInstance().getSavePoints().get(size - 1).getType() == OperationUtils.DRAW_PEN) {\n                mDbView.redo();\n            } else if (OperationUtils.getInstance().getSavePoints().get(size - 1).getType() == OperationUtils.DRAW_TEXT) {\n                mDtView.redo();\n            }\n            showUndoRedo();\n        }\n\n    }\n\n    @Override\n    protected int getLayoutId() {\n        return R.layout.activity_white_board;\n    }\n\n    /**\n     * 文字编辑之后\n     */\n    private void afterEdit(boolean isSave) {\n        mIvWhiteBoardBack.setVisibility(View.VISIBLE);\n        mIvWhiteBoardExport.setVisibility(View.VISIBLE);\n        mIvWhiteBoardSave.setVisibility(View.VISIBLE);\n        mRlBottom.setVisibility(View.VISIBLE);\n        mIvWhiteBoardDisable.setVisibility(View.VISIBLE);\n//        mLayoutParams = (RelativeLayout.LayoutParams) mRlContent.getLayoutParams();\n//        mLayoutParams.setMargins(OperationUtils.dip2px(24), 0, OperationUtils.dip2px(24), OperationUtils.dip2px(24));\n//        mRlContent.setLayoutParams(mLayoutParams);\n        mIvWhiteBoardQuit.setVisibility(View.GONE);\n        mIvWhiteBoardConfirm.setVisibility(View.GONE);\n        mDbView.showPoints();\n        mDtView.afterEdit(isSave);\n    }\n\n    /**\n     * 白板工具栏点击切换操作\n     */\n    private void ToolsOperation(int currentOperation) {\n        setPenOperation(currentOperation);\n        setColorOperation(currentOperation);\n        setTextOperation(currentOperation);\n        setEraserOperation(currentOperation);\n        showOutSideView();\n    }\n\n    /**\n     * 显示挡板\n     */\n    private void showOutSideView() {\n        new Handler().postDelayed(new Runnable() {\n            @Override\n            public void run() {\n                if (OperationUtils.getInstance().mCurrentOPerationPen == WhiteBoardVariable.Operation.PEN_EXPAND\n                        || OperationUtils.getInstance().mCurrentOPerationColor == WhiteBoardVariable.Operation.COLOR_EXPAND\n                        || OperationUtils.getInstance().mCurrentOPerationText == WhiteBoardVariable.Operation.TEXT_EXPAND\n                        || OperationUtils.getInstance().mCurrentOPerationEraser == WhiteBoardVariable.Operation.ERASER_EXPAND) {\n                    mVBottomBack.setVisibility(View.VISIBLE);\n                } else {\n                    mVBottomBack.setVisibility(View.GONE);\n                }\n            }\n        }, 100);\n\n    }\n\n    /**\n     * 白板工具栏点击切换操作-画笔\n     */\n    private void setPenOperation(int currentOperation) {\n        switch (currentOperation) {\n            case WhiteBoardVariable.Operation.PEN_CLICK:\n                switch (OperationUtils.getInstance().mCurrentOPerationPen) {\n                    case WhiteBoardVariable.Operation.PEN_NORMAL:\n                        OperationUtils.getInstance().mCurrentDrawType = OperationUtils.DRAW_PEN;\n                        mDbView.setPaint(null);\n                        mFabMenuSize.setAddButtonBackground(R.drawable.white_board_pen_selected_selector);\n                        OperationUtils.getInstance().mCurrentOPerationPen = WhiteBoardVariable.Operation.PEN_CLICK;\n                        break;\n                    case WhiteBoardVariable.Operation.PEN_CLICK:\n                        mFabMenuSize.expand();\n                        changePenBack();\n                        OperationUtils.getInstance().mCurrentOPerationPen = WhiteBoardVariable.Operation.PEN_EXPAND;\n                        break;\n                    case WhiteBoardVariable.Operation.PEN_EXPAND:\n                        mFabMenuSize.collapse();\n                        OperationUtils.getInstance().mCurrentOPerationPen = WhiteBoardVariable.Operation.PEN_CLICK;\n                        break;\n                }\n                break;\n            case WhiteBoardVariable.Operation.TEXT_CLICK:\n            case WhiteBoardVariable.Operation.ERASER_CLICK:\n                switch (OperationUtils.getInstance().mCurrentOPerationPen) {\n                    case WhiteBoardVariable.Operation.PEN_NORMAL:\n                        break;\n                    case WhiteBoardVariable.Operation.PEN_CLICK:\n                        mFabMenuSize.clearDraw();\n                        mFabMenuSize.setAddButtonBackground(R.drawable.white_board_pen_selector);\n                        OperationUtils.getInstance().mCurrentOPerationPen = WhiteBoardVariable.Operation.PEN_NORMAL;\n                        break;\n                    case WhiteBoardVariable.Operation.PEN_EXPAND:\n                        mFabMenuSize.collapse();\n                        mFabMenuSize.clearDraw();\n                        mFabMenuSize.setAddButtonBackground(R.drawable.white_board_pen_selector);\n                        OperationUtils.getInstance().mCurrentOPerationPen = WhiteBoardVariable.Operation.PEN_NORMAL;\n                        break;\n                }\n                break;\n            case WhiteBoardVariable.Operation.COLOR_CLICK:\n            case WhiteBoardVariable.Operation.OUTSIDE_CLICK:\n                switch (OperationUtils.getInstance().mCurrentOPerationPen) {\n                    case WhiteBoardVariable.Operation.PEN_NORMAL:\n                        break;\n                    case WhiteBoardVariable.Operation.PEN_CLICK:\n                        break;\n                    case WhiteBoardVariable.Operation.PEN_EXPAND:\n                        mFabMenuSize.collapse();\n                        OperationUtils.getInstance().mCurrentOPerationPen = WhiteBoardVariable.Operation.PEN_CLICK;\n                        break;\n                }\n                break;\n\n        }\n\n    }\n\n    /**\n     * 白板工具栏点击切换操作-颜色\n     */\n    private void setColorOperation(int currentOperation) {\n        switch (currentOperation) {\n            case WhiteBoardVariable.Operation.PEN_CLICK:\n            case WhiteBoardVariable.Operation.TEXT_CLICK:\n            case WhiteBoardVariable.Operation.ERASER_CLICK:\n            case WhiteBoardVariable.Operation.OUTSIDE_CLICK:\n                switch (OperationUtils.getInstance().mCurrentOPerationColor) {\n                    case WhiteBoardVariable.Operation.COLOR_NORMAL:\n                        break;\n                    case WhiteBoardVariable.Operation.COLOR_EXPAND:\n                        mFabMenuColor.collapse();\n                        OperationUtils.getInstance().mCurrentOPerationColor = WhiteBoardVariable.Operation.COLOR_NORMAL;\n                        break;\n                }\n                break;\n            case WhiteBoardVariable.Operation.COLOR_CLICK:\n                switch (OperationUtils.getInstance().mCurrentOPerationColor) {\n                    case WhiteBoardVariable.Operation.COLOR_NORMAL:\n                        mFabMenuColor.expand();\n                        OperationUtils.getInstance().mCurrentOPerationColor = WhiteBoardVariable.Operation.COLOR_EXPAND;\n                        break;\n                    case WhiteBoardVariable.Operation.COLOR_EXPAND:\n                        mFabMenuColor.collapse();\n                        OperationUtils.getInstance().mCurrentOPerationColor = WhiteBoardVariable.Operation.COLOR_NORMAL;\n                        break;\n                }\n                break;\n\n        }\n\n    }\n\n    /**\n     * 白板工具栏点击切换操作-文字\n     */\n    private void setTextOperation(int currentOperation) {\n        switch (currentOperation) {\n            case WhiteBoardVariable.Operation.TEXT_CLICK:\n                switch (OperationUtils.getInstance().mCurrentOPerationText) {\n                    case WhiteBoardVariable.Operation.TEXT_NORMAL:\n                        OperationUtils.getInstance().mCurrentDrawType = OperationUtils.DRAW_TEXT;\n                        mFabMenuText.setAddButtonBackground(R.drawable.white_board_text_selected_selector);\n                        OperationUtils.getInstance().mCurrentOPerationText = WhiteBoardVariable.Operation.TEXT_CLICK;\n                        break;\n                    case WhiteBoardVariable.Operation.TEXT_CLICK:\n                        int size = OperationUtils.getInstance().getSavePoints().size();\n                        if (size > 0) {\n                            DrawPoint dp = OperationUtils.getInstance().getSavePoints().get(size - 1);\n                            if (dp.getType() == OperationUtils.DRAW_TEXT && dp.getDrawText().getStatus() == DrawTextView.TEXT_DETAIL) {\n                                changeTextBack();\n                                mFabMenuText.expand();\n                                OperationUtils.getInstance().mCurrentOPerationText = WhiteBoardVariable.Operation.TEXT_EXPAND;\n                            }\n                        }\n                        break;\n                    case WhiteBoardVariable.Operation.TEXT_EXPAND:\n                        mFabMenuText.collapse();\n                        OperationUtils.getInstance().mCurrentOPerationText = WhiteBoardVariable.Operation.TEXT_CLICK;\n                        break;\n                }\n                break;\n            case WhiteBoardVariable.Operation.PEN_CLICK:\n            case WhiteBoardVariable.Operation.ERASER_CLICK:\n                switch (OperationUtils.getInstance().mCurrentOPerationText) {\n                    case WhiteBoardVariable.Operation.TEXT_NORMAL:\n                        break;\n                    case WhiteBoardVariable.Operation.TEXT_CLICK:\n                        mFabMenuText.clearDraw();\n                        mFabMenuText.setAddButtonBackground(R.drawable.white_board_text_selector);\n                        OperationUtils.getInstance().mCurrentOPerationText = WhiteBoardVariable.Operation.TEXT_NORMAL;\n                        break;\n                    case WhiteBoardVariable.Operation.TEXT_EXPAND:\n                        mFabMenuText.collapse();\n                        mFabMenuText.clearDraw();\n                        mFabMenuText.setAddButtonBackground(R.drawable.white_board_text_selector);\n                        OperationUtils.getInstance().mCurrentOPerationText = WhiteBoardVariable.Operation.TEXT_NORMAL;\n                        break;\n                }\n                break;\n            case WhiteBoardVariable.Operation.COLOR_CLICK:\n            case WhiteBoardVariable.Operation.OUTSIDE_CLICK:\n                switch (OperationUtils.getInstance().mCurrentOPerationText) {\n                    case WhiteBoardVariable.Operation.TEXT_NORMAL:\n                        break;\n                    case WhiteBoardVariable.Operation.TEXT_CLICK:\n                        break;\n                    case WhiteBoardVariable.Operation.TEXT_EXPAND:\n                        mFabMenuText.collapse();\n                        OperationUtils.getInstance().mCurrentOPerationText = WhiteBoardVariable.Operation.TEXT_CLICK;\n                        break;\n                }\n                break;\n\n        }\n\n    }\n\n    /**\n     * 白板工具栏点击切换操作-橡皮擦\n     */\n    private void setEraserOperation(int currentOperation) {\n        switch (currentOperation) {\n            case WhiteBoardVariable.Operation.ERASER_CLICK:\n                switch (OperationUtils.getInstance().mCurrentOPerationEraser) {\n                    case WhiteBoardVariable.Operation.ERASER_NORMAL:\n                        OperationUtils.getInstance().mCurrentDrawType = OperationUtils.DRAW_ERASER;\n                        mDbView.changeEraser();\n                        mFabMenuEraser.setAddButtonBackground(R.drawable.white_board_eraser_selected_selector);\n                        OperationUtils.getInstance().mCurrentOPerationEraser = WhiteBoardVariable.Operation.ERASER_CLICK;\n                        break;\n                    case WhiteBoardVariable.Operation.ERASER_CLICK:\n                        mFabMenuEraser.expand();\n                        changeEraserBack();\n                        OperationUtils.getInstance().mCurrentOPerationEraser = WhiteBoardVariable.Operation.ERASER_EXPAND;\n                        break;\n                    case WhiteBoardVariable.Operation.ERASER_EXPAND:\n                        mFabMenuEraser.collapse();\n                        OperationUtils.getInstance().mCurrentOPerationEraser = WhiteBoardVariable.Operation.ERASER_CLICK;\n                        break;\n                }\n                break;\n            case WhiteBoardVariable.Operation.TEXT_CLICK:\n            case WhiteBoardVariable.Operation.PEN_CLICK:\n                switch (OperationUtils.getInstance().mCurrentOPerationEraser) {\n                    case WhiteBoardVariable.Operation.ERASER_NORMAL:\n                        break;\n                    case WhiteBoardVariable.Operation.ERASER_CLICK:\n                        mFabMenuEraser.clearDraw();\n                        mFabMenuEraser.setAddButtonBackground(R.drawable.white_board_eraser_selector);\n                        OperationUtils.getInstance().mCurrentOPerationEraser = WhiteBoardVariable.Operation.ERASER_NORMAL;\n                        break;\n                    case WhiteBoardVariable.Operation.ERASER_EXPAND:\n                        mFabMenuEraser.collapse();\n                        mFabMenuEraser.clearDraw();\n                        mFabMenuEraser.setAddButtonBackground(R.drawable.white_board_eraser_selector);\n                        OperationUtils.getInstance().mCurrentOPerationEraser = WhiteBoardVariable.Operation.ERASER_NORMAL;\n                        break;\n                }\n                break;\n            case WhiteBoardVariable.Operation.COLOR_CLICK:\n            case WhiteBoardVariable.Operation.OUTSIDE_CLICK:\n                switch (OperationUtils.getInstance().mCurrentOPerationEraser) {\n                    case WhiteBoardVariable.Operation.ERASER_NORMAL:\n                        break;\n                    case WhiteBoardVariable.Operation.ERASER_CLICK:\n                        break;\n                    case WhiteBoardVariable.Operation.ERASER_EXPAND:\n                        mFabMenuEraser.collapse();\n                        OperationUtils.getInstance().mCurrentOPerationEraser = WhiteBoardVariable.Operation.ERASER_CLICK;\n                        break;\n                }\n                break;\n\n        }\n\n    }\n\n    /**\n     * 保存当前白板为图片\n     */\n    public void saveImage() {\n        String fileName = StoreUtil.getPhotoSavePath();\n        Log.e(\"gpy\", fileName);\n        File file = new File(fileName);\n        try {\n            File directory = file.getParentFile();\n            if (!directory.exists() && !directory.mkdirs()) {\n                showMessage(getString(R.string.white_board_export_fail));\n                return;\n            }\n            file.createNewFile();\n            FileOutputStream out = new FileOutputStream(file);\n            mFlView.setDrawingCacheEnabled(true);\n            mFlView.buildDrawingCache();\n            Bitmap bitmap = mFlView.getDrawingCache();\n            bitmap.compress(Bitmap.CompressFormat.PNG, 100, out);\n            out.flush();\n            out.close();\n            mFlView.destroyDrawingCache();\n\n            Intent intent = new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE);\n            Uri uri = Uri.fromFile(file);\n            intent.setData(uri);\n            sendBroadcast(intent);//这个广播的目的就是更新图库\n\n            showMessage(getString(R.string.white_board_export_tip) + fileName);\n        } catch (Exception e) {\n            showMessage(getString(R.string.white_board_export_fail));\n            e.printStackTrace();\n        }\n    }\n\n    @Override\n    public void onBackPressed() {\n        super.onBackPressed();\n\n    }\n\n    @ReceiveEvents(name = Events.WHITE_BOARD_TEXT_EDIT)\n    private void textEdit() {//文字编辑\n        mIvWhiteBoardBack.setVisibility(View.GONE);\n        mIvWhiteBoardExport.setVisibility(View.GONE);\n        mIvWhiteBoardSave.setVisibility(View.GONE);\n        mRlBottom.setVisibility(View.GONE);\n        mIvWhiteBoardDisable.setVisibility(View.GONE);\n//        mLayoutParams = (RelativeLayout.LayoutParams) mRlContent.getLayoutParams();\n//        mLayoutParams.setMargins(OperationUtils.dip2px(24), 0, OperationUtils.dip2px(24), 0);\n//        mRlContent.setLayoutParams(mLayoutParams);\n\n        mIvWhiteBoardQuit.setVisibility(View.VISIBLE);\n        mIvWhiteBoardConfirm.setVisibility(View.VISIBLE);\n    }\n\n    @ReceiveEvents(name = Events.WHITE_BOARD_UNDO_REDO)\n    private void showUndoRedo() {//是否显示撤销、重装按钮\n        if (OperationUtils.getInstance().getSavePoints().isEmpty()) {\n            mIvWhiteBoardUndo.setVisibility(View.INVISIBLE);\n            mIvWhiteBoardExport.setVisibility(View.INVISIBLE);\n            mIvWhiteBoardSave.setVisibility(View.INVISIBLE);\n        } else {\n            mIvWhiteBoardUndo.setVisibility(View.VISIBLE);\n            mIvWhiteBoardExport.setVisibility(View.VISIBLE);\n            mIvWhiteBoardSave.setVisibility(View.VISIBLE);\n        }\n        if (OperationUtils.getInstance().getDeletePoints().isEmpty()) {\n            mIvWhiteBoardRedo.setVisibility(View.INVISIBLE);\n        } else {\n            mIvWhiteBoardRedo.setVisibility(View.VISIBLE);\n        }\n    }\n\n}\n"
  },
  {
    "path": "app/src/main/java/com/example/gpy/whiteboard/view/base/BaseActivity.java",
    "content": "package com.example.gpy.whiteboard.view.base;\n\nimport android.content.Intent;\nimport android.os.Bundle;\nimport android.support.annotation.Nullable;\nimport android.support.v4.app.FragmentActivity;\nimport android.widget.Toast;\n\nimport com.github.guanpy.library.EventBus;\n\nimport butterknife.ButterKnife;\n\n/**\n * Created by gpy on 2016/2/17.\n */\npublic abstract class BaseActivity extends FragmentActivity {\n\n    @Override\n    protected void onCreate(@Nullable Bundle savedInstanceState) {\n        super.onCreate(savedInstanceState);\n        this.setContentView(this.getLayoutId());\n        ButterKnife.inject(this);\n        this.afterCreate(savedInstanceState);\n\n    }\n\n    protected abstract int getLayoutId();\n\n    protected abstract void afterCreate(Bundle savedInstanceState);\n\n    protected void showMessage(CharSequence msg) {\n        Toast.makeText(this,msg,Toast.LENGTH_SHORT).show();\n    }\n\n    @Override\n    protected void onResume() {\n        super.onResume();\n        EventBus.registerAnnotatedReceiver(this);\n    }\n\n    @Override\n    protected void onPause() {\n        super.onPause();\n        EventBus.unregisterAnnotatedReceiver(this);\n    }\n\n    public void navi2Page(final Class<?> page) {\n        this.navi2Page(page, false);\n    }\n\n    public void navi2Page(final Class<?> page, final boolean shut) {\n        this.navi2Page(page, null, shut);\n    }\n\n    public void navi2Page(final Class<?> page, final Bundle data, final boolean shut) {\n        final Intent intent = new Intent(this, page);\n        if (null != data) {\n            intent.putExtras(data);\n        }\n        this.startActivity(intent);\n        if (shut) {\n            this.finish();\n        }\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/com/example/gpy/whiteboard/view/widget/floatingactionmenu/AddFloatingActionButton.java",
    "content": "package com.example.gpy.whiteboard.view.widget.floatingactionmenu;\n\nimport android.content.Context;\nimport android.content.res.TypedArray;\nimport android.graphics.Canvas;\nimport android.graphics.Paint;\nimport android.graphics.Paint.Style;\nimport android.graphics.drawable.Drawable;\nimport android.graphics.drawable.ShapeDrawable;\nimport android.graphics.drawable.shapes.Shape;\nimport android.support.annotation.ColorRes;\nimport android.support.annotation.DrawableRes;\nimport android.util.AttributeSet;\n\nimport com.example.gpy.whiteboard.R;\n\n\npublic class AddFloatingActionButton extends FloatingActionButton {\n  int mPlusColor;\n\n  public AddFloatingActionButton(Context context) {\n    this(context, null);\n  }\n\n  public AddFloatingActionButton(Context context, AttributeSet attrs) {\n    super(context, attrs);\n  }\n\n  public AddFloatingActionButton(Context context, AttributeSet attrs, int defStyle) {\n    super(context, attrs, defStyle);\n  }\n\n  @Override\n  void init(Context context, AttributeSet attributeSet) {\n    TypedArray attr = context.obtainStyledAttributes(attributeSet, R.styleable.AddFloatingActionButton, 0, 0);\n    mPlusColor = attr.getColor(R.styleable.AddFloatingActionButton_fab_plusIconColor, getColor(android.R.color.white));\n    attr.recycle();\n\n    super.init(context, attributeSet);\n  }\n\n  /**\n   * @return the current Color of plus icon.\n   */\n  public int getPlusColor() {\n    return mPlusColor;\n  }\n\n  public void setPlusColorResId(@ColorRes int plusColor) {\n    setPlusColor(getColor(plusColor));\n  }\n\n  public void setPlusColor(int color) {\n    if (mPlusColor != color) {\n      mPlusColor = color;\n      updateBackground();\n    }\n  }\n\n  @Override\n  public void setIcon(@DrawableRes int icon) {\n    throw new UnsupportedOperationException(\"Use FloatingActionButton if you want to use custom icon\");\n  }\n\n  @Override\n  Drawable getIconDrawable() {\n    final float iconSize = getDimension(R.dimen.fab_icon_size);\n    final float iconHalfSize = iconSize / 2f;\n\n    final float plusSize = getDimension(R.dimen.fab_plus_icon_size);\n    final float plusHalfStroke = getDimension(R.dimen.fab_plus_icon_stroke) / 2f;\n    final float plusOffset = (iconSize - plusSize) / 2f;\n\n    final Shape shape = new Shape() {\n      @Override\n      public void draw(Canvas canvas, Paint paint) {\n        canvas.drawRect(plusOffset, iconHalfSize - plusHalfStroke, iconSize - plusOffset, iconHalfSize + plusHalfStroke, paint);\n        canvas.drawRect(iconHalfSize - plusHalfStroke, plusOffset, iconHalfSize + plusHalfStroke, iconSize - plusOffset, paint);\n      }\n    };\n\n    ShapeDrawable drawable = new ShapeDrawable(shape);\n\n    final Paint paint = drawable.getPaint();\n    paint.setColor(mPlusColor);\n    paint.setStyle(Style.FILL);\n    paint.setAntiAlias(true);\n\n    return drawable;\n  }\n}\n"
  },
  {
    "path": "app/src/main/java/com/example/gpy/whiteboard/view/widget/floatingactionmenu/FloatingActionButton.java",
    "content": "package com.example.gpy.whiteboard.view.widget.floatingactionmenu;\n\nimport android.annotation.SuppressLint;\nimport android.content.Context;\nimport android.content.res.TypedArray;\nimport android.graphics.Canvas;\nimport android.graphics.Color;\nimport android.graphics.LinearGradient;\nimport android.graphics.Paint;\nimport android.graphics.Paint.Style;\nimport android.graphics.Rect;\nimport android.graphics.Shader;\nimport android.graphics.Shader.TileMode;\nimport android.graphics.drawable.ColorDrawable;\nimport android.graphics.drawable.Drawable;\nimport android.graphics.drawable.LayerDrawable;\nimport android.graphics.drawable.ShapeDrawable;\nimport android.graphics.drawable.ShapeDrawable.ShaderFactory;\nimport android.graphics.drawable.StateListDrawable;\nimport android.graphics.drawable.shapes.OvalShape;\nimport android.os.Build;\nimport android.os.Build.VERSION_CODES;\nimport android.support.annotation.ColorRes;\nimport android.support.annotation.DimenRes;\nimport android.support.annotation.DrawableRes;\nimport android.support.annotation.IntDef;\nimport android.support.annotation.NonNull;\nimport android.util.AttributeSet;\nimport android.widget.TextView;\n\nimport com.example.gpy.whiteboard.R;\n\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\n\n\npublic class FloatingActionButton extends FloatingImageButton {\n\n  public static final int SIZE_NORMAL = 0;\n  public static final int SIZE_MINI = 1;\n\n  @Retention(RetentionPolicy.SOURCE)\n  @IntDef({ SIZE_NORMAL, SIZE_MINI })\n  public @interface FAB_SIZE {\n  }\n\n  int mColorNormal;\n  int mColorPressed;\n  int mColorDisabled;\n  String mTitle;\n  @DrawableRes\n  private int mIcon;\n  private Drawable mIconDrawable;\n  private int mSize;\n\n  private float mCircleSize;\n  private float mShadowRadius;\n  private float mShadowOffset;\n  private int mDrawableSize;\n  boolean mStrokeVisible;\n\n  public FloatingActionButton(Context context) {\n    this(context, null);\n  }\n\n  public FloatingActionButton(Context context, AttributeSet attrs) {\n    super(context, attrs);\n    init(context, attrs);\n  }\n\n  public FloatingActionButton(Context context, AttributeSet attrs, int defStyle) {\n    super(context, attrs, defStyle);\n    init(context, attrs);\n  }\n\n  void init(Context context, AttributeSet attributeSet) {\n    TypedArray attr = context.obtainStyledAttributes(attributeSet, R.styleable.FloatingActionButton, 0, 0);\n    mColorNormal = attr.getColor(R.styleable.FloatingActionButton_fab_colorNormal, getColor(android.R.color.holo_blue_dark));\n    mColorPressed = attr.getColor(R.styleable.FloatingActionButton_fab_colorPressed, getColor(android.R.color.holo_blue_light));\n    mColorDisabled = attr.getColor(R.styleable.FloatingActionButton_fab_colorDisabled, getColor(android.R.color.darker_gray));\n    mSize = attr.getInt(R.styleable.FloatingActionButton_fab_size, SIZE_NORMAL);\n    mIcon = attr.getResourceId(R.styleable.FloatingActionButton_fab_icon, 0);\n    mTitle = attr.getString(R.styleable.FloatingActionButton_fab_title);\n    mStrokeVisible = attr.getBoolean(R.styleable.FloatingActionButton_fab_stroke_visible, true);\n    attr.recycle();\n\n    updateCircleSize();\n    mShadowRadius = getDimension(R.dimen.fab_shadow_radius);\n    mShadowOffset = getDimension(R.dimen.fab_shadow_offset);\n    updateDrawableSize();\n\n    updateBackground();\n  }\n\n  private void updateDrawableSize() {\n    mDrawableSize = (int) (mCircleSize + 2 * mShadowRadius);\n  }\n\n  private void updateCircleSize() {\n    mCircleSize = getDimension(mSize == SIZE_NORMAL ? R.dimen.fab_size_normal : R.dimen.fab_size_mini);\n  }\n\n  public void setSize(@FAB_SIZE int size) {\n    if (size != SIZE_MINI && size != SIZE_NORMAL) {\n      throw new IllegalArgumentException(\"Use @FAB_SIZE constants only!\");\n    }\n\n    if (mSize != size) {\n      mSize = size;\n      updateCircleSize();\n      updateDrawableSize();\n      updateBackground();\n    }\n  }\n\n  @FAB_SIZE\n  public int getSize() {\n    return mSize;\n  }\n\n  public void setIcon(@DrawableRes int icon) {\n    if (mIcon != icon) {\n      mIcon = icon;\n      mIconDrawable = null;\n      updateBackground();\n    }\n  }\n\n  public void setIconDrawable(@NonNull Drawable iconDrawable) {\n    if (mIconDrawable != iconDrawable) {\n      mIcon = 0;\n      mIconDrawable = iconDrawable;\n      updateBackground();\n    }\n  }\n\n  /**\n   * @return the current Color for normal state.\n   */\n  public int getColorNormal() {\n    return mColorNormal;\n  }\n\n  public void setColorNormalResId(@ColorRes int colorNormal) {\n    setColorNormal(getColor(colorNormal));\n  }\n\n  public void setColorNormal(int color) {\n    if (mColorNormal != color) {\n      mColorNormal = color;\n      updateBackground();\n    }\n  }\n\n  /**\n   * @return the current color for pressed state.\n   */\n  public int getColorPressed() {\n    return mColorPressed;\n  }\n\n  public void setColorPressedResId(@ColorRes int colorPressed) {\n    setColorPressed(getColor(colorPressed));\n  }\n\n  public void setColorPressed(int color) {\n    if (mColorPressed != color) {\n      mColorPressed = color;\n      updateBackground();\n    }\n  }\n\n  /**\n  * @return the current color for disabled state.\n  */\n  public int getColorDisabled() {\n    return mColorDisabled;\n  }\n\n  public void setColorDisabledResId(@ColorRes int colorDisabled) {\n    setColorDisabled(getColor(colorDisabled));\n  }\n\n  public void setColorDisabled(int color) {\n    if (mColorDisabled != color) {\n        mColorDisabled = color;\n        updateBackground();\n    }\n  }\n\n  public void setStrokeVisible(boolean visible) {\n    if (mStrokeVisible != visible) {\n      mStrokeVisible = visible;\n      updateBackground();\n    }\n  }\n\n  public boolean isStrokeVisible() {\n    return mStrokeVisible;\n  }\n\n  int getColor(@ColorRes int id) {\n    return getResources().getColor(id);\n  }\n\n  float getDimension(@DimenRes int id) {\n    return getResources().getDimension(id);\n  }\n\n  public void setTitle(String title) {\n    mTitle = title;\n    TextView label = getLabelView();\n    if (label != null) {\n      label.setText(title);\n    }\n  }\n\n  TextView getLabelView() {\n    return (TextView) getTag(R.id.fab_label);\n  }\n\n  public String getTitle() {\n    return mTitle;\n  }\n\n  @Override\n  protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {\n    super.onMeasure(widthMeasureSpec, heightMeasureSpec);\n    setMeasuredDimension(mDrawableSize, mDrawableSize);\n  }\n\n  void updateBackground() {\n    final float strokeWidth = getDimension(R.dimen.fab_stroke_width);\n    final float halfStrokeWidth = strokeWidth / 2f;\n\n    LayerDrawable layerDrawable = new LayerDrawable(\n        new Drawable[] {\n            getResources().getDrawable(mSize == SIZE_NORMAL ? R.drawable.fab_bg_normal : R.drawable.fab_bg_mini),\n            createFillDrawable(strokeWidth),\n            createOuterStrokeDrawable(strokeWidth),\n            getIconDrawable()\n        });\n\n    int iconOffset = (int) (mCircleSize - getDimension(R.dimen.fab_icon_size)) / 2;\n\n    int circleInsetHorizontal = (int) (mShadowRadius);\n    int circleInsetTop = (int) (mShadowRadius - mShadowOffset);\n    int circleInsetBottom = (int) (mShadowRadius + mShadowOffset);\n\n    layerDrawable.setLayerInset(1,\n        circleInsetHorizontal,\n        circleInsetTop,\n        circleInsetHorizontal,\n        circleInsetBottom);\n\n    layerDrawable.setLayerInset(2,\n        (int) (circleInsetHorizontal - halfStrokeWidth),\n        (int) (circleInsetTop - halfStrokeWidth),\n        (int) (circleInsetHorizontal - halfStrokeWidth),\n        (int) (circleInsetBottom - halfStrokeWidth));\n\n    layerDrawable.setLayerInset(3,\n        circleInsetHorizontal + iconOffset,\n        circleInsetTop + iconOffset,\n        circleInsetHorizontal + iconOffset,\n        circleInsetBottom + iconOffset);\n\n    setBackgroundCompat(layerDrawable);\n  }\n\n  Drawable getIconDrawable() {\n    if (mIconDrawable != null) {\n      return mIconDrawable;\n    } else if (mIcon != 0) {\n      return getResources().getDrawable(mIcon);\n    } else {\n      return new ColorDrawable(Color.TRANSPARENT);\n    }\n  }\n\n  private StateListDrawable createFillDrawable(float strokeWidth) {\n    StateListDrawable drawable = new StateListDrawable();\n    drawable.addState(new int[] { -android.R.attr.state_enabled }, createCircleDrawable(mColorDisabled, strokeWidth));\n    drawable.addState(new int[] { android.R.attr.state_pressed }, createCircleDrawable(mColorPressed, strokeWidth));\n    drawable.addState(new int[] { }, createCircleDrawable(mColorNormal, strokeWidth));\n    return drawable;\n  }\n\n  private Drawable createCircleDrawable(int color, float strokeWidth) {\n    int alpha = Color.alpha(color);\n    int opaqueColor = opaque(color);\n\n    ShapeDrawable fillDrawable = new ShapeDrawable(new OvalShape());\n\n    final Paint paint = fillDrawable.getPaint();\n    paint.setAntiAlias(true);\n    paint.setColor(opaqueColor);\n\n    Drawable[] layers = {\n        fillDrawable,\n        createInnerStrokesDrawable(opaqueColor, strokeWidth)\n    };\n\n    LayerDrawable drawable = alpha == 255 || !mStrokeVisible\n        ? new LayerDrawable(layers)\n        : new TranslucentLayerDrawable(alpha, layers);\n\n    int halfStrokeWidth = (int) (strokeWidth / 2f);\n    drawable.setLayerInset(1, halfStrokeWidth, halfStrokeWidth, halfStrokeWidth, halfStrokeWidth);\n\n    return drawable;\n  }\n\n  private static class TranslucentLayerDrawable extends LayerDrawable {\n    private final int mAlpha;\n\n    public TranslucentLayerDrawable(int alpha, Drawable... layers) {\n      super(layers);\n      mAlpha = alpha;\n    }\n\n    @Override\n    public void draw(Canvas canvas) {\n      Rect bounds = getBounds();\n      canvas.saveLayerAlpha(bounds.left, bounds.top, bounds.right, bounds.bottom, mAlpha, Canvas.ALL_SAVE_FLAG);\n      super.draw(canvas);\n      canvas.restore();\n    }\n  }\n\n  private Drawable createOuterStrokeDrawable(float strokeWidth) {\n    ShapeDrawable shapeDrawable = new ShapeDrawable(new OvalShape());\n\n    final Paint paint = shapeDrawable.getPaint();\n    paint.setAntiAlias(true);\n    paint.setStrokeWidth(strokeWidth);\n    paint.setStyle(Style.STROKE);\n    paint.setColor(Color.BLACK);\n    paint.setAlpha(opacityToAlpha(0.02f));\n\n    return shapeDrawable;\n  }\n\n  private int opacityToAlpha(float opacity) {\n    return (int) (255f * opacity);\n  }\n\n  private int darkenColor(int argb) {\n    return adjustColorBrightness(argb, 0.9f);\n  }\n\n  private int lightenColor(int argb) {\n    return adjustColorBrightness(argb, 1.1f);\n  }\n\n  private int adjustColorBrightness(int argb, float factor) {\n    float[] hsv = new float[3];\n    Color.colorToHSV(argb, hsv);\n\n    hsv[2] = Math.min(hsv[2] * factor, 1f);\n\n    return Color.HSVToColor(Color.alpha(argb), hsv);\n  }\n\n  private int halfTransparent(int argb) {\n    return Color.argb(\n        Color.alpha(argb) / 2,\n        Color.red(argb),\n        Color.green(argb),\n        Color.blue(argb)\n    );\n  }\n\n  private int opaque(int argb) {\n    return Color.rgb(\n        Color.red(argb),\n        Color.green(argb),\n        Color.blue(argb)\n    );\n  }\n\n  private Drawable createInnerStrokesDrawable(final int color, float strokeWidth) {\n    if (!mStrokeVisible) {\n      return new ColorDrawable(Color.TRANSPARENT);\n    }\n\n    ShapeDrawable shapeDrawable = new ShapeDrawable(new OvalShape());\n\n    final int bottomStrokeColor = darkenColor(color);\n    final int bottomStrokeColorHalfTransparent = halfTransparent(bottomStrokeColor);\n    final int topStrokeColor = lightenColor(color);\n    final int topStrokeColorHalfTransparent = halfTransparent(topStrokeColor);\n\n    final Paint paint = shapeDrawable.getPaint();\n    paint.setAntiAlias(true);\n    paint.setStrokeWidth(strokeWidth);\n    paint.setStyle(Style.STROKE);\n    shapeDrawable.setShaderFactory(new ShaderFactory() {\n      @Override\n      public Shader resize(int width, int height) {\n        return new LinearGradient(width / 2, 0, width / 2, height,\n            new int[] { topStrokeColor, topStrokeColorHalfTransparent, color, bottomStrokeColorHalfTransparent, bottomStrokeColor },\n            new float[] { 0f, 0.2f, 0.5f, 0.8f, 1f },\n            TileMode.CLAMP\n        );\n      }\n    });\n\n    return shapeDrawable;\n  }\n\n  @SuppressWarnings(\"deprecation\")\n  @SuppressLint(\"NewApi\")\n  private void setBackgroundCompat(Drawable drawable) {\n    if (Build.VERSION.SDK_INT >= VERSION_CODES.JELLY_BEAN) {\n      setBackground(drawable);\n    } else {\n      setBackgroundDrawable(drawable);\n    }\n  }\n\n  @Override\n  public void setVisibility(int visibility) {\n    TextView label = getLabelView();\n    if (label != null) {\n      label.setVisibility(visibility);\n    }\n\n    super.setVisibility(visibility);\n  }\n}\n"
  },
  {
    "path": "app/src/main/java/com/example/gpy/whiteboard/view/widget/floatingactionmenu/FloatingActionsMenu.java",
    "content": "package com.example.gpy.whiteboard.view.widget.floatingactionmenu;\n\nimport android.animation.AnimatorSet;\nimport android.animation.ObjectAnimator;\nimport android.content.Context;\nimport android.content.res.TypedArray;\nimport android.graphics.Canvas;\nimport android.graphics.Rect;\nimport android.graphics.drawable.Drawable;\nimport android.graphics.drawable.LayerDrawable;\nimport android.os.Parcel;\nimport android.os.Parcelable;\nimport android.support.annotation.ColorRes;\nimport android.support.annotation.NonNull;\nimport android.util.AttributeSet;\nimport android.view.TouchDelegate;\nimport android.view.View;\nimport android.view.ViewGroup;\nimport android.view.animation.DecelerateInterpolator;\nimport android.view.animation.Interpolator;\nimport android.view.animation.OvershootInterpolator;\nimport android.widget.ImageView;\nimport android.widget.TextView;\n\nimport com.example.gpy.whiteboard.R;\nimport com.github.guanpy.wblib.utils.AppContextUtil;\nimport com.github.guanpy.wblib.utils.WhiteBoardVariable;\n\npublic class FloatingActionsMenu extends ViewGroup {\n    public static final int STYLE_DEFAULT = 0;\n    public static final int STYLE_CUSTOM = 1;\n\n    public static final int EXPAND_UP = 0;\n    public static final int EXPAND_DOWN = 1;\n    public static final int EXPAND_LEFT = 2;\n    public static final int EXPAND_RIGHT = 3;\n\n    public static final int LABELS_ON_LEFT_SIDE = 0;\n    public static final int LABELS_ON_RIGHT_SIDE = 1;\n\n    private static final int ANIMATION_DURATION = 300;\n    private static final float COLLAPSED_PLUS_ROTATION = 0f;\n    private static final float EXPANDED_PLUS_ROTATION = 90f + 45f;\n\n    private Drawable mAddButtonBackground;\n    private float mAddButtonWidth;\n    private float mAddButtonHeight;\n    private int mAddButtonStyle;\n    private int mAddButtonPlusColor;\n    private int mAddButtonColorNormal;\n    private int mAddButtonColorPressed;\n    private int mAddButtonSize;\n    private boolean mAddButtonStrokeVisible;\n    private int mExpandDirection;\n\n    private int mButtonSpacing;\n    private int mLabelsMargin;\n    private int mLabelsVerticalOffset;\n\n    private boolean mExpanded;\n\n    private AnimatorSet mExpandAnimation = new AnimatorSet().setDuration(ANIMATION_DURATION);\n    private AnimatorSet mCollapseAnimation = new AnimatorSet().setDuration(ANIMATION_DURATION);\n    //  private AddFloatingActionButton mAddButton;\n    private FloatingImageButton mAddButton;\n    private RotatingDrawable mRotatingDrawable;\n    private int mMaxButtonWidth;\n    private int mMaxButtonHeight;\n    private int mLabelsStyle;\n    private int mLabelsPosition;\n    private int mButtonsCount;\n\n    private TouchDelegateGroup mTouchDelegateGroup;\n    private OnFloatingActionsMenuUpdateListener mListener;\n    private OnFloatingActionsMenuClickListener mClickListener;\n\n    public interface OnFloatingActionsMenuUpdateListener {\n        void onMenuExpanded();\n\n        void onMenuCollapsed();\n    }\n\n    public FloatingActionsMenu(Context context) {\n        this(context, null);\n    }\n\n    public FloatingActionsMenu(Context context, AttributeSet attrs) {\n        super(context, attrs);\n        init(context, attrs);\n    }\n\n    public FloatingActionsMenu(Context context, AttributeSet attrs, int defStyle) {\n        super(context, attrs, defStyle);\n        init(context, attrs);\n    }\n    public interface OnFloatingActionsMenuClickListener{\n\n        void addButtonLister();\n    }\n\n    public void  setOnFloatingActionsMenuClickListener(OnFloatingActionsMenuClickListener flLister){\n        mClickListener = flLister;\n    }\n    /**\n     * 在图片中间画圆环\n     * @param size  圆的半径\n     * @param color  圆的颜色\n     * */\n    /**控制按钮外圈*/\n    public void drawRing(int color){\n       mAddButton.drawRing(WhiteBoardVariable.RingSize.LARRGE, color);\n    }\n    /**\n     * 清除绘画\n     * */\n    public void clearDraw(){\n        mAddButton.clearDraw();\n    }\n\n    /**\n     * 切换控制按钮背景图\n     * */\n    public void setAddButtonBackground(int drawable){\n            mAddButton.setBackgroundResource(drawable);\n    }\n    /**\n     * dip转px\n     */\n    private int dip2px(float dpValue) {\n        final float scale = AppContextUtil.getContext().getResources().getDisplayMetrics().density;\n        return (int) (dpValue * scale + 0.5f);\n    }\n    private void init(Context context, AttributeSet attributeSet) {\n//    mButtonSpacing = (int) (getResources().getDimension(R.dimen.fab_actions_spacing) - getResources().getDimension(R.dimen.fab_shadow_radius) - getResources().getDimension(R.dimen.fab_shadow_offset));\n\n        mLabelsVerticalOffset = getResources().getDimensionPixelSize(R.dimen.fab_shadow_offset);\n\n        mTouchDelegateGroup = new TouchDelegateGroup(this);\n        setTouchDelegate(mTouchDelegateGroup);\n\n        TypedArray attr = context.obtainStyledAttributes(attributeSet, R.styleable.FloatingActionsMenu, 0, 0);\n        mButtonSpacing =dip2px(attr.getDimension(R.styleable.FloatingActionsMenu_fab_buttonSpacing, 4));\n        mAddButtonBackground = attr.getDrawable(R.styleable.FloatingActionsMenu_fab_addButtonBackground);\n        mAddButtonWidth = attr.getDimension(R.styleable.FloatingActionsMenu_fab_addButtonWidth, 0);\n        mAddButtonHeight = attr.getDimension(R.styleable.FloatingActionsMenu_fab_addButtonHeight, 0);\n        mAddButtonStyle = attr.getInt(R.styleable.FloatingActionsMenu_fab_addButtonStyle, STYLE_DEFAULT);\n\n        mAddButtonPlusColor = attr.getColor(R.styleable.FloatingActionsMenu_fab_addButtonPlusIconColor, getColor(android.R.color.white));\n        mAddButtonColorNormal = attr.getColor(R.styleable.FloatingActionsMenu_fab_addButtonColorNormal, getColor(android.R.color.holo_blue_dark));\n        mAddButtonColorPressed = attr.getColor(R.styleable.FloatingActionsMenu_fab_addButtonColorPressed, getColor(android.R.color.holo_blue_light));\n        mAddButtonSize = attr.getInt(R.styleable.FloatingActionsMenu_fab_addButtonSize, FloatingActionButton.SIZE_NORMAL);\n        mAddButtonStrokeVisible = attr.getBoolean(R.styleable.FloatingActionsMenu_fab_addButtonStrokeVisible, true);\n        mExpandDirection = attr.getInt(R.styleable.FloatingActionsMenu_fab_expandDirection, EXPAND_UP);\n        mLabelsStyle = attr.getResourceId(R.styleable.FloatingActionsMenu_fab_labelStyle, 0);\n        mLabelsPosition = attr.getInt(R.styleable.FloatingActionsMenu_fab_labelsPosition, LABELS_ON_LEFT_SIDE);\n        attr.recycle();\n\n        if (mLabelsStyle != 0 && expandsHorizontally()) {\n            throw new IllegalStateException(\"Action labels in horizontal expand orientation is not supported.\");\n        }\n\n        createAddButton(context);\n    }\n\n    public void setOnFloatingActionsMenuUpdateListener(OnFloatingActionsMenuUpdateListener listener) {\n        mListener = listener;\n    }\n\n    private boolean expandsHorizontally() {\n        return mExpandDirection == EXPAND_LEFT || mExpandDirection == EXPAND_RIGHT;\n    }\n\n    private static class RotatingDrawable extends LayerDrawable {\n        public RotatingDrawable(Drawable drawable) {\n            super(new Drawable[]{drawable});\n        }\n\n        private float mRotation;\n\n        @SuppressWarnings(\"UnusedDeclaration\")\n        public float getRotation() {\n            return mRotation;\n        }\n\n        @SuppressWarnings(\"UnusedDeclaration\")\n        public void setRotation(float rotation) {\n            mRotation = rotation;\n            invalidateSelf();\n        }\n\n        @Override\n        public void draw(Canvas canvas) {\n            canvas.save();\n            canvas.rotate(mRotation, getBounds().centerX(), getBounds().centerY());\n            super.draw(canvas);\n            canvas.restore();\n        }\n    }\n\n    /**\n     * 增加菜单的控制按钮\n     */\n    private void createAddButton(Context context) {\n        if (mAddButtonStyle == STYLE_DEFAULT) {\n            mAddButton = new AddFloatingActionButton(context) {\n                @Override\n                void updateBackground() {\n                    mPlusColor = mAddButtonPlusColor;\n                    mColorNormal = mAddButtonColorNormal;\n                    mColorPressed = mAddButtonColorPressed;\n                    mStrokeVisible = mAddButtonStrokeVisible;\n                    super.updateBackground();\n                }\n\n                @Override\n                Drawable getIconDrawable() {\n                    final RotatingDrawable rotatingDrawable = new RotatingDrawable(super.getIconDrawable());\n                    mRotatingDrawable = rotatingDrawable;\n\n                    final OvershootInterpolator interpolator = new OvershootInterpolator();\n\n                    final ObjectAnimator collapseAnimator = ObjectAnimator.ofFloat(rotatingDrawable, \"rotation\", EXPANDED_PLUS_ROTATION, COLLAPSED_PLUS_ROTATION);\n                    final ObjectAnimator expandAnimator = ObjectAnimator.ofFloat(rotatingDrawable, \"rotation\", COLLAPSED_PLUS_ROTATION, EXPANDED_PLUS_ROTATION);\n\n                    collapseAnimator.setInterpolator(interpolator);\n                    expandAnimator.setInterpolator(interpolator);\n\n                    mExpandAnimation.play(expandAnimator);\n                    mCollapseAnimation.play(collapseAnimator);\n\n                    return rotatingDrawable;\n                }\n            };\n\n            mAddButton.setId(R.id.fab_expand_menu_button);\n            ((AddFloatingActionButton) mAddButton).setSize(mAddButtonSize);\n        } else if (mAddButtonStyle == STYLE_CUSTOM) {\n            mAddButton = new FloatingImageButton(context);\n            mAddButton.setId(R.id.fab_expand_menu_button);\n            ViewGroup.LayoutParams layoutParams = new ViewGroup.LayoutParams(dip2px(mAddButtonWidth), dip2px(mAddButtonHeight));\n            mAddButton.setLayoutParams(layoutParams);\n            mAddButton.setBackgroundDrawable(mAddButtonBackground);\n            mAddButton.setScaleType(ImageView.ScaleType.CENTER_CROP);\n        }\n\n        mAddButton.setOnClickListener(new OnClickListener() {\n            @Override\n            public void onClick(View v) {\n                if(null!=mClickListener){\n                    mClickListener.addButtonLister();\n                }else{\n                    toggle();\n                }\n            }\n        });\n\n        addView(mAddButton, super.generateDefaultLayoutParams());\n    }\n\n\n    private int getColor(@ColorRes int id) {\n        return getResources().getColor(id);\n    }\n\n    @Override\n    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {\n        measureChildren(widthMeasureSpec, heightMeasureSpec);\n\n        int width = 0;\n        int height = 0;\n\n        mMaxButtonWidth = 0;\n        mMaxButtonHeight = 0;\n        int maxLabelWidth = 0;\n\n        for (int i = 0; i < mButtonsCount; i++) {\n            View child = getChildAt(i);\n\n            if (child.getVisibility() == GONE) {\n                continue;\n            }\n\n            switch (mExpandDirection) {\n                case EXPAND_UP:\n                case EXPAND_DOWN:\n                    mMaxButtonWidth = Math.max(mMaxButtonWidth, child.getMeasuredWidth());\n                    height += child.getMeasuredHeight();\n                    break;\n                case EXPAND_LEFT:\n                case EXPAND_RIGHT:\n                    width += child.getMeasuredWidth();\n                    mMaxButtonHeight = Math.max(mMaxButtonHeight, child.getMeasuredHeight());\n                    break;\n            }\n\n            if (!expandsHorizontally()) {\n                TextView label = (TextView) child.getTag(R.id.fab_label);\n                if (label != null) {\n                    maxLabelWidth = Math.max(maxLabelWidth, label.getMeasuredWidth());\n                }\n            }\n        }\n\n        if (!expandsHorizontally()) {\n            width = mMaxButtonWidth + (maxLabelWidth > 0 ? maxLabelWidth + mLabelsMargin : 0);\n        } else {\n            height = mMaxButtonHeight;\n        }\n\n        switch (mExpandDirection) {\n            case EXPAND_UP:\n            case EXPAND_DOWN:\n                height += mButtonSpacing * (getChildCount() - 1);\n                height = adjustForOvershoot(height);\n                break;\n            case EXPAND_LEFT:\n            case EXPAND_RIGHT:\n                width += mButtonSpacing * (getChildCount() - 1);\n                width = adjustForOvershoot(width);\n                break;\n        }\n\n        setMeasuredDimension(width, height);\n    }\n\n    private int adjustForOvershoot(int dimension) {\n        return dimension * 12 / 10;\n    }\n\n    @Override\n    protected void onLayout(boolean changed, int l, int t, int r, int b) {\n        switch (mExpandDirection) {\n            case EXPAND_UP:\n            case EXPAND_DOWN:\n                boolean expandUp = mExpandDirection == EXPAND_UP;\n\n                if (changed) {\n                    mTouchDelegateGroup.clearTouchDelegates();\n                }\n\n                int addButtonY = expandUp ? b - t - mAddButton.getMeasuredHeight() : 0;\n                // Ensure mAddButton is centered on the line where the buttons should be\n                int buttonsHorizontalCenter = mLabelsPosition == LABELS_ON_LEFT_SIDE\n                        ? r - l - mMaxButtonWidth / 2\n                        : mMaxButtonWidth / 2;\n                int addButtonLeft = buttonsHorizontalCenter - mAddButton.getMeasuredWidth() / 2;\n                mAddButton.layout(addButtonLeft, addButtonY, addButtonLeft + mAddButton.getMeasuredWidth(), addButtonY + mAddButton.getMeasuredHeight());\n\n                int labelsOffset = mMaxButtonWidth / 2 + mLabelsMargin;\n                int labelsXNearButton = mLabelsPosition == LABELS_ON_LEFT_SIDE\n                        ? buttonsHorizontalCenter - labelsOffset\n                        : buttonsHorizontalCenter + labelsOffset;\n\n                int nextY = expandUp ?\n                        addButtonY - mButtonSpacing :\n                        addButtonY + mAddButton.getMeasuredHeight() + mButtonSpacing;\n\n                for (int i = mButtonsCount - 1; i >= 0; i--) {\n                    final View child = getChildAt(i);\n\n                    if (child == mAddButton || child.getVisibility() == GONE) continue;\n\n                    int childX = buttonsHorizontalCenter - child.getMeasuredWidth() / 2;\n                    int childY = expandUp ? nextY - child.getMeasuredHeight() : nextY;\n                    child.layout(childX, childY, childX + child.getMeasuredWidth(), childY + child.getMeasuredHeight());\n\n                    float collapsedTranslation = addButtonY - childY;\n                    float expandedTranslation = 0f;\n\n                    child.setTranslationY(mExpanded ? expandedTranslation : collapsedTranslation);\n                    child.setAlpha(mExpanded ? 1f : 0f);\n\n                    LayoutParams params = (LayoutParams) child.getLayoutParams();\n                    params.mCollapseDir.setFloatValues(expandedTranslation, collapsedTranslation);\n                    params.mExpandDir.setFloatValues(collapsedTranslation, expandedTranslation);\n                    params.setAnimationsTarget(child);\n\n                    View label = (View) child.getTag(R.id.fab_label);\n                    if (label != null) {\n                        int labelXAwayFromButton = mLabelsPosition == LABELS_ON_LEFT_SIDE\n                                ? labelsXNearButton - label.getMeasuredWidth()\n                                : labelsXNearButton + label.getMeasuredWidth();\n\n                        int labelLeft = mLabelsPosition == LABELS_ON_LEFT_SIDE\n                                ? labelXAwayFromButton\n                                : labelsXNearButton;\n\n                        int labelRight = mLabelsPosition == LABELS_ON_LEFT_SIDE\n                                ? labelsXNearButton\n                                : labelXAwayFromButton;\n\n                        int labelTop = childY - mLabelsVerticalOffset + (child.getMeasuredHeight() - label.getMeasuredHeight()) / 2;\n\n                        label.layout(labelLeft, labelTop, labelRight, labelTop + label.getMeasuredHeight());\n\n                        Rect touchArea = new Rect(\n                                Math.min(childX, labelLeft),\n                                childY - mButtonSpacing / 2,\n                                Math.max(childX + child.getMeasuredWidth(), labelRight),\n                                childY + child.getMeasuredHeight() + mButtonSpacing / 2);\n                        mTouchDelegateGroup.addTouchDelegate(new TouchDelegate(touchArea, child));\n\n                        label.setTranslationY(mExpanded ? expandedTranslation : collapsedTranslation);\n                        label.setAlpha(mExpanded ? 1f : 0f);\n\n                        LayoutParams labelParams = (LayoutParams) label.getLayoutParams();\n                        labelParams.mCollapseDir.setFloatValues(expandedTranslation, collapsedTranslation);\n                        labelParams.mExpandDir.setFloatValues(collapsedTranslation, expandedTranslation);\n                        labelParams.setAnimationsTarget(label);\n                    }\n\n                    nextY = expandUp ?\n                            childY - mButtonSpacing :\n                            childY + child.getMeasuredHeight() + mButtonSpacing;\n                }\n                break;\n\n            case EXPAND_LEFT:\n            case EXPAND_RIGHT:\n                boolean expandLeft = mExpandDirection == EXPAND_LEFT;\n\n                int addButtonX = expandLeft ? r - l - mAddButton.getMeasuredWidth() : 0;\n                // Ensure mAddButton is centered on the line where the buttons should be\n                int addButtonTop = b - t - mMaxButtonHeight + (mMaxButtonHeight - mAddButton.getMeasuredHeight()) / 2;\n                mAddButton.layout(addButtonX, addButtonTop, addButtonX + mAddButton.getMeasuredWidth(), addButtonTop + mAddButton.getMeasuredHeight());\n\n                int nextX = expandLeft ?\n                        addButtonX - mButtonSpacing :\n                        addButtonX + mAddButton.getMeasuredWidth() + mButtonSpacing;\n\n                for (int i = mButtonsCount - 1; i >= 0; i--) {\n                    final View child = getChildAt(i);\n\n                    if (child == mAddButton || child.getVisibility() == GONE) continue;\n\n                    int childX = expandLeft ? nextX - child.getMeasuredWidth() : nextX;\n                    int childY = addButtonTop + (mAddButton.getMeasuredHeight() - child.getMeasuredHeight()) / 2;\n                    child.layout(childX, childY, childX + child.getMeasuredWidth(), childY + child.getMeasuredHeight());\n\n                    float collapsedTranslation = addButtonX - childX;\n                    float expandedTranslation = 0f;\n\n                    child.setTranslationX(mExpanded ? expandedTranslation : collapsedTranslation);\n                    child.setAlpha(mExpanded ? 1f : 0f);\n\n                    LayoutParams params = (LayoutParams) child.getLayoutParams();\n                    params.mCollapseDir.setFloatValues(expandedTranslation, collapsedTranslation);\n                    params.mExpandDir.setFloatValues(collapsedTranslation, expandedTranslation);\n                    params.setAnimationsTarget(child);\n\n                    nextX = expandLeft ?\n                            childX - mButtonSpacing :\n                            childX + child.getMeasuredWidth() + mButtonSpacing;\n                }\n\n                break;\n        }\n    }\n\n    @Override\n    protected ViewGroup.LayoutParams generateDefaultLayoutParams() {\n        return new LayoutParams(super.generateDefaultLayoutParams());\n    }\n\n    @Override\n    public ViewGroup.LayoutParams generateLayoutParams(AttributeSet attrs) {\n        return new LayoutParams(super.generateLayoutParams(attrs));\n    }\n\n    @Override\n    protected ViewGroup.LayoutParams generateLayoutParams(ViewGroup.LayoutParams p) {\n        return new LayoutParams(super.generateLayoutParams(p));\n    }\n\n    @Override\n    protected boolean checkLayoutParams(ViewGroup.LayoutParams p) {\n        return super.checkLayoutParams(p);\n    }\n\n    private static Interpolator sExpandInterpolator = new OvershootInterpolator();\n    private static Interpolator sCollapseInterpolator = new DecelerateInterpolator(3f);\n    private static Interpolator sAlphaExpandInterpolator = new DecelerateInterpolator();\n\n    private class LayoutParams extends ViewGroup.LayoutParams {\n\n        private ObjectAnimator mExpandDir = new ObjectAnimator();\n        private ObjectAnimator mExpandAlpha = new ObjectAnimator();\n        private ObjectAnimator mCollapseDir = new ObjectAnimator();\n        private ObjectAnimator mCollapseAlpha = new ObjectAnimator();\n        private boolean animationsSetToPlay;\n\n        public LayoutParams(ViewGroup.LayoutParams source) {\n            super(source);\n\n            mExpandDir.setInterpolator(sExpandInterpolator);\n            mExpandAlpha.setInterpolator(sAlphaExpandInterpolator);\n            mCollapseDir.setInterpolator(sCollapseInterpolator);\n            mCollapseAlpha.setInterpolator(sCollapseInterpolator);\n\n            mCollapseAlpha.setProperty(View.ALPHA);\n            mCollapseAlpha.setFloatValues(1f, 0f);\n\n            mExpandAlpha.setProperty(View.ALPHA);\n            mExpandAlpha.setFloatValues(0f, 1f);\n\n            switch (mExpandDirection) {\n                case EXPAND_UP:\n                case EXPAND_DOWN:\n                    mCollapseDir.setProperty(View.TRANSLATION_Y);\n                    mExpandDir.setProperty(View.TRANSLATION_Y);\n                    break;\n                case EXPAND_LEFT:\n                case EXPAND_RIGHT:\n                    mCollapseDir.setProperty(View.TRANSLATION_X);\n                    mExpandDir.setProperty(View.TRANSLATION_X);\n                    break;\n            }\n        }\n\n        public void setAnimationsTarget(View view) {\n            mCollapseAlpha.setTarget(view);\n            mCollapseDir.setTarget(view);\n            mExpandAlpha.setTarget(view);\n            mExpandDir.setTarget(view);\n\n            // Now that the animations have targets, set them to be played\n            if (!animationsSetToPlay) {\n                mCollapseAnimation.play(mCollapseAlpha);\n                mCollapseAnimation.play(mCollapseDir);\n                mExpandAnimation.play(mExpandAlpha);\n                mExpandAnimation.play(mExpandDir);\n                animationsSetToPlay = true;\n            }\n        }\n    }\n\n    @Override\n    protected void onFinishInflate() {\n        super.onFinishInflate();\n\n        bringChildToFront(mAddButton);\n        mButtonsCount = getChildCount();\n\n    }\n\n\n    public void collapse() {\n        if (mExpanded) {\n            mExpanded = false;\n            mTouchDelegateGroup.setEnabled(false);\n            mCollapseAnimation.start();\n            mExpandAnimation.cancel();\n\n            if (mListener != null) {\n                mListener.onMenuCollapsed();\n            }\n        }\n    }\n\n    public void toggle() {\n        if (mExpanded) {\n            collapse();\n        } else {\n            expand();\n        }\n    }\n\n    public void expand() {\n        if (!mExpanded) {\n            mExpanded = true;\n            mTouchDelegateGroup.setEnabled(true);\n            mCollapseAnimation.cancel();\n            mExpandAnimation.start();\n\n            if (mListener != null) {\n                mListener.onMenuExpanded();\n            }\n        }\n    }\n\n    public boolean isExpanded() {\n        return mExpanded;\n    }\n\n    @Override\n    public Parcelable onSaveInstanceState() {\n        Parcelable superState = super.onSaveInstanceState();\n        SavedState savedState = new SavedState(superState);\n        savedState.mExpanded = mExpanded;\n\n        return savedState;\n    }\n\n    @Override\n    public void onRestoreInstanceState(Parcelable state) {\n        if (state instanceof SavedState) {\n            SavedState savedState = (SavedState) state;\n            mExpanded = savedState.mExpanded;\n            mTouchDelegateGroup.setEnabled(mExpanded);\n\n            if (mRotatingDrawable != null) {\n                mRotatingDrawable.setRotation(mExpanded ? EXPANDED_PLUS_ROTATION : COLLAPSED_PLUS_ROTATION);\n            }\n\n            super.onRestoreInstanceState(savedState.getSuperState());\n        } else {\n            super.onRestoreInstanceState(state);\n        }\n    }\n\n    public static class SavedState extends BaseSavedState {\n        public boolean mExpanded;\n\n        public SavedState(Parcelable parcel) {\n            super(parcel);\n        }\n\n        private SavedState(Parcel in) {\n            super(in);\n            mExpanded = in.readInt() == 1;\n        }\n\n        @Override\n        public void writeToParcel(@NonNull Parcel out, int flags) {\n            super.writeToParcel(out, flags);\n            out.writeInt(mExpanded ? 1 : 0);\n        }\n\n        public static final Creator<SavedState> CREATOR = new Creator<SavedState>() {\n\n            @Override\n            public SavedState createFromParcel(Parcel in) {\n                return new SavedState(in);\n            }\n\n            @Override\n            public SavedState[] newArray(int size) {\n                return new SavedState[size];\n            }\n        };\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/com/example/gpy/whiteboard/view/widget/floatingactionmenu/FloatingImageButton.java",
    "content": "package com.example.gpy.whiteboard.view.widget.floatingactionmenu;\n\nimport android.content.Context;\nimport android.graphics.Canvas;\nimport android.graphics.Paint;\nimport android.util.AttributeSet;\nimport android.widget.ImageButton;\n\nimport com.github.guanpy.wblib.utils.OperationUtils;\nimport com.github.guanpy.wblib.utils.WhiteBoardVariable;\n\n/**\n * FloatingActionButton 不具备的功能\n */\npublic class FloatingImageButton extends ImageButton {\n    Paint mPaint;\n\n    /**不做绘画操作*/\n    static final int DRAW_NULL = 0;\n    /**画圆环*/\n    static final int DRAW_RING = 1;\n    /**画圆*/\n    static final int DRAW_CIRCLE= 2;\n    /**画圆和圆环*/\n    static final int DRAW_CIRCLE_AND_RING= 3;\n    int mDrawType ;\n\n    public FloatingImageButton(Context context) {\n        this(context, null);\n    }\n\n    public FloatingImageButton(Context context, AttributeSet attrs) {\n        super(context, attrs);\n        init(context);\n    }\n\n    public FloatingImageButton(Context context, AttributeSet attrs, int defStyle) {\n        super(context, attrs, defStyle);\n        init(context);\n    }\n    private void init(Context context){\n       mPaint = new Paint();\n       mPaint.setAntiAlias(true); //消除锯齿\n    }\n    /**\n     * 在图片中间画圆环(按钮小圆环)\n     * @param color  圆的颜色\n     * */\n    public void drawMiniRing(int color){\n        drawRing(WhiteBoardVariable.RingSize.MINI, color);\n    }\n    /**\n     * 在图片中间画圆环(按钮大圆环)\n     * @param color  圆的颜色\n     * */\n    public void drawLargeRing(int color){\n        drawRing(WhiteBoardVariable.RingSize.LARRGE, color);\n    }\n    /**\n     * 在图片中间画圆环\n     * @param size  圆的半径\n     * @param color  圆的颜色\n     * */\n    public void drawRing(int size,int color){\n       mPaint.setColor(color);\n       mPaint.setStrokeWidth(size);\n       mPaint.setStyle(Paint.Style.STROKE); //绘制空心圆\n        mDrawType = DRAW_RING;\n        postInvalidate();\n    }\n    /**\n     * 在图片中间画圆\n     * @param size  圆的半径\n     * */\n    public void drawCircle(int size){\n        drawCircle(size, OperationUtils.getInstance().mCurrentColor);\n    }\n    /**\n     * 在图片中间画圆\n     * @param size  圆的半径\n     * @param color  圆的颜色\n     * */\n    public void drawCircle(int size,int color){\n        mPaint.setColor(color);\n        mPaint.setStrokeWidth(size);\n        mPaint.setStyle(Paint.Style.FILL); //绘制实心圆\n        mDrawType = DRAW_CIRCLE;\n        postInvalidate();\n    }\n    /**\n     * 在图片中间画圆和外圈圆环\n     * @param size  圆的半径\n     * @param color  圆的颜色\n     * */\n    public void drawCircleAndRing(int size,int color){\n        mPaint.setColor(color);\n        mPaint.setStrokeWidth(size);\n        mPaint.setStyle(Paint.Style.FILL); //绘制实心圆\n        mDrawType = DRAW_CIRCLE_AND_RING;\n        postInvalidate();\n    }\n    /**\n     * 清除绘画\n     * */\n    public void clearDraw(){\n        mDrawType = DRAW_NULL;\n        postInvalidate();\n    }\n    @Override\n    protected void onDraw(Canvas canvas) {\n        super.onDraw(canvas);\n        int center = getWidth()/2;\n        if(mDrawType==DRAW_RING){\n            canvas.drawCircle(center, center, center - mPaint.getStrokeWidth(),mPaint);\n        }else if(mDrawType==DRAW_CIRCLE){\n            canvas.drawCircle(center, center, mPaint.getStrokeWidth(),mPaint);\n        }else if(mDrawType==DRAW_CIRCLE_AND_RING){\n            canvas.drawCircle(center, center, mPaint.getStrokeWidth(), mPaint);\n            mPaint.setStrokeWidth(WhiteBoardVariable.RingSize.MINI);\n            mPaint.setStyle(Paint.Style.STROKE); //绘制空心圆\n            canvas.drawCircle(center, center, center - WhiteBoardVariable.RingSize.MINI, mPaint);\n        }\n\n\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/com/example/gpy/whiteboard/view/widget/floatingactionmenu/TouchDelegateGroup.java",
    "content": "package com.example.gpy.whiteboard.view.widget.floatingactionmenu;\n\nimport android.graphics.Rect;\nimport android.support.annotation.NonNull;\nimport android.view.MotionEvent;\nimport android.view.TouchDelegate;\nimport android.view.View;\n\nimport java.util.ArrayList;\n\npublic class TouchDelegateGroup extends TouchDelegate {\n  private static final Rect USELESS_HACKY_RECT = new Rect();\n  private final ArrayList<TouchDelegate> mTouchDelegates = new ArrayList<TouchDelegate>();\n  private TouchDelegate mCurrentTouchDelegate;\n  private boolean mEnabled;\n\n  public TouchDelegateGroup(View uselessHackyView) {\n    super(USELESS_HACKY_RECT, uselessHackyView);\n  }\n\n  public void addTouchDelegate(@NonNull TouchDelegate touchDelegate) {\n    mTouchDelegates.add(touchDelegate);\n  }\n\n  public void removeTouchDelegate(TouchDelegate touchDelegate) {\n    mTouchDelegates.remove(touchDelegate);\n    if (mCurrentTouchDelegate == touchDelegate) {\n      mCurrentTouchDelegate = null;\n    }\n  }\n\n  public void clearTouchDelegates() {\n    mTouchDelegates.clear();\n    mCurrentTouchDelegate = null;\n  }\n\n  @Override\n  public boolean onTouchEvent(@NonNull MotionEvent event) {\n    if (!mEnabled) return false;\n\n    TouchDelegate delegate = null;\n\n    switch (event.getAction()) {\n    case MotionEvent.ACTION_DOWN:\n      for (int i = 0; i < mTouchDelegates.size(); i++) {\n        TouchDelegate touchDelegate = mTouchDelegates.get(i);\n        if (touchDelegate.onTouchEvent(event)) {\n          mCurrentTouchDelegate = touchDelegate;\n          return true;\n        }\n      }\n      break;\n\n    case MotionEvent.ACTION_MOVE:\n      delegate = mCurrentTouchDelegate;\n      break;\n\n    case MotionEvent.ACTION_CANCEL:\n    case MotionEvent.ACTION_UP:\n      delegate = mCurrentTouchDelegate;\n      mCurrentTouchDelegate = null;\n      break;\n    }\n\n    return delegate != null && delegate.onTouchEvent(event);\n  }\n\n  public void setEnabled(boolean enabled) {\n    mEnabled = enabled;\n  }\n}"
  },
  {
    "path": "app/src/main/res/drawable/bg_white_board.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<shape xmlns:android=\"http://schemas.android.com/apk/res/android\">\n    <solid android:color=\"@color/white\"/>\n    <corners android:radius=\"4dp\"/>\n</shape>"
  },
  {
    "path": "app/src/main/res/drawable/common_cancel_selector.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n\n<selector xmlns:android=\"http://schemas.android.com/apk/res/android\">\n    <item android:state_pressed=\"true\" android:drawable=\"@drawable/common_cancel_click\"/>\n    <item android:state_focused=\"true\" android:drawable=\"@drawable/common_cancel_click\" />\n    <item android:state_pressed=\"false\" android:drawable=\"@drawable/common_cancel_normal\"/>\n</selector>"
  },
  {
    "path": "app/src/main/res/drawable/common_confirm_selector.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n\n<selector xmlns:android=\"http://schemas.android.com/apk/res/android\">\n    <item android:state_pressed=\"true\" android:drawable=\"@drawable/common_confirm_click\"/>\n    <item android:state_focused=\"true\" android:drawable=\"@drawable/common_confirm_click\" />\n    <item android:state_pressed=\"false\" android:drawable=\"@drawable/common_confirm_normal\"/>\n</selector>"
  },
  {
    "path": "app/src/main/res/drawable/draw_text_border.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<shape xmlns:android=\"http://schemas.android.com/apk/res/android\" \nandroid:shape=\"rectangle\" >\n   <solid android:color=\"@color/white_board_drawtext_back\" />\n   <stroke android:width=\"0.5dip\" android:color=\"@color/grey_3e\"/>\n</shape>"
  },
  {
    "path": "app/src/main/res/drawable/fab_label_background.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<shape xmlns:android=\"http://schemas.android.com/apk/res/android\">\n    <solid android:color=\"@color/black_semi_transparent\"/>\n    <padding\n        android:left=\"16dp\"\n        android:top=\"4dp\"\n        android:right=\"16dp\"\n        android:bottom=\"4dp\"/>\n    <corners\n        android:radius=\"2dp\"/>\n</shape>"
  },
  {
    "path": "app/src/main/res/drawable/ic_back_selector.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<selector xmlns:android=\"http://schemas.android.com/apk/res/android\">\n    <item android:state_pressed=\"true\" android:drawable=\"@drawable/ic_back_pressed\"/>\n    <item android:state_focused=\"true\" android:drawable=\"@drawable/ic_back_pressed\"/>\n    <item android:drawable=\"@drawable/ic_back_normal\"/>\n</selector>"
  },
  {
    "path": "app/src/main/res/drawable/white_board_add_selector.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n\n<selector xmlns:android=\"http://schemas.android.com/apk/res/android\">\n    <item android:state_pressed=\"true\" android:drawable=\"@drawable/white_board_add_click\"/>\n    <item android:state_focused=\"true\" android:drawable=\"@drawable/white_board_add_click\" />\n    <item android:state_pressed=\"false\" android:drawable=\"@drawable/white_board_add_normal\"/>\n</selector>"
  },
  {
    "path": "app/src/main/res/drawable/white_board_color_black_selector.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n\n<selector xmlns:android=\"http://schemas.android.com/apk/res/android\">\n    <item android:state_pressed=\"true\" android:drawable=\"@drawable/white_board_color_black_click\"/>\n    <item android:state_focused=\"true\" android:drawable=\"@drawable/white_board_color_black_click\" />\n    <item android:state_pressed=\"false\" android:drawable=\"@drawable/white_board_color_black_normal\"/>\n</selector>"
  },
  {
    "path": "app/src/main/res/drawable/white_board_color_green_selector.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n\n<selector xmlns:android=\"http://schemas.android.com/apk/res/android\">\n    <item android:state_pressed=\"true\" android:drawable=\"@drawable/white_board_color_green_click\"/>\n    <item android:state_focused=\"true\" android:drawable=\"@drawable/white_board_color_green_click\" />\n    <item android:state_pressed=\"false\" android:drawable=\"@drawable/white_board_color_green_normal\"/>\n</selector>"
  },
  {
    "path": "app/src/main/res/drawable/white_board_color_orange_selector.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n\n<selector xmlns:android=\"http://schemas.android.com/apk/res/android\">\n    <item android:state_pressed=\"true\" android:drawable=\"@drawable/white_board_color_orange_click\"/>\n    <item android:state_focused=\"true\" android:drawable=\"@drawable/white_board_color_orange_click\" />\n    <item android:state_pressed=\"false\" android:drawable=\"@drawable/white_board_color_orange_normal\"/>\n</selector>"
  },
  {
    "path": "app/src/main/res/drawable/white_board_color_pink_selector.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n\n<selector xmlns:android=\"http://schemas.android.com/apk/res/android\">\n    <item android:state_pressed=\"true\" android:drawable=\"@drawable/white_board_color_pink_click\"/>\n    <item android:state_focused=\"true\" android:drawable=\"@drawable/white_board_color_pink_click\" />\n    <item android:state_pressed=\"false\" android:drawable=\"@drawable/white_board_color_pink_normal\"/>\n</selector>"
  },
  {
    "path": "app/src/main/res/drawable/white_board_color_purple_selector.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n\n<selector xmlns:android=\"http://schemas.android.com/apk/res/android\">\n    <item android:state_pressed=\"true\" android:drawable=\"@drawable/white_board_color_purple_click\"/>\n    <item android:state_focused=\"true\" android:drawable=\"@drawable/white_board_color_purple_click\" />\n    <item android:state_pressed=\"false\" android:drawable=\"@drawable/white_board_color_purple_normal\"/>\n</selector>"
  },
  {
    "path": "app/src/main/res/drawable/white_board_disable_selector.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n\n<selector xmlns:android=\"http://schemas.android.com/apk/res/android\">\n    <item android:state_pressed=\"true\" android:drawable=\"@drawable/white_board_disable_click\"/>\n    <item android:state_focused=\"true\" android:drawable=\"@drawable/white_board_disable_click\" />\n    <item android:state_pressed=\"false\" android:drawable=\"@drawable/white_board_disable_normal\"/>\n</selector>"
  },
  {
    "path": "app/src/main/res/drawable/white_board_eraser_selected_selector.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n\n<selector xmlns:android=\"http://schemas.android.com/apk/res/android\">\n    <item android:state_pressed=\"true\" android:drawable=\"@drawable/white_board_eraser_selected_click\"/>\n    <item android:state_focused=\"true\" android:drawable=\"@drawable/white_board_eraser_selected_click\" />\n    <item android:state_pressed=\"false\" android:drawable=\"@drawable/white_board_eraser_selected_normal\"/>\n</selector>"
  },
  {
    "path": "app/src/main/res/drawable/white_board_eraser_selector.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n\n<selector xmlns:android=\"http://schemas.android.com/apk/res/android\">\n    <item android:state_pressed=\"true\" android:drawable=\"@drawable/white_board_eraser_click\"/>\n    <item android:state_focused=\"true\" android:drawable=\"@drawable/white_board_eraser_click\" />\n    <item android:state_pressed=\"false\" android:drawable=\"@drawable/white_board_eraser_normal\"/>\n</selector>"
  },
  {
    "path": "app/src/main/res/drawable/white_board_export_selector.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n\n<selector xmlns:android=\"http://schemas.android.com/apk/res/android\">\n    <item android:state_pressed=\"true\" android:drawable=\"@drawable/white_board_export_click\"/>\n    <item android:state_focused=\"true\" android:drawable=\"@drawable/white_board_export_click\" />\n    <item android:state_pressed=\"false\" android:drawable=\"@drawable/white_board_export_normal\"/>\n</selector>"
  },
  {
    "path": "app/src/main/res/drawable/white_board_next_page_selector.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n\n<selector xmlns:android=\"http://schemas.android.com/apk/res/android\">\n    <item android:state_pressed=\"true\" android:drawable=\"@drawable/white_board_next_page_click\"/>\n    <item android:state_focused=\"true\" android:drawable=\"@drawable/white_board_next_page_click\" />\n    <item android:state_pressed=\"false\" android:drawable=\"@drawable/white_board_next_page_normal\"/>\n</selector>"
  },
  {
    "path": "app/src/main/res/drawable/white_board_pen_selected_selector.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n\n<selector xmlns:android=\"http://schemas.android.com/apk/res/android\">\n    <item android:state_pressed=\"true\" android:drawable=\"@drawable/white_board_pen_selected_click\"/>\n    <item android:state_focused=\"true\" android:drawable=\"@drawable/white_board_pen_selected_click\" />\n    <item android:state_pressed=\"false\" android:drawable=\"@drawable/white_board_pen_selected_normal\"/>\n</selector>"
  },
  {
    "path": "app/src/main/res/drawable/white_board_pen_selector.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n\n<selector xmlns:android=\"http://schemas.android.com/apk/res/android\">\n    <item android:state_pressed=\"true\" android:drawable=\"@drawable/white_board_pen_click\"/>\n    <item android:state_focused=\"true\" android:drawable=\"@drawable/white_board_pen_click\" />\n    <item android:state_pressed=\"false\" android:drawable=\"@drawable/white_board_pen_normal\"/>\n</selector>"
  },
  {
    "path": "app/src/main/res/drawable/white_board_pre_page_selector.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n\n<selector xmlns:android=\"http://schemas.android.com/apk/res/android\">\n    <item android:state_pressed=\"true\" android:drawable=\"@drawable/white_board_pre_page_click\"/>\n    <item android:state_focused=\"true\" android:drawable=\"@drawable/white_board_pre_page_click\" />\n    <item android:state_pressed=\"false\" android:drawable=\"@drawable/white_board_pre_page_normal\"/>\n</selector>"
  },
  {
    "path": "app/src/main/res/drawable/white_board_redo_selector.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n\n<selector xmlns:android=\"http://schemas.android.com/apk/res/android\">\n    <item android:state_pressed=\"true\" android:drawable=\"@drawable/white_board_redo_click\"/>\n    <item android:state_focused=\"true\" android:drawable=\"@drawable/white_board_redo_click\" />\n    <item android:state_pressed=\"false\" android:drawable=\"@drawable/white_board_redo_normal\"/>\n</selector>"
  },
  {
    "path": "app/src/main/res/drawable/white_board_save_selector.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n\n<selector xmlns:android=\"http://schemas.android.com/apk/res/android\">\n    <item android:state_pressed=\"true\" android:drawable=\"@drawable/white_board_save_click\"/>\n    <item android:state_focused=\"true\" android:drawable=\"@drawable/white_board_save_click\" />\n    <item android:state_pressed=\"false\" android:drawable=\"@drawable/white_board_save_normal\"/>\n</selector>"
  },
  {
    "path": "app/src/main/res/drawable/white_board_text_bold_selected_selector.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n\n<selector xmlns:android=\"http://schemas.android.com/apk/res/android\">\n    <item android:state_pressed=\"true\" android:drawable=\"@drawable/white_board_text_bold_selected_click\"/>\n    <item android:state_focused=\"true\" android:drawable=\"@drawable/white_board_text_bold_selected_click\" />\n    <item android:state_pressed=\"false\" android:drawable=\"@drawable/white_board_text_bold_selected_normal\"/>\n</selector>"
  },
  {
    "path": "app/src/main/res/drawable/white_board_text_bold_selector.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n\n<selector xmlns:android=\"http://schemas.android.com/apk/res/android\">\n    <item android:state_pressed=\"true\" android:drawable=\"@drawable/white_board_text_bold_click\"/>\n    <item android:state_focused=\"true\" android:drawable=\"@drawable/white_board_text_bold_click\" />\n    <item android:state_pressed=\"false\" android:drawable=\"@drawable/white_board_text_bold_normal\"/>\n</selector>"
  },
  {
    "path": "app/src/main/res/drawable/white_board_text_italics_selected_selector.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n\n<selector xmlns:android=\"http://schemas.android.com/apk/res/android\">\n    <item android:state_pressed=\"true\" android:drawable=\"@drawable/white_board_text_italics_selected_click\"/>\n    <item android:state_focused=\"true\" android:drawable=\"@drawable/white_board_text_italics_selected_click\" />\n    <item android:state_pressed=\"false\" android:drawable=\"@drawable/white_board_text_italics_selected_normal\"/>\n</selector>"
  },
  {
    "path": "app/src/main/res/drawable/white_board_text_italics_selector.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n\n<selector xmlns:android=\"http://schemas.android.com/apk/res/android\">\n    <item android:state_pressed=\"true\" android:drawable=\"@drawable/white_board_text_italics_click\"/>\n    <item android:state_focused=\"true\" android:drawable=\"@drawable/white_board_text_italics_click\" />\n    <item android:state_pressed=\"false\" android:drawable=\"@drawable/white_board_text_italics_normal\"/>\n</selector>"
  },
  {
    "path": "app/src/main/res/drawable/white_board_text_selected_selector.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n\n<selector xmlns:android=\"http://schemas.android.com/apk/res/android\">\n    <item android:state_pressed=\"true\" android:drawable=\"@drawable/white_board_text_selected_click\"/>\n    <item android:state_focused=\"true\" android:drawable=\"@drawable/white_board_text_selected_click\" />\n    <item android:state_pressed=\"false\" android:drawable=\"@drawable/white_board_text_selected_normal\"/>\n</selector>"
  },
  {
    "path": "app/src/main/res/drawable/white_board_text_selector.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n\n<selector xmlns:android=\"http://schemas.android.com/apk/res/android\">\n    <item android:state_pressed=\"true\" android:drawable=\"@drawable/white_board_text_click\"/>\n    <item android:state_focused=\"true\" android:drawable=\"@drawable/white_board_text_click\" />\n    <item android:state_pressed=\"false\" android:drawable=\"@drawable/white_board_text_normal\"/>\n</selector>"
  },
  {
    "path": "app/src/main/res/drawable/white_board_text_underline_selected_selector.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n\n<selector xmlns:android=\"http://schemas.android.com/apk/res/android\">\n    <item android:state_pressed=\"true\" android:drawable=\"@drawable/white_board_text_underline_selected_click\"/>\n    <item android:state_focused=\"true\" android:drawable=\"@drawable/white_board_text_underline_selected_click\" />\n    <item android:state_pressed=\"false\" android:drawable=\"@drawable/white_board_text_underline_selected_normal\"/>\n</selector>"
  },
  {
    "path": "app/src/main/res/drawable/white_board_text_underline_selector.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n\n<selector xmlns:android=\"http://schemas.android.com/apk/res/android\">\n    <item android:state_pressed=\"true\" android:drawable=\"@drawable/white_board_text_underline_click\"/>\n    <item android:state_focused=\"true\" android:drawable=\"@drawable/white_board_text_underline_click\" />\n    <item android:state_pressed=\"false\" android:drawable=\"@drawable/white_board_text_underline_normal\"/>\n</selector>"
  },
  {
    "path": "app/src/main/res/drawable/white_board_undisable_selector.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n\n<selector xmlns:android=\"http://schemas.android.com/apk/res/android\">\n    <item android:state_pressed=\"true\" android:drawable=\"@drawable/white_board_undisable_click\"/>\n    <item android:state_focused=\"true\" android:drawable=\"@drawable/white_board_undisable_click\" />\n    <item android:state_pressed=\"false\" android:drawable=\"@drawable/white_board_undisable_normal\"/>\n</selector>"
  },
  {
    "path": "app/src/main/res/drawable/white_board_undo_selector.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n\n<selector xmlns:android=\"http://schemas.android.com/apk/res/android\">\n    <item android:state_pressed=\"true\" android:drawable=\"@drawable/white_board_undo_click\"/>\n    <item android:state_focused=\"true\" android:drawable=\"@drawable/white_board_undo_click\" />\n    <item android:state_pressed=\"false\" android:drawable=\"@drawable/white_board_undo_normal\"/>\n</selector>"
  },
  {
    "path": "app/src/main/res/layout/activity_main.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<LinearLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\"\n    android:orientation=\"vertical\">\n\n    <RelativeLayout\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"50dp\"\n        android:background=\"@color/colorPrimary\">\n\n        <TextView\n            android:layout_width=\"wrap_content\"\n            android:layout_height=\"wrap_content\"\n            android:layout_centerInParent=\"true\"\n            android:text=\"@string/app_list\"\n            android:textColor=\"@color/white\"\n            android:textSize=\"20sp\" />\n\n        <ImageView\n            android:id=\"@+id/iv_wb_add\"\n            android:layout_width=\"wrap_content\"\n            android:layout_height=\"wrap_content\"\n            android:layout_alignParentRight=\"true\"\n            android:layout_centerVertical=\"true\"\n            android:layout_marginRight=\"24dip\"\n            android:src=\"@drawable/ic_wb_add\" />\n    </RelativeLayout>\n\n    <RelativeLayout\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"match_parent\">\n\n        <TextView\n            android:id=\"@+id/tv_list_loading\"\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"match_parent\"\n            android:text=\"@string/app_list_loading\"\n            android:gravity=\"center\"\n            android:visibility=\"gone\"\n            android:textSize=\"20sp\" />\n\n        <ListView\n            android:id=\"@+id/lv_wb\"\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"wrap_content\"\n            android:layout_marginLeft=\"10dp\"\n            android:layout_marginRight=\"10dp\"\n            android:divider=\"@color/colorDivide\"\n            android:dividerHeight=\"1dp\"\n\n            android:listSelector=\"@null\" />\n\n    </RelativeLayout>\n</LinearLayout>\n"
  },
  {
    "path": "app/src/main/res/layout/activity_white_board.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<RelativeLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:fab=\"http://schemas.android.com/apk/res-auto\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\">\n\n    <FrameLayout\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"match_parent\">\n\n        <ImageView\n            android:id=\"@+id/iv_white_board_book\"\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"match_parent\"\n            android:scaleType=\"centerCrop\" />\n\n        <View\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"match_parent\"\n            android:background=\"@color/cover\" />\n\n    </FrameLayout>\n\n\n    <RelativeLayout\n        android:id=\"@+id/rl_head\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"64dp\"\n        android:layout_marginLeft=\"24dp\"\n        android:layout_marginRight=\"24dp\">\n\n        <ImageView\n            android:id=\"@+id/iv_white_board_back\"\n            android:layout_width=\"wrap_content\"\n            android:layout_height=\"wrap_content\"\n            android:layout_alignParentLeft=\"true\"\n            android:layout_centerVertical=\"true\"\n            android:clickable=\"true\"\n            android:scaleType=\"centerCrop\"\n            android:src=\"@drawable/ic_back_selector\" />\n\n        <ImageView\n            android:id=\"@+id/iv_white_board_quit\"\n            android:layout_width=\"wrap_content\"\n            android:layout_height=\"wrap_content\"\n            android:layout_alignParentLeft=\"true\"\n            android:layout_centerVertical=\"true\"\n            android:clickable=\"true\"\n            android:scaleType=\"centerCrop\"\n            android:src=\"@drawable/common_cancel_selector\"\n            android:visibility=\"gone\" />\n\n        <TextView\n            android:id=\"@+id/tv_white_board_head\"\n            style=\"@style/HeaderTextView\"\n            android:layout_centerInParent=\"true\"\n            android:text=\"@string/white_board_name\" />\n\n        <ImageView\n            android:id=\"@+id/iv_white_board_confirm\"\n            android:layout_width=\"30dip\"\n            android:layout_height=\"30dip\"\n            android:layout_alignParentRight=\"true\"\n            android:layout_centerInParent=\"true\"\n            android:clickable=\"true\"\n            android:scaleType=\"centerCrop\"\n            android:src=\"@drawable/common_confirm_selector\"\n            android:visibility=\"gone\" />\n\n        <LinearLayout\n            android:layout_width=\"wrap_content\"\n            android:layout_height=\"match_parent\"\n            android:layout_alignParentRight=\"true\"\n            android:layout_marginRight=\"60dp\">\n\n            <ImageView\n                android:id=\"@+id/iv_white_board_export\"\n                android:layout_width=\"30dip\"\n                android:layout_height=\"30dip\"\n                android:layout_gravity=\"center_vertical\"\n                android:clickable=\"true\"\n                android:scaleType=\"centerCrop\"\n                android:src=\"@drawable/white_board_save_selector\" />\n\n            <ImageView\n                android:id=\"@+id/iv_white_board_save\"\n                android:layout_width=\"30dip\"\n                android:layout_height=\"30dip\"\n                android:layout_gravity=\"center_vertical\"\n                android:layout_marginLeft=\"30dp\"\n                android:clickable=\"true\"\n                android:scaleType=\"centerCrop\"\n                android:src=\"@drawable/white_board_export_selector\" />\n\n        </LinearLayout>\n\n    </RelativeLayout>\n\n    <RelativeLayout\n        android:id=\"@+id/rl_content\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"match_parent\"\n        android:layout_below=\"@+id/rl_head\"\n        android:layout_marginBottom=\"24dp\"\n        android:layout_marginLeft=\"24dp\"\n        android:layout_marginRight=\"24dp\">\n        <ScrollView\n            android:id=\"@+id/sv_content\"\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"match_parent\"\n            android:fillViewport=\"true\"\n            android:fadingEdge=\"none\"\n            android:scrollbars=\"none\"\n            >\n        <FrameLayout\n            android:id=\"@+id/fl_view\"\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"match_parent\"\n            android:background=\"@drawable/bg_white_board\"\n            >\n\n            <com.github.guanpy.wblib.widget.DrawPenView\n                android:id=\"@+id/db_view\"\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"wrap_content\"\n                 />\n\n            <com.github.guanpy.wblib.widget.DrawTextLayout\n                android:id=\"@+id/dt_view\"\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"match_parent\"\n                />\n        </FrameLayout>\n        </ScrollView>\n        <RelativeLayout\n            android:id=\"@+id/rl_bottom\"\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"match_parent\"\n            >\n\n            <View\n                android:id=\"@+id/v_bottom_back\"\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"match_parent\"\n                android:visibility=\"gone\"\n                android:background=\"@color/transparent\" />\n\n            <com.example.gpy.whiteboard.view.widget.floatingactionmenu.FloatingActionsMenu\n                android:id=\"@+id/fab_menu_size\"\n                android:layout_width=\"wrap_content\"\n                android:layout_height=\"wrap_content\"\n                android:layout_alignParentBottom=\"true\"\n                android:layout_marginBottom=\"16dp\"\n                android:layout_marginLeft=\"16dp\"\n                fab:fab_addButtonBackground=\"@drawable/white_board_pen_selector\"\n                fab:fab_addButtonHeight=\"44dip\"\n                fab:fab_addButtonStyle=\"customStyle\"\n                fab:fab_addButtonWidth=\"44dip\"\n                fab:fab_buttonSpacing=\"12dp\"\n                fab:fab_expandDirection=\"up\"\n                fab:fab_labelStyle=\"@style/menu_labels_style\">\n\n                <com.example.gpy.whiteboard.view.widget.floatingactionmenu.FloatingImageButton\n                    android:id=\"@+id/bt_size_large\"\n                    android:layout_width=\"44dip\"\n                    android:layout_height=\"44dip\"\n                    android:background=\"@drawable/white_board_drable_back_normal\" />\n\n\n                <com.example.gpy.whiteboard.view.widget.floatingactionmenu.FloatingImageButton\n                    android:id=\"@+id/bt_size_middle\"\n                    android:layout_width=\"44dip\"\n                    android:layout_height=\"44dip\"\n                    android:background=\"@drawable/white_board_drable_back_normal\" />\n\n                <com.example.gpy.whiteboard.view.widget.floatingactionmenu.FloatingImageButton\n                    android:id=\"@+id/bt_size_mini\"\n                    android:layout_width=\"44dip\"\n                    android:layout_height=\"44dip\"\n                    android:background=\"@drawable/white_board_drable_back_normal\" />\n\n            </com.example.gpy.whiteboard.view.widget.floatingactionmenu.FloatingActionsMenu>\n\n            <com.example.gpy.whiteboard.view.widget.floatingactionmenu.FloatingActionsMenu\n                android:id=\"@+id/fab_menu_color\"\n                android:layout_width=\"wrap_content\"\n                android:layout_height=\"wrap_content\"\n                android:layout_alignParentBottom=\"true\"\n                android:layout_marginBottom=\"16dp\"\n                android:layout_marginLeft=\"12dp\"\n                android:layout_toRightOf=\"@+id/fab_menu_size\"\n                fab:fab_addButtonBackground=\"@drawable/white_board_color_black_selector\"\n                fab:fab_addButtonHeight=\"44dip\"\n                fab:fab_addButtonStyle=\"customStyle\"\n                fab:fab_addButtonWidth=\"44dip\"\n                fab:fab_buttonSpacing=\"12dp\"\n                fab:fab_expandDirection=\"up\"\n                fab:fab_labelStyle=\"@style/menu_labels_style\">\n\n\n                <com.example.gpy.whiteboard.view.widget.floatingactionmenu.FloatingImageButton\n                    android:id=\"@+id/bt_color_green\"\n                    android:layout_width=\"44dip\"\n                    android:layout_height=\"44dip\"\n                    android:background=\"@drawable/white_board_color_green_selector\" />\n\n                <com.example.gpy.whiteboard.view.widget.floatingactionmenu.FloatingImageButton\n                    android:id=\"@+id/bt_color_purple\"\n                    android:layout_width=\"44dip\"\n                    android:layout_height=\"44dip\"\n                    android:background=\"@drawable/white_board_color_purple_selector\" />\n\n                <com.example.gpy.whiteboard.view.widget.floatingactionmenu.FloatingImageButton\n                    android:id=\"@+id/bt_color_pink\"\n                    android:layout_width=\"44dip\"\n                    android:layout_height=\"44dip\"\n                    android:background=\"@drawable/white_board_color_pink_selector\" />\n\n                <com.example.gpy.whiteboard.view.widget.floatingactionmenu.FloatingImageButton\n                    android:id=\"@+id/bt_color_orange\"\n                    android:layout_width=\"44dip\"\n                    android:layout_height=\"44dip\"\n                    android:background=\"@drawable/white_board_color_orange_selector\" />\n\n                <com.example.gpy.whiteboard.view.widget.floatingactionmenu.FloatingImageButton\n                    android:id=\"@+id/bt_color_black\"\n                    android:layout_width=\"44dip\"\n                    android:layout_height=\"44dip\"\n                    android:background=\"@drawable/white_board_color_black_selector\" />\n\n            </com.example.gpy.whiteboard.view.widget.floatingactionmenu.FloatingActionsMenu>\n\n            <com.example.gpy.whiteboard.view.widget.floatingactionmenu.FloatingActionsMenu\n                android:id=\"@+id/fab_menu_text\"\n                android:layout_width=\"wrap_content\"\n                android:layout_height=\"wrap_content\"\n                android:layout_alignParentBottom=\"true\"\n                android:layout_marginBottom=\"16dp\"\n                android:layout_marginLeft=\"12dp\"\n                android:layout_toRightOf=\"@+id/fab_menu_color\"\n                fab:fab_addButtonBackground=\"@drawable/white_board_text_selector\"\n                fab:fab_addButtonHeight=\"44dip\"\n                fab:fab_addButtonStyle=\"customStyle\"\n                fab:fab_addButtonWidth=\"44dip\"\n                fab:fab_buttonSpacing=\"12dp\"\n                fab:fab_expandDirection=\"up\"\n                fab:fab_labelStyle=\"@style/menu_labels_style\">\n\n                <com.example.gpy.whiteboard.view.widget.floatingactionmenu.FloatingImageButton\n                    android:id=\"@+id/bt_text_underline\"\n                    android:layout_width=\"44dip\"\n                    android:layout_height=\"44dip\"\n                    android:background=\"@drawable/white_board_text_underline_selector\" />\n\n\n                <com.example.gpy.whiteboard.view.widget.floatingactionmenu.FloatingImageButton\n                    android:id=\"@+id/bt_text_italics\"\n                    android:layout_width=\"44dip\"\n                    android:layout_height=\"44dip\"\n                    android:background=\"@drawable/white_board_text_italics_selector\"\n                    android:visibility=\"gone\" />\n\n                <com.example.gpy.whiteboard.view.widget.floatingactionmenu.FloatingImageButton\n                    android:id=\"@+id/bt_text_bold\"\n                    android:layout_width=\"44dip\"\n                    android:layout_height=\"44dip\"\n                    android:background=\"@drawable/white_board_text_bold_selector\" />\n\n            </com.example.gpy.whiteboard.view.widget.floatingactionmenu.FloatingActionsMenu>\n\n            <com.example.gpy.whiteboard.view.widget.floatingactionmenu.FloatingActionsMenu\n                android:id=\"@+id/fab_menu_eraser\"\n                android:layout_width=\"wrap_content\"\n                android:layout_height=\"wrap_content\"\n                android:layout_alignParentBottom=\"true\"\n                android:layout_marginBottom=\"16dp\"\n                android:layout_marginLeft=\"12dp\"\n                android:layout_toRightOf=\"@+id/fab_menu_text\"\n                fab:fab_addButtonBackground=\"@drawable/white_board_eraser_selector\"\n                fab:fab_addButtonHeight=\"44dip\"\n                fab:fab_addButtonStyle=\"customStyle\"\n                fab:fab_addButtonWidth=\"44dip\"\n                fab:fab_buttonSpacing=\"12dp\"\n                fab:fab_expandDirection=\"up\"\n                fab:fab_labelStyle=\"@style/menu_labels_style\">\n\n\n                <com.example.gpy.whiteboard.view.widget.floatingactionmenu.FloatingImageButton\n                    android:id=\"@+id/bt_eraser_large\"\n                    android:layout_width=\"44dip\"\n                    android:layout_height=\"44dip\"\n                    android:background=\"@drawable/white_board_drable_back_normal\" />\n\n\n                <com.example.gpy.whiteboard.view.widget.floatingactionmenu.FloatingImageButton\n                    android:id=\"@+id/bt_eraser_middle\"\n                    android:layout_width=\"44dip\"\n                    android:layout_height=\"44dip\"\n                    android:background=\"@drawable/white_board_drable_back_normal\" />\n\n                <com.example.gpy.whiteboard.view.widget.floatingactionmenu.FloatingImageButton\n                    android:id=\"@+id/bt_eraser_mini\"\n                    android:layout_width=\"44dip\"\n                    android:layout_height=\"44dip\"\n                    android:background=\"@drawable/white_board_drable_back_normal\" />\n\n            </com.example.gpy.whiteboard.view.widget.floatingactionmenu.FloatingActionsMenu>\n\n\n            <ImageView\n                android:id=\"@+id/iv_white_board_undo\"\n                android:layout_width=\"44dp\"\n                android:layout_height=\"44dp\"\n                android:layout_alignParentBottom=\"true\"\n                android:layout_gravity=\"center_vertical\"\n                android:layout_marginBottom=\"16dp\"\n                android:layout_marginLeft=\"12dp\"\n                android:layout_toRightOf=\"@+id/fab_menu_eraser\"\n                android:clickable=\"true\"\n                android:scaleType=\"centerCrop\"\n                android:src=\"@drawable/white_board_undo_selector\" />\n\n            <ImageView\n                android:id=\"@+id/iv_white_board_redo\"\n                android:layout_width=\"44dp\"\n                android:layout_height=\"44dp\"\n                android:layout_alignParentBottom=\"true\"\n                android:layout_gravity=\"center_vertical\"\n                android:layout_marginBottom=\"16dp\"\n                android:layout_marginLeft=\"12dp\"\n                android:layout_toRightOf=\"@+id/iv_white_board_undo\"\n                android:clickable=\"true\"\n                android:scaleType=\"centerCrop\"\n                android:src=\"@drawable/white_board_redo_selector\" />\n\n            <LinearLayout\n                android:id=\"@+id/ll_white_board_page\"\n                android:layout_width=\"wrap_content\"\n                android:layout_height=\"44dip\"\n                android:layout_alignParentBottom=\"true\"\n                android:layout_marginBottom=\"16dp\"\n                android:layout_marginRight=\"16dp\"\n                android:layout_toLeftOf=\"@+id/iv_white_board_add\"\n                android:background=\"@drawable/white_board_page_back\"\n                android:orientation=\"horizontal\">\n            <LinearLayout\n                android:id=\"@+id/ll_white_board_pre\"\n                android:layout_width=\"wrap_content\"\n                android:layout_height=\"44dip\"\n                android:orientation=\"horizontal\">\n                <ImageView\n                    android:id=\"@+id/iv_white_board_pre\"\n                    android:layout_width=\"7dp\"\n                    android:layout_height=\"14dp\"\n                    android:layout_gravity=\"center_vertical\"\n                    android:layout_marginLeft=\"16dip\"\n                    android:layout_marginRight=\"10dip\"\n                    android:clickable=\"true\"\n                    android:scaleType=\"centerCrop\"\n                    android:src=\"@drawable/white_board_pre_page_selector\" />\n            </LinearLayout>\n                <TextView\n                    android:id=\"@+id/tv_white_board_page\"\n                    android:layout_width=\"wrap_content\"\n                    android:layout_height=\"wrap_content\"\n                    android:layout_gravity=\"center_vertical\"\n                    android:layout_marginLeft=\"10dip\"\n                    android:layout_marginRight=\"10dip\"\n                    android:text=\"1/3\"\n                    android:textColor=\"@color/primary_black\" />\n            <LinearLayout\n                android:id=\"@+id/ll_white_board_next\"\n                android:layout_width=\"wrap_content\"\n                android:layout_height=\"44dip\"\n                android:orientation=\"horizontal\">\n                <ImageView\n                    android:id=\"@+id/iv_white_board_next\"\n                    android:layout_width=\"7dp\"\n                    android:layout_height=\"14dp\"\n                    android:layout_gravity=\"center_vertical\"\n                    android:layout_marginLeft=\"10dip\"\n                    android:layout_marginRight=\"16dip\"\n                    android:clickable=\"true\"\n                    android:scaleType=\"centerCrop\"\n                    android:src=\"@drawable/white_board_next_page_selector\" />\n            </LinearLayout>\n            </LinearLayout>\n\n            <ImageView\n                android:id=\"@+id/iv_white_board_add\"\n                android:layout_width=\"44dp\"\n                android:layout_height=\"44dp\"\n                android:layout_alignParentBottom=\"true\"\n                android:layout_gravity=\"center_vertical\"\n                android:layout_marginBottom=\"16dp\"\n                android:layout_marginRight=\"76dp\"\n                android:layout_alignParentRight=\"true\"\n\n                android:clickable=\"true\"\n                android:scaleType=\"centerCrop\"\n                android:src=\"@drawable/white_board_add_selector\" />\n\n\n        </RelativeLayout>\n        <ImageView\n            android:id=\"@+id/iv_white_board_disable\"\n            android:layout_width=\"44dp\"\n            android:layout_height=\"44dp\"\n            android:layout_alignParentBottom=\"true\"\n            android:layout_alignParentRight=\"true\"\n            android:layout_gravity=\"center_vertical\"\n            android:layout_marginBottom=\"16dp\"\n            android:layout_marginRight=\"16dp\"\n            android:clickable=\"true\"\n            android:scaleType=\"centerCrop\"\n            android:src=\"@drawable/white_board_disable_selector\" />\n    </RelativeLayout>\n\n</RelativeLayout>"
  },
  {
    "path": "app/src/main/res/layout/draw_text.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<RelativeLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\"\n    android:background=\"@color/transparent\" >\n\n    <View\n        android:id=\"@+id/v_outside\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"match_parent\"\n        android:background=\"@color/transparent\" />\n\n    <RelativeLayout\n        android:id=\"@+id/rl_content\"\n        android:layout_width=\"wrap_content\"\n        android:layout_height=\"wrap_content\" >\n\n        <RelativeLayout\n            android:id=\"@+id/rl_text\"\n            android:layout_width=\"wrap_content\"\n            android:layout_height=\"wrap_content\"\n            android:layout_marginLeft=\"15dip\"\n            android:layout_marginRight=\"15dip\"\n            android:background=\"@drawable/draw_text_border\"\n            android:gravity=\"center_vertical\"\n            android:paddingTop=\"25dip\"\n            android:paddingBottom=\"25dip\"\n            android:paddingLeft=\"30dip\"\n            android:paddingRight=\"30dip\" >\n\n            <EditText\n                android:id=\"@+id/et_text_edit\"\n                android:layout_width=\"wrap_content\"\n                android:layout_height=\"wrap_content\"\n                android:background=\"@color/transparent\"\n                android:minWidth=\"20dip\"\n                android:textSize=\"24sp\"\n                android:singleLine=\"true\"\n                android:visibility=\"gone\" />\n\n            <TextView\n                android:id=\"@+id/tv_text_edit\"\n                android:layout_width=\"wrap_content\"\n                android:layout_height=\"wrap_content\"\n                android:background=\"@color/transparent\"\n                android:minWidth=\"20dip\"\n                android:textSize=\"24sp\"\n                android:singleLine=\"true\"\n                android:clickable=\"true\"  \n                android:visibility=\"visible\" />\n        </RelativeLayout>\n\n        <Button\n            android:id=\"@+id/bt_text_delete\"\n            android:layout_width=\"30dip\"\n            android:layout_height=\"30dip\"\n            android:layout_alignParentLeft=\"true\"\n            android:layout_centerVertical=\"true\"\n            android:background=\"@drawable/draw_text_delete\" />\n\n        <Button\n            android:id=\"@+id/bt_text_edit\"\n            android:layout_width=\"30dip\"\n            android:layout_height=\"30dip\"\n            android:layout_centerVertical=\"true\"\n            android:layout_marginLeft=\"-30dip\"\n            android:layout_toRightOf=\"@+id/rl_text\"\n            android:background=\"@drawable/draw_text_edit\" />\n    </RelativeLayout>\n\n</RelativeLayout>"
  },
  {
    "path": "app/src/main/res/layout/wb_item.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<FrameLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"wrap_content\">\n\n    <LinearLayout\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"80dp\"\n        android:layout_marginBottom=\"10dp\"\n        android:layout_marginTop=\"10dp\"\n        android:orientation=\"horizontal\">\n\n        <TextView\n            android:id=\"@+id/tv_wb_name\"\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"wrap_content\"\n            android:ellipsize=\"end\"\n            android:textSize=\"19sp\" />\n\n\n    </LinearLayout>\n\n</FrameLayout>\n"
  },
  {
    "path": "app/src/main/res/values/attrs.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <declare-styleable name=\"FloatingActionButton\">\n        <attr name=\"fab_colorPressed\" format=\"color\"/>\n        <attr name=\"fab_colorDisabled\" format=\"color\"/>\n        <attr name=\"fab_colorNormal\" format=\"color\"/>\n        <attr name=\"fab_icon\" format=\"reference\"/>\n        <attr name=\"fab_size\" format=\"enum\">\n            <enum name=\"normal\" value=\"0\"/>\n            <enum name=\"mini\" value=\"1\"/>\n        </attr>\n        <attr name=\"fab_title\" format=\"string\"/>\n        <attr name=\"fab_stroke_visible\" format=\"boolean\"/>\n    </declare-styleable>\n    <declare-styleable name=\"AddFloatingActionButton\">\n        <attr name=\"fab_plusIconColor\" format=\"color\"/>\n    </declare-styleable>\n    <declare-styleable name=\"FloatingActionsMenu\">\n        <attr name=\"fab_buttonSpacing\" format=\"dimension\"/>\n        <attr name=\"fab_addButtonColorPressed\" format=\"color\"/>\n        <attr name=\"fab_addButtonColorNormal\" format=\"color\"/>\n        <attr name=\"fab_addButtonSize\" format=\"enum\">\n            <enum name=\"normal\" value=\"0\"/>\n            <enum name=\"mini\" value=\"1\"/>\n        </attr>\n        <attr name=\"fab_addButtonPlusIconColor\" format=\"color\"/>\n        <attr name=\"fab_addButtonStrokeVisible\" format=\"boolean\"/>\n\n        <attr name=\"fab_addButtonStyle\" format=\"enum\">\n            <enum name=\"defaultStyle\" value=\"0\"/>\n            <enum name=\"customStyle\" value=\"1\"/>\n        </attr>\n        <attr name=\"fab_addButtonBackground\" format=\"reference\"/>\n        <attr name=\"fab_addButtonWidth\" format=\"dimension\"/>\n        <attr name=\"fab_addButtonHeight\" format=\"dimension\"/>\n\n        <attr name=\"fab_labelStyle\" format=\"reference\"/>\n        <attr name=\"fab_labelsPosition\" format=\"enum\">\n            <enum name=\"left\" value=\"0\"/>\n            <enum name=\"right\" value=\"1\"/>\n        </attr>\n        <attr name=\"fab_expandDirection\" format=\"enum\">\n            <enum name=\"up\" value=\"0\"/>\n            <enum name=\"down\" value=\"1\"/>\n            <enum name=\"left\" value=\"2\"/>\n            <enum name=\"right\" value=\"3\"/>\n        </attr>\n    </declare-styleable>\n</resources>"
  },
  {
    "path": "app/src/main/res/values/colors.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <color name=\"colorPrimary\">#3F51B5</color>\n    <color name=\"colorPrimaryDark\">#303F9F</color>\n    <color name=\"colorAccent\">#FF4081</color>\n    <color name=\"colorDivide\">#DDDDDD</color>\n    <color name=\"white\">#ffffff</color>\n    <color name=\"transparent\">#00000000</color>\n    <color name=\"transparent_50\">#7f000000</color>\n    <color name=\"cover\">#cc2c1670</color>\n    <color name=\"black_semi_transparent\">#B2000000</color>\n    <color name=\"primary_black\">#3e3e3e</color>\n    <color name=\"grey_3e\">#3e3e3e</color>\n    <color name=\"orange\">#ff6a00</color>\n    <color name=\"light_red\">#f54983</color>\n    <color name=\"primary_purple\">#663fde</color>\n    <color name=\"green\">#24a8a3</color>\n    <color name=\"white_board_drawtext_back\">#f7f7f7</color>\n</resources>\n"
  },
  {
    "path": "app/src/main/res/values/dimens.xml",
    "content": "<resources>\n    <!-- Default screen margins, per the Android Design guidelines. -->\n    <dimen name=\"activity_horizontal_margin\">16dp</dimen>\n    <dimen name=\"activity_vertical_margin\">16dp</dimen>\n    <dimen name=\"font_200px\">100sp</dimen>\n    <dimen name=\"font_160px\">80sp</dimen>\n    <dimen name=\"font_80px\">40sp</dimen>\n    <dimen name=\"font_72px\">36sp</dimen>\n    <dimen name=\"font_60px\">30sp</dimen>\n    <dimen name=\"font_44px\">22sp</dimen>\n    <dimen name=\"font_40px\">20sp</dimen>\n    <dimen name=\"font_36px\">18sp</dimen>\n    <dimen name=\"font_32px\">16sp</dimen>\n    <dimen name=\"font_30px\">15sp</dimen>\n    <dimen name=\"font_28px\">14sp</dimen>\n    <dimen name=\"font_24px\">12sp</dimen>\n    <dimen name=\"font_22px\">11sp</dimen>\n    <dimen name=\"font_20px\">10sp</dimen>\n\n    <dimen name=\"fab_size_normal\">56dp</dimen>\n    <dimen name=\"fab_size_mini\">30dp</dimen>\n\n    <dimen name=\"fab_icon_size\">24dp</dimen>\n\n    <dimen name=\"fab_plus_icon_size\">14dp</dimen>\n    <dimen name=\"fab_plus_icon_stroke\">2dp</dimen>\n\n    <dimen name=\"fab_shadow_offset\">3dp</dimen>\n    <dimen name=\"fab_shadow_radius\">9dp</dimen>\n\n    <dimen name=\"fab_stroke_width\">1dp</dimen>\n\n    <dimen name=\"fab_actions_spacing\">16dp</dimen>\n    <dimen name=\"fab_labels_margin\">8dp</dimen>\n</resources>\n"
  },
  {
    "path": "app/src/main/res/values/ids.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <item type=\"id\" name=\"tag_loader\"/>\n    <item type=\"id\" name=\"tag_nodata\"/>\n    <item type=\"id\" name=\"tag_holder\"/>\n    <item type=\"id\" name=\"tag_other\"/>\n\n    <item type=\"id\" name=\"fab_expand_menu_button\"/>\n    <item type=\"id\" name=\"fab_label\"/>\n\n    <item type=\"id\" name=\"ex_tag_holder\"/>\n</resources>"
  },
  {
    "path": "app/src/main/res/values/strings.xml",
    "content": "<resources>\n    <string name=\"app_name\">WhiteBoard</string>\n\n    <!--白板-->\n    <string name=\"white_board_name\">白板工具</string>\n    <string name=\"white_board_export\">导出</string>\n    <string name=\"white_board_save\">保存</string>\n    <string name=\"white_board_pen\">画笔设置</string>\n    <string name=\"white_board_text\">文本设置</string>\n    <string name=\"white_board_text_hint\">双击修改</string>\n    <string name=\"white_board_eraser\">橡皮擦</string>\n    <string name=\"white_board_eraser_clear\">全部清除</string>\n    <string name=\"white_board_export_tip\">导出成功，该页已保存图片至</string>\n    <string name=\"white_board_export_fail\">导出失败，请稍后重试！</string>\n    <string name=\"white_board_save_sucess\">保存成功！</string>\n    <string name=\"app_logout\">继续按返回键退出</string>\n    <string name=\"app_list\">本地资源</string>\n    <string name=\"app_list_loading\">载入中...</string>\n</resources>\n"
  },
  {
    "path": "app/src/main/res/values/styles.xml",
    "content": "<resources>\n\n    <!-- Base application theme. -->\n    <style name=\"AppTheme\" parent=\"Theme.AppCompat.Light.DarkActionBar\">\n        <!-- Customize your theme here. -->\n        <item name=\"colorPrimary\">@color/colorPrimary</item>\n        <item name=\"colorPrimaryDark\">@color/colorPrimaryDark</item>\n        <item name=\"colorAccent\">@color/colorAccent</item>\n    </style>\n    <style name=\"HeaderTextView\">\n        <item name=\"android:layout_width\">wrap_content</item>\n        <item name=\"android:layout_height\">match_parent</item>\n        <item name=\"android:gravity\">center</item>\n        <item name=\"android:textSize\">@dimen/font_40px</item>\n        <item name=\"android:textColor\">@color/white</item>\n    </style>\n    <style name=\"menu_labels_style\">\n        <item name=\"android:background\">@drawable/fab_label_background</item>\n        <item name=\"android:textColor\">@color/white</item>\n    </style>\n</resources>\n"
  },
  {
    "path": "app/src/main/res/values-w820dp/dimens.xml",
    "content": "<resources>\n    <!-- Example customization of dimensions originally defined in res/values/dimens.xml\n         (such as screen margins) for screens with more than 820dp of available width. This\n         would include 7\" and 10\" devices in landscape (~960dp and ~1280dp respectively). -->\n    <dimen name=\"activity_horizontal_margin\">64dp</dimen>\n</resources>\n"
  },
  {
    "path": "build.gradle",
    "content": "buildscript {\n    repositories {\n        maven { url 'http://maven.oschina.net/content/groups/public/' }\n        jcenter()\n    }\n    dependencies {\n        classpath 'com.android.tools.build:gradle:2.0.0'\n    }\n}\n\nallprojects {\n    repositories {\n        maven { url 'http://maven.oschina.net/content/groups/public/' }\n        jcenter()\n    }\n}\n\ntask clean(type: Delete) {\n    delete rootProject.buildDir\n}\n"
  },
  {
    "path": "gradle.properties",
    "content": "# Project-wide Gradle settings.\n\n# IDE (e.g. Android Studio) users:\n# Gradle settings configured through the IDE *will override*\n# any settings specified in this file.\n\n# For more details on how to configure your build environment visit\n# http://www.gradle.org/docs/current/userguide/build_environment.html\n\n# Specifies the JVM arguments used for the daemon process.\n# The setting is particularly useful for tweaking memory settings.\n# Default value: -Xmx10248m -XX:MaxPermSize=256m\n# org.gradle.jvmargs=-Xmx2048m -XX:MaxPermSize=512m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8\n\n# When configured, Gradle will run in incubating parallel mode.\n# This option should only be used with decoupled projects. More details, visit\n# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects\n# org.gradle.parallel=true"
  },
  {
    "path": "settings.gradle",
    "content": "include ':app', ':wblib'\n"
  },
  {
    "path": "wblib/.gitignore",
    "content": "/build\n"
  },
  {
    "path": "wblib/build.gradle",
    "content": "apply plugin: 'com.android.library'\n\nandroid {\n    compileSdkVersion 23\n    buildToolsVersion \"23.0.3\"\n\n    defaultConfig {\n        minSdkVersion 14\n        targetSdkVersion 23\n        versionCode 1\n        versionName \"1.0\"\n    }\n    buildTypes {\n        release {\n            minifyEnabled false\n            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'\n        }\n    }\n}\n\ndependencies {\n    compile fileTree(dir: 'libs', include: ['*.jar'])\n    compile 'com.github.guanpy:eventbus:1.0.0'\n}\n"
  },
  {
    "path": "wblib/proguard-rules.pro",
    "content": "# Add project specific ProGuard rules here.\n# By default, the flags in this file are appended to flags specified\n# in D:\\software\\Java\\Android\\sdk_studio/tools/proguard/proguard-android.txt\n# You can edit the include path and order by changing the proguardFiles\n# directive in build.gradle.\n#\n# For more details, see\n#   http://developer.android.com/guide/developing/tools/proguard.html\n\n# Add any project specific keep options here:\n\n# If your project uses WebView with JS, uncomment the following\n# and specify the fully qualified class name to the JavaScript interface\n# class:\n#-keepclassmembers class fqcn.of.javascript.interface.for.webview {\n#   public *;\n#}\n"
  },
  {
    "path": "wblib/src/androidTest/java/com/github/guanpy/wblib/ApplicationTest.java",
    "content": "package com.github.guanpy.wblib;\n\nimport android.app.Application;\nimport android.test.ApplicationTestCase;\n\n/**\n * <a href=\"http://d.android.com/tools/testing/testing_android.html\">Testing Fundamentals</a>\n */\npublic class ApplicationTest extends ApplicationTestCase<Application> {\n    public ApplicationTest() {\n        super(Application.class);\n    }\n}"
  },
  {
    "path": "wblib/src/main/AndroidManifest.xml",
    "content": "<manifest xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    package=\"com.github.guanpy.wblib\">\n\n    <application\n        android:allowBackup=\"true\"\n        android:label=\"@string/app_name\"\n        android:supportsRtl=\"true\">\n\n    </application>\n\n</manifest>\n"
  },
  {
    "path": "wblib/src/main/java/com/github/guanpy/wblib/bean/DrawPenPoint.java",
    "content": "package com.github.guanpy.wblib.bean;\n\nimport android.graphics.Paint;\nimport android.graphics.Path;\n\n/**\n * 绘画存储-画笔路径\n * Created 2015-7-13 10:36:1\n *\n * @author gpy\n */\npublic class DrawPenPoint {\n\n    /**\n     * 绘画路径\n     */\n    private Path mPath;\n    /**\n     * 画笔\n     */\n    private Paint mPaint;\n\n    /**\n     * 获得绘画路径\n     * Created 2015-7-13 10:36:1\n     *\n     * @return 绘画路径\n     * @author gpy\n     */\n    public Path getPath() {\n        return mPath;\n    }\n\n    /**\n     * 设置绘画路径\n     * Created 2015-7-13 10:36:1\n     *\n     * @param path 绘画路径\n     * @author gpy\n     */\n    public void setPath(Path path) {\n        this.mPath = path;\n    }\n\n    /**\n     * 获得画笔\n     * Created 2015-7-13 10:36:1\n     *\n     * @return 画笔\n     * @author gpy\n     */\n    public Paint getPaint() {\n        return mPaint;\n    }\n\n    /**\n     * 设置画笔\n     * Created 2015-7-13 10:36:1\n     *\n     * @param paint 画笔\n     * @author gpy\n     */\n    public void setPaint(Paint paint) {\n        this.mPaint = paint;\n    }\n\n}\n"
  },
  {
    "path": "wblib/src/main/java/com/github/guanpy/wblib/bean/DrawPenStr.java",
    "content": "package com.github.guanpy.wblib.bean;\n\nimport java.util.ArrayList;\nimport java.util.List;\n\n/**\n * 绘画存储-画笔路径(字符串格式，方便储存)\n * Created 2015-7-13 10:36:1\n *\n * @author gpy\n */\npublic class DrawPenStr {\n\n\n    /**画笔颜色*/\n    private int mColor;\n    /**画笔粗细*/\n    private float mStrokeWidth;\n    /**是否橡皮擦*/\n    private boolean mIsEraser;\n    /**移动到初始点坐标*/\n    private Point mMoveTo;\n    /**移动中A集*/\n    private List<Point> mQuadToA;\n    /**移动中B集*/\n    private List<Point> mQuadToB;\n    /**移动到终点坐标*/\n    private Point mLineTo;\n    /**所在界面高距坐标*/\n    private Point mOffset;\n\n    /**\n     *获得画笔颜色\n     *Created 2015-7-21 18:11:48\n     *@return 画笔颜色\n     *@author gpy\n     */\n    public int getColor() {\n        return mColor;\n    }\n\n    /**\n     *设置画笔颜色\n     *Created 2015-7-21 18:11:48\n     *@param color 画笔颜色\n     *@author gpy\n     */\n    public void setColor(int color) {\n        this.mColor = color;\n    }\n\n    /**\n     *获得画笔粗细\n     *Created 2015-7-21 18:11:48\n     *@return 画笔粗细\n     *@author gpy\n     */\n    public float getStrokeWidth() {\n        return mStrokeWidth;\n    }\n\n    /**\n     *设置画笔粗细\n     *Created 2015-7-21 18:11:48\n     *@param strokeWidth 画笔粗细\n     *@author gpy\n     */\n    public void setStrokeWidth(float strokeWidth) {\n        this.mStrokeWidth = strokeWidth;\n    }\n\n    /**\n     *获得是否橡皮擦\n     *Created 2015-7-21 18:11:48\n     *@return 是否橡皮擦\n     *@author gpy\n     */\n    public boolean getIsEraser() {\n        return mIsEraser;\n    }\n\n    /**\n     *设置是否橡皮擦\n     *Created 2015-7-21 18:11:48\n     *@param isEraser 是否橡皮擦\n     *@author gpy\n     */\n    public void setIsEraser(boolean isEraser) {\n        this.mIsEraser = isEraser;\n    }\n\n    /**\n     *获得移动到初始点坐标\n     *Created 2015-7-21 18:11:48\n     *@return 移动到初始点坐标\n     *@author gpy\n     */\n    public Point getMoveTo() {\n        return mMoveTo;\n    }\n\n    /**\n     *设置移动到初始点坐标\n     *Created 2015-7-21 18:11:48\n     *@param moveTo 移动到初始点坐标\n     *@author gpy\n     */\n    public void setMoveTo(Point moveTo) {\n        this.mMoveTo = moveTo;\n    }\n\n    /**\n     *获得移动中A集\n     *Created 2015-7-21 18:11:48\n     *@return 移动中A集\n     *@author gpy\n     */\n    public List<Point> getQuadToA() {\n        if(null==mQuadToA){\n            mQuadToA = new ArrayList<Point>();\n        }\n        return mQuadToA;\n    }\n\n    /**\n     *设置移动中A集\n     *Created 2015-7-21 18:11:48\n     *@param quadToA 移动中A集\n     *@author gpy\n     */\n    public void setQuadToA(List<Point> quadToA) {\n        this.mQuadToA = quadToA;\n    }\n\n    /**\n     *获得移动中B集\n     *Created 2015-7-21 18:11:48\n     *@return 移动中B集\n     *@author gpy\n     */\n    public List<Point> getQuadToB() {\n        if(null==mQuadToB){\n            mQuadToB = new ArrayList<Point>();\n        }\n        return mQuadToB;\n    }\n\n    /**\n     *设置移动中B集\n     *Created 2015-7-21 18:11:48\n     *@param quadToB 移动中B集\n     *@author gpy\n     */\n    public void setQuadToB(List<Point> quadToB) {\n        this.mQuadToB = quadToB;\n    }\n\n    /**\n     *获得移动到终点坐标\n     *Created 2015-7-21 18:11:48\n     *@return 移动到终点坐标\n     *@author gpy\n     */\n    public Point getLineTo() {\n        return mLineTo;\n    }\n\n    /**\n     *设置移动到终点坐标\n     *Created 2015-7-21 18:11:48\n     *@param lineTo 移动到终点坐标\n     *@author gpy\n     */\n    public void setLineTo(Point lineTo) {\n        this.mLineTo = lineTo;\n    }\n\n    /**\n     *获得所在界面高距坐标\n     *Created 2015-7-21 18:11:48\n     *@return 所在界面高距坐标\n     *@author gpy\n     */\n    public Point getOffset() {\n        return mOffset;\n    }\n\n    /**\n     *设置所在界面高距坐标\n     *Created 2015-7-21 18:11:48\n     *@param offset 所在界面高距坐标\n     *@author gpy\n     */\n    public void setOffset(Point offset) {\n        this.mOffset = offset;\n    }\n\n\n}\n"
  },
  {
    "path": "wblib/src/main/java/com/github/guanpy/wblib/bean/DrawPoint.java",
    "content": "package com.github.guanpy.wblib.bean;\n\n\nimport com.github.guanpy.wblib.utils.BeanUtil;\n\npublic class DrawPoint {\n\n    /**绘画类型*/\n    private int mType;\n\n    /**画笔路径*/\n    private DrawPenPoint mDrawPen;\n    /**文字*/\n    private DrawTextPoint mDrawText;\n    /**画笔路径（字符形式）*/\n    private DrawPenStr mDrawPenStr;\n\n    /**\n     *获得画笔路径（字符形式）\n     *Created 2015-7-21 17:9:7\n     *@return 画笔路径（字符形式）\n     *@author gpy\n     */\n    public DrawPenStr getDrawPenStr() {\n        return mDrawPenStr;\n    }\n\n    /**\n     *设置画笔路径（字符形式）\n     *Created 2015-7-21 17:9:7\n     *@param DrawPenStr 画笔路径（字符形式）\n     *@author gpy\n     */\n    public void setDrawPenStr(DrawPenStr DrawPenStr) {\n        this.mDrawPenStr = DrawPenStr;\n    }\n\n\n    /**\n     *获得绘画类型\n     *Created 2015-7-13 10:42:14\n     *@return 绘画类型\n     *@author gpy\n     */\n    public int getType() {\n        return mType;\n    }\n\n    /**\n     *设置绘画类型\n     *Created 2015-7-13 10:42:14\n     *@param type 绘画类型\n     *@author gpy\n     */\n    public void setType(int type) {\n        this.mType = type;\n    }\n\n\n\n    /**\n     *获得画笔路径\n     *Created 2015-7-13 10:42:14\n     *@return 画笔路径\n     *@author gpy\n     */\n    public DrawPenPoint getDrawPen() {\n        return mDrawPen;\n    }\n\n    /**\n     *设置画笔路径\n     *Created 2015-7-13 10:42:14\n     *@param drawPen 画笔路径\n     *@author gpy\n     */\n    public void setDrawPen(DrawPenPoint drawPen) {\n        this.mDrawPen = drawPen;\n    }\n\n    /**\n     *获得文字\n     *Created 2015-7-13 10:42:14\n     *@return 文字\n     *@author gpy\n     */\n    public DrawTextPoint getDrawText() {\n        return mDrawText;\n//        if(null==mDrawTexts||mDrawTexts.size()==0){\n//          return null;\n//        }\n//        return mDrawTexts.get(0);\n    }\n\n\n    /**\n     *设置文字\n     *Created 2015-7-13 10:42:14\n     *@param drawText 文字\n     *@author gpy\n     */\n    public void setDrawText(DrawTextPoint drawText) {\n        mDrawText = drawText;\n//        if(null==drawText){\n//            return;\n//        }\n//        if(null==mDrawTexts){\n//            mDrawTexts = new ArrayList<DrawTextPoint>();\n//        }\n//        mDrawTexts.add(0,drawText);\n    }\n    /**\n     * 拷贝数据，防止引用传递 <br>\n     * 只在文字情况下使用\n     * Created 2015-8-10 16:55:49\n     *\n     * @author : gpy\n     */\n    public static DrawPoint copyDrawPoint(DrawPoint drawPoint) {\n        DrawPoint dp = new DrawPoint();\n        try {\n            dp.setType(drawPoint.getType());\n            DrawTextPoint dtp = new DrawTextPoint();\n            dtp = (DrawTextPoint) BeanUtil.CopyBeanToBean(drawPoint.getDrawText(), dtp);\n            dp.setDrawText(dtp);\n        } catch (Exception e) {\n            e.printStackTrace();\n        }\n        return dp;\n    }\n}\n"
  },
  {
    "path": "wblib/src/main/java/com/github/guanpy/wblib/bean/DrawTextPoint.java",
    "content": "package com.github.guanpy.wblib.bean;\n\n/**\n * 绘画存储-文字\n * Created 2015-7-13 10:36:1\n *\n * @author gpy\n */\npublic class DrawTextPoint {\n\n    /**\n     * 唯一性标识\n     */\n    private long mId;\n    /**\n     * 文字x坐标\n     */\n    private float mX;\n    /**\n     * 文字y坐标\n     */\n    private float mY;\n    /**\n     * 文字\n     */\n    private String mStr;\n    /**\n     * 是否有下划线\n     */\n    private boolean mIsUnderline;\n    /**\n     * 是否斜体\n     */\n    private boolean mIsItalics;\n    /**\n     * 是否粗体\n     */\n    private boolean mIsBold;\n\n    /**\n     * 文字颜色\n     */\n    private int mColor;\n    /**\n     * 当前文字状态\n     */\n    private int mStatus;\n\n    /**\n     * 是否显示\n     */\n    private boolean mIsVisible;\n\n    /**\n     * 获得唯一性标识\n     * Created 2015-7-13 10:42:14\n     *\n     * @return 唯一性标识\n     * @author gpy\n     */\n    public long getId() {\n        return mId;\n    }\n\n    /**\n     * 设置唯一性标识\n     * Created 2015-7-13 10:42:14\n     *\n     * @param id 唯一性标识\n     * @author gpy\n     */\n    public void setId(long id) {\n        this.mId = id;\n    }\n\n    /**\n     * 获得文字x坐标\n     * Created 2015-7-13 10:34:39\n     *\n     * @return 文字x坐标\n     * @author gpy\n     */\n    public float getX() {\n        return mX;\n    }\n\n    /**\n     * 设置文字x坐标\n     * Created 2015-7-13 10:34:39\n     *\n     * @param x 文字x坐标\n     * @author gpy\n     */\n    public void setX(float x) {\n        this.mX = x;\n    }\n\n    /**\n     * 获得文字y坐标\n     * Created 2015-7-13 10:34:39\n     *\n     * @return 文字y坐标\n     * @author gpy\n     */\n    public float getY() {\n        return mY;\n    }\n\n    /**\n     * 设置文字y坐标\n     * Created 2015-7-13 10:34:39\n     *\n     * @param y 文字y坐标\n     * @author gpy\n     */\n    public void setY(float y) {\n        this.mY = y;\n    }\n\n    /**\n     * 获得文字\n     * Created 2015-7-13 10:34:39\n     *\n     * @return 文字\n     * @author gpy\n     */\n    public String getStr() {\n        return mStr;\n    }\n\n    /**\n     * 设置文字\n     * Created 2015-7-13 10:34:39\n     *\n     * @param str 文字\n     * @author gpy\n     */\n    public void setStr(String str) {\n        this.mStr = str;\n    }\n\n    /**\n     * 获得是否有下划线\n     * Created 2015-7-17 14:57:13\n     *\n     * @return 是否有下划线\n     * @author gpy\n     */\n    public boolean getIsUnderline() {\n        return mIsUnderline;\n    }\n\n    /**\n     * 设置是否有下划线\n     * Created 2015-7-17 14:57:13\n     *\n     * @param isUnderline 是否有下划线\n     * @author gpy\n     */\n    public void setIsUnderline(boolean isUnderline) {\n        this.mIsUnderline = isUnderline;\n    }\n\n    /**\n     * 获得是否斜体\n     * Created 2015-7-17 14:57:13\n     *\n     * @return 是否斜体\n     * @author gpy\n     */\n    public boolean getIsItalics() {\n        return mIsItalics;\n    }\n\n    /**\n     * 设置是否斜体\n     * Created 2015-7-17 14:57:13\n     *\n     * @param isItalics 是否斜体\n     * @author gpy\n     */\n    public void setIsItalics(boolean isItalics) {\n        this.mIsItalics = isItalics;\n    }\n\n    /**\n     * 获得是否粗体\n     * Created 2015-7-17 14:57:13\n     *\n     * @return 是否粗体\n     * @author gpy\n     */\n    public boolean getIsBold() {\n        return mIsBold;\n    }\n\n    /**\n     * 设置是否粗体\n     * Created 2015-7-17 14:57:13\n     *\n     * @param isBold 是否粗体\n     * @author gpy\n     */\n    public void setIsBold(boolean isBold) {\n        this.mIsBold = isBold;\n    }\n\n    /**\n     * 获得文字颜色\n     * Created 2015-7-17 15:40:0\n     *\n     * @return 文字颜色\n     * @author gpy\n     */\n    public int getColor() {\n        return mColor;\n    }\n\n    /**\n     * 设置文字颜色\n     * Created 2015-7-17 15:40:0\n     *\n     * @param color 文字颜色\n     * @author gpy\n     */\n    public void setColor(int color) {\n        this.mColor = color;\n    }\n\n    /**\n     * 获得当前文字状态\n     * Created 2015-7-13 10:34:39\n     *\n     * @return 当前文字状态\n     * @author gpy\n     */\n    public int getStatus() {\n        return mStatus;\n    }\n\n    /**\n     * 设置当前文字状态\n     * Created 2015-7-13 10:34:39\n     *\n     * @param status 当前文字状态\n     * @author gpy\n     */\n    public void setStatus(int status) {\n        this.mStatus = status;\n    }\n\n    /**\n     * 获得是否显示\n     * Created 2015-7-13 11:31:52\n     *\n     * @return 是否显示\n     * @author gpy\n     */\n    public boolean getIsVisible() {\n        return mIsVisible;\n    }\n\n    /**\n     * 设置是否显示\n     * Created 2015-7-13 11:31:52\n     *\n     * @param isVisible 是否显示\n     * @author gpy\n     */\n    public void setIsVisible(boolean isVisible) {\n        this.mIsVisible = isVisible;\n    }\n}"
  },
  {
    "path": "wblib/src/main/java/com/github/guanpy/wblib/bean/Point.java",
    "content": "package com.github.guanpy.wblib.bean;\n\n/**\n * Created by gpy on 2015/8/21.\n */\npublic class Point {\n\n    /**\n     * X坐标\n     */\n    private float mX;\n    /**\n     * Y坐标\n     */\n    private float mY;\n    public Point(){\n    }\n    public Point(float x,float y){\n        mX = x;\n        mY = y;\n    }\n    /**\n     * 获得X坐标\n     * Created 2015-7-21 18:6:32\n     *\n     * @return X坐标\n     * @author gpy\n     */\n    public float getX() {\n        return mX;\n    }\n\n    /**\n     * 设置X坐标\n     * Created 2015-7-21 18:6:32\n     *\n     * @param x X坐标\n     * @author gpy\n     */\n    public void setX(float x) {\n        this.mX = x;\n    }\n\n    /**\n     * 获得Y坐标\n     * Created 2015-7-21 18:6:32\n     *\n     * @return Y坐标\n     * @author gpy\n     */\n    public float getY() {\n        return mY;\n    }\n\n    /**\n     * 设置Y坐标\n     * Created 2015-7-21 18:6:32\n     *\n     * @param y Y坐标\n     * @author gpy\n     */\n    public void setY(float y) {\n        this.mY = y;\n    }\n\n\n}\n"
  },
  {
    "path": "wblib/src/main/java/com/github/guanpy/wblib/bean/WhiteBoardPoint.java",
    "content": "package com.github.guanpy.wblib.bean;\n\n\n\nimport java.util.ArrayList;\nimport java.util.List;\n\n/**\n * 画板绘画路径存储\n *\n * @author gpy\n */\npublic class WhiteBoardPoint {\n\n\n\n\n    /**\n     * 画板id\n     */\n    private int mId;\n    /**\n     * 保存路径\n     */\n    private List<DrawPoint> mSavePoints;\n    /**\n     * 撤销路径\n     */\n    private List<DrawPoint> mDeletePoints;\n\n    /**\n     * 获得画板id Created 2015-7-12 10:6:10\n     *\n     * @return 画板id\n     * @author gpy\n     */\n    public int getId() {\n        return mId;\n    }\n\n    /**\n     * 设置画板id Created 2015-7-12 10:6:10\n     *\n     * @param id 画板id\n     * @author gpy\n     */\n    public void setId(int id) {\n        this.mId = id;\n    }\n\n    /**\n     * 获得保存路径 Created 2015-7-12 10:6:10\n     *\n     * @return 保存路径\n     * @author gpy\n     */\n    public List<DrawPoint> getSavePoints() {\n        if (mSavePoints == null) {\n            mSavePoints = new ArrayList<DrawPoint>();\n        }\n        return mSavePoints;\n    }\n\n    /**\n     * 获得撤销路径 Created 2015-7-12 10:6:10\n     *\n     * @return 撤销路径\n     * @author gpy\n     */\n    public List<DrawPoint> getDeletePoints() {\n        if (mDeletePoints == null) {\n            mDeletePoints = new ArrayList<DrawPoint>();\n        }\n        return mDeletePoints;\n    }\n\n}\n"
  },
  {
    "path": "wblib/src/main/java/com/github/guanpy/wblib/bean/WhiteBoardPoints.java",
    "content": "package com.github.guanpy.wblib.bean;\n\nimport java.util.List;\n\n/**\n * 画板合集\n * Created by gpy on 2015/8/21.\n */\npublic class WhiteBoardPoints {\n\n    /**唯一性id*/\n    private String mId;\n    /**画板合集*/\n    private List<WhiteBoardPoint> mWhiteBoardPoints;\n\n    /**\n     *获得唯一性id\n     *Created 2015-7-21 15:19:17\n     *@return 唯一性id\n     *@author gpy\n     */\n    public String getId() {\n        return mId;\n    }\n\n    /**\n     *设置唯一性id\n     *Created 2015-7-21 15:19:17\n     *@param id 唯一性id\n     *@author gpy\n     */\n    public void setId(String id) {\n        this.mId = id;\n    }\n\n    /**\n     *获得画板合集\n     *Created 2015-7-21 15:19:17\n     *@return 画板合集\n     *@author gpy\n     */\n    public List<WhiteBoardPoint> getWhiteBoardPoints() {\n        return mWhiteBoardPoints;\n    }\n\n    /**\n     *设置画板合集\n     *Created 2015-7-21 15:19:17\n     *@param whiteBoardPoints 画板合集\n     *@author gpy\n     */\n    public void setWhiteBoardPoints(List<WhiteBoardPoint> whiteBoardPoints) {\n        this.mWhiteBoardPoints = whiteBoardPoints;\n    }\n\n\n}\n"
  },
  {
    "path": "wblib/src/main/java/com/github/guanpy/wblib/utils/AppContextUtil.java",
    "content": "package com.github.guanpy.wblib.utils;\n\nimport android.content.Context;\n\n/**\n * AppContextUtil\n *\n * @author yangz\n * @version 2014/11/4\n */\npublic class AppContextUtil {\n\n    private static Context sContext;\n\n    public static void init(Context ctx) {\n        sContext = ctx.getApplicationContext();\n    }\n\n    public static Context getContext() {\n        return sContext;\n    }\n\n    public static int getColor(int resId) {\n        if (sContext == null) {\n            return -1;\n        }\n        return sContext.getResources().getColor(resId);\n    }\n\n    public static String getString(int resId) {\n        if (sContext == null) {\n            return null;\n        }\n        return sContext.getResources().getString(resId);\n    }\n\n    public static String getString(int resId, Object... objs) {\n        if (sContext == null) {\n            return null;\n        }\n        return sContext.getResources().getString(resId, objs);\n    }\n\n    /**\n     * dip转px\n     */\n    public static int dip2px(float dpValue) {\n        final float scale = AppContextUtil.getContext().getResources().getDisplayMetrics().density;\n        return (int) (dpValue * scale + 0.5f);\n    }\n}\n"
  },
  {
    "path": "wblib/src/main/java/com/github/guanpy/wblib/utils/BeanUtil.java",
    "content": "package com.github.guanpy.wblib.utils;\n\nimport java.lang.reflect.Method;\n\n/**\n * Created by gpy on 2015/8/13.\n */\npublic class BeanUtil {\n    /**\n     * @return Object\n     * <p/>\n     * 用到反射机制\n     * <p/>\n     * 此方法将调用obj1的getter方法，将得到的值作为相应的参数传给obj2的setter方法\n     * <p/>\n     * 注意，obj1的getter方法和obj2方法必须是public类型\n     * @parameter Object obj1,Object obj2\n     */\n\n    public static Object CopyBeanToBean(Object obj1, Object obj2) throws Exception {\n\n        Method[] method1 = obj1.getClass().getMethods();\n\n        Method[] method2 = obj2.getClass().getMethods();\n\n        String methodName1;\n\n        String methodFix1;\n\n        String methodName2;\n\n        String methodFix2;\n\n        for (int i = 0; i < method1.length; i++) {\n\n            methodName1 = method1[i].getName();\n\n            methodFix1 = methodName1.substring(3, methodName1.length());\n\n            if (methodName1.startsWith(\"get\")) {\n\n                for (int j = 0; j < method2.length; j++) {\n\n                    methodName2 = method2[j].getName();\n\n                    methodFix2 = methodName2.substring(3, methodName2.length());\n\n                    if (methodName2.startsWith(\"set\")) {\n\n                        if (methodFix2.equals(methodFix1)) {\n\n                            Object[] objs1 = new Object[0];\n\n                            Object[] objs2 = new Object[1];\n\n                            objs2[0] = method1[i].invoke(obj1, objs1);//激活obj1的相应的get的方法，objs1数组存放调用该方法的参数,此例中没有参数，该数组的长度为0\n\n                            method2[j].invoke(obj2, objs2);//激活obj2的相应的set的方法，objs2数组存放调用该方法的参数\n\n                            continue;\n\n                        }\n\n                    }\n\n                }\n\n            }\n\n        }\n\n        return obj2;\n\n    }\n\n}\n"
  },
  {
    "path": "wblib/src/main/java/com/github/guanpy/wblib/utils/Events.java",
    "content": "package com.github.guanpy.wblib.utils;\n\n/**\n * @author gpy\n * @version 2015/8/26.\n */\npublic class Events {\n\t/**\n\t * 白板相关\n\t */\n\tpublic static final String WHITE_BOARD_UNDO_REDO = \"undo_redo\";\n\n\tpublic static final String WHITE_BOARD_TEXT_EDIT = \"text_edit\";\n}"
  },
  {
    "path": "wblib/src/main/java/com/github/guanpy/wblib/utils/OperationUtils.java",
    "content": "package com.github.guanpy.wblib.utils;\n\nimport com.github.guanpy.wblib.bean.DrawPoint;\nimport com.github.guanpy.wblib.bean.WhiteBoardPoint;\nimport com.github.guanpy.wblib.bean.WhiteBoardPoints;\n\nimport java.util.ArrayList;\nimport java.util.List;\n\n/**\n * 白板操作公共类\n *\n * @author gpy\n */\n\npublic class OperationUtils {\n    /**\n     * 操作类型-画笔\n     */\n    public static final int DRAW_PEN = 1;\n    /**\n     * 操作类型-文字\n     */\n    public static final int DRAW_TEXT = 2;\n    /**\n     * 操作类型-橡皮擦\n     */\n    public static final int DRAW_ERASER = 3;\n    /**\n     * 单例\n     */\n    private static OperationUtils mOperationStack;\n    /**\n     * 当前是否禁止白板操作\n     */\n    public boolean DISABLE = true;\n    /**\n     * 当前所在白板位置\n     */\n    public int mCurrentIndex = 0;\n    /**\n     * 每次操作的唯一标识\n     */\n    private long markId = 0;\n    /**\n     * 当前按钮点击\n     */\n    public int mCurrentOPerationPen = WhiteBoardVariable.Operation.PEN_CLICK;\n    /**\n     * 当前按钮点击\n     */\n    public int mCurrentOPerationColor = WhiteBoardVariable.Operation.COLOR_NORMAL;\n    /**\n     * 当前按钮点击\n     */\n    public int mCurrentOPerationText = WhiteBoardVariable.Operation.TEXT_NORMAL;\n    /**\n     * 当前按钮点击\n     */\n    public int mCurrentOPerationEraser = WhiteBoardVariable.Operation.ERASER_NORMAL;\n    /**\n     * 当前绘画类型：笔或者文字等\n     */\n    public int mCurrentDrawType = DRAW_PEN;\n\n    /**\n     * 当前颜色\n     */\n    public int mCurrentColor = WhiteBoardVariable.Color.ORANGE;\n    /**\n     * 当前画笔大小\n     */\n    public int mCurrentPenSize = WhiteBoardVariable.PenSize.MIDDLE;\n    /**\n     * 当前橡皮擦大小\n     */\n    public int mCurrentEraserSize = WhiteBoardVariable.EraserSize.MIDDLE;\n    /**\n     * 白板操作集\n     */\n    private WhiteBoardPoints mWhiteBoardPoints;\n\n    /**\n     * 单例\n     */\n    public static OperationUtils getInstance() {\n        if (mOperationStack == null) {\n            mOperationStack = new OperationUtils();\n        }\n        return mOperationStack;\n    }\n\n    /**\n     * 私有实例化\n     */\n    private OperationUtils() {\n    }\n\n    /**\n     * 初始化操作集\n     */\n    public void init() {\n        DISABLE = true;\n        mCurrentIndex = 0;\n        markId = 0;\n        mCurrentOPerationPen = WhiteBoardVariable.Operation.PEN_NORMAL;\n        mCurrentOPerationColor = WhiteBoardVariable.Operation.COLOR_NORMAL;\n        mCurrentOPerationText = WhiteBoardVariable.Operation.TEXT_NORMAL;\n        mCurrentOPerationEraser = WhiteBoardVariable.Operation.ERASER_NORMAL;\n        mCurrentDrawType = DRAW_PEN;\n        mCurrentColor = WhiteBoardVariable.Color.ORANGE;\n        mCurrentPenSize = WhiteBoardVariable.PenSize.MIDDLE;\n        mCurrentEraserSize = WhiteBoardVariable.EraserSize.MIDDLE;\n        OperationUtils.getInstance().initDrawPointList();\n    }\n\n    /**\n     * 返回指定白板的操作集\n     */\n    public WhiteBoardPoint getDrawPointList(int i) {\n        if (null != mWhiteBoardPoints) {\n            if (mWhiteBoardPoints.getWhiteBoardPoints().size() <= i) {\n                WhiteBoardPoint drawPointList = new WhiteBoardPoint();\n                drawPointList.setId(i);\n                mWhiteBoardPoints.getWhiteBoardPoints().add(drawPointList);\n                return getDrawPointList(i);\n            } else {\n                return mWhiteBoardPoints.getWhiteBoardPoints().get(i);\n            }\n        } else {\n            mWhiteBoardPoints = new WhiteBoardPoints();\n            mWhiteBoardPoints.setWhiteBoardPoints(new ArrayList<WhiteBoardPoint>());\n            return getDrawPointList(i);\n        }\n    }\n\n    /**\n     * 返回指定白板的操作集大小\n     */\n    public int getDrawPointSize() {\n        if (mWhiteBoardPoints != null && null != mWhiteBoardPoints.getWhiteBoardPoints()) {\n            return mWhiteBoardPoints.getWhiteBoardPoints().size();\n        } else {\n            getDrawPointList(mCurrentIndex);\n            return getDrawPointSize();\n        }\n    }\n\n    /**\n     * 返回指定白板的操作集\n     */\n    public WhiteBoardPoints getWhiteBoardPoints() {\n        return mWhiteBoardPoints;\n    }\n\n    /**\n     * 返回指定白板的操作集\n     */\n    public void setWhiteBoardPoints(WhiteBoardPoints whiteBoardPoints) {\n        mWhiteBoardPoints = whiteBoardPoints;\n    }\n\n    /**\n     * 初始化白板\n     */\n    public void initDrawPointList() {\n        if (mWhiteBoardPoints != null && mWhiteBoardPoints.getWhiteBoardPoints() != null) {\n            mWhiteBoardPoints.getWhiteBoardPoints().clear();\n        } else {\n            getDrawPointList(mCurrentIndex);\n        }\n\n    }\n\n    /**\n     * 新建白板\n     */\n    public void newPage() {\n        mCurrentIndex = getDrawPointSize();\n        getDrawPointList(mCurrentIndex);\n    }\n\n\n    /**\n     * 获取每次操作的唯一标识\n     */\n    public long getNewMarkId() {\n        return markId++;\n    }\n\n    /**\n     * 获取当前白板操作集\n     */\n    public List<DrawPoint> getSavePoints() {\n        return OperationUtils.getInstance().getDrawPointList(OperationUtils.getInstance().mCurrentIndex).getSavePoints();\n    }\n\n    /**\n     * 获取当前白板删除操作集\n     */\n    public List<DrawPoint> getDeletePoints() {\n        return OperationUtils.getInstance().getDrawPointList(OperationUtils.getInstance().mCurrentIndex).getDeletePoints();\n    }\n\n\n}\n"
  },
  {
    "path": "wblib/src/main/java/com/github/guanpy/wblib/utils/WhiteBoardVariable.java",
    "content": "package com.github.guanpy.wblib.utils;\n\nimport com.github.guanpy.wblib.R;\n\n/**\n * 白板属性值汇总\n * Created by gpy on 2015/8/17.\n */\npublic final class WhiteBoardVariable {\n    /**白板工具栏操作*/\n    public interface Operation{\n        /**画笔-正常*/\n        int PEN_NORMAL = 1 ;\n        /**画笔-点击*/\n        int PEN_CLICK = 2 ;\n        /**画笔-展开*/\n        int PEN_EXPAND = 3 ;\n\n        /**颜色-正常*/\n        int COLOR_NORMAL = 4 ;\n        /**颜色-点击*/\n        int COLOR_CLICK = 5 ;\n        /**颜色-展开*/\n        int COLOR_EXPAND = 6 ;\n        /**文字-正常*/\n        int TEXT_NORMAL = 7 ;\n        /**文字-点击*/\n        int TEXT_CLICK = 8 ;\n        /**文字-展开*/\n        int TEXT_EXPAND =9 ;\n        /**橡皮擦-正常*/\n        int ERASER_NORMAL = 10 ;\n        /**橡皮擦-点击*/\n        int ERASER_CLICK = 11 ;\n        /**橡皮擦-展开*/\n        int ERASER_EXPAND = 12 ;\n        /**点击外围*/\n        int OUTSIDE_CLICK = 13 ;\n\n    }\n\n\n    /**颜色*/\n    public interface  Color{\n        /**黑色*/\n        int BLACK =  AppContextUtil.getContext().getResources().getColor(R.color.grey_3e);\n        /**橙色*/\n        int ORANGE =  AppContextUtil.getContext().getResources().getColor(R.color.orange);\n        /**粉色*/\n        int PINK =  AppContextUtil.getContext().getResources().getColor(R.color.light_red);\n        /**紫色*/\n        int PURPLE =  AppContextUtil.getContext().getResources().getColor(R.color.primary_purple);\n        /**绿色*/\n        int GREEN =  AppContextUtil.getContext().getResources().getColor(R.color.green);\n    }\n    /**画笔大小*/\n    public interface  PenSize{\n        /**大*/\n        int LARRGE = AppContextUtil.dip2px(9);\n        /**中*/\n        int MIDDLE = AppContextUtil.dip2px(6);\n        /**小*/\n        int MINI = AppContextUtil.dip2px(4);\n    }\n    /**橡皮擦大小*/\n    public interface  EraserSize{\n        /**大*/\n        int LARRGE = AppContextUtil.dip2px(16);\n        /**中*/\n        int MIDDLE = AppContextUtil.dip2px(9);\n        /**小*/\n        int MINI = AppContextUtil.dip2px(4);\n    }\n    /**圆环宽度大小*/\n    public interface  RingSize{\n        /**大*/\n        int LARRGE = AppContextUtil.dip2px(3);\n        /**小*/\n        int MINI = AppContextUtil.dip2px(1);\n    }\n    /**文字风格*/\n    public interface  TextStyle{\n        /**设置下划线*/\n        int CHANGE_UNDERLINE = 1;\n        /**设置斜体*/\n         int CHANGE_ITALICS =2;\n        /**设置粗体*/\n        int CHANGE_BOLD = 3;\n    }\n}\n"
  },
  {
    "path": "wblib/src/main/java/com/github/guanpy/wblib/widget/DrawPenView.java",
    "content": "package com.github.guanpy.wblib.widget;\n\nimport android.content.Context;\nimport android.graphics.Bitmap;\nimport android.graphics.Canvas;\nimport android.graphics.Paint;\nimport android.graphics.Path;\nimport android.graphics.PorterDuff;\nimport android.graphics.PorterDuffXfermode;\nimport android.util.AttributeSet;\nimport android.view.MotionEvent;\nimport android.view.View;\n\nimport com.github.guanpy.library.EventBus;\nimport com.github.guanpy.wblib.R;\nimport com.github.guanpy.wblib.bean.DrawPenPoint;\nimport com.github.guanpy.wblib.bean.DrawPenStr;\nimport com.github.guanpy.wblib.bean.DrawPoint;\nimport com.github.guanpy.wblib.bean.Point;\nimport com.github.guanpy.wblib.utils.Events;\nimport com.github.guanpy.wblib.utils.OperationUtils;\n\nimport java.util.Iterator;\n\n\npublic class DrawPenView extends View {\n    /**\n     * 用于画线\n     */\n    private Paint mPaint = null;\n    /**\n     * 用于画图\n     */\n    private Paint mBitmapPaint = null;\n    /**\n     * 画图路径\n     */\n    private Path mPath = null;\n    /**\n     * 步骤存储bean\n     */\n    private DrawPoint mDrawPath = null;\n    /**\n     * 绘画存储-画笔路径(字符串格式，方便储存)\n     */\n    private DrawPenStr mDrawPenStr = null;\n    /**\n     * 画图\n     */\n    private Bitmap mBottomBitmap = null;\n    private int mBottomBitmapDrawHeight = 0;\n    float posX, posY;\n    private final float TOUCH_TOLERANCE = 4;\n    private Context mContext;\n    private Canvas mCanvas = null;\n\n    public DrawPenView(Context context, AttributeSet attr, int defStyle) {\n        super(context, attr, defStyle);\n        initView(context);\n    }\n\n    public DrawPenView(Context context, AttributeSet attr) {\n        super(context, attr);\n        initView(context);\n    }\n\n    public DrawPenView(Context context) {\n        super(context);\n        initView(context);\n    }\n\n    private void initView(Context context) {\n        mContext = context;\n        initPaint();\n        mBitmapPaint = new Paint(Paint.DITHER_FLAG);\n\n    }\n\n    public void init(Paint paint) {\n        if (paint == null) {\n            initPaint();\n        } else {\n            mPaint = paint;\n        }\n    }\n\n    /**\n     * 初始化画笔\n     */\n    private void initPaint() {\n\n        mPaint = new Paint();\n        mPaint.setAntiAlias(true);//是否使用抗锯齿功能,会消耗较大资源，绘制图形速度会变慢\n        mPaint.setDither(true);// 设定是否使用图像抖动处理，会使绘制出来的图片颜色更加平滑和饱满，图像更加清晰\n        mPaint.setColor(OperationUtils.getInstance().mCurrentColor);//设置绘制的颜色\n        mPaint.setStyle(Paint.Style.STROKE);//设置画笔的样式\n        mPaint.setStrokeJoin(Paint.Join.ROUND);//设置绘制时各图形的结合方式，如平滑效果等\n        mPaint.setStrokeCap(Paint.Cap.ROUND);//当画笔样式为STROKE或FILL_OR_STROKE时，设置笔刷的图形样式，如圆形样式    Cap.ROUND,或方形样式Cap.SQUARE\n        mPaint.setStrokeWidth(2 * OperationUtils.getInstance().mCurrentPenSize);//当画笔样式为STROKE或FILL_OR_STROKE时，设置笔刷的粗细度\n    }\n\n    /**\n     * 初始化画笔\n     */\n    public void changeEraser() {\n        mPaint.setColor(mContext.getResources().getColor(R.color.transparent));\n        mPaint.setStrokeWidth(2 * OperationUtils.getInstance().mCurrentEraserSize);\n        mPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR));//擦除模式\n        postInvalidate();\n    }\n    /**\n     * 修改橡皮擦尺寸\n     */\n    public void setEraserSize() {\n        mPaint.setStrokeWidth(2 * OperationUtils.getInstance().mCurrentEraserSize);//size为圆半径\n        postInvalidate();\n    }\n    /**\n     * 修改画笔尺寸\n     */\n    public void setPenSize() {\n        mPaint.setStrokeWidth(2 * OperationUtils.getInstance().mCurrentPenSize);//size为圆半径\n        postInvalidate();\n    }\n    /**\n     * 修改画笔颜色\n     */\n    public void setPenColor() {\n        mPaint.setColor(OperationUtils.getInstance().mCurrentColor);\n        postInvalidate();\n    }\n\n    @Override\n    protected void onSizeChanged(int w, int h, int oldw, int oldh) {\n        super.onSizeChanged(w, h, oldw, oldh);\n        if(w>0&&h>0){\n            mBottomBitmap = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888);\n            mCanvas = new Canvas(mBottomBitmap);\n        }\n\n    }\n\n    @Override\n    public void onDraw(Canvas canvas) {\n\n        canvas.drawColor(mContext.getResources().getColor(R.color.transparent));\n        int nCanvasHeight = canvas.getHeight();\n        int nBitmapHeight = mBottomBitmap.getHeight();\n        mBottomBitmapDrawHeight = (nCanvasHeight - nBitmapHeight) / 2;\n        canvas.drawBitmap(mBottomBitmap, 0, mBottomBitmapDrawHeight, mBitmapPaint);\n        if (mPath != null) {\n            canvas.drawPath(mPath, mPaint);\n        }\n\n\n    }\n\n    @Override\n    public boolean onTouchEvent(MotionEvent event) {\n        if (OperationUtils.getInstance().DISABLE && (OperationUtils.getInstance().mCurrentDrawType == OperationUtils.DRAW_PEN || OperationUtils.getInstance().mCurrentDrawType == OperationUtils.DRAW_ERASER)) {\n            float x = event.getX();\n            float y = event.getY();\n\n            switch (event.getAction()) {\n                case MotionEvent.ACTION_DOWN:\n                    mPath = new Path();\n                    mDrawPath = new DrawPoint();\n                    mPath.moveTo(x, y);\n                    DrawPenPoint dpp = new DrawPenPoint();\n                    dpp.setPaint(new Paint(mPaint));\n                    dpp.setPath(mPath);\n                    //绘画时存储字符形式\n                    mDrawPenStr = new DrawPenStr();\n                    mDrawPenStr.setColor(mPaint.getColor());\n                    mDrawPenStr.setStrokeWidth(mPaint.getStrokeWidth());\n                    mDrawPenStr.setMoveTo(new Point(x,y));\n                    if(OperationUtils.getInstance().mCurrentDrawType == OperationUtils.DRAW_ERASER){\n                        mDrawPenStr.setIsEraser(true);\n                    }else{\n                        mDrawPenStr.setIsEraser(false);\n                    }\n                    mDrawPath.setDrawPen(dpp);\n                    mDrawPath.setType(OperationUtils.DRAW_PEN);\n                    posX = x;\n                    posY = y;\n                    postInvalidate();\n\n                    break;\n                case MotionEvent.ACTION_MOVE:\n                    float dx = Math.abs(x - posX);\n                    float dy = Math.abs(y - posY);\n                    if (dx >= TOUCH_TOLERANCE || dy > TOUCH_TOLERANCE) {\n                        mDrawPenStr.getQuadToA().add(new Point(posX,posY));\n                        mDrawPenStr.getQuadToB().add(new Point((x + posX) / 2,(y + posY) / 2));\n                        mPath.quadTo(posX, posY, (x + posX) / 2, (y + posY) / 2);\n                        posX = x;\n                        posY = y;\n                    }\n                    postInvalidate();\n                    break;\n                case MotionEvent.ACTION_UP:\n                    mDrawPenStr.setLineTo(new Point(posX, posY));\n                    mPath.lineTo(posX, posY);\n                    mDrawPenStr.setOffset(new Point(0, -mBottomBitmapDrawHeight));\n                    mPath.offset(0, -mBottomBitmapDrawHeight);\n                    mCanvas.drawPath(mPath, mPaint);\n                    mDrawPath.setDrawPenStr(mDrawPenStr);\n                    OperationUtils.getInstance().getSavePoints().add(mDrawPath);\n                    OperationUtils.getInstance().getDeletePoints().clear();\n                    EventBus.postEvent(Events.WHITE_BOARD_UNDO_REDO);\n                    mPath = null;\n                    postInvalidate();\n                    break;\n            }\n        }\n        return true;\n    }\n\n    public void setPaint(Paint paint) {\n        if (paint == null) {\n            initPaint();\n            postInvalidate();\n            return;\n        }\n        mPaint = paint;\n        postInvalidate();\n\n    }\n\n\n    public void clearImage() {\n        OperationUtils.getInstance().getSavePoints().clear();\n        OperationUtils.getInstance().getDeletePoints().clear();\n        int width = mCanvas.getWidth();\n        int height = mCanvas.getHeight();\n        mBottomBitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);\n        mCanvas.setBitmap(mBottomBitmap);\n        postInvalidate();\n\n    }\n\n    public void undo() {\n        showPoints();\n\n    }\n\n\n    public void redo() {\n        showPoints();\n    }\n\n    /**\n     * 重绘一遍路径\n     */\n    public void showPoints() {\n        int width = mCanvas.getWidth();\n        int height = mCanvas.getHeight();\n        mBottomBitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);\n        mCanvas.setBitmap(mBottomBitmap);\n\n        Iterator<DrawPoint> iter = OperationUtils.getInstance().getSavePoints().iterator();\n        DrawPoint temp;\n        while (iter.hasNext()) {\n            temp = iter.next();\n            if (temp.getType() == OperationUtils.DRAW_PEN) {\n                mCanvas.drawPath(temp.getDrawPen().getPath(), temp.getDrawPen().getPaint());\n            }\n\n        }\n        postInvalidate();\n    }\n}\n"
  },
  {
    "path": "wblib/src/main/java/com/github/guanpy/wblib/widget/DrawTextLayout.java",
    "content": "package com.github.guanpy.wblib.widget;\n\nimport android.app.Activity;\nimport android.content.Context;\nimport android.text.TextUtils;\nimport android.util.AttributeSet;\nimport android.util.Log;\nimport android.view.Display;\nimport android.view.MotionEvent;\nimport android.widget.FrameLayout;\n\nimport com.github.guanpy.library.EventBus;\nimport com.github.guanpy.wblib.R;\nimport com.github.guanpy.wblib.bean.DrawPoint;\nimport com.github.guanpy.wblib.bean.DrawTextPoint;\nimport com.github.guanpy.wblib.utils.Events;\nimport com.github.guanpy.wblib.utils.OperationUtils;\nimport com.github.guanpy.wblib.utils.WhiteBoardVariable;\n\n/**\n * 白板--文字层\n * @author  gpy\n */\npublic class DrawTextLayout extends FrameLayout {\n\n\n    private Context mContext;\n\n\n    private static final int MARGIN_RIGHT = 100;\n    private static final int MARGIN_BOTTOM = 75;\n\n    public DrawTextLayout(Context context, AttributeSet attrs) {\n        super(context, attrs);\n        initView(context);\n    }\n\n\n    public DrawTextLayout(Context context) {\n        super(context);\n        initView(context);\n    }\n\n    private void initView(Context context) {\n        mContext = context;\n\n    }\n\n    public void init(Activity activity) {\n        LayoutParams params = (LayoutParams) this.getLayoutParams();\n        if (activity.getWindowManager() != null) {\n            Display display = activity.getWindowManager().getDefaultDisplay();\n            params.width = display.getWidth();\n            params.height = display.getWidth();\n        }\n        this.setLayoutParams(params);\n        this.setBackgroundColor(getResources().getColor(R.color.transparent));\n        showPoints();\n    }\n\n    @Override\n    public boolean onTouchEvent(MotionEvent event) {\n        if (OperationUtils.getInstance().mCurrentDrawType == OperationUtils.DRAW_TEXT&&OperationUtils.getInstance().DISABLE) {\n            switch (event.getAction()) {\n                case MotionEvent.ACTION_DOWN:\n                    float moveX =  event.getX();\n                    float moveY =  event.getY();\n                    if(getHeight()-moveY<dip2px(MARGIN_BOTTOM)){\n                        moveY = moveY - dip2px(MARGIN_BOTTOM);\n                    }\n                    if(getWidth()-moveX<dip2px(MARGIN_RIGHT)){\n                        moveX = moveX - dip2px(MARGIN_RIGHT);\n                    }\n                    Log.d(\"添加文字\", \"-\" + moveX + \",\" + moveY);\n                    DrawTextPoint ip = new DrawTextPoint();\n                    ip.setX(moveX);\n                    ip.setY(moveY);\n                    ip.setColor(OperationUtils.getInstance().mCurrentColor);\n                    ip.setStatus(DrawTextView.TEXT_EDIT);\n                    ip.setIsVisible(true);\n                    ip.setId(OperationUtils.getInstance().getNewMarkId());\n\n                    DrawPoint drawPoint = new DrawPoint();\n                    drawPoint.setType(OperationUtils.DRAW_TEXT);\n                    drawPoint.setDrawText(ip);\n//                    OperationUtils.getInstance().getSavePoints().add(drawPoint);\n                    showPoints();\n                    showNewPoint(drawPoint);\n                    break;\n            }\n        }\n        return super.onTouchEvent(event);\n    }\n\n    public void showPoints() {\n        int size = OperationUtils.getInstance().getSavePoints().size();\n        Log.d(\"gpy\", \"显示文字列表--\"+size);\n        this.removeAllViews();\n        if(size==0){\n            return;\n        }\n        for(int i = 0;i<size;i++){\n            DrawPoint dp =  OperationUtils.getInstance().getSavePoints().get(i);\n            if(dp.getType() == OperationUtils.DRAW_TEXT&&dp.getDrawText().getIsVisible()&&dp.getDrawText().getStatus()!=DrawTextView.TEXT_DELETE){\n                final DrawTextView dw = new DrawTextView(mContext,\n                        dp, mCallBackListener);\n                dw.setTag(i);\n                this.addView(dw);\n//                }\n            }\n        }\n    }\n    /**\n     * 文字编辑之后\n     */\n    public  void afterEdit(boolean isSave){\n        ((DrawTextView)getChildAt(getChildCount()-1)).afterEdit(isSave);\n    }\n\n    private void showNewPoint(DrawPoint dp) {\n        Log.d(\"gpy\", \"显示新建文字\");\n            if(dp.getType() == OperationUtils.DRAW_TEXT&&dp.getDrawText().getIsVisible()&&dp.getDrawText().getStatus()!=DrawTextView.TEXT_DELETE){\n                final DrawTextView dw = new DrawTextView(mContext,\n                        dp, mCallBackListener);\n                this.addView(dw);\n            }\n    }\n\n    private DrawTextView.CallBackListener mCallBackListener = new  DrawTextView.CallBackListener() {\n\n        @Override\n        public void onUpdate(DrawPoint drawPoint) {\n            updatePoint(drawPoint);\n            showPoints();\n        }\n\n    };\n\n    private void updatePoint(DrawPoint drawPoint) {\n        Log.d(\"修改标注\", \"-\" + drawPoint.getDrawText().getX() + \",\" + drawPoint.getDrawText().getY());\n        int size = OperationUtils.getInstance().getSavePoints().size();\n        for (int i = size - 1; i >= 0; i--) {\n            DrawPoint temp = OperationUtils.getInstance().getSavePoints().get(i);\n            if (temp.getType()== OperationUtils.DRAW_TEXT&&temp.getDrawText().getId() == drawPoint.getDrawText().getId()) {//如果文字组件是之前已存在，则隐藏之前的\n                OperationUtils.getInstance().getSavePoints().get(i).getDrawText().setIsVisible(false);\n                break;\n            }\n        }\n        if(!TextUtils.isEmpty(drawPoint.getDrawText().getStr())){\n            OperationUtils.getInstance().getSavePoints().add(drawPoint);\n            EventBus.postEvent(Events.WHITE_BOARD_UNDO_REDO);\n        }\n        OperationUtils.getInstance().getDeletePoints().clear();\n\n\n    }\n    /**设置文字风格：下划线、粗体、斜体等*/\n    public void setTextStyle(int changeStyle){\n        int size = OperationUtils.getInstance().getSavePoints().size();\n        if(size==0){\n            return;\n        }\n        DrawPoint dp = OperationUtils.getInstance().getSavePoints().get(size - 1);\n        if(dp.getType()== OperationUtils.DRAW_TEXT){\n            DrawPoint temp = DrawPoint.copyDrawPoint(dp);\n            switch (changeStyle){\n                case WhiteBoardVariable.TextStyle.CHANGE_UNDERLINE:\n                    temp.getDrawText().setIsUnderline(!temp.getDrawText().getIsUnderline());\n                    break;\n                case  WhiteBoardVariable.TextStyle.CHANGE_ITALICS:\n                    temp.getDrawText().setIsItalics(!temp.getDrawText().getIsItalics());\n                    break;\n                case  WhiteBoardVariable.TextStyle.CHANGE_BOLD:\n                    temp.getDrawText().setIsBold(!temp.getDrawText().getIsBold());\n                    break;\n            }\n\n            updatePoint(temp);\n            showPoints();\n        }\n    }\n    /**设置文字颜色*/\n    public void setTextColor(){\n        int size = OperationUtils.getInstance().getSavePoints().size();\n        if(size==0){\n            return;\n        }\n        DrawPoint dp = OperationUtils.getInstance().getSavePoints().get(size-1);\n        if(dp.getType()== OperationUtils.DRAW_TEXT&&dp.getDrawText().getStatus()==DrawTextView.TEXT_DETAIL){\n            DrawPoint temp = DrawPoint.copyDrawPoint(dp);\n            temp.getDrawText().setColor(OperationUtils.getInstance().mCurrentColor);\n            updatePoint(temp);\n            showPoints();\n        }\n    }\n    /**撤销*/\n    public void undo(){\n        DrawPoint drawPoint = OperationUtils.getInstance().getDeletePoints().get(OperationUtils.getInstance().getDeletePoints().size()-1);\n        int size = OperationUtils.getInstance().getSavePoints().size();\n        if(size>0) {\n            for (int i = size - 1; i >= 0; i--) {\n                DrawPoint temp = OperationUtils.getInstance().getSavePoints().get(i);\n                if (temp.getType() == OperationUtils.DRAW_TEXT && temp.getDrawText().getId() == drawPoint.getDrawText().getId()) {//如果文字组件是之前已存在，则显示最近的\n                    OperationUtils.getInstance().getSavePoints().get(i).getDrawText().setIsVisible(true);\n                    break;\n                }\n            }\n        }\n        showPoints();\n    }\n    /**重做*/\n    public void redo(){\n        int size = OperationUtils.getInstance().getSavePoints().size();\n        DrawPoint drawPoint = OperationUtils.getInstance().getSavePoints().get(size - 1);\n        if(size>1) {\n            for (int i = size - 2; i >= 0; i--) {\n                DrawPoint temp = OperationUtils.getInstance().getSavePoints().get(i);\n                if (temp.getType() == OperationUtils.DRAW_TEXT && temp.getDrawText().getId() == drawPoint.getDrawText().getId()) {//如果文字组件是之前已存在，则隐藏之前的\n                    OperationUtils.getInstance().getSavePoints().get(i).getDrawText().setIsVisible(false);\n                    break;\n                }\n            }\n        }\n        showPoints();\n    }\n\n    /**\n     * 根据手机的分辨率从 dp 的单位 转成为 px(像素)\n     */\n    public int dip2px(float dpValue) {\n        final float scale = mContext.getResources().getDisplayMetrics().density;\n        return (int) (dpValue * scale + 0.5f);\n    }\n}\n"
  },
  {
    "path": "wblib/src/main/java/com/github/guanpy/wblib/widget/DrawTextView.java",
    "content": "package com.github.guanpy.wblib.widget;\n\nimport android.app.Activity;\nimport android.content.Context;\nimport android.graphics.Paint;\nimport android.text.Spannable;\nimport android.text.TextUtils;\nimport android.util.Log;\nimport android.view.Display;\nimport android.view.LayoutInflater;\nimport android.view.MotionEvent;\nimport android.view.View;\nimport android.view.inputmethod.InputMethodManager;\nimport android.widget.Button;\nimport android.widget.EditText;\nimport android.widget.RelativeLayout;\nimport android.widget.TextView;\n\nimport com.github.guanpy.library.EventBus;\nimport com.github.guanpy.wblib.R;\nimport com.github.guanpy.wblib.bean.DrawPoint;\nimport com.github.guanpy.wblib.utils.Events;\nimport com.github.guanpy.wblib.utils.OperationUtils;\n\n\npublic class DrawTextView extends RelativeLayout implements\n        View.OnClickListener {\n\n    /**\n     * 显示状态\n     */\n    public static final int TEXT_VIEW = 1;\n    /**\n     * 编辑（文字编辑）状态\n     */\n    public static final int TEXT_EDIT = 2;\n    /**\n     * 详情（显示删除、编辑按钮）状态\n     */\n    public static final int TEXT_DETAIL = 3;\n    /**\n     * 被删除状态\n     */\n    public static final int TEXT_DELETE = 4;\n\n    /** */\n    private View mVOutside;\n    /** */\n    private RelativeLayout mRlContent;\n    /** */\n    private RelativeLayout mRlText;\n    /** */\n    private EditText mEtTextEdit;\n    /** */\n    private TextView mTvTextEdit;\n    /** */\n    private Button mBtTextDelete;\n    /** */\n    private Button mBtTextEdit;\n\n    private Context mContext;\n\n    private CallBackListener mCallBackListener;\n\n    private DrawPoint mDrawPoint;\n\n    private int mWidth;\n    /**\n     * 特殊字符所需\n     */\n    private Spannable mSpannable;\n\n    public DrawTextView(Context context\n            , DrawPoint drawPoint,\n                        CallBackListener callBackListener) {\n        super(context);\n        init(context, drawPoint, callBackListener);\n    }\n\n    private void init(Context context\n            , DrawPoint drawPoint,\n                      CallBackListener callBackListener) {\n        mContext = context;\n        mDrawPoint = DrawPoint.copyDrawPoint(drawPoint);\n        mCallBackListener = callBackListener;\n        Display display = ((Activity) mContext).getWindowManager()\n                .getDefaultDisplay();\n        mWidth = display.getWidth();\n        initUI();\n        initEvent();\n        switchView(mDrawPoint.getDrawText().getStatus());\n\n    }\n\n\n    /**\n     * 初始化界面控件 <br>\n     * Created 2015-8-10 16:55:49\n     *\n     * @author : gpy\n     */\n    private void initUI() {\n        LayoutInflater.from(mContext).inflate(R.layout.draw_text, this, true);\n        mVOutside = (View) findViewById(R.id.v_outside);\n        mRlContent = (RelativeLayout) findViewById(R.id.rl_content);\n        mRlText = (RelativeLayout) findViewById(R.id.rl_text);\n        mEtTextEdit = (EditText) findViewById(R.id.et_text_edit);\n        mTvTextEdit = (TextView) findViewById(R.id.tv_text_edit);\n        mBtTextDelete = (Button) findViewById(R.id.bt_text_delete);\n        mBtTextEdit = (Button) findViewById(R.id.bt_text_edit);\n        if (null != mDrawPoint) {\n            setText(mDrawPoint.getDrawText().getStr());\n        }\n        setLayoutParams();\n\n    }\n\n    /**\n     * 初始化监听 <br>\n     * Created 2015-8-10 16:55:49\n     *\n     * @author : gpy\n     */\n    private void initEvent() {\n        mVOutside.setOnClickListener(this);\n        mRlText.setOnClickListener(this);\n        mEtTextEdit.setOnClickListener(this);\n        mBtTextDelete.setOnClickListener(this);\n        mBtTextEdit.setOnClickListener(this);\n        mTvTextEdit.setOnClickListener(this);\n        mTvTextEdit.setOnTouchListener(new OnTouchListener() {\n            int lastX, lastY;\n\n            @Override\n            public boolean onTouch(View view, MotionEvent event) {\n                if (mDrawPoint.getDrawText().getStatus() == TEXT_DETAIL&& OperationUtils.getInstance().DISABLE) {\n                    int ea = event.getAction();\n                    switch (ea) {\n                        case MotionEvent.ACTION_DOWN:\n                            // 获取触摸事件触摸位置的原始X坐标\n                            lastX = (int) event.getRawX();\n                            lastY = (int) event.getRawY();\n                            break;\n                        case MotionEvent.ACTION_MOVE:\n                            int dx = (int) event.getRawX() - lastX;\n                            int dy = (int) event.getRawY() - lastY;\n\n                            int left = mRlContent.getLeft() + dx;\n                            int top = mRlContent.getTop() + dy;\n                            int right = mRlContent.getRight() + dx;\n                            int bottom = mRlContent.getBottom() + dy;\n                            if (left < 0) {\n                                left = 0;\n                                right = left + mRlContent.getWidth();\n                            }\n                            if (right > getWidth()) {\n                                right = getWidth();\n                                left = right - mRlContent.getWidth();\n                            }\n                            if (top < 0) {\n                                top = 0;\n                                bottom = top + mRlContent.getHeight();\n                            }\n                            if (bottom > getHeight()) {\n                                bottom = getHeight();\n                                top = bottom - mRlContent.getHeight();\n                            }\n                            mDrawPoint.getDrawText().setX(left);\n                            mDrawPoint.getDrawText().setY(top);\n                            Log.e(\"移动\", \"-\" + left + \",\" + top);\n                            mRlContent.layout(left, top, right, bottom);\n                            lastX = (int) event.getRawX();\n                            lastY = (int) event.getRawY();\n                            break;\n                        case MotionEvent.ACTION_UP:\n                            if (null != mCallBackListener) {\n                                mCallBackListener.onUpdate(mDrawPoint);\n                            }\n                            break;\n                    }\n                }\n\n                return false;\n            }\n        });\n    }\n\n\n    private void setText(String strText) {\n        if (!TextUtils.isEmpty(strText)) {\n            mEtTextEdit.setText(strText);\n            mTvTextEdit.setText(strText);\n        }\n        mEtTextEdit.setTextColor(mDrawPoint.getDrawText().getColor());\n        mTvTextEdit.setTextColor(mDrawPoint.getDrawText().getColor());\n        if (mDrawPoint.getDrawText().getIsUnderline()) {\n            mTvTextEdit.getPaint().setFlags(Paint.UNDERLINE_TEXT_FLAG);\n            mEtTextEdit.getPaint().setFlags(Paint.UNDERLINE_TEXT_FLAG);\n        }\n        if (mDrawPoint.getDrawText().getIsBold()) {\n            mTvTextEdit.getPaint().setFakeBoldText(true);\n            mEtTextEdit.getPaint().setFakeBoldText(true);\n        }\n\n    }\n\n    private void setLayoutParams() {\n        LayoutParams layParamsTxt = new LayoutParams(\n                LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);\n        layParamsTxt.leftMargin = (int) mDrawPoint.getDrawText().getX();\n        layParamsTxt.topMargin = (int) mDrawPoint.getDrawText().getY();\n        mRlContent.setLayoutParams(layParamsTxt);\n    }\n\n    public void switchView(int currentStatus) {\n        switch (currentStatus) {\n            case TEXT_VIEW:\n                mVOutside.setVisibility(View.GONE);\n                mEtTextEdit.setVisibility(View.GONE);\n                mTvTextEdit.setVisibility(View.VISIBLE);\n                mRlText.setBackgroundResource(\n                        R.color.transparent);\n                mBtTextEdit.setVisibility(View.GONE);\n                mBtTextDelete.setVisibility(View.GONE);\n                break;\n            case TEXT_EDIT:\n                mVOutside.setBackgroundResource(R.color.white);\n                mVOutside.setVisibility(View.VISIBLE);\n                mEtTextEdit.setVisibility(View.VISIBLE);\n                mTvTextEdit.setVisibility(View.GONE);\n                mRlText.setBackgroundResource(R.drawable.draw_text_border);\n                mBtTextEdit.setVisibility(View.GONE);\n                mEtTextEdit.setSelection(mEtTextEdit.getText().length());\n                mBtTextDelete.setVisibility(View.GONE);\n                EventBus.postEvent(Events.WHITE_BOARD_TEXT_EDIT);\n                showSoftKeyBoard(mEtTextEdit);\n                break;\n            case TEXT_DETAIL:\n                mVOutside.setBackgroundResource(R.color.transparent);\n                mVOutside.setVisibility(View.VISIBLE);\n                mEtTextEdit.setVisibility(View.GONE);\n                mTvTextEdit.setVisibility(View.VISIBLE);\n                mRlText.setBackgroundResource(R.drawable.draw_text_border);\n                mBtTextEdit.setVisibility(View.VISIBLE);\n                mBtTextDelete.setVisibility(View.VISIBLE);\n                break;\n            case TEXT_DELETE:\n\n                break;\n            default:\n                break;\n        }\n        Log.d(\"gpy\",\"文字宽：\"+mRlText.getHeight());\n        if (mDrawPoint.getDrawText().getStatus() != currentStatus) {\n            mDrawPoint.getDrawText().setStatus(currentStatus);\n            if (null != mCallBackListener && currentStatus != TEXT_EDIT) {\n                mCallBackListener.onUpdate(mDrawPoint);\n            }\n        }\n\n    }\n\n    /**\n     * 文字编辑完成\n     *\n     * @param isSave 是否保存\n     */\n    public void afterEdit(boolean isSave) {\n        Log.d(\"gpy\", \"要保存的文字：\" + mEtTextEdit.getText().toString());\n        if (isSave) {\n            mDrawPoint.getDrawText().setStr(mEtTextEdit.getText().toString());\n        }\n        switchView(TEXT_VIEW);\n        hideSoftInput();\n    }\n\n    @Override\n    public void onClick(View v) {\n        int vId = v.getId();\n        if (vId == R.id.v_outside) {\n            if (mDrawPoint.getDrawText().getStatus() == TEXT_DETAIL && OperationUtils.getInstance().DISABLE) {\n                switchView(TEXT_VIEW);\n            }\n            hideSoftInput();\n        } else if (vId == R.id.tv_text_edit) {\n            if (OperationUtils.getInstance().DISABLE) {\n                switchView(TEXT_DETAIL);\n            }\n        } else if (vId == R.id.bt_text_delete) {\n            if (OperationUtils.getInstance().DISABLE) {\n                switchView(TEXT_DELETE);\n            }\n        } else if (vId == R.id.bt_text_edit) {\n            if (OperationUtils.getInstance().DISABLE) {\n                switchView(TEXT_EDIT);\n            }\n        }\n    }\n\n    public interface CallBackListener {\n        /**\n         * 更新文字属性\n         */\n        void onUpdate(DrawPoint drawPoint);\n    }\n\n    private void showSoftKeyBoard(final EditText et) {\n        et.requestFocus();\n        et.post(new Runnable() {\n            @Override\n            public void run() {\n                // 弹出输入法\n                InputMethodManager imm = (InputMethodManager) mContext.getSystemService(Context.INPUT_METHOD_SERVICE);\n                imm.showSoftInput(et, InputMethodManager.RESULT_UNCHANGED_SHOWN);\n            }\n        });\n    }\n\n    private void hideSoftInput() {\n        if (this == null || mContext == null || mEtTextEdit == null) {\n            return;\n        }\n        // 隐藏输入法\n        ((InputMethodManager) mContext.getSystemService(Context.INPUT_METHOD_SERVICE))\n                .hideSoftInputFromWindow(mEtTextEdit.getWindowToken(), 0);\n    }\n}\n"
  },
  {
    "path": "wblib/src/main/res/drawable/draw_text_border.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<shape xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:shape=\"rectangle\">\n    <solid android:color=\"@color/white_board_drawtext_back\" />\n    <stroke\n        android:width=\"0.5dip\"\n        android:color=\"@color/grey_3e\" />\n</shape>"
  },
  {
    "path": "wblib/src/main/res/layout/draw_text.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<RelativeLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\"\n    android:background=\"@color/transparent\">\n\n    <View\n        android:id=\"@+id/v_outside\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"match_parent\"\n        android:background=\"@color/transparent\" />\n\n    <RelativeLayout\n        android:id=\"@+id/rl_content\"\n        android:layout_width=\"wrap_content\"\n        android:layout_height=\"wrap_content\">\n\n        <RelativeLayout\n            android:id=\"@+id/rl_text\"\n            android:layout_width=\"wrap_content\"\n            android:layout_height=\"wrap_content\"\n            android:layout_marginLeft=\"15dip\"\n            android:layout_marginRight=\"15dip\"\n            android:background=\"@drawable/draw_text_border\"\n            android:gravity=\"center_vertical\"\n            android:paddingTop=\"25dip\"\n            android:paddingBottom=\"25dip\"\n            android:paddingLeft=\"30dip\"\n            android:paddingRight=\"30dip\">\n\n            <EditText\n                android:id=\"@+id/et_text_edit\"\n                android:layout_width=\"wrap_content\"\n                android:layout_height=\"wrap_content\"\n                android:background=\"@color/transparent\"\n                android:minWidth=\"20dip\"\n                android:textSize=\"24sp\"\n                android:singleLine=\"true\"\n                android:visibility=\"gone\" />\n\n            <TextView\n                android:id=\"@+id/tv_text_edit\"\n                android:layout_width=\"wrap_content\"\n                android:layout_height=\"wrap_content\"\n                android:background=\"@color/transparent\"\n                android:minWidth=\"20dip\"\n                android:textSize=\"24sp\"\n                android:singleLine=\"true\"\n                android:clickable=\"true\"\n                android:visibility=\"visible\" />\n        </RelativeLayout>\n\n        <Button\n            android:id=\"@+id/bt_text_delete\"\n            android:layout_width=\"30dip\"\n            android:layout_height=\"30dip\"\n            android:layout_alignParentLeft=\"true\"\n            android:layout_centerVertical=\"true\"\n            android:background=\"@drawable/draw_text_delete\" />\n\n        <Button\n            android:id=\"@+id/bt_text_edit\"\n            android:layout_width=\"30dip\"\n            android:layout_height=\"30dip\"\n            android:layout_centerVertical=\"true\"\n            android:layout_marginLeft=\"-30dip\"\n            android:layout_toRightOf=\"@+id/rl_text\"\n            android:background=\"@drawable/draw_text_edit\" />\n    </RelativeLayout>\n\n</RelativeLayout>"
  },
  {
    "path": "wblib/src/main/res/values/colors.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <color name=\"colorPrimary\">#3F51B5</color>\n    <color name=\"colorPrimaryDark\">#303F9F</color>\n    <color name=\"colorAccent\">#FF4081</color>\n\n    <color name=\"white\">#ffffff</color>\n    <color name=\"transparent\">#00000000</color>\n    <color name=\"transparent_50\">#7f000000</color>\n    <color name=\"cover\">#cc2c1670</color>\n    <color name=\"black_semi_transparent\">#B2000000</color>\n    <color name=\"primary_black\">#3e3e3e</color>\n    <color name=\"grey_3e\">#3e3e3e</color>\n    <color name=\"orange\">#ff6a00</color>\n    <color name=\"light_red\">#f54983</color>\n    <color name=\"primary_purple\">#663fde</color>\n    <color name=\"green\">#24a8a3</color>\n    <color name=\"white_board_drawtext_back\">#f7f7f7</color>\n</resources>\n"
  },
  {
    "path": "wblib/src/main/res/values/strings.xml",
    "content": "<resources>\n    <string name=\"app_name\">wblib</string>\n</resources>\n"
  }
]